Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs =================================================================== diff -u -r3266 -r3268 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (.../SoilSurfaceProfile.cs) (revision 3266) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Geotechnics/SoilSurfaceProfile.cs (.../SoilSurfaceProfile.cs) (revision 3268) @@ -149,18 +149,18 @@ { var filteredSoilLayers = FilterSoilLayersToConvert(originalSoilProfile1D, surfaceLine2); - var xCoordinatesToTraverse = GetXCoordinates(filteredSoilLayers, surfaceLine2).ToArray(); - var layerData = CreateLayerData(filteredSoilLayers, surfaceLine2, xCoordinatesToTraverse); + var localSurfaceLinePoints = GetLocalSurfaceLinePoints(filteredSoilLayers, surfaceLine2); + var layerData = CreateLayerData(filteredSoilLayers, localSurfaceLinePoints); - BuildGeometryModel(Geometry, layerData, originalSoilProfile1D, surfaceLine2, xCoordinatesToTraverse); + BuildGeometryModel(Geometry, layerData, originalSoilProfile1D, surfaceLine2, localSurfaceLinePoints); AssignSoilLayer2DProperties(Surfaces, layerData, Geometry); } private static void BuildGeometryModel(GeometryData geometryData, IEnumerable layers, SoilProfile1D profile, SurfaceLine2 surfaceLine, - IEnumerable xCoordinates) + IEnumerable localSurfaceLinePoints) { if (surfaceLine.Geometry == null || profile == null @@ -180,8 +180,7 @@ geometryData.Right = maxX; geometryData.Bottom = Math.Min(profile.BottomLevel, surfaceLine.Geometry.GetMinZ() - 1); - var localSurfaceLinePoints = GenerateLocalSurfaceLineGeometry(xCoordinates, surfaceLine).ToList(); - var localSurfaceLineCurves = GenerateCurves(localSurfaceLinePoints); + var localSurfaceLineCurves = GenerateCurves(localSurfaceLinePoints.ToList()); var pointsToBeAdded = layers.SelectMany(l => l.Points) .Concat(localSurfaceLinePoints); @@ -258,16 +257,22 @@ copiedLayer.WaterpressureInterpolationModel = originalLayer.WaterpressureInterpolationModel; } - private static bool IsLayerBelowSurfaceLine(SoilLayer1D soilLayer, SurfaceLine2 surfaceLine) + private static bool IsLayerBelowSurfaceLine(SoilLayer1D soilLayer, IEnumerable surfaceLinePoints) { - return surfaceLine.Geometry.GetMinZ() > soilLayer.TopLevel; + return surfaceLinePoints.Min(p => p.Z) > soilLayer.TopLevel; } private static bool IsLayerAboveSurfaceLine(SoilLayer1D soilLayer, SurfaceLine2 surfaceLine2) { return soilLayer.BottomLevel > surfaceLine2.Geometry.GetMaxZ(); } + private static IEnumerable GetLocalSurfaceLinePoints(IEnumerable soilLayers, SurfaceLine2 surfaceLine) + { + var xCoordinates = GetXCoordinates(soilLayers, surfaceLine); + return xCoordinates.Select(x => new Point2D(x, surfaceLine.Geometry.GetZatX(x))).ToArray(); + } + /// /// Gets the X coordinates to determine the coordinates for through each layer. /// @@ -311,59 +316,56 @@ return xCoordinates.Distinct(); } - private static IEnumerable CreateLayerData(IEnumerable soilLayers, - SurfaceLine2 surfaceLine, IEnumerable xCoordinates) + private static IEnumerable CreateLayerData(IEnumerable soilLayers, IEnumerable surfaceLinePoints) { var layerData = new List(); foreach (SoilLayer1D soilLayer in soilLayers) { - if (IsLayerBelowSurfaceLine(soilLayer, surfaceLine)) + if (IsLayerBelowSurfaceLine(soilLayer, surfaceLinePoints)) { - layerData.Add(CreateSurfaceLineWideSoilLayer(soilLayer, xCoordinates)); + layerData.Add(CreateSurfaceLineWideSoilLayer(soilLayer, surfaceLinePoints)); } else { - layerData.AddRange(CreateSoilLayerWithSurfaceLineIntersection(soilLayer, surfaceLine, xCoordinates)); + layerData.AddRange(CreateSoilLayerWithSurfaceLineIntersection(soilLayer, surfaceLinePoints)); } } return layerData; } /// - /// Creates a 2D soil layer with points at . + /// Creates a 2D soil layer with points at . /// /// The to create the 2D soil layer for. - /// The collection of x coordinates to define the 2D soil layer for. + /// The collection of x coordinates to define the 2D soil layer for. /// A based on the input arguments. - private static LayerData CreateSurfaceLineWideSoilLayer(SoilLayer1D soilLayer, IEnumerable xCoordinates) + private static LayerData CreateSurfaceLineWideSoilLayer(SoilLayer1D soilLayer, IEnumerable surfaceLinePoints) { // A single square definition does not suffice for the area definition. The // curves need to overlap each other or the geometry generator fails to recognize // a surface double layerTopLevel = soilLayer.TopLevel; double layerBottomLevel = soilLayer.BottomLevel; - var pointsToConvert = xCoordinates.Select(xCoordinate => new Point2D(xCoordinate, layerTopLevel)).ToList(); - pointsToConvert.AddRange(xCoordinates.Reverse().Select(xCoordinate => new Point2D(xCoordinate, layerBottomLevel)).ToArray()); + var pointsToConvert = surfaceLinePoints.Select(p => new Point2D(p.X, layerTopLevel)).ToList(); + pointsToConvert.AddRange(surfaceLinePoints.Reverse().Select(p => new Point2D(p.X, layerBottomLevel)).ToArray()); var curves = GenerateClosedLoopCurves(pointsToConvert); return new LayerData(pointsToConvert, curves, soilLayer.Soil, soilLayer.IsAquifer, soilLayer.WaterpressureInterpolationModel); } /// - /// Creates a 2D soil layer with points at based on its input arguments. + /// Creates a 2D soil layer with points at based on its input arguments. /// /// The to create the 2D soil layer for. - /// The surface line to create the 2D soil layer with. - /// The collection of x coordinates to define the 2D soil layer for. + /// The collection of x coordinates to define the 2D soil layer for. /// A collection of based on the input arguments. /// The collection only contains with non-empty coordinates. - private static IEnumerable CreateSoilLayerWithSurfaceLineIntersection(SoilLayer1D soilLayer, - SurfaceLine2 surfaceLine, IEnumerable xCoordinates) + private static IEnumerable CreateSoilLayerWithSurfaceLineIntersection(SoilLayer1D soilLayer, IEnumerable surfaceLinePoints) { // Surface cannot be determined if there are not at least 2 coordinates - var xCoordinateArray = xCoordinates.ToArray(); - if (xCoordinateArray.Length < 2) + var pointsArray = surfaceLinePoints.ToArray(); + if (pointsArray.Length < 2) { return Enumerable.Empty(); } @@ -375,14 +377,15 @@ var currentArea = new EnclosedArea(); var enclosedAreas = new List(); - double previousZCoordinate = xCoordinateArray[0]; + double previousZCoordinate = pointsArray[0].Z; int j = 1; - for (int i = 0; i < xCoordinateArray.Length; i++) + for (int i = 0; i < pointsArray.Length; i++) { - double xCoordinate = xCoordinateArray[i]; + Point2D currentPoint = pointsArray[i]; + double xCoordinate = currentPoint.X; - double nextZCoordinate = surfaceLine.Geometry.GetZatX(xCoordinateArray[j]); - double zCoordinateSurfaceLine = surfaceLine.Geometry.GetZatX(xCoordinate); + double nextSurfaceLineZCoordinate = pointsArray[j].Z; + double zCoordinateSurfaceLine = currentPoint.Z; double currentZCoordinate = zCoordinateSurfaceLine; if (zCoordinateSurfaceLine > layerTopLevel) { @@ -395,18 +398,25 @@ 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 + // Determine if the current surface line point is located as a point on the horizontal line on the layer bottom level. + // If yes, then a new area should be added + if (Math.Abs(zCoordinateSurfaceLine - layerBottomLevel) < GeometryConstants.Accuracy + && Math.Abs(nextSurfaceLineZCoordinate - layerBottomLevel) < GeometryConstants.Accuracy) { enclosedAreas.Add(currentArea); currentArea = new EnclosedArea(); + } + else if (previousZCoordinate > layerBottomLevel // Area should also be added when 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(); // If the next z coordinate is increasing, it means that the surface line is intersecting // the bottom level with an inflection point. In this situation, the current coordinate should be // added to the new area - if (nextZCoordinate > currentZCoordinate) + if (nextSurfaceLineZCoordinate > currentZCoordinate) { currentArea.AddCoordinate(new Point2D(xCoordinate, currentZCoordinate)); } @@ -415,13 +425,13 @@ previousZCoordinate = currentZCoordinate; // End of array, take the last Z coordinate as the next coordinate - j = i == xCoordinateArray.Length - 2 ? j : j + 1; + j = i == pointsArray.Length - 2 ? j : j + 1; } // The last area needs to be added manually enclosedAreas.Add(currentArea); - return enclosedAreas.Where(area => area.Coordinates.Any()) + return enclosedAreas.Where(area => area.Coordinates.Count() > 1) .Select(a => CreateLayerData(a, soilLayer)) .ToArray(); } @@ -448,11 +458,6 @@ 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 based on a collection of points. ///