Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/SurfaceLineShoulderAdapter.cs =================================================================== diff -u -r4000 -r4052 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/SurfaceLineShoulderAdapter.cs (.../SurfaceLineShoulderAdapter.cs) (revision 4000) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/SurfaceLineShoulderAdapter.cs (.../SurfaceLineShoulderAdapter.cs) (revision 4052) @@ -27,254 +27,253 @@ using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; -namespace Deltares.DamEngine.Calculators.DikesDesign +namespace Deltares.DamEngine.Calculators.DikesDesign; + +/// +/// Class for adapting the shoulder (berm) of a surfaceline +/// +public class SurfaceLineShoulderAdapter : SurfaceLineAdapter { /// - /// Class for adapting the shoulder (berm) of a surfaceline + /// Initializes a new instance of the class. /// - public class SurfaceLineShoulderAdapter : SurfaceLineAdapter + /// + /// + /// + /// + public SurfaceLineShoulderAdapter(SurfaceLine2 surfaceLine, Location location, double scenarioPolderLevel) : base(surfaceLine, location, scenarioPolderLevel) { - /// - /// Initializes a new instance of the class. - /// - /// - /// - /// - /// - public SurfaceLineShoulderAdapter(SurfaceLine2 surfaceLine, Location location, double scenarioPolderLevel) : base(surfaceLine, location, scenarioPolderLevel) + if (!surfaceLine.HasAnnotation(CharacteristicPointType.SurfaceLevelInside)) { - if (!surfaceLine.HasAnnotation(CharacteristicPointType.SurfaceLevelInside)) - { - throw new SurfaceLineAdapterException(); - } + throw new SurfaceLineAdapterException(); + } - SlopeOfNewShoulder = 3; // CoTangent i.e. width (dx) : height (dz) = 3 : 1 (= tangent: 1/3) - // It must be possible to define SlopeOfNewShoulder hard in code for certain options (such as Rijnland option) which should not be overriden - // by this use option. So the use option has to be implemented here in the constructor. - if (Location.UseNewShoulderBaseSlope) - { - SlopeOfNewShoulder = 1 / Location.NewShoulderBaseSlope; - } - - MaxShoulderLevel = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z; + SlopeOfNewShoulder = 3; // CoTangent i.e. width (dx) : height (dz) = 3 : 1 (= tangent: 1/3) + // It must be possible to define SlopeOfNewShoulder hard in code for certain options (such as Rijnland option) which should not be overriden + // by this use option. So the use option has to be implemented here in the constructor. + if (Location.UseNewShoulderBaseSlope) + { + SlopeOfNewShoulder = 1 / Location.NewShoulderBaseSlope; } - /// - /// Gets or sets the maximum shoulder level. - /// - /// - /// The maximum shoulder level. - /// - public double MaxShoulderLevel { get; set; } + MaxShoulderLevel = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z; + } - /// - /// Gets or sets the slope of new shoulder. - /// - /// - /// The slope of new shoulder. - /// - public double SlopeOfNewShoulder { get; set; } + /// + /// Gets or sets the maximum shoulder level. + /// + /// + /// The maximum shoulder level. + /// + public double MaxShoulderLevel { get; set; } - /// - /// shoulderLength = horizontal distance between ShoulderTopInside and ShoulderBaseInside - /// shoulderHeight = vertical distance between ShoulderTopInside and DikeToeAtPolder - /// The default slope of the shoulder will be 1 : 3 - /// The height has a maximum of MaxFractionOfDikeHeightForShoulderHeight (default 2/3) * dike height - /// - /// - /// - /// Ensure that shoulder complies with piping design Demands (shoulder from toe instead of intersection old dike, height gives error - /// - public SurfaceLine2 ConstructNewSurfaceLine(double shoulderLength, double shoulderHeight, bool designFromDikeToe) + /// + /// Gets or sets the slope of new shoulder. + /// + /// + /// The slope of new shoulder. + /// + public double SlopeOfNewShoulder { get; set; } + + /// + /// shoulderLength = horizontal distance between ShoulderTopInside and ShoulderBaseInside + /// shoulderHeight = vertical distance between ShoulderTopInside and DikeToeAtPolder + /// The default slope of the shoulder will be 1 : 3 + /// The height has a maximum of MaxFractionOfDikeHeightForShoulderHeight (default 2/3) * dike height + /// + /// + /// + /// Ensure that shoulder complies with piping design Demands (shoulder from toe instead of intersection old dike, height gives error + /// + public SurfaceLine2 ConstructNewSurfaceLine(double shoulderLength, double shoulderHeight, bool designFromDikeToe) + { + double orgMaxX = surfaceLine.Geometry.GetMaxX(); + if (double.IsNaN(orgMaxX)) { - double orgMaxX = surfaceLine.Geometry.GetMaxX(); - if (double.IsNaN(orgMaxX)) - { - orgMaxX = double.MaxValue; - } + orgMaxX = double.MaxValue; + } - // Make dike and shoulder straight - RemovePointsBetweenCharacteristicPointsDikeTopAtPolderDikeToeAtPolder(surfaceLine); - // See it there is a ditch, if so store its characteristics. - DitchDefinition? ditchDefinition = GetDitchDefinition(); - // Then delete it from the surfaceline - RemoveExistingDitch(ditchDefinition); - ValidateNewShoulderSize(shoulderLength, shoulderHeight); - GeometryPoint dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); - GeometryPoint dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + // Make dike and shoulder straight + RemovePointsBetweenCharacteristicPointsDikeTopAtPolderDikeToeAtPolder(surfaceLine); + // See it there is a ditch, if so store its characteristics. + DitchDefinition? ditchDefinition = GetDitchDefinition(); + // Then delete it from the surfaceline + RemoveExistingDitch(ditchDefinition); + ValidateNewShoulderSize(shoulderLength, shoulderHeight); + GeometryPoint dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + GeometryPoint dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); - if (designFromDikeToe) + if (designFromDikeToe) + { + // for piping design, when the required new height is larger than allowed, it is an error! + if ((MaxShoulderLevel - dikeToeAtPolder.Z) < shoulderHeight) { - // for piping design, when the required new height is larger than allowed, it is an error! - if ((MaxShoulderLevel - dikeToeAtPolder.Z) < shoulderHeight) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightTooLargeError); - } + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightTooLargeError); } - else - { - // Assure new height is less then or equal to the maximum height - shoulderHeight = Math.Min(shoulderHeight, (MaxShoulderLevel - dikeToeAtPolder.Z)); - } + } + else + { + // Assure new height is less then or equal to the maximum height + shoulderHeight = Math.Min(shoulderHeight, (MaxShoulderLevel - dikeToeAtPolder.Z)); + } - // Find the intersection point at new shoulder height with the dike, this is where the new shoulder starts - bool hasShoulderInside = surfaceLine.HasShoulderInside(); - double dikeToeZ = dikeToeAtPolder.Z; - GeometryPoint dikeBaseInside = hasShoulderInside ? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside) : dikeToeAtPolder; - // Determine intersectionpoint with slope for a horizontal shoulder - GeometryPoint intersectionPointAtDike; - intersectionPointAtDike = LineHelper.GetIntersectionPointWithExtrapolation(dikeTopAtPolder, dikeBaseInside, - new GeometryPoint(dikeToeAtPolder.X, shoulderHeight + dikeToeZ), - new GeometryPoint(dikeToeAtPolder.X + 1, shoulderHeight + dikeToeZ)); - var newTopShoulder = new GeometryPoint(intersectionPointAtDike.X + shoulderLength, shoulderHeight + dikeToeZ); - if (Location.UseNewShoulderTopSlope) + // Find the intersection point at new shoulder height with the dike, this is where the new shoulder starts + bool hasShoulderInside = surfaceLine.HasShoulderInside(); + double dikeToeZ = dikeToeAtPolder.Z; + GeometryPoint dikeBaseInside = hasShoulderInside ? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside) : dikeToeAtPolder; + // Determine intersectionpoint with slope for a horizontal shoulder + GeometryPoint intersectionPointAtDike; + intersectionPointAtDike = LineHelper.GetIntersectionPointWithExtrapolation(dikeTopAtPolder, dikeBaseInside, + new GeometryPoint(dikeToeAtPolder.X, shoulderHeight + dikeToeZ), + new GeometryPoint(dikeToeAtPolder.X + 1, shoulderHeight + dikeToeZ)); + var newTopShoulder = new GeometryPoint(intersectionPointAtDike.X + shoulderLength, shoulderHeight + dikeToeZ); + if (Location.UseNewShoulderTopSlope) + { + // if top slope is not to be horizontal then recalculate the intersection from a point at required slope width + // from the horizontal intersection point. This will result in the actual width of the shoulder being a bit + // larger than the requested size but that can not be helped (classic chicken-egg problem) + var pb = new GeometryPoint(newTopShoulder.X - 100, newTopShoulder.Z + (100 * Location.NewShoulderTopSlope)); + intersectionPointAtDike = LineHelper.GetIntersectionPointWithExtrapolation(dikeTopAtPolder, dikeBaseInside, pb, newTopShoulder); + if (intersectionPointAtDike.Z > MaxShoulderLevel) { - // if top slope is not to be horizontal then recalculate the intersection from a point at required slope width - // from the horizontal intersection point. This will result in the actual width of the shoulder being a bit - // larger than the requested size but that can not be helped (classic chicken-egg problem) - var pb = new GeometryPoint(newTopShoulder.X - 100, newTopShoulder.Z + (100 * Location.NewShoulderTopSlope)); - intersectionPointAtDike = LineHelper.GetIntersectionPointWithExtrapolation(dikeTopAtPolder, dikeBaseInside, pb, newTopShoulder); - if (intersectionPointAtDike.Z > MaxShoulderLevel) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightTooLargeTopSlopeError); - } + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightTooLargeTopSlopeError); } + } - // Find the intersection at the surface line from a line starting at the end of the new shoulder sloping down at 1 : SlopeOfNewShoulder - // to get the new point of the toe. Note that for stability the shoulder length is applied directly to the intersection point as for piping - // the shoulder length is applied from the original diketoe (so for piping the complete shoulder is longer). - double xStart = intersectionPointAtDike.X; - const double offset = 100.0; - if (designFromDikeToe) - { - xStart = dikeToeAtPolder.X; - } + // Find the intersection at the surface line from a line starting at the end of the new shoulder sloping down at 1 : SlopeOfNewShoulder + // to get the new point of the toe. Note that for stability the shoulder length is applied directly to the intersection point as for piping + // the shoulder length is applied from the original diketoe (so for piping the complete shoulder is longer). + double xStart = intersectionPointAtDike.X; + const double offset = 100.0; + if (designFromDikeToe) + { + xStart = dikeToeAtPolder.X; + } - var line = new Line + var line = new Line + { + BeginPoint = new Point2D(newTopShoulder.X, newTopShoulder.Z), + EndPoint = new Point2D(newTopShoulder.X + offset, newTopShoulder.Z - offset / SlopeOfNewShoulder) + }; + IList intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); + GeometryPoint newToeAtPolder = null; + if (intersectionpoints.Count > 0) + { + Point2D firstIntersectionPoint = intersectionpoints.First(); + newToeAtPolder = new GeometryPoint(firstIntersectionPoint.X, firstIntersectionPoint.Z); + } + + if (newToeAtPolder == null) + { + // If the intersection was not found, this could mean that A) the new shoulder intersects the surfaceline at the + // shoulderheight itself or B) that the original surfaceline is not long enough to intersect the new shoulder + // (this happens when the end of the new shoulder falls pratically at the end of the surfaceline in which case + // there is no room to fit the entire shoulder in the original surfaceline). For A) try to find that intersection + // point and use it as new toe. If not, something is very wrong (probably B) and an exception must be raised. + var line1 = new Line { - BeginPoint = new Point2D(newTopShoulder.X, newTopShoulder.Z), - EndPoint = new Point2D(newTopShoulder.X + offset, newTopShoulder.Z - offset / SlopeOfNewShoulder) + BeginPoint = new Point2D(xStart + 0.001, intersectionPointAtDike.Z), + EndPoint = new Point2D(xStart + shoulderLength, intersectionPointAtDike.Z) }; - IList intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); - GeometryPoint newToeAtPolder = null; - if (intersectionpoints.Count > 0) + IList intersectionpoints2 = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line1); + if (intersectionpoints2.Count > 0) { - Point2D firstIntersectionPoint = intersectionpoints.First(); + Point2D firstIntersectionPoint = intersectionpoints2.First(); newToeAtPolder = new GeometryPoint(firstIntersectionPoint.X, firstIntersectionPoint.Z); } if (newToeAtPolder == null) { - // If the intersection was not found, this could mean that A) the new shoulder intersects the surfaceline at the - // shoulderheight itself or B) that the original surfaceline is not long enough to intersect the new shoulder - // (this happens when the end of the new shoulder falls pratically at the end of the surfaceline in which case - // there is no room to fit the entire shoulder in the original surfaceline). For A) try to find that intersection - // point and use it as new toe. If not, something is very wrong (probably B) and an exception must be raised. - var line1 = new Line - { - BeginPoint = new Point2D(xStart + 0.001, intersectionPointAtDike.Z), - EndPoint = new Point2D(xStart + shoulderLength, intersectionPointAtDike.Z) - }; - IList intersectionpoints2 = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line1); - if (intersectionpoints2.Count > 0) - { - Point2D firstIntersectionPoint = intersectionpoints2.First(); - newToeAtPolder = new GeometryPoint(firstIntersectionPoint.X, firstIntersectionPoint.Z); - } - - if (newToeAtPolder == null) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderNoIntersectionError); - } + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderNoIntersectionError); } + } - if (designFromDikeToe) - { - // for piping design, the new toe must be placed at shoulderLength from the original toe, not from the new intersection point. - newToeAtPolder.X = dikeToeAtPolder.X + shoulderLength + shoulderHeight * SlopeOfNewShoulder; - } + if (designFromDikeToe) + { + // for piping design, the new toe must be placed at shoulderLength from the original toe, not from the new intersection point. + newToeAtPolder.X = dikeToeAtPolder.X + shoulderLength + shoulderHeight * SlopeOfNewShoulder; + } - // remove old line (point) segment starting from intersection dike inside to new intersection ground - surfaceLine.RemoveSegmentBetween(intersectionPointAtDike.X, newToeAtPolder.X); + // remove old line (point) segment starting from intersection dike inside to new intersection ground + surfaceLine.RemoveSegmentBetween(intersectionPointAtDike.X, newToeAtPolder.X); - // insert the new shoulder points - surfaceLine.EnsurePointOfType(intersectionPointAtDike.X, intersectionPointAtDike.Z, CharacteristicPointType.ShoulderBaseInside); - surfaceLine.EnsurePointOfType(newTopShoulder.X, newTopShoulder.Z, CharacteristicPointType.ShoulderTopInside); + // insert the new shoulder points + surfaceLine.EnsurePointOfType(intersectionPointAtDike.X, intersectionPointAtDike.Z, CharacteristicPointType.ShoulderBaseInside); + surfaceLine.EnsurePointOfType(newTopShoulder.X, newTopShoulder.Z, CharacteristicPointType.ShoulderTopInside); - // Place new dike toe - surfaceLine.EnsurePointOfType(newToeAtPolder.X, newToeAtPolder.Z, CharacteristicPointType.DikeToeAtPolder); + // Place new dike toe + surfaceLine.EnsurePointOfType(newToeAtPolder.X, newToeAtPolder.Z, CharacteristicPointType.DikeToeAtPolder); - // Check whether the surface line is extended. This is not allowed! - if (surfaceLine.Geometry.GetMaxX() > orgMaxX) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderLengthTooLargeError); - } + // Check whether the surface line is extended. This is not allowed! + if (surfaceLine.Geometry.GetMaxX() > orgMaxX) + { + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderLengthTooLargeError); + } - // Restore Ditch (if any) - RestoreDitch(ditchDefinition); + // Restore Ditch (if any) + RestoreDitch(ditchDefinition); - // Restore traffic load - RestoreTrafficLoad(); - surfaceLine.SortPoints(); + // Restore traffic load + RestoreTrafficLoad(); + surfaceLine.SortPoints(); - return surfaceLine; - } + return surfaceLine; + } - /// - /// Raise exception if new shoulder is smaller than existing shoulder - /// - /// - /// - /// - private void ValidateNewShoulderSize(double shoulderLength, double shoulderHeight) + /// + /// Raise exception if new shoulder is smaller than existing shoulder + /// + /// + /// + /// + private void ValidateNewShoulderSize(double shoulderLength, double shoulderHeight) + { + if (surfaceLine.HasShoulderInside()) { - if (surfaceLine.HasShoulderInside()) + double currentShoulderLength = surfaceLine.DetermineShoulderLengthForGivenShoulderTopInside(surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside)); + if (currentShoulderLength > shoulderLength) { - double currentShoulderLength = surfaceLine.DetermineShoulderLengthForGivenShoulderTopInside(surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside)); - if (currentShoulderLength > shoulderLength) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderLengthError); - } + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderLengthError); + } - double currentShoulderHeight = surfaceLine.DetermineShoulderHeight(); - if (currentShoulderHeight > shoulderHeight) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightError); - } - - if (shoulderLength < 0) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderLengthError); - } - - if (shoulderHeight < 0) - { - throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightZeroError); - } + double currentShoulderHeight = surfaceLine.DetermineShoulderHeight(); + if (currentShoulderHeight > shoulderHeight) + { + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightError); } - } - /// - /// Remove all non characteristic points between DikeTopAtPolder and DikeToeAtPolder - /// - /// The surface line. - private void RemovePointsBetweenCharacteristicPointsDikeTopAtPolderDikeToeAtPolder(SurfaceLine2 surfaceLine2) - { - bool hasShoulderInside = surfaceLine2.HasShoulderInside(); - GeometryPoint dikeTopAtPolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); - GeometryPoint dikeToeAtPolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); - if (hasShoulderInside) + if (shoulderLength < 0) { - GeometryPoint shoulderBaseInside = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); - GeometryPoint shoulderTopInside = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); - surfaceLine2.RemoveSegmentBetween(dikeTopAtPolder.X, shoulderBaseInside.X); - surfaceLine2.RemoveSegmentBetween(shoulderBaseInside.X, shoulderTopInside.X); - surfaceLine2.RemoveSegmentBetween(shoulderTopInside.X, dikeToeAtPolder.X); + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderLengthError); } - else + + if (shoulderHeight < 0) { - surfaceLine2.RemoveSegmentBetween(dikeTopAtPolder.X, dikeToeAtPolder.X); + throw new SurfaceLineAdapterException(Resources.SurfaceLineShoulderAdapterNewShoulderHeightZeroError); } } } + + /// + /// Remove all non characteristic points between DikeTopAtPolder and DikeToeAtPolder + /// + /// The surface line. + private void RemovePointsBetweenCharacteristicPointsDikeTopAtPolderDikeToeAtPolder(SurfaceLine2 surfaceLine2) + { + bool hasShoulderInside = surfaceLine2.HasShoulderInside(); + GeometryPoint dikeTopAtPolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + GeometryPoint dikeToeAtPolder = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + if (hasShoulderInside) + { + GeometryPoint shoulderBaseInside = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); + GeometryPoint shoulderTopInside = surfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); + surfaceLine2.RemoveSegmentBetween(dikeTopAtPolder.X, shoulderBaseInside.X); + surfaceLine2.RemoveSegmentBetween(shoulderBaseInside.X, shoulderTopInside.X); + surfaceLine2.RemoveSegmentBetween(shoulderTopInside.X, dikeToeAtPolder.X); + } + else + { + surfaceLine2.RemoveSegmentBetween(dikeTopAtPolder.X, dikeToeAtPolder.X); + } + } } \ No newline at end of file