Index: DamEngine/trunk/src/Deltares.DamEngine.Data.Tests/Geotechnics/GeometryHelperTests.cs =================================================================== diff -u -r4901 -r4984 --- DamEngine/trunk/src/Deltares.DamEngine.Data.Tests/Geotechnics/GeometryHelperTests.cs (.../GeometryHelperTests.cs) (revision 4901) +++ DamEngine/trunk/src/Deltares.DamEngine.Data.Tests/Geotechnics/GeometryHelperTests.cs (.../GeometryHelperTests.cs) (revision 4984) @@ -23,6 +23,7 @@ using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.TestHelpers.Factories; +using Deltares.DamEngine.TestHelpers.Geometry; using NUnit.Framework; namespace Deltares.DamEngine.Data.Tests.Geotechnics; @@ -31,9 +32,9 @@ public class GeometryHelperTests { // For debugging purposes - private const string visualizationFolder = @"D:\src\dam\DamTools\GeometryVisualizer\"; + private const string visualizationFolder = @"C:\Dam\DamTools\GeometryVisualizer\"; // Use the following code to export the geometry to a file - // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); + //GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); const double cTolerance = 1e-6; @@ -44,14 +45,14 @@ // Given SoilProfile2D soilProfile2D = FactoryForSoilProfiles.CreateSoilProfile2DWithThreeLayers(); // For debugging purposes - // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); - // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); + //GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); + //GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); // When GeometryHelper.ExtendGeometryLeft(soilProfile2D.Geometry, -2); // For debugging purposes - // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); - // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); + GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); + GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); // Then GeometryBounds geometryBounds = soilProfile2D.Geometry.GetGeometryBounds(); @@ -61,7 +62,10 @@ Assert.That(soilProfile2D.Geometry.Left, Is.EqualTo(-2).Within(cTolerance)); // At first there are 3 surfaces, but after extending the right boundary, there are 6 surfaces Assert.That(soilProfile2D.Geometry.Surfaces.Count, Is.EqualTo(6)); - // TODO: MWDAM-2132 still 3 loose lines + // the number of points should now be 12 + 4 = 16 + Assert.That(soilProfile2D.Geometry.Points.Count, Is.EqualTo(16)); + // the number of curves should now be 14 + 7 = 21 + Assert.That(soilProfile2D.Geometry.Curves.Count, Is.EqualTo(21)); }); } @@ -84,15 +88,19 @@ // When GeometryHelper.ExtendGeometryRight(soilProfile2D.Geometry, 12); // For debugging purposes - // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); - // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); + GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); + GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); // Then Assert.Multiple(() => { Assert.That(soilProfile2D.Geometry.Right, Is.EqualTo(12).Within(cTolerance)); // At first there are 3 surfaces, but after extending the right boundary, there are 6 surfaces Assert.That(soilProfile2D.Geometry.Surfaces.Count, Is.EqualTo(6)); + // the number of points should now be 12 + 4 = 16 + Assert.That(soilProfile2D.Geometry.Points.Count, Is.EqualTo(16)); + // the number of curves should now be 14 + 7 = 21 + Assert.That(soilProfile2D.Geometry.Curves.Count, Is.EqualTo(21)); }); } @@ -106,20 +114,20 @@ Assert.Throws(() => { GeometryHelper.ExtendGeometryRight(soilProfile2D.Geometry, 8); }); } - [Test, Ignore("Work in progress")] + [Test] public void GivenTwoLayerGeometryWhenCuttingLeftThenLeftBoundaryIsChanged() { // Given SoilProfile2D soilProfile2D = FactoryForSoilProfiles.CreateSoilProfile2DWithThreeLayers(); // For debugging purposes - // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); - // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); + GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); + GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); // When GeometryHelper.CutGeometryLeft(soilProfile2D.Geometry, 2); // For debugging purposes - // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); - // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); + GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); + GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); // Then GeometryBounds geometryBounds = soilProfile2D.Geometry.GetGeometryBounds(); @@ -131,20 +139,20 @@ }); } - [Test, Ignore("Work in progress")] + [Test] public void GivenTwoLayerGeometryWhenCuttingRightThenRightBoundaryIsChanged() { // Given SoilProfile2D soilProfile2D = FactoryForSoilProfiles.CreateSoilProfile2DWithThreeLayers(); // For debugging purposes // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); - // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); + GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); // When - GeometryHelper.CutGeometryLeft(soilProfile2D.Geometry, 8); + GeometryHelper.CutGeometryRight(soilProfile2D.Geometry, 8); // For debugging purposes - // GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); - // GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); + GeometryExporter.ExportToFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.txt"); + GeometryExporter.ExportToJsonFile(soilProfile2D.Geometry, visualizationFolder + "Geometry.json"); // Then GeometryBounds geometryBounds = soilProfile2D.Geometry.GetGeometryBounds(); Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryConstants.cs =================================================================== diff -u -r4540 -r4984 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryConstants.cs (.../GeometryConstants.cs) (revision 4540) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryConstants.cs (.../GeometryConstants.cs) (revision 4984) @@ -45,6 +45,11 @@ /// The accuracy as used for the geometry objects /// public const double Accuracy = 0.001; + + /// + /// The accuracy as used for testing similarity of the geometry objects + /// + public const double TestAccuracy = Accuracy / 2.0; /// /// The volumic weight of water Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryHelper.cs =================================================================== diff -u -r4899 -r4984 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryHelper.cs (.../GeometryHelper.cs) (revision 4899) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Geometry/GeometryHelper.cs (.../GeometryHelper.cs) (revision 4984) @@ -41,33 +41,7 @@ Point2D[] leftPoints = geometry.GetLeftPoints().OrderBy(x => x.Z).ToArray(); List leftCurves = geometry.GetLeftCurves(); - Point2D prevPoint = null; - for (var i = 0; i < leftPoints.Count(); i++) - { - var newPoint = new Point2D(toX, leftPoints[i].Z); - geometry.Points.Add(newPoint); - var newhorizontalCurve = new GeometryCurve(newPoint, leftPoints[i]); - geometry.Curves.Add(newhorizontalCurve); - if (i > 0) - { - var newVerticalCurve = new GeometryCurve(newPoint, prevPoint); - geometry.Curves.Add(newVerticalCurve); - } - - prevPoint = newPoint; - } - - foreach (GeometryCurve geometryCurve in leftCurves) - { - // check if curve is vertical, only then it is on the "old" boundary and needs to be deleted - if (Math.Abs(geometryCurve.HeadPoint.X - geometryCurve.EndPoint.X) < GeometryConstants.Accuracy) - { - geometry.DeleteCurve(geometryCurve, false); - } - } - - // geometry.DeleteLooseCurves(); - geometry.RegenerateGeometry(); + AddNewPointsCurvesLoopsAndSurfacesForExtension(geometry, toX, leftPoints, leftCurves); geometry.Rebox(); geometry.Left = toX; } @@ -86,35 +60,50 @@ Point2D[] rightPoints = geometry.GetRightPoints().OrderBy(x => x.Z).ToArray(); List rightCurves = geometry.GetRightCurves(); - Point2D prevPoint = null; - for (var i = 0; i < rightPoints.Length; i++) + AddNewPointsCurvesLoopsAndSurfacesForExtension(geometry, toX, rightPoints, rightCurves); + geometry.Rebox(); + geometry.Right = toX; + } + + private static void AddNewPointsCurvesLoopsAndSurfacesForExtension(GeometryData geometry, double toX, Point2D[] edgePoints, + List edgeCurves) + { + var newBottomPoint = new Point2D(toX, edgePoints[0].Z); + geometry.Points.Add(newBottomPoint); + var newhorizontalCurve1 = new GeometryCurve(edgePoints[0], newBottomPoint); + geometry.Curves.Add(newhorizontalCurve1); + for (var i = 1; i < edgePoints.Length; i++) { - var newPoint = new Point2D(toX, rightPoints[i].Z); - geometry.Points.Add(newPoint); - var newhorizontalCurve = new GeometryCurve(rightPoints[i], newPoint); - geometry.Curves.Add(newhorizontalCurve); - if (i > 0) + var newSurface = new GeometrySurface(); + + var newTopPoint = new Point2D(toX, edgePoints[i].Z); + geometry.Points.Add(newTopPoint); + var newhorizontalCurve2 = new GeometryCurve(edgePoints[i], newTopPoint); + geometry.Curves.Add(newhorizontalCurve2); + var newVerticalCurve = new GeometryCurve(newBottomPoint, newTopPoint); + geometry.Curves.Add(newVerticalCurve); + + var newLoop = new GeometryLoop(); + newLoop.CurveList.Add(newhorizontalCurve1); + newLoop.CurveList.Add(newVerticalCurve); + newhorizontalCurve2.Reverse(); + newLoop.CurveList.Add(newhorizontalCurve2); + var existingVerticalCurve = GetCurvesWithPoints(edgePoints[i], edgePoints[i - 1], edgeCurves); + newLoop.CurveList.Add(existingVerticalCurve); + if (newLoop.IsContinuous()) { - var newVerticalCurve = new GeometryCurve(newPoint, prevPoint); - geometry.Curves.Add(newVerticalCurve); + geometry.Loops.Add(newLoop); + newSurface.OuterLoop = newLoop; + geometry.Surfaces.Add(newSurface); } - - prevPoint = newPoint; - } - - foreach (GeometryCurve geometryCurve in rightCurves) - { - // check if curve is vertical, only then it is on the "old" boundary and needs to be deleted - if (Math.Abs(geometryCurve.HeadPoint.X - geometryCurve.EndPoint.X) < GeometryConstants.Accuracy) + else { - geometry.DeleteCurve(geometryCurve, false); + // Should not ever happen so can not be tested. + throw new ArgumentException("The new loop is not a real continuous loop."); } + newBottomPoint = newTopPoint; + newhorizontalCurve1 = newhorizontalCurve2; } - - // geometry.DeleteLooseCurves(); - geometry.RegenerateGeometry(); - geometry.Rebox(); - geometry.Right = toX; } /// @@ -125,14 +114,16 @@ public static void CutGeometryLeft(GeometryData geometry, double atX) { GeometryCurve intersectionCurve = GetIntersectionCurveAt(geometry, atX); + // check if a curve intersects the atX, if so move point. GeometryCurve[] curves = geometry.Curves.ToArray(); + var splitPoints = new List(); foreach (GeometryCurve geometryCurve in curves) { var p1 = new Point2D(geometryCurve.HeadPoint.X, geometryCurve.HeadPoint.Z); var p2 = new Point2D(geometryCurve.EndPoint.X, geometryCurve.EndPoint.Z); // If head or endpoint is at atX, skip this curve - if (Math.Abs(p1.X - atX) > GeometryConstants.Accuracy && Math.Abs(p2.X - atX) > GeometryConstants.Accuracy) + if (Math.Abs(p1.X - atX) > GeometryConstants.Accuracy && Math.Abs(p2.X - atX) > GeometryConstants.TestAccuracy) { var p3 = new Point2D(intersectionCurve.HeadPoint.X, intersectionCurve.HeadPoint.Z); var p4 = new Point2D(intersectionCurve.EndPoint.X, intersectionCurve.EndPoint.Z); @@ -142,21 +133,47 @@ var splitPoint = new Point2D(resPoint.X, resPoint.Z); // Split the curve at the split point SplitCurveAtPoint(geometry, geometryCurve, splitPoint); + splitPoints.Add(splitPoint); } } } + + // Add the vertical curves between the split points + AddCurvesBetweenSplitPoints(geometry, splitPoints); + + geometry.RegenerateGeometry(); + + // Remove all surfaces left of the new limit + List surfs = GetSurfacesLeftOfNewLimit(geometry, atX); + foreach (GeometrySurface aSurface in surfs) + { + DeleteSurface(geometry, aSurface); + } + + // Remove all now obsolete curves and point at the left of the new limit + Point2D[] points = geometry.Points.ToArray(); + for (var i = 0; i < points.Length; i++) + { + if (points[i].X < atX - GeometryConstants.TestAccuracy) + { + geometry.DeletePointWithCurves(points[i]); + } + } + geometry.Rebox(); } /// /// Cuts the geometry right at the given value of x. /// /// The geometry. /// X position to cut the geometry. - private static void CutGeometryRight(GeometryData geometry, double atX) + public static void CutGeometryRight(GeometryData geometry, double atX) { GeometryCurve intersectionCurve = GetIntersectionCurveAt(geometry, atX); + // check if a curve intersects the atX, if so move point. GeometryCurve[] curves = geometry.Curves.ToArray(); + var splitPoints = new List(); foreach (GeometryCurve geometryCurve in curves) { var p1 = new Point2D(geometryCurve.HeadPoint.X, geometryCurve.HeadPoint.Z); @@ -171,54 +188,120 @@ { var splitPoint = new Point2D(resPoint.X, resPoint.Z); // Split the curve at the split point - SplitCurveAtPoint(geometry, geometryCurve, splitPoint); + //SplitCurveAtPoint(geometry, geometryCurve, splitPoint); + splitPoints.Add(splitPoint); } } } + + // Add the vertical curves between the split points + AddCurvesBetweenSplitPoints(geometry, splitPoints); + + // List surfaces = geometry.Surfaces.ToList(); + // foreach (GeometrySurface aSurface in surfaces) + // { + // DeleteSurface(geometry, aSurface); + // } + // geometry.NewlyEffectedCurves.AddRange(geometry.Curves); + // geometry.Curves.Clear(); + // geometry.NewlyEffectedPoints.AddRange(geometry.Points); + // geometry.Points.Clear(); Hier heb ik schijnbaar nog maar 1 loop ipv 3. Nakijken hoe dit loopt bij left + geometry.RegenerateGeometry(); - // To ensure that curves right of the atX are removed when they are completely right (so no intersection) - // remove all points right of the at X. + // Remove all surfaces right of the new limit + List surfs = GetSurfacesRightOfNewLimit(geometry, atX); + foreach (GeometrySurface aSurface in surfs) + { + DeleteSurface(geometry, aSurface); + } + + // Remove all now obsolete curves and points at the right of the new limit Point2D[] points = geometry.Points.ToArray(); for (var i = 0; i < points.Length; i++) { - if (points[i].X > atX + GeometryConstants.Accuracy) + if (points[i].X > atX + GeometryConstants.TestAccuracy) { geometry.DeletePointWithCurves(points[i]); } } - // Set the right boundary geometry.Rebox(); - geometry.Right = atX; + } + + private static void AddCurvesBetweenSplitPoints(GeometryData geometry, List splitPoints) + { + if (splitPoints.Count > 1) + { + SortSplitPoints(splitPoints); + geometry.NewlyEffectedPoints.Add(splitPoints[0]); + for (var i = 1; i < splitPoints.Count; i++) + { + var newCurve = new GeometryCurve(splitPoints[i - 1], splitPoints[i]); + geometry.NewlyEffectedPoints.Add(splitPoints[i]); + geometry.NewlyEffectedCurves.Add(newCurve); + //geometry.Curves.Add(newCurve); + } + } + } - // Add missing vertical curves on the right boundary - List rightPoints = geometry.GetRightPoints().OrderBy(a => a.Z).ToList(); - AddMissingBoundaryCurves(geometry, rightPoints); + private static void SortSplitPoints(List splitPoints) + { + splitPoints.Sort((a, b) => a.Z.CompareTo(b.Z)); } - /// - /// Adds the missing boundary curves. - /// - /// The geometry - /// The boundary points. - private static void AddMissingBoundaryCurves(GeometryData geometry, List boundaryPoints) + private static List GetSurfacesLeftOfNewLimit(GeometryData geometry, double atX) { - for (var i = 1; i < boundaryPoints.Count; i++) + List surfacesLeftOfLimits = new List(); + foreach (GeometrySurface surface in geometry.Surfaces) { - // get the centerpoint of the "would be" curve - var midPoint = new Point2D((boundaryPoints[i - 1].X + boundaryPoints[i].X) / 2, - (boundaryPoints[i - 1].Z + boundaryPoints[i].Z) / 2); - // Check if the "would be" curve exists, if not add it - var existingCurves = new List(); - geometry.GetCurvesCoincidingWithPoint(midPoint, ref existingCurves); - if (existingCurves.Count == 0) + foreach (Point2D point in (IEnumerable) surface.OuterLoop.CalcPoints) { - var newCurve = new GeometryCurve(boundaryPoints[i - 1], boundaryPoints[i]); - geometry.Curves.Add(newCurve); + if (point.X < atX - GeometryConstants.TestAccuracy) + { + surfacesLeftOfLimits.Add(surface); + break; + } } } + return surfacesLeftOfLimits; } - + + private static List GetSurfacesRightOfNewLimit(GeometryData geometry, double atX) + { + List surfacesRightOfLimits = new List(); + foreach (GeometrySurface surface in geometry.Surfaces) + { + foreach (Point2D point in (IEnumerable) surface.OuterLoop.CalcPoints) + { + if (point.X > atX + GeometryConstants.TestAccuracy) + { + surfacesRightOfLimits.Add(surface); + break; + } + } + } + return surfacesRightOfLimits; + } + + private static void DeleteSurface(GeometryData geometry, GeometrySurface aSurface) + { + GeometrySurface aData = aSurface; + GeometryLoop outerLoop = aSurface.OuterLoop; + List geometryCurveList = new List(); + foreach (GeometryCurve curve in outerLoop.CurveList) + { + if (((curve.SurfaceAtLeft == null ? (true ? 1 : 0) : (curve.SurfaceAtLeft == aData ? 1 : 0)) & + (curve.SurfaceAtRight == null ? 1 : (curve.SurfaceAtRight == aData ? 1 : 0))) != 0) + geometryCurveList.Add(curve); + else + geometry.NewlyEffectedCurves.Add(curve); + } + foreach (GeometryCurve aCurve in geometryCurveList) + geometry.DeleteCurve(aCurve, true); + geometry.Remove( outerLoop, false); + geometry.Remove( aSurface, false); + } + /// /// Gets the intersection curve which is a vertical helper line which can be used to find all intersections at a given x. /// @@ -240,7 +323,7 @@ /// The split point. private static void SplitCurveAtPoint(GeometryData geometry, GeometryCurve geometryCurve, Point2D splitPoint) { - Point2D existingPoint = geometry.GetPointAtLocation(new Point2D(splitPoint.X, splitPoint.Z), GeometryConstants.Accuracy); + Point2D existingPoint = geometry.GetPointAtLocation(new Point2D(splitPoint.X, splitPoint.Z), GeometryConstants.TestAccuracy); // If point already exists do not add but use it if (existingPoint == null) { @@ -257,4 +340,24 @@ var newCurve = new GeometryCurve(splitPoint, oldEnd); geometry.Curves.Add(newCurve); } + + public static GeometryCurve GetCurvesWithPoints(Point2D headPoint, Point2D endPoint, List curves) + { + + int curveCount = curves.Count; + + // loop through the list of curves, check if point on line + for (var index = 0; index < curveCount; index++) + { + GeometryCurve curve = curves[index]; + + // does the input point exist in this line (within aValue1 tolerance) + if (Routines2D.DoesPointExistInLine(curve.HeadPoint, curve.EndPoint, headPoint, GeometryConstants.Accuracy)) + { + if (Routines2D.DoesPointExistInLine(curve.HeadPoint, curve.EndPoint, endPoint, GeometryConstants.Accuracy)) + return curve; + } + } + return null; + } } \ No newline at end of file