Index: dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Extensions.cs
===================================================================
diff -u -r316 -r330
--- dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Extensions.cs (.../SurfaceLine2Extensions.cs) (revision 316)
+++ dam engine/branches/Initial Source/Deltares.DamEngine.Data/Geotechnics/SurfaceLine2Extensions.cs (.../SurfaceLine2Extensions.cs) (revision 330)
@@ -23,6 +23,7 @@
using System.Collections.Generic;
using System.Linq;
using Deltares.DamEngine.Data.Geometry;
+using Deltares.DamEngine.Data.Standard;
namespace Deltares.DamEngine.Data.Geotechnics
{
@@ -134,5 +135,412 @@
IsDefined(line, CharacteristicPointType.DikeTopAtPolder) &&
IsDefined(line, CharacteristicPointType.DikeToeAtPolder);
}
+
+ ///
+ /// Add 2D characteristic point without a type
+ ///
+ /// The surfaceline to be modified.
+ /// The x.
+ /// The z.
+ public static void EnsurePoint(this SurfaceLine2 line, double x, double z)
+ {
+ line.EnsurePointOfType(x, z, null);
+ }
+
+ ///
+ /// Add characteristic point in X-Z plane
+ ///
+ /// The surfaceline to be modified.
+ /// The x.
+ /// The z.
+ /// The type.
+ public static void EnsurePointOfType(this SurfaceLine2 line, double x, double z, CharacteristicPointType? type)
+ {
+ if (!line.CharacteristicPoints.GeometryMustContainPoint)
+ {
+ throw new NotImplementedException("SurfaceLine specific method, not implemented for 'Ringtoets'-mode.");
+ }
+
+ bool movedPointToMatch = false;
+ bool addPoint = false;
+ Point2D point = null;
+ var newPoint = new Point2D()
+ {
+ X = x,
+ Z = z
+ };
+ GeometryPoint gp = null;
+ if (type.HasValue)
+ {
+ // Get point of this type..
+ gp = line.CharacteristicPoints.GetGeometryPoint(type.Value);
+ if (gp != null)
+ {
+ point = new Point2D(gp.X, gp.Z);
+ // Characteristic point annotation set, check location...
+ if (point.LocationEquals(newPoint))
+ {
+ // Annotated point is at given location; We're done here! :)
+ return;
+ }
+ else
+ {
+ bool isAssignedToOtherCharacteristicPoints =
+ line.GetCharacteristicPoints(gp).Count(cpt => cpt != CharacteristicPointType.None) > 1;
+ if (isAssignedToOtherCharacteristicPoints)
+ {
+ // Other characteristic points exist with the same coordinates so add as new point
+ point = line.Geometry.GetPointAt(newPoint.X, newPoint.Z); // Get point at specified coords
+ if (point == null)
+ {
+ point = newPoint;
+ addPoint = true;
+ }
+ }
+ else
+ {
+ // Point is unique as characteristic point so set its coords to specified coords
+ point.X = x;
+ point.Z = z;
+ movedPointToMatch = true;
+ }
+ gp.X = point.X;
+ gp.Z = point.Z;
+ }
+ }
+ }
+ if (point == null)
+ {
+ point = line.Geometry.GetPointAt(x, z); // Get point at specified coords
+ }
+ if (point == null)
+ {
+ point = new Point2D()
+ {
+ X = x,
+ Z = z
+ };
+ addPoint = true;
+ }
+ if (addPoint)
+ {
+ var newgp = new GeometryPoint(point.X, point.Z);
+ line.Geometry.Points.Add(newgp);
+ line.AddCharacteristicPoint(newgp, type ?? CharacteristicPointType.None);
+ }
+ else if (type.HasValue && !movedPointToMatch)
+ {
+ if (line.CharacteristicPoints.Any(cp => ReferenceEquals(cp.GeometryPoint, gp) &&
+ cp.CharacteristicPointType != CharacteristicPointType.None))
+ {
+ line.AddCharacteristicPoint(gp, type.Value);
+ }
+ else
+ {
+ int index = -1;
+ for (int i = 0; i < line.CharacteristicPoints.Count; i++)
+ {
+ if (ReferenceEquals(line.CharacteristicPoints[i].GeometryPoint, gp))
+ {
+ index = i;
+ break;
+ }
+ }
+ line.CharacteristicPoints.Annotate(index, type.Value);
+ }
+ }
+ }
+
+ ///
+ /// Removes the points between the two x values. The start and end points will
+ /// not be removed.
+ ///
+ /// Surfaceline being modified.
+ /// The non-inclusive starting X-coordinate.
+ /// The non-inclusive ending X-coordinate.
+ ///
+ public static void RemoveSegmentBetween(this SurfaceLine2 line, double startX, double endX)
+ {
+ RemoveGeometryPointsInRange(line, startX, endX, false);
+ }
+
+ ///
+ /// Removes the points between the two x values.
+ ///
+ /// Surfaceline being modified.
+ /// The inclusive starting X-Coordinate.
+ /// The inclusive ending X-Coordinate.
+ ///
+ public static void RemoveSegmentIncluding(this SurfaceLine2 line, double startX, double endX)
+ {
+ RemoveGeometryPointsInRange(line, startX, endX, true);
+ }
+
+ ///
+ /// Removes the points between the two x values.
+ ///
+ /// Surfaceline being modified.
+ /// The starting X-Coordinate.
+ /// The ending X-Coordinate.
+ /// Indicates if and
+ /// are inclusive bounds or not.
+ private static void RemoveGeometryPointsInRange(SurfaceLine2 line, double startX, double endX, bool isInclusiveRange)
+ {
+ foreach (var geometryPoint in GetGeometryPointsWithinRange(line, startX, endX, isInclusiveRange).ToArray())
+ {
+ var characteristicPoints = line.CharacteristicPoints.Where(cp => ReferenceEquals(cp.GeometryPoint, geometryPoint)).ToArray();
+ if (characteristicPoints.Length > 0)
+ {
+ // CharacteristicPointSet will manage both collections of CharacteristicPoint instances and Geometry
+ foreach (var characteristicPoint in characteristicPoints)
+ {
+ line.CharacteristicPoints.Remove(characteristicPoint);
+ }
+ }
+ else
+ {
+ // Notify change such that CharacteristicPointSet instances observing this
+ // geometry can update if required.
+ line.Geometry.Points.Remove(geometryPoint);
+ }
+ }
+ }
+
+ ///
+ /// Retrieve all instances of a surfaceline that
+ /// fall with the range.
+ ///
+ /// Surfaceline being evaluated.
+ /// Starting X-coordinate.
+ /// Ending X-coordinate.
+ /// Indicates if and
+ /// are inclusive bounds or not.
+ /// Collection of characteristic points within the given range.
+ private static IEnumerable GetGeometryPointsWithinRange(SurfaceLine2 line,
+ double startX, double endX, bool isInclusiveRange)
+ {
+ if (isInclusiveRange)
+ {
+ return line.Geometry.Points.Where(cp => (cp.X >= startX || cp.X.AlmostEquals(startX, GeometryPoint.Precision)) &&
+ (cp.X <= endX || cp.X.AlmostEquals(endX, GeometryPoint.Precision)));
+ }
+ return line.Geometry.Points.Where(cp => cp.X > startX && cp.X < endX);
+ }
+
+ ///
+ /// Checks if a surfaceline has all characteristic point types required to describe
+ /// an inside shoulder.
+ ///
+ /// Surfaceline to be checked.
+ /// True if there are characteristic points defined that described the
+ /// inside shoulder; False otherwise.
+ public static bool HasShoulderInside(this SurfaceLine2 line)
+ {
+ return IsDefined(line, CharacteristicPointType.ShoulderTopInside) &&
+ IsDefined(line, CharacteristicPointType.ShoulderBaseInside);
+ }
+
+ ///
+ /// Checks if a surfaceline has all characteristic point types required to describe
+ /// a ditch.
+ ///
+ /// Surfaceline to be checked.
+ /// True if there are characteristic points defined that described the
+ /// ditch; False otherwise.
+ public static bool HasDitch(this SurfaceLine2 line)
+ {
+ return IsDefined(line, CharacteristicPointType.DitchDikeSide) &&
+ IsDefined(line, CharacteristicPointType.DitchPolderSide);
+ }
+
+ ///
+ /// Determines whether ditch is correct.
+ ///
+ /// true if ditch is correct, otherwise false
+ /// This methods checks if the following points have their X cooridnates
+ /// properly defined:
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static bool IsDitchCorrect(this SurfaceLine2 line)
+ {
+ // No ditch then always ok
+ bool res = !line.HasDitch();
+ if (!res)
+ {
+ // check the unchecked points
+ var bottomDitchDikeSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide);
+ var bottomDitchPolderSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide);
+ res = (bottomDitchDikeSide != null && bottomDitchPolderSide != null);
+
+ // check the ditch points describe following shape:
+ // 0 0
+ // \ /
+ // 0---0
+ var ditchPolderSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide);
+ var ditchDikeSide = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide);
+ if (res)
+ {
+ res = ditchPolderSide.X >= bottomDitchPolderSide.X &&
+ bottomDitchPolderSide.X >= bottomDitchDikeSide.X &&
+ bottomDitchDikeSide.X >= ditchDikeSide.X &&
+ bottomDitchDikeSide.Z <= ditchDikeSide.Z &&
+ bottomDitchPolderSide.Z <= ditchPolderSide.Z;
+ }
+ }
+ return res;
+ }
+
+ ///
+ /// Gets the starting point of the surface line.
+ ///
+ /// Starting point, or null if none of the considered points can be found.
+ ///
+ /// Method looks for the following characteristic points (in this order) and returns
+ /// the corresponding geometry point if present:
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static GeometryPoint GetStartingPoint(this SurfaceLine2 line)
+ {
+ return line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseOutside) ??
+ line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopOutside) ??
+ line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver);
+ }
+
+ ///
+ /// Gets the default height of the dike table.
+ ///
+ /// null or height of table
+ public static double? GetDefaultDikeTableHeight(this SurfaceLine2 line)
+ {
+ // Consulted Erik Vastenburg about this: Use buitenkruinlijn as default DTH
+ GeometryPoint point = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
+ return point == null ? null : (double?)point.Z;
+ }
+
+ ///
+ /// Make sure river level is above the bottom of the river.
+ ///
+ /// The evaluated surfaceline.
+ /// The current river level.
+ /// Bottom of the river if bottomlevel is above riverLevel, else
+ /// is required to have the characteristic point
+ /// when
+ /// is not null.
+ ///
+ public static double? EnsureWaterLevelIsAboveRiverBottom(this SurfaceLine2 line, double? riverLevel)
+ {
+ // Waterlevel is supposed to be at level of SurfaceLevelOutside when waterlevel
+ // is below SurfaceLevelOutside (is the bottom of the river)
+ if (riverLevel.HasValue)
+ {
+ double z = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside).Z;
+ riverLevel = Math.Max(z, riverLevel.Value);
+ }
+ return riverLevel;
+ }
+
+ ///
+ /// Determines the intersection of a horizontal line with the surfaceline, starting
+ /// from to .
+ ///
+ /// The surfaceline being evaluated.
+ /// The height of the horizontal line.
+ /// The GeometryPoint at the intersection, or null if no intersection can
+ /// be found.
+ ///
+ /// Requires that the following characteristic points are defined:
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// This method draws the horizontal line starting from the smallest X available
+ /// in the geometry to .
+ ///
+ /// When greater than
+ /// the height of the characteristic point .
+ ///
+ public static GeometryPoint DetermineIntersectionWithLevel(this SurfaceLine2 line, double level)
+ {
+ double startXCoordinate = line.Geometry.GetMinX();
+ var waterlevelLine = GetWaterlevelLineStartingFrom(line, level, startXCoordinate);
+
+ return DetermineIntersectionWithHorizontalLevel(line, waterlevelLine);
+ }
+
+ ///
+ /// Create a horizontal line from a given starting X coordinate and ending at the
+ /// X coordinate of defined
+ /// in the surfaceline.
+ ///
+ /// The referenced surfaceline.
+ /// The height level of the horizontal line.
+ /// The starting coordinate.
+ /// The line segment.
+ private static Line GetWaterlevelLineStartingFrom(SurfaceLine2 line, double level, double startXCoordinate)
+ {
+ GeometryPoint pointEndOfprofile = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside);
+ var waterlevelLine = new Line();
+ waterlevelLine.CreateHorizontalZLine(startXCoordinate, pointEndOfprofile.X, level);
+
+ return waterlevelLine;
+ }
+
+ ///
+ /// Finds the intersection point of a given horizontal line and the river side talud.
+ ///
+ /// The evaluated surfaceline.
+ /// The horizontal line.
+ /// The intersection point, or null in case no intersection was found.
+ /// When height of the horizontal line is
+ /// greater than the height of the characteristic point .
+ private static GeometryPoint DetermineIntersectionWithHorizontalLevel(SurfaceLine2 line, Line waterlevelLine)
+ {
+ ThrowWhenLevelAboveDike(line, waterlevelLine.BeginPoint.Z);
+
+ var list = line.Geometry.Points.Where(point =>
+ point.X >= line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside).X &&
+ point.X <= line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X).ToList();
+
+ for (int i = 1; i < list.Count; i++)
+ {
+ var surfaceLineSegment = new Line();
+ surfaceLineSegment.SetBeginAndEndPoints(
+ new Point2D(list[i - 1].X, list[i - 1].Z),
+ new Point2D(list[i].X, list[i].Z));
+
+ var intersectPoint = surfaceLineSegment.GetIntersectPointXz(waterlevelLine);
+ if (intersectPoint != null)
+ {
+ return new GeometryPoint(intersectPoint.X, intersectPoint.Z);
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Throw an in case the given height level is
+ /// higher than the characteristic point .
+ ///
+ private static void ThrowWhenLevelAboveDike(SurfaceLine2 line, double Level)
+ {
+ var dikeTopAtRiver = line.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
+ if (Level > dikeTopAtRiver.Z)
+ {
+ throw new SurfaceLineException(String.Format(
+ "Level ({0:F2} m) should NOT be higher than surface line ({1:F2}))",
+ Level, dikeTopAtRiver.Z));
+ }
+ }
}
}
\ No newline at end of file