// 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 System.Collections.Generic; using System.Linq; using Deltares.DamEngine.Data.Geometry; using NUnit.Framework; namespace Deltares.DamEngine.Data.Tests.Geometry; [TestFixture] public class GeometryDataTests { [Test] public void TestRemoveDoublesFromNewlyEffectedPointsAndCurves() { var point1 = new Point2D(1, 0); // to be kept var point2 = new Point2D(1, 0); // to be removed as == p1 var point3 = new Point2D(5, 0); // to be kept var point4 = new Point2D(5, 0); // to be removed as == p3 var point5 = new Point2D(1, 0); // to be removed as == p1 var point6 = new Point2D(5, 0); // to be removed as == p3 var curve1 = new GeometryCurve(point1, point2); // to be removed as no lenght var curve2 = new GeometryCurve(point2, point3); // to be kept var curve3 = new GeometryCurve(point1, point2); // to be removed as no lenght var curve4 = new GeometryCurve(point4, point1); // to be removed as == c2 (in reverse order) var curve5 = new GeometryCurve(point3, point5); // to be removed as == c2 (in reverse order) var curve6 = new GeometryCurve(point1, point1); // to be removed as no lenght var curve7 = new GeometryCurve(point1, point1); // to be removed as no lenght var curve8 = new GeometryCurve(null, null); // to be removed as no points var curve9 = new GeometryCurve(null, point2); // to be removed as no headpoint var curve10 = new GeometryCurve(point3, null); // to be removed as no endpoint var geometrymodel = new GeometryData(); geometrymodel.NewlyEffectedPoints.Add(point1); geometrymodel.NewlyEffectedPoints.Add(point2); geometrymodel.NewlyEffectedPoints.Add(point3); geometrymodel.NewlyEffectedPoints.Add(point4); geometrymodel.NewlyEffectedPoints.Add(point5); geometrymodel.NewlyEffectedPoints.Add(point6); geometrymodel.NewlyEffectedCurves.Add(curve1); geometrymodel.NewlyEffectedCurves.Add(curve2); geometrymodel.NewlyEffectedCurves.Add(curve3); geometrymodel.NewlyEffectedCurves.Add(curve4); geometrymodel.NewlyEffectedCurves.Add(curve5); geometrymodel.NewlyEffectedCurves.Add(curve6); geometrymodel.NewlyEffectedCurves.Add(curve7); geometrymodel.NewlyEffectedCurves.Add(curve8); geometrymodel.NewlyEffectedCurves.Add(curve9); geometrymodel.NewlyEffectedCurves.Add(curve10); geometrymodel.RemoveDoublesFromNewlyEffectedPointsAndCurves(); // only two points are unique by location Assert.That(geometrymodel.NewlyEffectedPoints.Count, Is.EqualTo(2)); // only two curves hold both head and endpoint with unique locations Assert.That(geometrymodel.NewlyEffectedCurves.Count, Is.EqualTo(1)); } [Test] public void GeometryHelperTestSurfaceTwoVertLayers() { GeometryData gData = CreateGeometrySurface2(); GeometryPointString line = gData.SurfaceLine; Assert.That(line.CalcPoints.Count, Is.EqualTo(3)); Assert.That(line.CalcPoints.OrderBy(p => p.X).First().X, Is.EqualTo(1.0)); Assert.That(line.CalcPoints.OrderByDescending(p => p.X).First().X, Is.EqualTo(10.0)); } [Test] public void GeometryDataTestSurfaceTwoHorLayers() { GeometryData gData = CreateGeometrySurface(); GeometryPointString line = gData.SurfaceLine; Assert.That(line.CalcPoints.Count, Is.EqualTo(2)); Assert.That(line.CalcPoints.OrderBy(p => p.X).First().X, Is.EqualTo(1.0)); Assert.That(line.CalcPoints.OrderByDescending(p => p.X).First().X, Is.EqualTo(10.0)); } [Test] public void GeometryDataTestClear() { GeometryData gData = CreateGeometrySurface(); Assert.Multiple(() => { Assert.That(gData.Points, Has.Count.EqualTo(6)); Assert.That(gData.Curves, Has.Count.EqualTo(7)); Assert.That(gData.Loops, Has.Count.EqualTo(2)); Assert.That(gData.Surfaces, Has.Count.EqualTo(2)); }); gData.Clear(); Assert.Multiple(() => { Assert.That(gData.Points, Has.Count.EqualTo(0)); Assert.That(gData.Curves, Has.Count.EqualTo(0)); Assert.That(gData.Loops, Has.Count.EqualTo(0)); Assert.That(gData.Surfaces, Has.Count.EqualTo(0)); Assert.That(gData.NewlyEffectedPoints, Has.Count.EqualTo(0)); Assert.That(gData.NewlyEffectedCurves, Has.Count.EqualTo(0)); }); } [Test] public void GeometryDataTestGetRightCurves() { GeometryData gData = CreateGeometrySurface(); var rightCurves = gData.GetRightCurves(); Assert.Multiple(() => { Assert.That(rightCurves, Has.Count.EqualTo(5)); Assert.That(rightCurves[0].HeadPoint.X, Is.EqualTo(1.0)); Assert.That(rightCurves[0].EndPoint.X, Is.EqualTo(10.0)); Assert.That(rightCurves[1].HeadPoint.X, Is.EqualTo(10.0)); Assert.That(rightCurves[1].EndPoint.X, Is.EqualTo(10.0)); Assert.That(rightCurves[0].HeadPoint.Z, Is.EqualTo(0.0)); Assert.That(rightCurves[0].EndPoint.Z, Is.EqualTo(0.0)); Assert.That(rightCurves[1].HeadPoint.Z, Is.EqualTo(0.0)); Assert.That(rightCurves[1].EndPoint.Z, Is.EqualTo(5.0)); }); } [Test] public void GeometryDataTestGetLeftCurves() { GeometryData gData = CreateGeometrySurface(); var leftCurves = gData.GetLeftCurves(); Assert.Multiple(() => { Assert.That(leftCurves, Has.Count.EqualTo(5)); Assert.That(leftCurves[0].HeadPoint.X, Is.EqualTo(1.0)); Assert.That(leftCurves[0].EndPoint.X, Is.EqualTo(10.0)); Assert.That(leftCurves[1].HeadPoint.X, Is.EqualTo(10.0)); Assert.That(leftCurves[1].EndPoint.X, Is.EqualTo(1.0)); Assert.That(leftCurves[0].HeadPoint.Z, Is.EqualTo(0.0)); Assert.That(leftCurves[0].EndPoint.Z, Is.EqualTo(0.0)); Assert.That(leftCurves[1].HeadPoint.Z, Is.EqualTo(10.0)); Assert.That(leftCurves[1].EndPoint.Z, Is.EqualTo(10.0)); }); } [Test] public void TestSimpleGeneration() { var geom = new GeometryData { Left = 0, Bottom = 0, Right = 100 }; var p1 = new Point2D(0, 5); geom.NewlyEffectedPoints.Add(p1); var p2 = new Point2D(100, 5); geom.NewlyEffectedPoints.Add(p2); var p3 = new Point2D(0, 0); geom.NewlyEffectedPoints.Add(p3); var p4 = new Point2D(100, 0); geom.NewlyEffectedPoints.Add(p4); geom.NewlyEffectedCurves.Add(new GeometryCurve(p1, p2)); geom.NewlyEffectedCurves.Add(new GeometryCurve(p3, p4)); geom.NewlyEffectedCurves.Add(new GeometryCurve(p1, p3)); geom.NewlyEffectedCurves.Add(new GeometryCurve(p2, p4)); geom.RegenerateGeometry(); Assert.That(geom.Points.Count, Is.EqualTo(4)); Assert.That(geom.Curves.Count, Is.EqualTo(4)); Assert.That(geom.Surfaces.Count, Is.EqualTo(1)); Assert.That(geom.Surfaces[0].InnerLoops.Count, Is.EqualTo(0)); Assert.That(geom.Surfaces[0].OuterLoop.Count, Is.EqualTo(4)); Assert.That(geom.Surfaces[0].OuterLoop.CurveList.Count, Is.EqualTo(4)); Assert.That(geom.Surfaces[0].OuterLoop.CalcPoints.Count, Is.EqualTo(4)); Assert.That(geom.Surfaces[0].OuterLoop.HasArea(), Is.True); Assert.That(geom.Surfaces[0].OuterLoop.IsLoop(), Is.True); Assert.That(geom.Surfaces[0].OuterLoop.IsPointInLoopArea(new Point2D(25, 3)), Is.True); Assert.That(geom.Surfaces[0].OuterLoop.IsPointInLoopArea(new Point2D(25, 5.1)), Is.False); } [Test] [TestCase(1, 0, true)] [TestCase(10, 0, true)] [TestCase(10, 10, true)] [TestCase(1, 10, true)] [TestCase(1, 1, false)] [TestCase(0, 1, false)] public void GivenPointsWhenGetPointAtLocationCalledThenCorrectPointIsReturned(double x, double z, bool isPresent) { const double tolerance = 1e-6; var geometryModel = new GeometryData(); var point1 = new Point2D(1, 0); var point2 = new Point2D(10, 0); var point3 = new Point2D(10, 10); var point4 = new Point2D(1, 10); geometryModel.Points.AddRange(new[] { point1, point2, point3, point4 }); Point2D point = geometryModel.GetPointAtLocation(new Point2D(x, z)); if (isPresent) { Assert.Multiple(() => { Assert.That(point, Is.Not.Null); Assert.That(point.X, Is.EqualTo(x).Within(tolerance)); Assert.That(point.Z, Is.EqualTo(z).Within(tolerance)); }); } else { Assert.That(point, Is.Null); } } private GeometryData CreateGeometrySurface() { var geometryModel = new GeometryData(); /* The following model looks as follows * * |----------| * | | * |----------| * | | * |----------| * */ var point1 = new Point2D(1, 0); var point2 = new Point2D(10, 0); var point3 = new Point2D(10, 10); var point4 = new Point2D(1, 10); var point5 = new Point2D(1, 5); var point6 = new Point2D(10, 5); var curve1 = new GeometryCurve(point1, point2); var curve2 = new GeometryCurve(point2, point3); var curve3 = new GeometryCurve(point3, point4); var curve4 = new GeometryCurve(point4, point1); var curve5 = new GeometryCurve(point5, point6); geometryModel.Points.AddRange(new[] { point1, point2, point3, point4, point5, point6 }); geometryModel.Curves.AddRange(new[] { curve1, curve2, curve3, curve4, curve5 }); geometryModel.NewlyEffectedPoints.AddRange(geometryModel.Points); geometryModel.NewlyEffectedCurves.AddRange(geometryModel.Curves); geometryModel.RegenerateGeometry(); geometryModel.Rebox(); return geometryModel; } private GeometryData CreateGeometrySurface2() { var geometryModel = new GeometryData(); /* The following model looks as follows * * |-----|----| * | | | * | | | * | | | * |-----|----| * */ var point1 = new Point2D(1, 0); var point2 = new Point2D(1, 10); var point3 = new Point2D(5, 10); var point4 = new Point2D(5, 0); var point5 = new Point2D(10, 10); var point6 = new Point2D(10, 0); var curve1 = new GeometryCurve(point1, point2); var curve2 = new GeometryCurve(point2, point3); var curve3 = new GeometryCurve(point3, point4); var curve4 = new GeometryCurve(point4, point1); var curve5 = new GeometryCurve(point3, point5); var curve6 = new GeometryCurve(point5, point6); var curve7 = new GeometryCurve(point6, point4); geometryModel.Points.AddRange(new[] { point1, point2, point3, point4, point5, point6 }); geometryModel.Curves.AddRange(new[] { curve1, curve2, curve3, curve4, curve5, curve6, curve7 }); geometryModel.NewlyEffectedPoints.AddRange(geometryModel.Points); geometryModel.NewlyEffectedCurves.AddRange(geometryModel.Curves); geometryModel.RegenerateGeometry(); return geometryModel; } private GeometryData CreateDonutGeometry() { var geometryModel = new GeometryData { Left = -10, Bottom = -10, Right = 20 }; /* The following model looks as follows * * |----------| * | ------ | * | | | | * | | | | * | ------ | * |----------| * */ var point1 = new Point2D(0, 0); var point2 = new Point2D(0, 10); var point3 = new Point2D(10, 10); var point4 = new Point2D(10, 0); var point5 = new Point2D(3, 3); var point6 = new Point2D(3, 7); var point7 = new Point2D(7, 7); var point8 = new Point2D(7, 3); var curve1 = new GeometryCurve(point1, point2); var curve2 = new GeometryCurve(point2, point3); var curve3 = new GeometryCurve(point3, point4); var curve4 = new GeometryCurve(point4, point1); var curve5 = new GeometryCurve(point5, point6); var curve6 = new GeometryCurve(point6, point7); var curve7 = new GeometryCurve(point7, point8); var curve8 = new GeometryCurve(point8, point5); geometryModel.Points.AddRange(new[] { point1, point2, point3, point4, point5, point6, point7, point8 }); geometryModel.Curves.AddRange(new[] { curve1, curve2, curve3, curve4, curve5, curve5, curve6, curve7, curve8 }); geometryModel.NewlyEffectedPoints.AddRange(geometryModel.Points); geometryModel.NewlyEffectedCurves.AddRange(geometryModel.Curves); geometryModel.RegenerateGeometry(); return geometryModel; } public class GivenGeometryData { private static readonly GeometryData originalGeometryData = CreateGeometryData(); [TestFixture] public class WhenCloned : GivenGeometryData { private readonly GeometryData clonedGeometryData = originalGeometryData.Clone(); [Test] public void ThenBaseDataIsCopied() { Assert.That(clonedGeometryData, Is.Not.EqualTo(originalGeometryData)); Assert.Multiple(() => { Assert.That(clonedGeometryData.Left, Is.EqualTo(originalGeometryData.Left)); Assert.That(clonedGeometryData.Right, Is.EqualTo(originalGeometryData.Right)); Assert.That(clonedGeometryData.Bottom, Is.EqualTo(originalGeometryData.Bottom)); }); } [Test] public void ThenPointsAreCopied() { Assert.That(clonedGeometryData.Points, Has.Count.EqualTo(originalGeometryData.Points.Count)); Assert.That(clonedGeometryData.Points, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.Points[0], Is.Not.EqualTo(originalGeometryData.Points[0])); Assert.That(clonedGeometryData.Points[0].X, Is.EqualTo(originalGeometryData.Points[0].X)); } [Test] public void ThenNewlyEffectedPointsAreCopied() { Assert.That(clonedGeometryData.NewlyEffectedPoints, Has.Count.EqualTo(originalGeometryData.NewlyEffectedPoints.Count)); Assert.That(clonedGeometryData.NewlyEffectedPoints, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.NewlyEffectedPoints[0], Is.Not.EqualTo(originalGeometryData.NewlyEffectedPoints[0])); Assert.That(clonedGeometryData.NewlyEffectedPoints[0].X, Is.EqualTo(originalGeometryData.NewlyEffectedPoints[0].X)); } [Test] public void ThenCurvesAreCopied() { Assert.That(clonedGeometryData.Curves, Has.Count.EqualTo(originalGeometryData.Curves.Count)); Assert.That(clonedGeometryData.Curves, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.Curves[0], Is.Not.EqualTo(originalGeometryData.Curves[0])); Assert.That(clonedGeometryData.Curves[0].HeadPoint.X, Is.EqualTo(originalGeometryData.Curves[0].HeadPoint.X)); } [Test] public void ThenNewlyEffectedCurvesAreCopied() { Assert.That(clonedGeometryData.NewlyEffectedCurves, Has.Count.EqualTo(originalGeometryData.NewlyEffectedCurves.Count)); Assert.That(clonedGeometryData.NewlyEffectedCurves, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.NewlyEffectedCurves[0], Is.Not.EqualTo(originalGeometryData.NewlyEffectedCurves[0])); Assert.That(clonedGeometryData.NewlyEffectedCurves[0].HeadPoint.X, Is.EqualTo(originalGeometryData.NewlyEffectedCurves[0].HeadPoint.X)); } [Test] public void ThenLoopsAreCopied() { Assert.That(clonedGeometryData.Loops, Has.Count.EqualTo(originalGeometryData.Loops.Count)); Assert.That(clonedGeometryData.Loops, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.Loops[0], Is.Not.EqualTo(originalGeometryData.Loops[0])); Assert.That(clonedGeometryData.Loops[0].CurveList, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.Loops[0].CurveList, Has.Count.EqualTo(originalGeometryData.Loops[0].CurveList.Count)); } [Test] public void ThenSurfacesAreCopied() { Assert.That(clonedGeometryData.Surfaces, Has.Count.EqualTo(originalGeometryData.Surfaces.Count)); Assert.That(clonedGeometryData.Surfaces, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.Surfaces[0], Is.Not.EqualTo(originalGeometryData.Surfaces[0])); Assert.That(clonedGeometryData.Surfaces[0].OuterLoop.CurveList, Has.Count.GreaterThan(0)); Assert.That(clonedGeometryData.Surfaces[0].OuterLoop.CurveList, Has.Count.EqualTo(originalGeometryData.Surfaces[0].OuterLoop.CurveList.Count)); } [Test] public void WhenModified_ThenGeometryDataAreNotEqual() { ModifyGeometryData(clonedGeometryData); Assert.Multiple(() => { Assert.That(clonedGeometryData.Left, Is.Not.EqualTo(originalGeometryData.Left)); Assert.That(clonedGeometryData.Right, Is.Not.EqualTo(originalGeometryData.Right)); Assert.That(clonedGeometryData.Bottom, Is.Not.EqualTo(originalGeometryData.Bottom)); Assert.That(clonedGeometryData.Points, Has.Count.Not.EqualTo(originalGeometryData.Points.Count)); Assert.That(clonedGeometryData.NewlyEffectedPoints, Has.Count.Not.EqualTo(originalGeometryData.NewlyEffectedPoints.Count)); Assert.That(clonedGeometryData.Curves, Has.Count.Not.EqualTo(originalGeometryData.Curves.Count)); Assert.That(clonedGeometryData.NewlyEffectedCurves, Has.Count.Not.EqualTo(originalGeometryData.NewlyEffectedCurves.Count)); Assert.That(clonedGeometryData.Loops, Has.Count.Not.EqualTo(originalGeometryData.Loops.Count)); Assert.That(clonedGeometryData.Surfaces, Has.Count.Not.EqualTo(originalGeometryData.Surfaces.Count)); }); } } private static GeometryData CreateGeometryData() { var geometryData = new GeometryData { Left = -10.0, Right = 10.0, Bottom = -10.0 }; geometryData.Points.Add(new Point2D(0.1, 1.1)); geometryData.Points.Add(new Point2D(0.2, 1.2)); geometryData.NewlyEffectedPoints.Add(new Point2D(0.3, 1.3)); geometryData.NewlyEffectedPoints.Add(new Point2D(0.4, 1.4)); geometryData.Curves.Add(new GeometryCurve(geometryData.Points[0], geometryData.Points[1])); geometryData.NewlyEffectedCurves.Add(new GeometryCurve(geometryData.NewlyEffectedPoints[0], geometryData.NewlyEffectedPoints[1])); var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(1.0, 2.0), new Point2D(3.0, 4.0))); geometryData.Loops.Add(loop); geometryData.Surfaces.Add(new GeometrySurface(loop)); return geometryData; } private static void ModifyGeometryData(GeometryData geometryData) { geometryData.Left = geometryData.Left + 1; geometryData.Right = geometryData.Right + 1; geometryData.Bottom = geometryData.Bottom + 1; geometryData.Points.Add(new Point2D(10.0, 20.0)); geometryData.NewlyEffectedPoints.Add(new Point2D(30.0, 40.0)); geometryData.Curves.Add(new GeometryCurve(geometryData.Points[1], geometryData.Points[2])); geometryData.NewlyEffectedCurves.Add(new GeometryCurve(geometryData.NewlyEffectedPoints[1], geometryData.NewlyEffectedPoints[2])); var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(5.0, 6.0), new Point2D(7.0, 8.0))); geometryData.Loops.Add(loop); geometryData.Surfaces.Add(new GeometrySurface()); } } [Test] public void GivenGeometryData_WhenGetNextTopCurve_ThenReturnsExpectedCurve() { var geometryData = new GeometryData { Left = 0.0, Right = 100.0 }; var leftCurve = new GeometryCurve(new Point2D(0.0, 10.0), new Point2D( 5.0, 200.0)); var curve = new GeometryCurve(new Point2D(5.0, 10.0), new Point2D( 6.0, 10.0)); var connectedCurveLow = new GeometryCurve(new Point2D(6.0, 10.0), new Point2D( 8.0, 11.0)); var connectedCurveHigh = new GeometryCurve(new Point2D(6.0, 10.0), new Point2D( 8.0, 12.0)); var connectedCurveExcluded = new GeometryCurve(new Point2D(6.0, 10.0), new Point2D( 8.0, 13.0)); var boundaryCurves = new List { leftCurve, // it is connected, but only curves on the right side are considered curve, // the curve for which the next top curve is to be found connectedCurveLow, // even though this is connected on the right side, it is not the highest connectedCurveHigh, // this is the curve we are looking for connectedCurveExcluded // even though this is the highest connected curve, it is excluded }; var excludedCurves = new List { connectedCurveExcluded }; GeometryCurve topCurve = geometryData.GetNextTopCurve(curve, boundaryCurves, excludedCurves); Assert.That(topCurve, Is.EqualTo(connectedCurveHigh)); } [Test] public void GivenRightCurve_WhenGetNextTopCurve_ThenReturnsNull() { var geometryData = new GeometryData { Left = 0.0, Right = 100.0 }; var curve = new GeometryCurve(new Point2D(5.0, 10.0), new Point2D( 100.0, 10.0)); var connectedCurve = new GeometryCurve(new Point2D(100.0, 10.0), new Point2D( 50.0, 20.0)); var boundaryCurves = new List { curve, connectedCurve }; var excludedCurves = new List(); GeometryCurve topCurve = geometryData.GetNextTopCurve(curve, boundaryCurves, excludedCurves); Assert.That(topCurve, Is.Null); } }