// Copyright (C) Stichting Deltares 2018. All rights reserved.
//
// This file is part of the Dam Engine.
//
// The Dam Engine is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Standard;
using Deltares.DamEngine.Data.Standard.Language;
using Deltares.DamEngine.Data.Standard.Validation;
namespace Deltares.DamEngine.Data.Geotechnics
{
///
/// Representation of a surface line with characteristic point annotations.
///
/// Extension methods can be found in .
public class SurfaceLine2 : GeometryObject
{
private CharacteristicPointSet characteristicPoints;
private GeometryPointString geometry;
///
/// Create a new empty surface line.
///
public SurfaceLine2()
{
geometry = new GeometryPointString();
characteristicPoints = new CharacteristicPointSet
{
GeometryMustContainPoint = true
};
LandwardDirection = LandwardDirection.PositiveX;
Name = LocalizationManager.GetTranslatedText(this, "DefaultNameSurfaceLine2");
}
///
/// Deep clone the object.
///
///
public SurfaceLine2 FullDeepClone()
{
SurfaceLine2 surfaceLine2 = new SurfaceLine2();
surfaceLine2.SetValuesFromOtherSurfaceLine(this, true);
return surfaceLine2;
}
///
/// The geometrical description of the surface line.
///
/// Aggregation relationship.
public GeometryPointString Geometry
{
get
{
return geometry;
}
set
{
geometry = value;
CharacteristicPoints.Geometry = geometry;
}
}
///
/// The characteristic point annotations for .
///
/// Cannot be null.
public CharacteristicPointSet CharacteristicPoints
{
get
{
return characteristicPoints;
}
set
{
characteristicPoints = value;
characteristicPoints.Geometry = geometry;
}
}
///
/// Determines toward which direction land is expected. Value is used as reference.
///
public LandwardDirection LandwardDirection { get; set; }
///
/// Define a new characteristic point on the surface line with the given characteristic
/// point annotation.
///
/// The point to be added. Cannot be null.
/// The annotations for .
public void AddCharacteristicPoint(GeometryPoint geometryPoint, params CharacteristicPointType[] annotations)
{
if (annotations == null || annotations.Length == 0)
{
CharacteristicPoints.Add(new CharacteristicPoint
{
GeometryPoint = geometryPoint,
CharacteristicPointType = CharacteristicPointType.None
});
}
else
{
foreach (var type in annotations)
{
CharacteristicPoints.Add(new CharacteristicPoint
{
GeometryPoint = geometryPoint,
CharacteristicPointType = type
});
}
}
}
///
/// Define a new characteristic point on the surface line with the given characteristic
/// point annotation.
///
/// The x.
/// The y.
/// The annotations for geometryPoint with x, z/>.
public void AddCharacteristicPoint(double x, double z, params CharacteristicPointType[] annotations)
{
GeometryPoint geometryPoint = new GeometryPoint(x, z);
AddCharacteristicPoint(geometryPoint, annotations);
}
///
/// Find all characteristic point annotations corresponding with the given location.
///
///
///
public IEnumerable GetCharacteristicPoints(GeometryPoint geometryPoint)
{
return CharacteristicPoints.Where(cp => ReferenceEquals(cp.GeometryPoint, geometryPoint))
.Select(cp => cp.CharacteristicPointType);
}
///
/// Sort all points on X in a ascending manner.
///
public void SortPoints()
{
CharacteristicPoints.Sort();
}
///
/// Gets the points orderd by x.
///
///
/// The points orderd by x.
///
private IEnumerable PointsOrderdByX
{
get
{
return Geometry.Points.OrderBy(p => p.X);
}
}
///
/// Tests if the given point is between the given start X and end X.
///
/// The point.
/// The start x.
/// The end x.
/// true if the given point is between the given start X and end X, otherwise false
private bool TestIncluding(GeometryPoint point, double startX, double endX)
{
if (point == null)
{
return false;
}
double x = point.X;
return (x >= startX || x.AlmostEquals(startX, GeometryPoint.Precision))
&& (x < endX || x.AlmostEquals(endX, GeometryPoint.Precision));
}
///
/// Gets the point segment including given start x and end x.
///
/// The start x.
/// The end x.
/// collection of points between start X and end X (inlcuding those)
/// End value is smaller then the start value
public virtual IEnumerable GetPointSegmentIncluding(double startX, double endX)
{
if (endX < startX)
{
throw new ArgumentException("End value is smaller then the start value");
}
return from point in PointsOrderdByX
where TestIncluding(point, startX, endX)
orderby point.X ascending
select point;
}
///
/// Validates this surfaceline.
///
/// All validation messages.
[Validate]
public ValidationResult[] Validate()
{
return new SurfaceLine2Validator().Validate(this).ToArray();
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return Name;
}
///
/// Gets the geometry bounds (i.e. the extents for drawing)
///
///
public override GeometryBounds GetGeometryBounds()
{
if (CharacteristicPoints.Geometry != null)
{
return CharacteristicPoints.Geometry.GetGeometryBounds();
}
return null;
}
///
/// Copy all characteristic point related data from another .
///
/// Data source
public void Assign(SurfaceLine2 source)
{
SetValuesFromOtherSurfaceLine(source);
}
///
/// Sets the values from another surface line.
///
/// The source.
/// If set to true, the of
/// will be deep cloned, otherwise the reference is shared.
private void SetValuesFromOtherSurfaceLine(SurfaceLine2 source, bool cloneGeometry = false)
{
CharacteristicPoints.Clear(); // clears the whole characteristic points state.
Name = source.Name;
Geometry.Name = Name;
LandwardDirection = source.LandwardDirection;
CharacteristicPoints.GeometryMustContainPoint = source.CharacteristicPoints.GeometryMustContainPoint;
Geometry = cloneGeometry ? source.Geometry.Clone() : source.Geometry;
var geometryAnnotations = GetCharacteristicAnnotationsInSource(source, cloneGeometry);
// Reconstruct annotation state from dictionary:
if (CharacteristicPoints.GeometryMustContainPoint)
{
foreach (var annotation in geometryAnnotations)
{
for (int i = 0; i < annotation.Value.Length; i++)
{
var index = -1;
for (int j = 0; j < CharacteristicPoints.Count; j++)
{
if (ReferenceEquals(CharacteristicPoints[j].GeometryPoint, annotation.Key))
{
index = j;
break;
}
}
if (i == 0)
{
// Reassign annotation of already created CharacteristicPoint:
CharacteristicPoints.Annotate(index, annotation.Value[i]);
}
else
{
// Add new CharacteristicPoint instance for all subsequent annotations and ensuring to keep the defined order:
CharacteristicPoints.Insert(index + i, new CharacteristicPoint(CharacteristicPoints, annotation.Key)
{
CharacteristicPointType = annotation.Value[i]
});
}
}
}
}
else
{
foreach (var annotation in geometryAnnotations)
{
AddCharacteristicPoint((GeometryPoint)annotation.Key.Clone(), annotation.Value);
}
}
}
///
/// Collapses all characteristic point annotations in the given surfaceline into
/// a dictionary keyed on instances in that surfaceline
/// and their annotations.
///
/// The referenced surfaceline.
/// True if should be a clone from
/// .; false if it should
/// take the same instance instead.
/// Dictionary keyed on instances in the surfaceline
/// that have annotations.
private Dictionary GetCharacteristicAnnotationsInSource(SurfaceLine2 source, bool cloneGeometry)
{
return CharacteristicPoints.GeometryMustContainPoint
? GetCharacteristicAnnotationsInSource_GeometryMustContainPoints(source, cloneGeometry)
: GetCharacteristicAnnotationsInSource_GeometryMustNotContainPoints(source);
}
///
/// Handlers return value in case
/// is true.
///
/// The referenced surfaceline.
/// True if should be a clone from
/// .; false if it should
/// take the same instance instead.
/// Dictionary keyed on instances in the surfaceline
/// that have annotations.
private Dictionary GetCharacteristicAnnotationsInSource_GeometryMustContainPoints(SurfaceLine2 source, bool cloneGeometry)
{
var geometryAnnotations = new Dictionary();
for (int i = 0; i < source.Geometry.Count; i++)
{
var annotationsForPoint = source.GetCharacteristicPoints(source.Geometry.Points[i]).Where(cpt => cpt != CharacteristicPointType.None).ToArray();
if (annotationsForPoint.Length > 0)
{
geometryAnnotations[Geometry.Points[i]] = annotationsForPoint;
}
}
return geometryAnnotations;
}
///
/// Handles return value in case
/// is false.
///
/// The referenced surfaceline.
/// Dictionary keyed on instances in the surfaceline
/// that have annotations.
private static Dictionary GetCharacteristicAnnotationsInSource_GeometryMustNotContainPoints(SurfaceLine2 source)
{
var geometryAnnotations = new Dictionary();
foreach (var characteristicPoint in source.CharacteristicPoints)
{
if (!geometryAnnotations.ContainsKey(characteristicPoint.GeometryPoint))
{
geometryAnnotations[characteristicPoint.GeometryPoint] =
source.GetCharacteristicPoints(characteristicPoint.GeometryPoint).ToArray();
}
}
return geometryAnnotations;
}
}
}