// 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; using System.Collections.Generic; using Deltares.DamEngine.Data.Geometry; using NUnit.Framework; namespace Deltares.DamEngine.Data.Tests.General; [TestFixture] public class GeometryLoopTests { [Test] public void DefaultConstructor_ExpectedValues() { // setup // call var loop = new GeometryLoop(); // assert Assert.That(loop.Count, Is.EqualTo(loop.Points.Count)); Assert.That(loop.Name, Is.EqualTo(String.Empty)); Assert.That(loop.Points, Is.Empty); //Assert.AreEqual(String.Empty, loop.PointsDescription); Assert.That(loop.CurveList, Is.Empty); } [Test] public void HasArea_LoopCurvesDescribeLine_ReturnFalse() { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(0.0, 0.0), new Point2D(1.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(2.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, loop.CurveList[0].HeadPoint)); // call bool hasArea = loop.HasArea(); // assert Assert.That(hasArea, Is.False); } [Test] public void HasArea_LoopDoesNotHaveAtLeast3DifferentPoints_ReturnFalse() { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].HeadPoint, loop.CurveList[0].EndPoint)); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].HeadPoint, loop.CurveList[0].EndPoint)); loop.CurveList.Add(new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6))); // call bool hasArea = loop.HasArea(); // assert Assert.That(hasArea, Is.False); } [Test] public void HasArea_LoopHasAtLeast3DifferentPoints_ReturnTrue() { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(1.1, 9.9))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, loop.CurveList[0].HeadPoint)); // call bool hasArea = loop.HasArea(); // assert Assert.That(hasArea, Is.True); } [Test] public void HasArea_LoopOrderCurveHasNoInfluenseOnBeingTrue() { // setup H-E H-E H-E var loop = new GeometryLoop(); var c1 = new GeometryCurve(new Point2D(10, 10), new Point2D(20, 10)); loop.CurveList.Add(c1); var c2 = new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(15, 20)); loop.CurveList.Add(c2); var c3 = new GeometryCurve(loop.CurveList[1].EndPoint, loop.CurveList[0].HeadPoint); loop.CurveList.Add(c3); // assert Assert.That(loop.HasArea(), Is.True); // reverse curve 1: E-H H-E H-E c1.Reverse(); var loop1 = new GeometryLoop(); loop1.CurveList.Add(c1); loop1.CurveList.Add(c2); loop1.CurveList.Add(c3); // assert Assert.That(loop1.HasArea(), Is.True); // rereverse c1, reverse c2: H-E E-H H-E c1.Reverse(); c2.Reverse(); var loop2 = new GeometryLoop(); loop2.CurveList.Add(c1); loop2.CurveList.Add(c2); loop2.CurveList.Add(c3); // assert Assert.That(loop2.HasArea(), Is.True); // rereverse c2, reverse c3: H-E H-E E-H c2.Reverse(); c3.Reverse(); var loop3 = new GeometryLoop(); loop3.CurveList.Add(c1); loop3.CurveList.Add(c2); loop3.CurveList.Add(c3); // assert Assert.That(loop3.HasArea(), Is.True); // rereverse c3, reverse c1 and c2 : E-H E-H H-E c3.Reverse(); c2.Reverse(); c1.Reverse(); var loop4 = new GeometryLoop(); loop4.CurveList.Add(c1); loop4.CurveList.Add(c2); loop4.CurveList.Add(c3); // assert Assert.That(loop4.HasArea(), Is.True); // reverse c3 : E-H E-H E-H c3.Reverse(); var loop5 = new GeometryLoop(); loop5.CurveList.Add(c1); loop5.CurveList.Add(c2); loop5.CurveList.Add(c3); // assert Assert.That(loop5.HasArea(), Is.True); // reverse c2 : E-H H-E E-H c2.Reverse(); var loop6 = new GeometryLoop(); loop6.CurveList.Add(c1); loop6.CurveList.Add(c2); loop6.CurveList.Add(c3); // assert Assert.That(loop6.HasArea(), Is.True); // reverse 1, rereverse c2 : H-E E-H E-H c1.Reverse(); c2.Reverse(); var loop7 = new GeometryLoop(); loop7.CurveList.Add(c1); loop7.CurveList.Add(c2); loop7.CurveList.Add(c3); // assert Assert.That(loop7.HasArea(), Is.True); } [Test] [TestCase(0)] [TestCase(1)] public void HasArea_LoopTooFewPoints_ReturnFalse(int count) { // setup var loop = new GeometryLoop(); for (var i = 0; i < count; i++) { loop.CurveList.Add(new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6))); } // call bool hasArea = loop.HasArea(); // assert Assert.That(hasArea, Is.False); } [Test] public void IsClockWise_CurvesFormClockwiseConcavePolygon_ReturnTrue() { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(-1.0, 1.0), new Point2D(0.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(1.0, 1.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, new Point2D(0.0, -1.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[2].EndPoint, loop.CurveList[0].HeadPoint)); // call bool isClockWise = loop.IsClockWise(); // assert Assert.That(isClockWise, Is.True); } [Test] [TestCase(3)] [TestCase(50)] public void IsClockWise_CurvesFormClockwiseConvexPolygon_ReturnTrue(int pointCount) { // setup var loop = new GeometryLoop(); double angleSegment = 2.0 * Math.PI / pointCount; Point2D first = null, last = null; for (var i = 0; i < pointCount - 1; i++) { double angleP0 = angleSegment * i; double angleP1 = angleP0 + angleSegment; var p1 = new Point2D(Math.Sin(angleP1), Math.Cos(angleP1)); if (i == 0) { first = new Point2D(Math.Sin(angleP0), Math.Cos(angleP0)); loop.CurveList.Add(new GeometryCurve(first, p1)); } else { loop.CurveList.Add(new GeometryCurve(last, p1)); } last = p1; } // TODO: Make GeometryLoop.Points less smart, such that one could simply do loop.Points.First()/.Last() :( loop.CurveList.Add(new GeometryCurve(last, first)); // call bool isClockWise = loop.IsClockWise(); // assert Assert.That(isClockWise, Is.True); } [Test] public void IsClockWise_CurvesFormCounterClockwiseConcavePolygon_ReturnFalse() { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(1.0, 1.0), new Point2D(0.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(-1.0, 1.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, new Point2D(0.0, -1.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[2].EndPoint, loop.CurveList[0].HeadPoint)); // call bool isClockWise = loop.IsClockWise(); // assert Assert.That(isClockWise, Is.False); } [Test] [TestCase(3)] [TestCase(50)] public void IsClockWise_CurvesFormCounterClockwiseConvexPolygon_ReturnFalse(int pointCount) { // setup var loop = new GeometryLoop(); double angleSegment = -2.0 * Math.PI / pointCount; Point2D first = null, last = null; for (var i = 0; i < pointCount - 1; i++) { double angleP0 = angleSegment * i; double angleP1 = angleP0 + angleSegment; var p1 = new Point2D(Math.Sin(angleP1), Math.Cos(angleP1)); if (i == 0) { first = new Point2D(Math.Sin(angleP0), Math.Cos(angleP0)); loop.CurveList.Add(new GeometryCurve(first, p1)); } else { loop.CurveList.Add(new GeometryCurve(last, p1)); } last = p1; } // TODO: Make GeometryLoop.Points less smart, such that one could simply do loop.Points.First()/.Last() :( loop.CurveList.Add(new GeometryCurve(last, first)); // call bool isClockWise = loop.IsClockWise(); // assert Assert.That(isClockWise, Is.False); } [Test] public void IsClockWise_CurvesFormStraightLine_ThrowInvalidOperationException() { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(0.0, 0.0), new Point2D(1.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(2.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, loop.CurveList[0].HeadPoint)); // call TestDelegate call = () => loop.IsClockWise(); // assert Assert.Throws(call); } [Test] [TestCase(0)] [TestCase(1)] [TestCase(5)] public void IsClockWise_TooFewUniquePoints_ThrowNotEnoughUniquePointsException(int curveCount) { // setup var loop = new GeometryLoop(); Point2D lastPoint = null; for (var i = 0; i < curveCount; i++) { var newPoint = new Point2D(); if (i == 0) { loop.CurveList.Add(new GeometryCurve(new Point2D(), newPoint)); } else { loop.CurveList.Add(new GeometryCurve(lastPoint, newPoint)); } lastPoint = newPoint; } int pointCount = loop.Points.Count; Assert.That(pointCount, Is.EqualTo(curveCount == 0 ? 0 : curveCount + 1)); // call TestDelegate call = () => loop.IsClockWise(); // assert Assert.Throws(call); } [Test] public void IsPointInLoop_PointIsInsideLoop_ReturnTrue() { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(0.0, 0.0), new Point2D(10.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(10.0, 10.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, new Point2D(0.0, 10.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[2].EndPoint, loop.CurveList[0].HeadPoint)); var point = new Point2D(1.2, 3.4); // call bool isContained = loop.IsPointInLoopArea(point); // assert Assert.That(isContained, Is.True); } [Test] [TestCase(5.0, 10.0)] [TestCase(5.0, 0.0)] [TestCase(0.0, 5.0)] [TestCase(10.0, 5.0)] public void IsPointInLoop_PointIsOnLoopEdge_ReturnTrue(double x, double z) { // setup var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(0.0, 0.0), new Point2D(10.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(10.0, 10.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, new Point2D(0.0, 10.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[2].EndPoint, loop.CurveList[0].HeadPoint)); var point = new Point2D(x, z); // call bool isContained = loop.IsPointInLoopArea(point); // assert Assert.That(isContained, Is.True); } [Test] [TestCase(0.0 - 1e-6, 5.0)] [TestCase(10.0 + 1e-6, 5.0)] [TestCase(5.0, 0.0 - 1e-6)] [TestCase(5.0, 10.0 + 1e-6)] public void IsPointInLoop_PointIsOutsideLoop_ReturnFalse(double x, double z) { // setup GeometryLoop loop = GenerateSquareGeometryLoop(); var point = new Point2D(x, z); // call bool isContained = loop.IsPointInLoopArea(point); // assert Assert.That(isContained, Is.False); } [Test] public void Points_OnGetWithMultipleCurves_SharingInstancesBetweenCurvePointsFormingLoop_ReturnOnlyConnectedCurveHeadAndEndPoints() { // setup var curve1 = new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6)); var curve2 = new GeometryCurve(new Point2D(7.7, 9.9), curve1.EndPoint); var curve3 = new GeometryCurve(curve2.HeadPoint, new Point2D(10.10, 12.12)); var curve4 = new GeometryCurve(new Point2D(13.13, 15.15), curve3.EndPoint); var curve5 = new GeometryCurve(curve4.HeadPoint, new Point2D(16.16, 18.18)); var curve6 = new GeometryCurve(curve5.EndPoint, new Point2D(19.19, 21.21)); var curve7 = new GeometryCurve(curve1.HeadPoint, curve6.EndPoint); var loop = new GeometryLoop(); loop.CurveList.AddRange(new[] { curve1, curve2, curve3, curve4, curve5, curve6, curve7 }); // call List points = loop.Points; // assert Assert.That(points.Count, Is.EqualTo(7)); Assert.That(points[0], Is.SameAs(curve1.HeadPoint)); Assert.That(points[1], Is.SameAs(curve1.EndPoint)); Assert.That(points[2], Is.SameAs(curve2.HeadPoint)); Assert.That(points[3], Is.SameAs(curve3.EndPoint)); Assert.That(points[4], Is.SameAs(curve4.HeadPoint)); Assert.That(points[5], Is.SameAs(curve5.EndPoint)); Assert.That(points[6], Is.SameAs(curve6.EndPoint)); } [Test] public void Points_OnGetWithMultipleCurves_SharingInstancesBetweenCurvePoints_ReturnOnlyConnectedCurveHeadAndEndPoints() { // setup var curve1 = new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6)); var curve2 = new GeometryCurve(new Point2D(7.7, 9.9), curve1.EndPoint); var curve3 = new GeometryCurve(curve2.HeadPoint, new Point2D(10.10, 12.12)); var curve4 = new GeometryCurve(new Point2D(13.13, 15.15), curve3.EndPoint); var curve5 = new GeometryCurve(curve4.HeadPoint, new Point2D(16.16, 18.18)); var curve6 = new GeometryCurve(curve5.EndPoint, new Point2D(19.19, 21.21)); var curve7 = new GeometryCurve(new Point2D(22.22, 24.24), new Point2D(25.25, 27.27)); var curve8 = new GeometryCurve(new Point2D(28.28, 30.30), new Point2D(31.31, 33.33)); var curve9 = new GeometryCurve(new Point2D(34.34, 36.36), curve6.EndPoint); var loop = new GeometryLoop(); loop.CurveList.AddRange(new[] { curve1, curve2, curve3, curve4, curve5, curve6, curve7, curve8, curve9 }); // call List points = loop.Points; // assert Assert.That(points.Count, Is.EqualTo(8)); Assert.That(points[0], Is.SameAs(curve1.HeadPoint)); Assert.That(points[1], Is.SameAs(curve1.EndPoint)); Assert.That(points[2], Is.SameAs(curve2.HeadPoint)); Assert.That(points[3], Is.SameAs(curve3.EndPoint)); Assert.That(points[4], Is.SameAs(curve4.HeadPoint)); Assert.That(points[5], Is.SameAs(curve5.EndPoint)); Assert.That(points[6], Is.SameAs(curve6.EndPoint)); Assert.That(points[7], Is.SameAs(curve9.HeadPoint)); } [Test] public void Points_OnGetWithMultipleCurves_SharingInstancesEndPointAndEndPoint_ReturnUniqueHeadAndEndPoints() { // setup var curve1 = new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6)); var curve2 = new GeometryCurve(new Point2D(7.7, 9.9), curve1.EndPoint); var loop = new GeometryLoop(); loop.CurveList.AddRange(new[] { curve1, curve2 }); // call List points = loop.Points; // assert Assert.That(points.Count, Is.EqualTo(3)); Assert.That(points[0], Is.SameAs(curve1.HeadPoint)); Assert.That(points[1], Is.SameAs(curve1.EndPoint)); Assert.That(points[2], Is.SameAs(curve2.HeadPoint)); } [Test] public void Points_OnGetWithMultipleCurves_SharingInstancesEndPointAndHeadPoint_ReturnUniqueHeadAndEndPoints() { // setup var curve1 = new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6)); var curve2 = new GeometryCurve(curve1.EndPoint, new Point2D(7.7, 9.9)); var loop = new GeometryLoop(); loop.CurveList.AddRange(new[] { curve1, curve2 }); // call List points = loop.Points; // assert Assert.That(points.Count, Is.EqualTo(3)); Assert.That(points[0], Is.SameAs(curve1.HeadPoint)); Assert.That(points[1], Is.SameAs(curve1.EndPoint)); Assert.That(points[2], Is.SameAs(curve2.EndPoint)); } [Test] public void Points_OnGetWithMultipleCurves_SharingInstancesHeadPointAndEndPoint_ReturnUniqueHeadAndEndPoints() { // setup var curve1 = new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6)); var curve2 = new GeometryCurve(new Point2D(7.7, 9.9), curve1.HeadPoint); var loop = new GeometryLoop(); loop.CurveList.AddRange(new[] { curve1, curve2 }); // call List points = loop.Points; // assert Assert.That(points.Count, Is.EqualTo(3)); Assert.That(points[0], Is.SameAs(curve1.EndPoint)); Assert.That(points[1], Is.SameAs(curve1.HeadPoint)); Assert.That(points[2], Is.SameAs(curve2.HeadPoint)); } [Test] public void Points_OnGetWithMultipleCurves_SharingInstancesHeadPointAndHeadPoint_ReturnUniqueHeadAndEndPoints() { // setup var curve1 = new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6)); var curve2 = new GeometryCurve(curve1.HeadPoint, new Point2D(7.7, 9.9)); var loop = new GeometryLoop(); loop.CurveList.AddRange(new[] { curve1, curve2 }); // call List points = loop.Points; // assert Assert.That(points.Count, Is.EqualTo(3)); Assert.That(points[0], Is.SameAs(curve1.EndPoint)); Assert.That(points[1], Is.SameAs(curve1.HeadPoint)); Assert.That(points[2], Is.SameAs(curve2.EndPoint)); } [Test] public void Points_OnGetWithOneCurve_ReturnThatCurveHeadAndEndPoints() { // setup var curve = new GeometryCurve(new Point2D(1.1, 3.3), new Point2D(4.4, 6.6)); var loop = new GeometryLoop(); loop.CurveList.Add(curve); // call List points = loop.Points; // assert Assert.That(points.Count, Is.EqualTo(2)); Assert.That(points[0], Is.SameAs(curve.HeadPoint)); Assert.That(points[1], Is.SameAs(curve.EndPoint)); } [Test] public void Points_OnGetWithoutCurves_ReturnEmptyCollection() { // setup var loop = new GeometryLoop(); // call IList points = loop.Points; // assert Assert.That(points, Is.Empty); } /// /// X=10 curve 1-2 X=20 /// Point 1 |------------------------| Points 2 and 3 Level -2 m /// | | /// | | curve 3-4 /// | | /// Point 6 |------------------------| Points 4 and 5 Level -5 m /// curve 5-6 /// [Test] public void GivenALoopWithCurvesConnectedByDifferentPointButSameLocation_WhenDeterminingIfCurveIsContinuous_ThenReturnsFalse() { var point1 = new Point2D(10.0, -2.0); var point2 = new Point2D(20.0, -2.0); var point3 = new Point2D(20.0, -2.0); var point4 = new Point2D(20.0, -5.0); var point5 = new Point2D(20.0, -5.0); var point6 = new Point2D(10.0, -5.0); var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(point1, point2)); loop.CurveList.Add(new GeometryCurve(point3, point4)); loop.CurveList.Add(new GeometryCurve(point5, point6)); loop.CurveList.Add(new GeometryCurve(point6, point1)); Assert.That(loop.IsContinuous(), Is.False); } /// /// X=10 curve 1-2 X=20 /// Point 1 |------------------------| Point 2 Level -2 m /// | | /// | | curve 2-3 /// | | /// Point 4 |------------------------| Point 3 Level -5 m /// curve 3-4 /// [Test] public void GivenALoopWithCurvesConnectedBySamePoint_WhenDeterminingIfCurveIsContinuous_ThenReturnsTrue() { var point1 = new Point2D(10.0, -2.0); var point2 = new Point2D(20.0, -2.0); var point3 = new Point2D(20.0, -5.0); var point4 = new Point2D(10.0, -5.0); var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(point1, point2)); loop.CurveList.Add(new GeometryCurve(point2, point3)); loop.CurveList.Add(new GeometryCurve(point3, point4)); loop.CurveList.Add(new GeometryCurve(point4, point1)); Assert.That(loop.IsContinuous(), Is.True); } [Test] public void TestHasSameCurves() { // setup GeometryLoop loop1 = GenerateSquareGeometryLoop(); // create identical loop but with also new (and thus by reference different) curves GeometryLoop loop2 = GenerateSquareGeometryLoop(); // call bool isEqual = loop1.HasSameCurves(loop2); // assert that result is true as it should be Assert.That(isEqual, Is.True); // setup for next test, now with same curves GeometryLoop loop3 = new GeometryLoop(); loop3.CurveList.AddRange(loop1.CurveList); // call isEqual = loop1.HasSameCurves(loop3); // assert that result is also True Assert.That(isEqual, Is.True); // setup for next test, now with different curves loop3.CurveList.Clear(); loop3.CurveList.Add(new GeometryCurve(new Point2D(0.0, 0.0), new Point2D(11.0, 0.0))); loop3.CurveList.Add(new GeometryCurve(loop3.CurveList[0].EndPoint, new Point2D(11.0, 10.0))); loop3.CurveList.Add(new GeometryCurve(loop3.CurveList[1].EndPoint, new Point2D(0.0, 10.0))); loop3.CurveList.Add(new GeometryCurve(loop3.CurveList[2].EndPoint, loop3.CurveList[0].HeadPoint)); // call isEqual = loop1.HasSameCurves(loop3); // assert that result is also True Assert.That(isEqual, Is.False); } private static GeometryLoop GenerateSquareGeometryLoop() { var loop = new GeometryLoop(); loop.CurveList.Add(new GeometryCurve(new Point2D(0.0, 0.0), new Point2D(10.0, 0.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[0].EndPoint, new Point2D(10.0, 10.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[1].EndPoint, new Point2D(0.0, 10.0))); loop.CurveList.Add(new GeometryCurve(loop.CurveList[2].EndPoint, loop.CurveList[0].HeadPoint)); return loop; } }