// Copyright (C) Stichting Deltares 2024. 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 Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; namespace Deltares.DamEngine.Calculators.DikesDesign; /// /// Class for adapting the height of the crest of a surfaceline /// public class SurfaceLineHeightAdapter : SurfaceLineAdapter { /// /// Initializes a new instance of the class. /// /// /// /// public SurfaceLineHeightAdapter(SurfaceLine2 surfaceLine, Location location, double scenarioPolderLevel) : base(surfaceLine, location, scenarioPolderLevel) {} /// /// Constructs a new surface line with a new height /// /// /// There are a few scenarios of that will be handled: /// - one without a shoulder inside /// - one with a shoulder inside but the adaption will remove the shoulder completly /// - one with a shoulder but a part of the shoulder remains intact /// - one where the new top falls completely above the old top /// /// The new height /// The adapted surface line /// public SurfaceLine2 ConstructNewSurfaceLine(double newDikeHeight) { //Input data Point2D pointAtTopRiver = surfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeTopAtRiver); Point2D pointAtTopPolder = surfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeTopAtPolder); Point2D pointDikeToeInward = surfaceLine.GetDikeToeInward(); Point2D startingPoint = surfaceLine.GetStartingPoint(); surfaceLine.RemoveSegmentBetween(startingPoint.X, pointAtTopRiver.X); Point2D newPointAtTopRiver; Point2D oldPointAtTopRiver = null; if (Location.UseNewDikeSlopeOutside) { var newOutsideSlopePoint = new Point2D { X = pointAtTopRiver.X + 100, Z = pointAtTopRiver.Z + 100 * Location.NewDikeSlopeOutside }; newPointAtTopRiver = LineHelper.DetermineIntersectionPointWithExtrapolation(pointAtTopRiver, newOutsideSlopePoint, new Point2D(pointAtTopRiver.X, newDikeHeight), new Point2D(pointAtTopPolder.X, newDikeHeight)); oldPointAtTopRiver = new Point2D { X = pointAtTopRiver.X, Z = pointAtTopRiver.Z }; } else { newPointAtTopRiver = LineHelper.DetermineIntersectionPointWithExtrapolation(startingPoint, pointAtTopRiver, new Point2D(pointAtTopRiver.X, newDikeHeight), new Point2D(pointAtTopPolder.X, newDikeHeight)); } // Determine the new point at DIKE TOP RIVER double dikeTopWidth = pointAtTopPolder.X - pointAtTopRiver.X; if (Location.UseNewDikeTopWidth) { dikeTopWidth = Location.NewDikeTopWidth; } // Determine the new point at DIKE TOP POLDER var newPointAtTopPolder = new Point2D(newPointAtTopRiver.X + dikeTopWidth, newDikeHeight); double slopeTangentInside = (pointAtTopPolder.Z - pointDikeToeInward.Z) / (pointDikeToeInward.X - pointAtTopPolder.X); if (Location.UseNewDikeSlopeInside) { slopeTangentInside = Location.NewDikeSlopeInside; } // check case where the new top falls completely above the old top Point2D intersectionPointDikeTop = IntersectionpointWithOldDikeTop(newPointAtTopPolder, slopeTangentInside); if (intersectionPointDikeTop != null) { // Remove all points between old dike top river and old dike top polder surfaceLine.RemoveSegmentBetween(pointAtTopRiver.X, pointAtTopPolder.X); // Add new dike top river, new dike top polder surfaceLine.AddCharacteristicPoint(newPointAtTopRiver, CharacteristicPointType.DikeTopAtRiver); surfaceLine.AddCharacteristicPoint(newPointAtTopPolder, CharacteristicPointType.DikeTopAtPolder); // check if intersection point equals old dike top polder, if so the ready else add intersection point as normal point if (!pointAtTopPolder.LocationEquals(intersectionPointDikeTop)) { surfaceLine.EnsurePoint(intersectionPointDikeTop.X, intersectionPointDikeTop.Z); } surfaceLine.SortPoints(); return surfaceLine; } // Remove points on inside slope surfaceLine.RemoveSegmentBetween(pointAtTopPolder.X, pointDikeToeInward.X); // Store the ditch (if any) DitchDefinition? ditchDefinition = GetDitchDefinition(); // Delete the ditch from the surfaceline (if any) RemoveExistingDitch(ditchDefinition); // Adjust for the new slope Point2D slopePoint = ReplaceBaseInsideForNewSlope(newPointAtTopPolder, slopeTangentInside); // Reset pointDikeToeInward for new position pointDikeToeInward = surfaceLine.GetDikeToeInward(); // Remove all points between "old" dike top river side and new toe inward surfaceLine.RemoveSegmentBetween(pointAtTopRiver.X, pointDikeToeInward.X); if (slopePoint != null) { // if the slope point exists (new end point of slope coincides with shouldertopinside), it has to be // re-added as "normal" point because it was deleted in the former RemoveSegmentBetween. surfaceLine.AddCharacteristicPoint(slopePoint, CharacteristicPointType.None); } // Adjust position of "old" dike top river surfaceLine.EnsurePointOfType(newPointAtTopRiver.X, newPointAtTopRiver.Z, CharacteristicPointType.DikeTopAtRiver); if (Location.UseNewDikeSlopeOutside) { // Re-add the old dike top river as "normal" point surfaceLine.AddCharacteristicPoint(oldPointAtTopRiver, CharacteristicPointType.None); } // Add the new dike top at polder side surfaceLine.EnsurePointOfType(newPointAtTopPolder.X, newPointAtTopPolder.Z, CharacteristicPointType.DikeTopAtPolder); // Restore Ditch (if any) RestoreDitch(ditchDefinition); // Restore traffic load RestoreTrafficLoad(); surfaceLine.SortPoints(); return surfaceLine; } /// /// Tries to find the intersection point between the old dike top and the new inside slope starting at the new /// dike top at polder side. /// /// /// /// The intersection point when found else null private Point2D IntersectionpointWithOldDikeTop(Point2D newPointAtTopPolder, double slopeTangent) { Point2D res = null; var newPoint = new Point2D { X = newPointAtTopPolder.X + 100, Z = newPointAtTopPolder.Z - 100 * slopeTangent }; Point2D dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeTopAtPolder); Point2D ip = LineHelper.DetermineIntersectionPointWithExtrapolation(newPointAtTopPolder, newPoint, surfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeTopAtRiver), dikeTopAtPolder); if (ip != null && ip.X <= dikeTopAtPolder.X) { res = ip; } return res; } }