// 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);
}
}