Index: DamEngine/trunk/src/Deltares.DamEngine.Data.Tests/Geotechnics/SoilSurfaceProfileTests.cs =================================================================== diff -u -r3257 -r3266 --- DamEngine/trunk/src/Deltares.DamEngine.Data.Tests/Geotechnics/SoilSurfaceProfileTests.cs (.../SoilSurfaceProfileTests.cs) (revision 3257) +++ DamEngine/trunk/src/Deltares.DamEngine.Data.Tests/Geotechnics/SoilSurfaceProfileTests.cs (.../SoilSurfaceProfileTests.cs) (revision 3266) @@ -631,6 +631,91 @@ }, bottomLayerSurface.GeometrySurface.OuterLoop.CurveList); } + [Test] + public void ConvertToSoilProfile2D_WithSurfaceLineStartingHorizontallyAtBottomLayer_ReturnsExpectedSoilProfile() + { + // Setup + const string bottomLayerName = "BottomLayer"; + const string middleLayerName = "MiddleLayer"; + const string topLayerName = "TopLayer"; + + SoilLayer1D bottomLayer = CreateSoilLayer(-2.5, bottomLayerName); + SoilLayer1D middleLayer = CreateSoilLayer(0, middleLayerName); + + var profile = new SoilProfile1D(); + profile.Layers.Add(bottomLayer); + profile.Layers.Add(middleLayer); + profile.BottomLevel = -10; + + SurfaceLine2 surfaceLine = CreateSurfaceLine(new[] + { + new GeometryPoint(0, -2.5), + new GeometryPoint(5, -2.5), + new GeometryPoint(10, 2.5), + new GeometryPoint(15, -2.5), + new GeometryPoint(20, -2.5) + }); + + var soilSurfaceProfile = new SoilSurfaceProfile + { + SoilProfile = profile, + SurfaceLine2 = surfaceLine, + DikeEmbankmentMaterial = new Soil + { + Name = topLayerName + } + }; + + // Call + SoilProfile2D soilProfile2D = soilSurfaceProfile.ConvertToSoilProfile2D(); + + // Assert + var soilLayer2Ds = soilProfile2D.Surfaces; + SoilLayer2D topSoilLayer2D = soilLayer2Ds.Single(l => string.Equals(l.Name, topLayerName)); + AssertDikeEmbankmentSoilLayerProperties(soilSurfaceProfile, topSoilLayer2D); + AssertGeometry(new[] + { + new GeometryCurve(new Point2D(7.5, 0), new Point2D(10, 2.5)), + new GeometryCurve(new Point2D(10, 2.5), new Point2D(12.5, 0)), + new GeometryCurve(new Point2D(12.5, 0), new Point2D(10, 0)), + new GeometryCurve(new Point2D(10, 0), new Point2D(7.5, 0)) + }, topSoilLayer2D.GeometrySurface.OuterLoop.CurveList); + + SoilLayer2D middleSoilLayer2D = soilLayer2Ds.Single(l => string.Equals(l.Name, middleLayerName)); + AssertSoilLayerProperties(middleLayer, middleSoilLayer2D); + AssertGeometry(new[] + { + new GeometryCurve(new Point2D(5, -2.5), new Point2D(7.5, 0)), + new GeometryCurve(new Point2D(7.5, 0), new Point2D(10, 0)), + new GeometryCurve(new Point2D(10, 0), new Point2D(12.5, 0)), + new GeometryCurve(new Point2D(12.5, 0), new Point2D(15, -2.5)), + new GeometryCurve(new Point2D(15, -2.5), new Point2D(12.5, -2.5)), + new GeometryCurve(new Point2D(12.5, -2.5), new Point2D(10, -2.5)), + new GeometryCurve(new Point2D(10, -2.5), new Point2D(7.5, -2.5)), + new GeometryCurve(new Point2D(7.5, -2.5), new Point2D(5, -2.5)) + }, middleSoilLayer2D.GeometrySurface.OuterLoop.CurveList); + + SoilLayer2D bottomSoilLayer2D = soilLayer2Ds.Single(l => string.Equals(l.Name, bottomLayerName)); + AssertSoilLayerProperties(bottomLayer, bottomSoilLayer2D); + AssertGeometry(new[] + { + new GeometryCurve(new Point2D(0, -2.5), new Point2D(5, -2.5)), + new GeometryCurve(new Point2D(5, -2.5), new Point2D(7.5, -2.5)), + new GeometryCurve(new Point2D(7.5, -2.5), new Point2D(10, -2.5)), + new GeometryCurve(new Point2D(10, -2.5), new Point2D(12.5, -2.5)), + new GeometryCurve(new Point2D(12.5, -2.5), new Point2D(15, -2.5)), + new GeometryCurve(new Point2D(15, -2.5), new Point2D(20, -2.5)), + new GeometryCurve(new Point2D(20, -2.5), new Point2D(20, -10)), + new GeometryCurve(new Point2D(20, -10), new Point2D(15, -10)), + new GeometryCurve(new Point2D(15, -10), new Point2D(12.5, -10)), + new GeometryCurve(new Point2D(12.5, -10), new Point2D(10, -10)), + new GeometryCurve(new Point2D(10, -10), new Point2D(7.5, -10)), + new GeometryCurve(new Point2D(7.5, -10), new Point2D(5, -10)), + new GeometryCurve(new Point2D(5, -10), new Point2D(0, -10)), + new GeometryCurve(new Point2D(0, -10), new Point2D(0, -2.5)) + }, bottomSoilLayer2D.GeometrySurface.OuterLoop.CurveList); + } + private static void AssertGeometry(IEnumerable expectedCurves, IEnumerable actualCurves) { int nrOfExpectedCurves = expectedCurves.Count(); Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs =================================================================== diff -u -r3261 -r3266 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (.../SoilSurfaceProfile.cs) (revision 3261) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (.../SoilSurfaceProfile.cs) (revision 3266) @@ -152,14 +152,15 @@ var xCoordinatesToTraverse = GetXCoordinates(filteredSoilLayers, surfaceLine2).ToArray(); var layerData = CreateLayerData(filteredSoilLayers, surfaceLine2, xCoordinatesToTraverse); - BuildGeometryModel(Geometry, layerData, originalSoilProfile1D, surfaceLine2); + BuildGeometryModel(Geometry, layerData, originalSoilProfile1D, surfaceLine2, xCoordinatesToTraverse); AssignSoilLayer2DProperties(Surfaces, layerData, Geometry); } private static void BuildGeometryModel(GeometryData geometryData, IEnumerable layers, SoilProfile1D profile, - SurfaceLine2 surfaceLine) + SurfaceLine2 surfaceLine, + IEnumerable xCoordinates) { if (surfaceLine.Geometry == null || profile == null @@ -179,8 +180,13 @@ geometryData.Right = maxX; geometryData.Bottom = Math.Min(profile.BottomLevel, surfaceLine.Geometry.GetMinZ() - 1); - var pointsToBeAdded = layers.SelectMany(l => l.Points); - var curvesToBeAdded = layers.SelectMany(l => l.Curves); + var localSurfaceLinePoints = GenerateLocalSurfaceLineGeometry(xCoordinates, surfaceLine).ToList(); + var localSurfaceLineCurves = GenerateCurves(localSurfaceLinePoints); + + var pointsToBeAdded = layers.SelectMany(l => l.Points) + .Concat(localSurfaceLinePoints); + var curvesToBeAdded = layers.SelectMany(l => l.Curves) + .Concat(localSurfaceLineCurves); geometryData.NewlyEffectedPoints.AddRange(pointsToBeAdded); geometryData.NewlyEffectedCurves.AddRange(curvesToBeAdded); geometryData.RegenerateGeometry(); @@ -369,7 +375,7 @@ var currentArea = new EnclosedArea(); var enclosedAreas = new List(); - double previousZCoordinate = double.NegativeInfinity; + double previousZCoordinate = xCoordinateArray[0]; int j = 1; for (int i = 0; i < xCoordinateArray.Length; i++) { @@ -383,15 +389,16 @@ currentZCoordinate = layerTopLevel; currentArea.AddCoordinate(new Point2D(xCoordinate, layerTopLevel)); } - else if (zCoordinateSurfaceLine >= layerBottomLevel && zCoordinateSurfaceLine <= layerTopLevel) + else if (Math.Abs(zCoordinateSurfaceLine - layerBottomLevel) < GeometryConstants.Accuracy // Surface line is at layer bottom level + || (zCoordinateSurfaceLine >= layerBottomLevel && zCoordinateSurfaceLine <= layerTopLevel)) // Surface line is between the layer top and bottom level { currentArea.AddCoordinate(new Point2D(xCoordinate, zCoordinateSurfaceLine)); } // Determine if a new area should be started. This should only happen when: - if (previousZCoordinate > layerBottomLevel // The area already started above or at the soil layer bottom - && zCoordinateSurfaceLine < previousZCoordinate // The surface line has a decreasing trend w.r.t. the previous z coordinate - && zCoordinateSurfaceLine <= layerBottomLevel) // The surface line crossed the bottom of the layer + if (previousZCoordinate > layerBottomLevel // The area already started above or at the soil layer bottom + && zCoordinateSurfaceLine < previousZCoordinate // The surface line has a decreasing trend w.r.t. the previous z coordinate + && zCoordinateSurfaceLine <= layerBottomLevel) // The surface line crossed the bottom of the layer { enclosedAreas.Add(currentArea); currentArea = new EnclosedArea(); @@ -441,12 +448,17 @@ return new LayerData(pointsToConvert, curves, soilLayer.Soil, soilLayer.IsAquifer, soilLayer.WaterpressureInterpolationModel); } + private static IEnumerable GenerateLocalSurfaceLineGeometry(IEnumerable xCoordinates, SurfaceLine2 surfaceLine2) + { + return xCoordinates.Select(xCoordinate => new Point2D(xCoordinate, surfaceLine2.Geometry.GetZatX(xCoordinate))).ToArray(); + } + /// - /// Generates curves that define a clockwise closed loop based on a collection of points. + /// Generates curves based on a collection of points. /// /// The collection points to generate a curve collection for. /// A collection of . - private static IEnumerable GenerateClosedLoopCurves(List pointsToConvert) + private static IEnumerable GenerateCurves(List pointsToConvert) { Point2D startPoint = pointsToConvert[0]; var curves = new List(); @@ -457,6 +469,18 @@ startPoint = endPoint; } + return curves; + } + + /// + /// Generates curves that define a clockwise closed loop based on a collection of points. + /// + /// The collection points to generate a curve collection for. + /// A collection of . + private static IEnumerable GenerateClosedLoopCurves(List pointsToConvert) + { + var curves = GenerateCurves(pointsToConvert).ToList(); + // Close the geometry by connecting the first and last points with each other // This closes the outer loop in a clockwise definition. curves.Add(new GeometryCurve(pointsToConvert.Last(), pointsToConvert.First()));