// 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 System.Diagnostics; using System.Linq; using Deltares.DamEngine.Data.Standard; namespace Deltares.DamEngine.Data.Geometry; // ---------------------------------------------------------- // The main geometry regeneration manager public class GeometryGenerator { private readonly Dictionary geometryCurveForwardsIsUsed = new Dictionary(); private readonly Dictionary geometryCurveReversedIsUsed = new Dictionary(); private readonly GeometryData geometryData; private readonly List intersectedCurveList = new List(); private readonly Dictionary> geometryLoopDirections = new Dictionary>(); private readonly List newlyDetectedSurfaceList = new List(); /// /// Regenerates the geometry. /// public GeometryGenerator(GeometryData aGeometryData) { geometryData = aGeometryData; } /// /// Regenerates the geometry. /// public void GenerateGeometry() { FilterOutDoublePoints(); SetupCurveSurfaceAssociations(); var firstRegeneration = true; while (true) { // break up all curves at intersections intersectedCurveList.Clear(); RegenerateAllCurvesIntersection(); newlyDetectedSurfaceList.Clear(); geometryLoopDirections.Clear(); int curvesCount = geometryData.Curves.Count; // initialise IsUsed of all curves to false for (var index1 = 0; index1 < curvesCount; index1++) { SetIsUsed(geometryData.Curves[index1], CurveDirection.Forward, false); SetIsUsed(geometryData.Curves[index1], CurveDirection.Reverse, false); } // detect surfaces... the plaxis algorithm int result = DetectSurfaces(firstRegeneration); // clear the effected & intersected curve list intersectedCurveList.Clear(); if (result < 0) { if (!firstRegeneration) { break; } } else { break; } firstRegeneration = false; } } /// /// Removes the curve from both the dictionaries geometryCurveForwardsIsUsed and geometryCurveReversedIsUsed. /// /// public void RemoveIsUsedCurve(GeometryCurve aCurve) { if ((geometryCurveForwardsIsUsed.ContainsKey(aCurve))) { geometryCurveForwardsIsUsed.Remove(aCurve); } if ((geometryCurveReversedIsUsed.ContainsKey(aCurve))) { geometryCurveReversedIsUsed.Remove(aCurve); } } /// /// Setups the curve surface associations. /// public void SetupCurveSurfaceAssociations() { SetUpGeometryLoopDirections(); // only try to connect curves to surfaces when there are loops (i.e. surfaces) if (geometryLoopDirections.Count > 0) { SetupCurveSurfaceAssociation(); } } /// /// Adds the curve to the list in given direction. /// /// /// /// /// private bool AddCurve(GeometryCurve aCurve, CurveDirection aDirection, GeometryLoop aEditedLoop) { if (FindCurveIndex(aEditedLoop, aCurve, aDirection) > -1) { return false; } aEditedLoop.CurveList.Add(aCurve); if (!geometryLoopDirections.ContainsKey(aEditedLoop)) { geometryLoopDirections.Add(aEditedLoop, new List()); } geometryLoopDirections[aEditedLoop].Add(aDirection); return true; } // ------------------------------------------------------------------------------------- // Loop Detection (Surface Creation) Algorithm from Plaxis /// /// Creates the surface. /// /// a loop. /// private GeometrySurface CreateSurface(GeometryLoop aLoop) { if (aLoop.IsLoop() && aLoop.HasArea()) { var newSurface = new GeometrySurface(); //newSurface.SetOuterLoop(aLoop); #Bka: replaced with newSurface.OuterLoop = aLoop; geometryData.Surfaces.Add(newSurface); return newSurface; } return null; } /// /// Finds the index of the curve. /// /// a geometry loop. /// a curve. /// a direction. /// private int FindCurveIndex(GeometryLoop aGeometryLoop, GeometryCurve aCurve, CurveDirection aDirection) { if (!aGeometryLoop.CurveList.Contains(aCurve)) { return -1; } int curvesCount = aGeometryLoop.CurveList.Count; for (var index = 0; index < curvesCount; index++) { // Note Bka: Checking the direction does allow one curve to be added to ONE loop twice! // This produces some strange surfaces (see LoopDetectionCase5) but that seems to be required if (aGeometryLoop.CurveList[index] == aCurve && geometryLoopDirections[aGeometryLoop][index] == aDirection) { return index; } } return -1; } /// /// /// /// /// /// public void SetIsUsed(GeometryCurve aCurve, CurveDirection aDirection, bool aValue) { if (aDirection == CurveDirection.Forward) { if (!(geometryCurveForwardsIsUsed.ContainsKey(aCurve))) { geometryCurveForwardsIsUsed.Add(aCurve, aValue); } else { geometryCurveForwardsIsUsed[aCurve] = aValue; } } else { if (!(geometryCurveReversedIsUsed.ContainsKey(aCurve))) { geometryCurveReversedIsUsed.Add(aCurve, aValue); } else { geometryCurveReversedIsUsed[aCurve] = aValue; } } } /// /// /// /// /// /// private bool GetIsUsed(GeometryCurve aCurve, CurveDirection aDirection) { if (aDirection == CurveDirection.Forward) { return geometryCurveForwardsIsUsed[aCurve]; } return geometryCurveReversedIsUsed[aCurve]; } /// /// Removes all double points, replaces them in curves and newlyeffectedpoints. /// Also deletes "zero" curves (beginpoint = endpoint) also from surface loops and newlyeffectedcurrves /// private void FilterOutDoublePoints() { var doublePoints = new Dictionary(); // Make sure all points (as pointers) in curves are in the point list foreach (GeometryCurve curve in geometryData.Curves) { if (!geometryData.Points.Contains(curve.HeadPoint)) { geometryData.Points.Add(curve.HeadPoint); } if (!geometryData.Points.Contains(curve.EndPoint)) { geometryData.Points.Add(curve.EndPoint); } } // find double points (by location!) in point list and register them with original for (var i = 0; i < geometryData.Points.Count; i++) { for (var j = 0; j < i; j++) { if (i != j && geometryData.Points[i].LocationEquals(geometryData.Points[j])) { // register the double point and the original point doublePoints[geometryData.Points[i]] = geometryData.Points[j]; break; } } } // replace double points in curves with originals foreach (Point2D doublePoint in doublePoints.Keys) { foreach (GeometryCurve curve in geometryData.Curves) { if (curve.HeadPoint == doublePoint) { curve.HeadPoint = doublePoints[doublePoint]; } if (curve.EndPoint == doublePoint) { curve.EndPoint = doublePoints[doublePoint]; } } } // remove curves which have the same head as end point foreach (GeometryCurve curve in geometryData.Curves.ToArray()) { if (curve.HeadPoint == curve.EndPoint) { geometryData.Curves.Remove(curve); if (geometryData.NewlyEffectedCurves.Contains(curve)) { geometryData.NewlyEffectedCurves.Remove(curve); } foreach (GeometrySurface surface in geometryData.Surfaces) { surface.OuterLoop.CurveList.Remove(curve); foreach (GeometryLoop loop in surface.InnerLoops) { loop.CurveList.Remove(curve); } } } } // removing curves from loops in surfaces may have created invalid surfaces, remove those here foreach (GeometrySurface surface in geometryData.Surfaces.ToArray()) { if (!surface.OuterLoop.HasArea()) { geometryData.Surfaces.Remove(surface); } } // remove double points from point list foreach (Point2D point in doublePoints.Keys) { geometryData.Points.Remove(point); if (geometryData.NewlyEffectedPoints.Contains(point)) { geometryData.NewlyEffectedPoints.Remove(point); if (!geometryData.NewlyEffectedPoints.Contains(doublePoints[point])) { geometryData.NewlyEffectedPoints.Add(doublePoints[point]); } } } } private int DetectSurfaces(bool aFirstRegeneration) { try { // declare some variables int curvesCount = geometryData.Curves.Count; var newLoopList = new List(); var attachedCurveList = new List(); // start the first iteration for (var index = 0; index < curvesCount * 2; index++) { int curveIndex = index / 2; // look for current curve GeometryCurve currentCurve = geometryData.Curves[curveIndex]; if (currentCurve == null) { continue; } // check the direction CurveDirection currentCurveDirection; if (index % 2 == 0) { if (GetIsUsed(currentCurve, CurveDirection.Forward)) { continue; } currentCurveDirection = CurveDirection.Forward; // get the direction of the current curve } else { if (GetIsUsed(currentCurve, CurveDirection.Reverse)) { continue; } currentCurveDirection = CurveDirection.Reverse; // get the direction of the current curve } // create aValue1 new loop var newLoop = new GeometryLoop(); //this.geometryData.Loops.Add(newLoop); newLoopList.Add(newLoop); // initialise LoopBeginCurve GeometryCurve loopBeginCurve = geometryData.Curves[curveIndex]; CurveDirection loopBeginDirection = currentCurveDirection; while (true) { // set the IsUsed status SetIsUsed(currentCurve, currentCurveDirection, true); // add the current curve to new loop if (!AddCurve(currentCurve, currentCurveDirection, newLoop)) { // the curve wasn't added bcos the curve-direction pair was already present in loop. // problem case - break here, else we'd get aValue1 hang! // Todo: Solve this problem if (!aFirstRegeneration) { //TODO:Show error message box break; } return -1; } Point2D curveEndPoint = currentCurve.GetEndPoint(currentCurveDirection); attachedCurveList.Clear(); var minAngle = 365.0; var minIndex = 0; // find all the curves that are connected to the Current Curve at curveEndPoint for (var index2 = 0; index2 < curvesCount; index2++) { GeometryCurve curve = geometryData.Curves[index2]; if (curve.LocationEquals(currentCurve)) // lets not get the reverse direction of the current curve here { continue; } if (curve.HeadPoint == curveEndPoint) { attachedCurveList.Add(new DirectionCurve(curve, CurveDirection.Forward)); } else if (curve.EndPoint == curveEndPoint) { attachedCurveList.Add(new DirectionCurve(curve, CurveDirection.Reverse)); } } if (attachedCurveList.Count == 0) // no curves found { CurveDirection oppCurrentDirection = currentCurveDirection == CurveDirection.Forward ? CurveDirection.Reverse : CurveDirection.Forward; // if the current curve is not used in the opposite direction, it is considered in the opposite direction if (!GetIsUsed(currentCurve, oppCurrentDirection)) { currentCurveDirection = oppCurrentDirection; continue; } break; } // we have aValue1 set of curves, find the one that turns right the most if (attachedCurveList.Count > 1) { minIndex = -1; Point2D point1 = currentCurve.GetEndPoint(currentCurveDirection); Point2D point2 = currentCurve.GetHeadPoint(currentCurveDirection); for (var index2 = 0; index2 < attachedCurveList.Count; index2++) { var point3 = new Point2D(); var point4 = new Point2D(); point3.X = attachedCurveList[index2].GetHeadPoint().X; point3.Z = attachedCurveList[index2].GetHeadPoint().Z; point4.X = attachedCurveList[index2].GetEndPoint().X; point4.Z = attachedCurveList[index2].GetEndPoint().Z; double angle = Routines2D.FindAngle(point1, point2, point3, point4); if (angle < minAngle) { minAngle = angle; minIndex = index2; } } } DirectionCurve pickedDirectionCurve = attachedCurveList[minIndex]; if (pickedDirectionCurve.Curve == loopBeginCurve && pickedDirectionCurve.Direction == loopBeginDirection) { break; } // assign the CurrentCurve from the picked one currentCurve = pickedDirectionCurve.Curve; currentCurveDirection = pickedDirectionCurve.Direction; } } // create surfaces! return CreateSurfaces(newLoopList); } #if DEBUG catch //(Exception ex) { //Todo:Show error msg box //var lm = new LogMessage(LogMessageType.FatalError, this, "DetectSurfaces:" + ex.Message); //LogManager.Add(lm); return 0; } #else catch { return 0; } #endif } private int CreateSurfaces(List aNewLoopList) { var newSurfacesGeoDtaObjectList = new List(); int loopsCount = aNewLoopList.Count; int curvesCount; GeometrySurface newSurface; var newSurfaceList = new List(); for (var index = 0; index < loopsCount; index++) { GeometryLoop loop = aNewLoopList[index]; curvesCount = loop.CurveList.Count; if (curvesCount < 2) // dont create aValue1 surface for loops that have less than 2 curves { continue; } if (curvesCount == 2) // if only 2 curves in loop, make sure they are distinct (non-repeated) { if (loop.CurveList[0] == loop.CurveList[1]) { continue; } } if (!loop.IsLoop()) { continue; } // if the loop is clockwise, create aValue1 surface if (loop.IsClockWise() && !CheckIfLoopEnclosesOpenPolyline(loop)) { // TEMP: aVector1 mechanism to remember surfaces after Geometry Regeneration // find the surface that is most repeated in the loop's in curves newSurface = GetReassignmentSurfaceFromCurves(loop); // an existing surface has been found if (newSurface != null) { newSurface = CreateSurface(loop); } else // no existing surface found from its comprising curves... create aValue1 brand new surface! { newSurface = CreateSurface(loop); newlyDetectedSurfaceList.Add(newSurface); // populate the newly detected surface list newSurfacesGeoDtaObjectList.Add(newSurface); } if (newSurface != null) { newSurfaceList.Add(newSurface); AssignSurfaceAtLeftOrRightToCurves(newSurface); } } } // clear the left and right surfaces for all curves (some curves will have redundant data) curvesCount = geometryData.Curves.Count; for (var index = 0; index < curvesCount; index++) { geometryData.Curves[index].SurfaceAtRight = null; geometryData.Curves[index].SurfaceAtLeft = null; } // for the new surfaces -- assign the left/right surfaces for comprising curves, and find inner loops int surfacesCount = newSurfaceList.Count; for (var index = 0; index < surfacesCount; index++) { newSurface = newSurfaceList[index]; AssignSurfaceAtLeftOrRightToCurves(newSurface); object newSurfaceObject = newSurface /*new object()*/; CheckAndAddInnerLoops(ref newSurfaceObject); //newSurface = (GeometrySurface)newSurfaceObject; } if (newSurfacesGeoDtaObjectList.Count > 0) { var lNewSurfaces = new List(); GetNewlyDetectedSurfaces(ref lNewSurfaces); } return surfacesCount; } /// /// Checks if loop encloses open polyline. /// /// a loop. /// private bool CheckIfLoopEnclosesOpenPolyline(GeometryLoop aLoop) { int curvesCount = aLoop.CurveList.Count; if (curvesCount < 3) { return true; } for (var index = 0; index < curvesCount; index++) { GeometryCurve curve = aLoop.CurveList[index]; CurveDirection direction = geometryLoopDirections[aLoop][index]; var foundOppDirection = false; for (var index1 = 0; index1 < curvesCount; index1++) { if (index == index1) { continue; } if (aLoop.CurveList[index1] == curve && geometryLoopDirections[aLoop][index] != direction) { foundOppDirection = true; break; } } if (!foundOppDirection) { return false; } } return true; } private GeometrySurface GetReassignmentSurfaceFromCurves(GeometryLoop aLoop) { GeometrySurface surface = null; GeometrySurface reassignmentSurface = null; int curvesCount = aLoop.CurveList.Count; if (!geometryLoopDirections.ContainsKey(aLoop)) { return null; } for (var index = 0; index < curvesCount; index++) { GeometryCurve curve = aLoop.CurveList[index]; if (geometryLoopDirections[aLoop][index] == CurveDirection.Forward) { if (curve.SurfaceAtRight != null) { surface = curve.SurfaceAtRight; } } else { if (curve.SurfaceAtLeft != null) { surface = curve.SurfaceAtLeft; } } if (surface == null) { continue; } var maxTimesSurfacesFound = 0; var noTimesSurfaceFound = 0; for (var index1 = 0; index1 < curvesCount; index1++) { if (geometryLoopDirections[aLoop][index] == CurveDirection.Forward) { if (curve.SurfaceAtRight == surface) { noTimesSurfaceFound++; } } else { if (curve.SurfaceAtLeft == surface) { noTimesSurfaceFound++; } } } if (noTimesSurfaceFound > maxTimesSurfacesFound) { maxTimesSurfacesFound = noTimesSurfaceFound; reassignmentSurface = surface; } } return reassignmentSurface; } /// /// Assigns the surface at left or right to its curves on the outerloop. This tells at which side of the curve the surface is present. /// So after this, for each curve in the outerloop of this surface, it is known at which side the surface is located. /// /// The surface. private void AssignSurfaceAtLeftOrRightToCurves(GeometrySurface surface) { GeometryLoop loop = surface.OuterLoop; int curvesCount = loop.CurveList.Count; var isClockwise = true; try { isClockwise = loop.IsClockWise(); } catch (GeometryLoop.NotEnoughUniquePointsException e) { Debug.WriteLine(e.Message); } catch (InvalidOperationException e) { Debug.WriteLine(e.Message); } for (var index = 0; index < curvesCount; index++) { if (isClockwise) { if (geometryLoopDirections[loop][index] == CurveDirection.Forward) { loop.CurveList[index].SurfaceAtRight = surface; } else { loop.CurveList[index].SurfaceAtLeft = surface; } } else { if (geometryLoopDirections[loop][index] == CurveDirection.Forward) { loop.CurveList[index].SurfaceAtLeft = surface; } else { loop.CurveList[index].SurfaceAtRight = surface; } } } } private void SetupCurveSurfaceAssociation() { // clear the data int count = geometryData.Curves.Count; for (var i = 0; i < count; i++) { geometryData.Curves[i].SurfaceAtLeft = null; geometryData.Curves[i].SurfaceAtRight = null; } // reset count = geometryData.Surfaces.Count; for (var i = 0; i < count; i++) { AssignSurfaceAtLeftOrRightToCurves(geometryData.Surfaces[i]); } } private void SetUpGeometryLoopDirections() { geometryLoopDirections.Clear(); foreach (GeometryLoop loop in geometryData.Loops) { if (!geometryLoopDirections.ContainsKey(loop)) { SetUpGeometryLoopDirections(loop); } } } private void SetUpGeometryLoopDirections(GeometryLoop aLoop) { if (aLoop.CurveList.Count > 0) { Point2D loopPoint; geometryLoopDirections.Add(aLoop, new List()); // get the first curve if (aLoop.CurveList[0].EndPoint == aLoop.CurveList[1].HeadPoint || aLoop.CurveList[0].EndPoint == aLoop.CurveList[1].EndPoint) { geometryLoopDirections[aLoop].Add(CurveDirection.Forward); loopPoint = aLoop.CurveList[0].EndPoint; } else { geometryLoopDirections[aLoop].Add(CurveDirection.Reverse); loopPoint = aLoop.CurveList[0].HeadPoint; } // the rest of the curves for (var index1 = 1; index1 < aLoop.CurveList.Count; index1++) { if (loopPoint == aLoop.CurveList[index1].HeadPoint) { geometryLoopDirections[aLoop].Add(CurveDirection.Forward); loopPoint = aLoop.CurveList[index1].EndPoint; } else { geometryLoopDirections[aLoop].Add(CurveDirection.Reverse); loopPoint = aLoop.CurveList[index1].HeadPoint; } } } } /// /// Checks and adds inner loop to the new surface. /// /// private void CheckAndAddInnerLoops(ref object aNewSurface) { var newSurface = (GeometrySurface) aNewSurface; int surfaceCount = geometryData.Surfaces.Count; GeometryLoop newLoop = newSurface.OuterLoop; int newPointCount = newLoop.CurveList.Count; List newPolygon = newLoop.CalcPoints; newSurface.InnerLoops.Clear(); for (var index = 0; index < surfaceCount; index++) { if (newSurface == geometryData.Surfaces[index]) { continue; } var innerPointCount = 0; var outerPointCount = 0; var isOnPointCount = 0; var hasOnPointCount = 0; GeometryLoop loop = geometryData.Surfaces[index].OuterLoop; List polygon = loop.CalcPoints; int existingLoopPointCount = polygon.Count; // check if it is an inner loop for (var innerIndex = 0; innerIndex < newPointCount; innerIndex++) { PointInPolygon location = Routines2D.CheckIfPointIsInPolygon(loop, newPolygon[innerIndex].X, newPolygon[innerIndex].Z); if (location == PointInPolygon.InsidePolygon) { innerPointCount++; } else if (location == PointInPolygon.OnPolygonEdge) { isOnPointCount++; } } // check if it has an inner loop for (var innerIndex1 = 0; innerIndex1 < existingLoopPointCount; innerIndex1++) { PointInPolygon location = Routines2D.CheckIfPointIsInPolygon(newLoop, polygon[innerIndex1].X, polygon[innerIndex1].Z); if (location == PointInPolygon.InsidePolygon) { outerPointCount++; } else if (location == PointInPolygon.OnPolygonEdge) { hasOnPointCount++; } } //Add New Loop as inner loop to the existing Surface if ((innerPointCount == newPointCount) || ((innerPointCount > 0) && (newPointCount == (innerPointCount + isOnPointCount)))) { geometryData.Surfaces[index].AddInnerLoop(newLoop); } //Add Inner Loop to the New Surface if ((outerPointCount == existingLoopPointCount) || ((outerPointCount > 0) && (existingLoopPointCount == (outerPointCount + hasOnPointCount)))) { newSurface.AddInnerLoop(loop); } } } /// /// Gets the newly detected surface from the list. /// /// private void GetNewlyDetectedSurfaces(ref List aNewSurfaceList) { aNewSurfaceList.AddRange(newlyDetectedSurfaceList); } #region Nested type: DirectionCurve internal struct DirectionCurve { internal DirectionCurve(GeometryCurve aCurve, CurveDirection aDirection) { Curve = aCurve; Direction = aDirection; } internal GeometryCurve Curve { get; } internal CurveDirection Direction { get; } internal Point2D GetHeadPoint() { return Curve.GetHeadPoint(Direction); } internal Point2D GetEndPoint() { return Curve.GetEndPoint(Direction); } } #endregion private void RegenerateAllCurvesIntersection() { //try { intersectedCurveList.Clear(); MergePoints(); bool isCurveInserted = false; bool flag = true; while (flag) { flag = false; List geometryCurveList = new List((IEnumerable) geometryData.NewlyEffectedCurves); geometryData.NewlyEffectedCurves.Clear(); foreach (GeometryCurve geometryCurve1 in geometryCurveList) { foreach (GeometryCurve geometryCurve2 in this.geometryData.Curves.ToArray()) { Point2D pointXz1 = geometryCurve1.HeadPoint; Point2D pointXz2 = geometryCurve1.EndPoint; Point2D pointXz3 = geometryCurve2.HeadPoint; Point2D pointXz4 = geometryCurve2.EndPoint; Point2D intersectionPoint; if (geometryCurve1 != geometryCurve2 && !RegenerateParallelCurves(geometryCurve2, geometryCurve1, ref isCurveInserted) && Routines2D.DetermineIf2DLinesIntersectStrickly(pointXz1, pointXz2, pointXz3, pointXz4, out intersectionPoint) == LineIntersection.Intersects) { if (!Routines2D.DetermineIfPointsCoincide(pointXz1.X, pointXz1.Z, intersectionPoint.X, intersectionPoint.Z, 0.001) && !Routines2D.DetermineIfPointsCoincide(pointXz2.X, pointXz2.Z, intersectionPoint.X, intersectionPoint.Z, 0.001)) { Point2D point = this.geometryData.CreatePoint(new Point2D(intersectionPoint.X, intersectionPoint.Z), true); SplitCurve(geometryCurve1, point); flag = true; } if (!Routines2D.DetermineIfPointsCoincide(pointXz3.X, pointXz3.Z, intersectionPoint.X, intersectionPoint.Z, 0.001) && !Routines2D.DetermineIfPointsCoincide(pointXz4.X, pointXz4.Z, intersectionPoint.X, intersectionPoint.Z, 0.001)) { Point2D point = this.geometryData.CreatePoint(new Point2D(intersectionPoint.X, intersectionPoint.Z), true); SplitCurve(geometryCurve2, point); flag = true; } } } } FilterOutDoublePoints(); } geometryData.NewlyEffectedCurves.Clear(); MergePoints(); this.DeleteDuplicateCurves(); } // catch (Exception ex) // { // LogManager.Add(new LogMessage(LogMessageType.FatalError, (object) this, "RegenerateAllCurvesIntersection: " + ex.Message)); // } } private void MergePoints() { //try { int count = geometryData.Points.Count; List aConnectedAtHeadCurveList = new List(); List aConnectedAtEndCurveList = new List(); List list = geometryData.NewlyEffectedPoints.Select((Func) (newPoint => geometryData.Points.IndexOf(newPoint))).ToList(); list.Reverse(); foreach (int index1 in list) { if (index1 >= 0 && index1 < geometryData.Points.Count) { for (int index2 = count - 1; index2 >= 0; --index2) { if (index2 != index1) { if (Routines2D.DetermineIfPointsCoincide(geometryData.Points[index1].X, geometryData.Points[index1].Z, geometryData.Points[index2].X, geometryData.Points[index2].Z, 0.001)) { aConnectedAtHeadCurveList.Clear(); aConnectedAtEndCurveList.Clear(); GetConnectedCurves(this.geometryData.Points[index1], ref aConnectedAtHeadCurveList, ref aConnectedAtEndCurveList); SetPointInCurves(aConnectedAtHeadCurveList, geometryData.Points[index2], true); SetPointInCurves(aConnectedAtEndCurveList, geometryData.Points[index2], false); --count; geometryData.DeletePoint(geometryData.Points[index1]); break; } } } } } } // catch (Exception ex) // { // LogManager.Add(new LogMessage(LogMessageType.FatalError, (object) this, "MergePoints: " + ex.Message)); // } geometryData.NewlyEffectedPoints.Clear(); } private bool RegenerateParallelCurves(GeometryCurve line1, GeometryCurve line2, ref bool isCurveInserted) { Point2D pointXz1 = line1.HeadPoint; Point2D pointXz2 = line1.EndPoint; Point2D pointXz3 = line2.HeadPoint; Point2D pointXz4 = line2.EndPoint; bool flag1 = Routines2D.DoesPointExistInLine(pointXz1, pointXz2, pointXz3, 0.001); bool flag2 = Routines2D.DoesPointExistInLine(pointXz1, pointXz2, pointXz4, 0.001); bool flag3 = Routines2D.DoesPointExistInLine(pointXz3, pointXz4, pointXz1, 0.001); bool flag4 = Routines2D.DoesPointExistInLine(pointXz3, pointXz4, pointXz2, 0.001); double num1 = !pointXz1.Z.IsNearEqual(pointXz2.Z) ? (pointXz1.X - pointXz2.X) / (pointXz1.Z - pointXz2.Z) : double.MaxValue; double num2 = !pointXz3.Z.IsNearEqual(pointXz4.Z) ? (pointXz3.X - pointXz4.X) / (pointXz3.Z - pointXz4.Z) : double.MaxValue; if (Math.Abs(Math.Abs(num1) - Math.Abs(num2)) > 5E-12) { if (flag3 & flag4) { if (Routines2D.CalculateDistanceToLine(pointXz1.X, pointXz1.Z, pointXz3.X, pointXz3.Z, pointXz4.X, pointXz4.Z) > Routines2D.CalculateDistanceToLine(pointXz2.X, pointXz2.Z, pointXz3.X, pointXz3.Z, pointXz4.X, pointXz4.Z)) flag3 = false; else flag4 = false; } if (flag1 & flag2) { if (Routines2D.CalculateDistanceToLine(pointXz3.X, pointXz3.Z, pointXz1.X, pointXz1.Z, pointXz2.X, pointXz2.Z) > Routines2D.CalculateDistanceToLine(pointXz4.X, pointXz4.Z, pointXz1.X, pointXz1.Z, pointXz2.X, pointXz2.Z)) flag1 = false; else flag2 = false; } } bool flag5 = Routines2D.DetermineIfPointsCoincide(pointXz1.X, pointXz1.Z, pointXz3.X, pointXz3.Z, 0.001); bool flag6 = Routines2D.DetermineIfPointsCoincide(pointXz1.X, pointXz1.Z, pointXz4.X, pointXz4.Z, 0.001); bool flag7 = Routines2D.DetermineIfPointsCoincide(pointXz2.X, pointXz2.Z, pointXz3.X, pointXz3.Z, 0.001); bool flag8 = Routines2D.DetermineIfPointsCoincide(pointXz2.X, pointXz2.Z, pointXz4.X, pointXz4.Z, 0.001); if (Math.Abs(Math.Abs(num1) - Math.Abs(num2)) > 5E-12) { if (flag5 & flag7) { if (Routines2D.Compute2DDistance(pointXz1.X, pointXz1.Z, pointXz3.X, pointXz3.Z) > Routines2D.Compute2DDistance(pointXz2.X, pointXz2.Z, pointXz3.X, pointXz3.Z)) flag5 = false; else flag7 = false; } if (flag6 & flag8) { if (Routines2D.Compute2DDistance(pointXz1.X, pointXz1.Z, pointXz4.X, pointXz4.Z) > Routines2D.Compute2DDistance(pointXz2.X, pointXz2.Z, pointXz4.X, pointXz4.Z)) flag6 = false; else flag8 = false; } } if (flag3 & flag4 || flag1 & flag2 || flag1 | flag2 && flag3 | flag4) { if (flag1 && !flag2 && !flag5 && !flag7) { GeometryCurve geometryCurve = this.SplitCurve(line1, line2.HeadPoint); line2.HeadPoint = flag4 ? geometryCurve.EndPoint : line1.HeadPoint; this.CheckAndAddToIntersectedCurveList(line2); isCurveInserted = true; return true; } if (flag2 && !flag1 && !flag6 && !flag8) { GeometryCurve geometryCurve = this.SplitCurve(line1, line2.EndPoint); line2.EndPoint = flag4 ? geometryCurve.EndPoint : line1.HeadPoint; this.CheckAndAddToIntersectedCurveList(line2); isCurveInserted = true; return true; } if (flag1 & flag2 && !flag5 && !flag8 && !flag7 && !flag6) { if (Routines2D.Compute2DDistance(pointXz1.X, pointXz1.Z, pointXz3.X, pointXz3.Z) < Routines2D.Compute2DDistance(pointXz1.X, pointXz1.Z, pointXz4.X, pointXz4.Z)) this.SplitCurve(line1, line2.HeadPoint).HeadPoint = line2.EndPoint; else this.SplitCurve(line1, line2.EndPoint).HeadPoint = line2.HeadPoint; this.CheckAndAddToIntersectedCurveList(line2); isCurveInserted = true; return true; } if (flag3 & flag4 && !flag5 && !flag8 && !flag7 && !flag6) { if (Routines2D.Compute2DDistance(pointXz3.X, pointXz3.Z, pointXz1.X, pointXz1.Z) < Routines2D.Compute2DDistance(pointXz3.X, pointXz3.Z, pointXz2.X, pointXz2.Z)) this.SplitCurve(line2, line1.HeadPoint).HeadPoint = line1.EndPoint; else this.SplitCurve(line2, line1.EndPoint).HeadPoint = line1.HeadPoint; this.CheckAndAddToIntersectedCurveList(line1); isCurveInserted = true; return true; } if (flag2 & flag1 && !(flag7 & flag6) && !(flag8 & flag5)) { if (flag5) line1.HeadPoint = line2.EndPoint; else if (flag7) line1.EndPoint = line2.EndPoint; else if (flag8) line1.EndPoint = line2.HeadPoint; else line1.HeadPoint = line2.HeadPoint; this.CheckAndAddToIntersectedCurveList(line1); this.CheckAndAddToIntersectedCurveList(line2); return true; } if (flag3 & flag4 && !(flag7 & flag6) && !(flag8 & flag5)) { if (flag5) line2.HeadPoint = line1.EndPoint; else if (flag6) line2.EndPoint = line1.EndPoint; else if (flag8) line2.EndPoint = line1.HeadPoint; else line2.HeadPoint = line1.HeadPoint; this.CheckAndAddToIntersectedCurveList(line1); this.CheckAndAddToIntersectedCurveList(line2); return true; } } if (!(flag5 & flag8) && !(flag6 & flag7)) return false; this.CheckAndAddToIntersectedCurveList(line1); this.CheckAndAddToIntersectedCurveList(line2); return true; } private GeometryCurve SplitCurve(GeometryCurve curve, Point2D aPointOnCurve) { if (aPointOnCurve.LocationEquals(curve.HeadPoint) || aPointOnCurve.LocationEquals(curve.EndPoint)) return (GeometryCurve) null; GeometryCurve curve1 = geometryData.CreateCurve((List) null, aPointOnCurve, curve.EndPoint); curve.EndPoint = curve1.HeadPoint; curve1.AssignSurfacesFromCurve(curve); this.CheckAndAddToIntersectedCurveList(curve); this.CheckAndAddToIntersectedCurveList(curve1); if (!geometryData.Curves.Contains(curve1)) geometryData.Curves.Add(curve1); return curve1; } private void GetConnectedCurves( Point2D aPoint, ref List aConnectedAtHeadCurveList, ref List aConnectedAtEndCurveList) { aConnectedAtHeadCurveList.Clear(); aConnectedAtEndCurveList.Clear(); int count = this.geometryData.Curves.Count; for (int index = 0; index < count; ++index) { GeometryCurve curve = this.geometryData.Curves[index]; if (curve.HeadPoint == aPoint) aConnectedAtHeadCurveList.Add(curve); if (curve.EndPoint == aPoint) aConnectedAtEndCurveList.Add(curve); } } private void SetPointInCurves(List aCurveList, Point2D aPoint, bool aHead) { int count = aCurveList.Count; if (count < 1) return; for (int index = 0; index < count; ++index) { if (aHead) aCurveList[index].HeadPoint = aPoint; else aCurveList[index].EndPoint = aPoint; } } private void DeleteDuplicateCurves() { List list = geometryData.Curves.Where((Func) (curve => curve.HeadPoint == curve.EndPoint)).ToList(); foreach (GeometryCurve aCurve in list) geometryData.DeleteCurve(aCurve, true); list.Clear(); for (int index1 = 0; index1 < geometryData.Curves.Count; ++index1) { GeometryCurve curve1 = geometryData.Curves[index1]; for (int index2 = index1 + 1; index2 < geometryData.Curves.Count; ++index2) { GeometryCurve curve2 = geometryData.Curves[index2]; if (curve1.HeadPoint == curve2.HeadPoint && curve1.EndPoint == curve2.EndPoint) list.Add(curve2); else if (curve1.HeadPoint == curve2.EndPoint && curve1.EndPoint == curve2.HeadPoint) list.Add(curve2); } } foreach (GeometryCurve aCurve in list) geometryData.DeleteCurve(aCurve, true); } private bool CheckAndAddToIntersectedCurveList(GeometryCurve aCurve) { if (intersectedCurveList.Contains(aCurve)) return false; intersectedCurveList.Add(aCurve); return true; } /// /// Split the curve at the coincident point. /// /// /// public void SplitCurvesAtCoincidentPoint(Point2D aPoint, List aCoincidentCurves) { int count = aCoincidentCurves.Count; for (int index = 0; index < count; ++index) SplitCurve(aCoincidentCurves[index], aPoint); } }