Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/SurfaceLineAdapter.cs =================================================================== diff -u -r3893 -r4000 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/SurfaceLineAdapter.cs (.../SurfaceLineAdapter.cs) (revision 3893) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/SurfaceLineAdapter.cs (.../SurfaceLineAdapter.cs) (revision 4000) @@ -48,27 +48,16 @@ /// public abstract class SurfaceLineAdapter { + const double offset = 100.0; - private struct DitchCoordinates - { - public double XAtDike; - public double ZAtDike; - public double XBottomAtDike; - public double ZBottom; - public double XBottomAtPolder; - public double XAtPolder; - public double ZAtPolder; - } - protected readonly Location Location; protected readonly SurfaceLine2 surfaceLine; protected double trafficLoadOffsetXfromRiverside; protected double trafficLoadOffsetXfromPolderside; protected double trafficLoadWidth; protected bool hasTrafficLoad; - protected bool isTrafficLoadOnCrest = false; + protected bool isTrafficLoadOnCrest; protected double polderLevel; - const double offset = 100.0; /// /// Constructor @@ -87,33 +76,6 @@ } /// - /// Store the parameters with which the traffic load can be restored. - /// The traffic load will be retained relative to the buitenkruinlijn. - /// If the traffic load is completly inside area between buitenkruinlijn and binnenkruinlijn the following will be done: - /// - The traffic load will be retained relative to the binnenkruinlijn. If the leftside of the traffic load passes the buitenkruinlijn, - /// the leftside of the traffic load will be placed on the buitenkruinlijn. It is possible that the rightside of the traffic load - /// passes the buitenkruinlijn. - /// See documentation in Issue [MWDAM-548] - /// - private void RetainTrafficLoad() - { - GeometryPoint pointTrafficLoadInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadInside); - GeometryPoint pointTrafficLoadOutside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadOutside); - GeometryPoint pointDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); - GeometryPoint pointDikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); - - hasTrafficLoad = ((pointTrafficLoadInside != null) && (pointTrafficLoadOutside != null)); - if (hasTrafficLoad) - { - trafficLoadOffsetXfromRiverside = pointTrafficLoadOutside.X - pointDikeTopAtRiver.X; - trafficLoadOffsetXfromPolderside = pointDikeTopAtPolder.X - pointTrafficLoadInside.X; - trafficLoadWidth = pointTrafficLoadInside.X - pointTrafficLoadOutside.X; - isTrafficLoadOnCrest = (pointTrafficLoadOutside.X >= pointDikeTopAtRiver.X) && (pointTrafficLoadInside.X <= pointDikeTopAtPolder.X); - } - - } - - /// /// Create traffic load based on the retained traffic load parameters /// See documentation in Issue [MWDAM-548] /// @@ -134,6 +96,7 @@ { xCoordinate = pointDikeTopAtRiver.X; } + double zCoordinate = surfaceLine.Geometry.GetZatX(xCoordinate); surfaceLine.EnsurePointOfType(xCoordinate, zCoordinate, CharacteristicPointType.TrafficLoadOutside); @@ -168,14 +131,14 @@ { GeometryPoint result = null; var line = new Line - { - BeginPoint = new Point2D(startPoint.X, startPoint.Z), - EndPoint = - new Point2D(startPoint.X + offset, - startPoint.Z - offset * slopeTangent) - }; + { + BeginPoint = new Point2D(startPoint.X, startPoint.Z), + EndPoint = + new Point2D(startPoint.X + offset, + startPoint.Z - offset * slopeTangent) + }; // Find the intersectionpoint(s) of the new slope with the surface line - var intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); + IList intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); Point2D newSlopeEndPoint = null; if (intersectionpoints.Count > 0) { @@ -191,24 +154,26 @@ } } } + if (newSlopeEndPoint == null) { throw new SurfaceLineAdapterException(Resources.SlopeErrorNoIntersection); } - var dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + + GeometryPoint dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); if (newSlopeEndPoint.X > dikeToeAtPolder.X) { // The new point is beyond the old dike toe so adapt that point. surfaceLine.EnsurePointOfType(newSlopeEndPoint.X, newSlopeEndPoint.Z, CharacteristicPointType.DikeToeAtPolder); // Remove all points between top and dike toe, surfaceLine.RemoveSegmentBetween( - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, - newSlopeEndPoint.X); + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, + newSlopeEndPoint.X); } else { - var shoulderTopInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); - var shoulderBaseInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); + GeometryPoint shoulderTopInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); + GeometryPoint shoulderBaseInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); if (shoulderBaseInside != null && shoulderTopInside != null) { if (newSlopeEndPoint.X > shoulderTopInside.X) @@ -230,23 +195,23 @@ surfaceLine.RemoveSegmentBetween(shoulderBaseInside.X, newSlopeEndPoint.X); surfaceLine.EnsurePointOfType(newSlopeEndPoint.X, newSlopeEndPoint.Z, CharacteristicPointType.ShoulderBaseInside); - } else { // The new point is equal to ShoulderTopInside. So remove that, add a normal point at its location // and remove all points between the top and the new point. - var toBeRemoved = surfaceLine.CharacteristicPoints.FirstOrDefault( - cp => cp.CharacteristicPointType == CharacteristicPointType.ShoulderTopInside); + CharacteristicPoint toBeRemoved = surfaceLine.CharacteristicPoints.FirstOrDefault( + cp => cp.CharacteristicPointType == CharacteristicPointType.ShoulderTopInside); if (toBeRemoved != null) { surfaceLine.CharacteristicPoints.Remove(toBeRemoved); } + surfaceLine.EnsurePoint(newSlopeEndPoint.X, newSlopeEndPoint.Z); surfaceLine.RemoveSegmentBetween( surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, newSlopeEndPoint.X); - result = new GeometryPoint(newSlopeEndPoint.X, newSlopeEndPoint.Z); + result = new GeometryPoint(newSlopeEndPoint.X, newSlopeEndPoint.Z); } } } @@ -256,74 +221,16 @@ if (!newSlopeEndPoint.LocationEquals(new Point2D(dikeToeAtPolder.X, dikeToeAtPolder.Z))) { // There is no shoulder so the slope must be too steep. - throw new SurfaceLineAdapterException(Resources.SlopeErrorNoIntersection); + throw new SurfaceLineAdapterException(Resources.SlopeErrorNoIntersection); } } } + surfaceLine.SortPoints(); return result; } /// - /// Throws an exception when the surface line does not comply to the specification - /// - /// - /// The specification is that there: - /// - There are should be at least 4 points in the surface line - /// - must be a dike - /// - that the point coords are non zero - /// - There is a surface line when a shoulder exists - /// - /// The candidate to test - private static void ThrowWhenSurfaceLineDoesNotSatisfyToSpecification(SurfaceLine2 surfaceLine) - { - ThrowWhenSurfaceLineHasNoOrLessThenFourPoints(surfaceLine.Geometry.Points); - ThrowWhenSurfaceHasNoDike(surfaceLine); - ThrowWhenSurfaceLineHasAShoulderInsideAndNoSurfaceLevel(surfaceLine, - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside)); - - var p1 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); - var p2 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); - - var zeroPoint = new GeometryPoint(); - - if (zeroPoint.LocationEquals(p1) || zeroPoint.LocationEquals(p2)) - throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterDikeHeightError); - - if (surfaceLine.HasShoulderInside()) - { - p1 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); - p2 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); - if (zeroPoint.LocationEquals(p1) || zeroPoint.LocationEquals(p2)) - throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterShoulderHeightError); - } - } - - private static void ThrowWhenSurfaceLineHasAShoulderInsideAndNoSurfaceLevel(SurfaceLine2 surfaceLine, GeometryPoint surfaceLevelPoint) - { - if (surfaceLine.HasShoulderInside() && surfaceLevelPoint == null) - throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterSurfaceLevelError); - } - - private static void ThrowWhenSurfaceHasNoDike(SurfaceLine2 surfaceLine) - { - if (!surfaceLine.HasDike()) - throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterInvalidDikeError); - } - - private static void ThrowWhenSurfaceLineIsNull(SurfaceLine2 surfaceLine) - { - if (surfaceLine == null) - throw new ArgumentNullException(Resources.SurfaceLineAdapterNoDikeError); - } - - private static void ThrowWhenSurfaceLineHasNoOrLessThenFourPoints(ICollection points) - { - if (points == null || points.Count < 4) - throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterNoDikePointsError); - } - - /// /// Gets the ditch definition. /// /// @@ -333,9 +240,9 @@ var ditchDefinition = new DitchDefinition(); if (surfaceLine.HasDitch() && surfaceLine.IsDitchCorrect()) { - var ditchDikeSide = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); + GeometryPoint ditchDikeSide = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide); ditchDefinition.DistanceFromToe = ditchDikeSide.X - - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; if (ditchDefinition.DistanceFromToe >= 0) { ditchDefinition.OriginalX = ditchDikeSide.X; @@ -349,9 +256,9 @@ surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X - ditchDikeSide.X; ditchDefinition.DepthBottomDikeSide = ditchDikeSide.Z - - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide).Z; + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide).Z; ditchDefinition.DepthBottomPolderSide = ditchDikeSide.Z - - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide).Z; + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide).Z; return ditchDefinition; } } @@ -363,6 +270,7 @@ throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterDikeDitchError); } } + return null; } @@ -396,58 +304,19 @@ } } - private DitchCoordinates GetCoordinatesForOldShape(double xDitchDike, DitchDefinition ditchDefinition) - { - var res = new DitchCoordinates(); - res.XAtDike = xDitchDike; - res.ZAtDike = surfaceLine.Geometry.GetZatX(res.XAtDike); - res.XBottomAtDike = xDitchDike + ditchDefinition.DistanceToBottomDikeSide; - res.ZBottom = res.ZAtDike - ditchDefinition.DepthBottomDikeSide; - res.XBottomAtPolder = xDitchDike + ditchDefinition.DistanceToBottomPolderSide; - res.XAtPolder = xDitchDike + ditchDefinition.DistanceToEndDitch; - res.ZAtPolder = surfaceLine.Geometry.GetZatX(res.XAtPolder); - return res; - } - - private DitchCoordinates GetCoordinatesForNewShape(double xDitchDike) - { - var res = new DitchCoordinates(); - res.XAtDike = xDitchDike; - res.ZAtDike = surfaceLine.Geometry.GetZatX(res.XAtDike); - // Depth of the ditch is defined towards PolderLevel - res.ZBottom = polderLevel - Location.NewDepthDitch; - res.XBottomAtDike = xDitchDike + (res.ZAtDike - res.ZBottom)*Location.NewSlopeAngleDitch; - res.XBottomAtPolder = res.XBottomAtDike + Location.NewWidthDitchBottom; - var line = new Line - { - BeginPoint = new Point2D(res.XBottomAtPolder, res.ZBottom), - EndPoint = new Point2D(res.XBottomAtPolder + offset, - res.ZBottom + offset * Location.NewSlopeAngleDitch) - }; - // Find the intersectionpoint(s) of the new ditch slope with the surface line - var intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); - if (intersectionpoints.Count > 0) - { - res.XAtPolder = intersectionpoints[0].X; - res.ZAtPolder = intersectionpoints[0].Z; - } - else - { - //new slope of ditch does not intersect with surface line (most probably because the bottom is too high) - throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterDitchSlopeError); - } - return res; - } - /// /// Restores the ditch. /// /// The ditch definition. /// protected void RestoreDitch(DitchDefinition? ditchDefinition) { - if (ditchDefinition == null) return; - var dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); + if (ditchDefinition == null) + { + return; + } + + GeometryPoint dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder); double distanceToNewToe = ditchDefinition.Value.OriginalX - dikeToeAtPolder.X; double xDitchDikeSide; DitchCoordinates coors; @@ -464,32 +333,34 @@ { // Use the new definition instead of the old shape coors = GetCoordinatesForNewShape(xDitchDikeSide); - } else { // replace the ditch with the same shape. - coors = GetCoordinatesForOldShape(xDitchDikeSide, ditchDefinition.Value); + coors = GetCoordinatesForOldShape(xDitchDikeSide, ditchDefinition.Value); } } else { // replace the ditch with the same shape and same location. xDitchDikeSide = dikeToeAtPolder.X + distanceToNewToe; - coors = GetCoordinatesForOldShape(xDitchDikeSide, ditchDefinition.Value); + coors = GetCoordinatesForOldShape(xDitchDikeSide, ditchDefinition.Value); } + // check if the new bottom is beneath the surface line. If not, the ditch must not be replaced at all if (coors.ZBottom >= surfaceLine.Geometry.GetZatX(coors.XBottomAtDike) || coors.ZBottom >= surfaceLine.Geometry.GetZatX(coors.XBottomAtPolder)) { return; } + double surfaceLevelInsideX = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside).X; if (coors.XAtPolder > surfaceLevelInsideX) { throw new SurfaceLineAdapterException(Resources.SurfaceLineHeightAdapterDitchOutsideSurfaceLine); } + // Add the outside points of the new ditch surfaceLine.EnsurePointOfType(coors.XAtDike, coors.ZAtDike, CharacteristicPointType.DitchDikeSide); surfaceLine.EnsurePointOfType(coors.XAtPolder, coors.ZAtPolder, CharacteristicPointType.DitchPolderSide); @@ -500,5 +371,157 @@ surfaceLine.EnsurePointOfType(coors.XBottomAtPolder, coors.ZBottom, CharacteristicPointType.BottomDitchPolderSide); surfaceLine.SortPoints(); } + + /// + /// Store the parameters with which the traffic load can be restored. + /// The traffic load will be retained relative to the buitenkruinlijn. + /// If the traffic load is completly inside area between buitenkruinlijn and binnenkruinlijn the following will be done: + /// - The traffic load will be retained relative to the binnenkruinlijn. If the leftside of the traffic load passes the buitenkruinlijn, + /// the leftside of the traffic load will be placed on the buitenkruinlijn. It is possible that the rightside of the traffic load + /// passes the buitenkruinlijn. + /// See documentation in Issue [MWDAM-548] + /// + private void RetainTrafficLoad() + { + GeometryPoint pointTrafficLoadInside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadInside); + GeometryPoint pointTrafficLoadOutside = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadOutside); + GeometryPoint pointDikeTopAtRiver = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + GeometryPoint pointDikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + + hasTrafficLoad = ((pointTrafficLoadInside != null) && (pointTrafficLoadOutside != null)); + if (hasTrafficLoad) + { + trafficLoadOffsetXfromRiverside = pointTrafficLoadOutside.X - pointDikeTopAtRiver.X; + trafficLoadOffsetXfromPolderside = pointDikeTopAtPolder.X - pointTrafficLoadInside.X; + trafficLoadWidth = pointTrafficLoadInside.X - pointTrafficLoadOutside.X; + isTrafficLoadOnCrest = (pointTrafficLoadOutside.X >= pointDikeTopAtRiver.X) && (pointTrafficLoadInside.X <= pointDikeTopAtPolder.X); + } + } + + /// + /// Throws an exception when the surface line does not comply to the specification + /// + /// + /// The specification is that there: + /// - There are should be at least 4 points in the surface line + /// - must be a dike + /// - that the point coords are non zero + /// - There is a surface line when a shoulder exists + /// + /// The candidate to test + private static void ThrowWhenSurfaceLineDoesNotSatisfyToSpecification(SurfaceLine2 surfaceLine) + { + ThrowWhenSurfaceLineHasNoOrLessThenFourPoints(surfaceLine.Geometry.Points); + ThrowWhenSurfaceHasNoDike(surfaceLine); + ThrowWhenSurfaceLineHasAShoulderInsideAndNoSurfaceLevel(surfaceLine, + surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside)); + + GeometryPoint p1 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); + GeometryPoint p2 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); + + var zeroPoint = new GeometryPoint(); + + if (zeroPoint.LocationEquals(p1) || zeroPoint.LocationEquals(p2)) + { + throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterDikeHeightError); + } + + if (surfaceLine.HasShoulderInside()) + { + p1 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside); + p2 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside); + if (zeroPoint.LocationEquals(p1) || zeroPoint.LocationEquals(p2)) + { + throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterShoulderHeightError); + } + } + } + + private static void ThrowWhenSurfaceLineHasAShoulderInsideAndNoSurfaceLevel(SurfaceLine2 surfaceLine, GeometryPoint surfaceLevelPoint) + { + if (surfaceLine.HasShoulderInside() && surfaceLevelPoint == null) + { + throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterSurfaceLevelError); + } + } + + private static void ThrowWhenSurfaceHasNoDike(SurfaceLine2 surfaceLine) + { + if (!surfaceLine.HasDike()) + { + throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterInvalidDikeError); + } + } + + private static void ThrowWhenSurfaceLineIsNull(SurfaceLine2 surfaceLine) + { + if (surfaceLine == null) + { + throw new ArgumentNullException(Resources.SurfaceLineAdapterNoDikeError); + } + } + + private static void ThrowWhenSurfaceLineHasNoOrLessThenFourPoints(ICollection points) + { + if (points == null || points.Count < 4) + { + throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterNoDikePointsError); + } + } + + private DitchCoordinates GetCoordinatesForOldShape(double xDitchDike, DitchDefinition ditchDefinition) + { + var res = new DitchCoordinates(); + res.XAtDike = xDitchDike; + res.ZAtDike = surfaceLine.Geometry.GetZatX(res.XAtDike); + res.XBottomAtDike = xDitchDike + ditchDefinition.DistanceToBottomDikeSide; + res.ZBottom = res.ZAtDike - ditchDefinition.DepthBottomDikeSide; + res.XBottomAtPolder = xDitchDike + ditchDefinition.DistanceToBottomPolderSide; + res.XAtPolder = xDitchDike + ditchDefinition.DistanceToEndDitch; + res.ZAtPolder = surfaceLine.Geometry.GetZatX(res.XAtPolder); + return res; + } + + private DitchCoordinates GetCoordinatesForNewShape(double xDitchDike) + { + var res = new DitchCoordinates(); + res.XAtDike = xDitchDike; + res.ZAtDike = surfaceLine.Geometry.GetZatX(res.XAtDike); + // Depth of the ditch is defined towards PolderLevel + res.ZBottom = polderLevel - Location.NewDepthDitch; + res.XBottomAtDike = xDitchDike + (res.ZAtDike - res.ZBottom) * Location.NewSlopeAngleDitch; + res.XBottomAtPolder = res.XBottomAtDike + Location.NewWidthDitchBottom; + var line = new Line + { + BeginPoint = new Point2D(res.XBottomAtPolder, res.ZBottom), + EndPoint = new Point2D(res.XBottomAtPolder + offset, + res.ZBottom + offset * Location.NewSlopeAngleDitch) + }; + // Find the intersectionpoint(s) of the new ditch slope with the surface line + IList intersectionpoints = surfaceLine.Geometry.IntersectionPointsXzWithLineXz(line); + if (intersectionpoints.Count > 0) + { + res.XAtPolder = intersectionpoints[0].X; + res.ZAtPolder = intersectionpoints[0].Z; + } + else + { + //new slope of ditch does not intersect with surface line (most probably because the bottom is too high) + throw new SurfaceLineAdapterException(Resources.SurfaceLineAdapterDitchSlopeError); + } + + return res; + } + + private struct DitchCoordinates + { + public double XAtDike; + public double ZAtDike; + public double XBottomAtDike; + public double ZBottom; + public double XBottomAtPolder; + public double XAtPolder; + public double ZAtPolder; + } } } \ No newline at end of file