// 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.Linq;
using Deltares.DamEngine.Data.Standard;
using Deltares.DamEngine.Data.Standard.Language;
using Deltares.DamEngine.Data.Standard.Validation;
namespace Deltares.DamEngine.Data.Geometry;
///
/// Class containing the geometry data
///
///
public class GeometryData : GeometryObject
{
private readonly GeometryPointString surfaceLine = new GeometryPointString();
private GeometryGenerator geometryGenerator;
private bool isRegeneratingGeometry;
private bool updatingSurfaceLine;
///
/// Initializes a new instance of the class.
///
public GeometryData()
{
geometryGenerator = null;
}
///
/// Ordered list of all geometry points at the surface
///
public virtual GeometryPointString SurfaceLine
{
get
{
if (surfaceLine.CalcPoints.Count == 0 && Points.Count > 0)
{
UpdateSurfaceLine();
}
return surfaceLine;
}
}
///
/// Checks geometry for loose curves and AutoRegeneration
///
///
[Validate]
public ValidationResult[] ValidateGeometry()
{
var validationList = new List();
{
foreach (Point2D point in Points)
{
foreach (Point2D point1 in Points)
{
if (point != point1)
{
var isValidated = false;
foreach (ValidationResult validatedItem in validationList)
{
if (validatedItem.Subject == point)
{
isValidated = true;
}
}
if (!isValidated)
{
if (Math.Abs(point.X - point1.X) < GeometryConstants.Accuracy &&
Math.Abs(point.Z - point1.Z) < GeometryConstants.Accuracy)
{
validationList.Add(new ValidationResult(ValidationResultType.Error,
point + " and " +
point1 + " values are same.",
point1));
}
}
}
}
}
}
if (Surfaces.Count < 1)
{
validationList.Add(new ValidationResult(ValidationResultType.Error, "No soil surface available.",
this));
}
return validationList.ToArray();
}
///
/// Deletes the point and the curves it belongs too.
///
/// The point.
public void DeletePointWithCurves(Point2D point)
{
var curvesToDelete = new List();
foreach (GeometryCurve curve in Curves)
{
if (curve.ContainsPoint(point))
{
curvesToDelete.Add(curve);
}
}
foreach (GeometryCurve curveToDelete in curvesToDelete)
{
Curves.Remove(curveToDelete);
}
Points.Remove(point);
}
///
/// Deletes all the loose curves.
/// Returns true when the loose curve is inside publisherEventArgs surface.
/// Calls Regeneration if the funtion returns true.
///
public bool DeleteLooseCurves()
{
SynchronizeLoops();
geometryGenerator.SetupCurveSurfaceAssociations();
var regenerateGeometry = false;
var curvesToDelete = new List();
foreach (GeometryCurve curve in Curves)
{
if ((curve.SurfaceAtLeft == null && curve.SurfaceAtRight == null))
{
curvesToDelete.Add(curve);
}
else if ((curve.SurfaceAtLeft != null && curve.SurfaceAtRight != null) &&
(curve.SurfaceAtLeft == curve.SurfaceAtRight))
{
regenerateGeometry = true;
curvesToDelete.Add(curve);
}
}
foreach (GeometryCurve curve in curvesToDelete)
{
DeleteCurve(curve, false);
}
if (regenerateGeometry)
{
RegenerateGeometry();
}
return regenerateGeometry;
}
///
/// Deletes the curve if the aValidate is true.
///
/// The curve to delete
/// Indocates whether the validation was successful
/// True if delete successful
public bool DeleteCurve(GeometryCurve geometryCurve, bool validate)
{
GeometryCurve curve = geometryCurve;
if (validate)
{
if (GetDependentCurveCount(curve.HeadPoint) <= 1 && Points.Contains(curve.HeadPoint))
{
Remove(curve.HeadPoint, false);
}
if (GetDependentCurveCount(curve.EndPoint) <= 1 && Points.Contains(curve.EndPoint))
{
Remove(curve.EndPoint, false);
}
Remove(geometryCurve, false);
if (geometryCurve.SurfaceAtLeft != null || geometryCurve.SurfaceAtRight != null)
{
return true;
}
}
else
{
Remove(geometryCurve, false);
}
return false;
}
///
/// Synchronizes the loops.
///
public void SynchronizeLoops()
{
DeleteAllLoops();
foreach (GeometrySurface surface in Surfaces)
{
// #Bka: as real donuts (or holes in geom) are not allowed, there can be no innerloop that
// is NOT an outerloop for another surface. So no need to sync innerloops.
if (surface.OuterLoop != null && surface.OuterLoop.IsLoop())
{
Loops.Add(surface.OuterLoop);
}
}
}
///
/// Finds the point at location.
///
/// Point location to be found.
/// The tolerance.
/// The point at the location; if not found returns null.
public Point2D GetPointAtLocation(Point2D point2D, double tolerance)
{
for (var i = 0; i < Points.Count; i++)
{
if (Routines2D.DetermineIfPointsCoincide(point2D.X, point2D.Z, Points[i].X, Points[i].Z, tolerance))
{
return Points[i];
}
}
return null;
}
///
/// Gets the list of curves which contain the given point.
///
/// The point
/// The curves containg the point
public void GetCurvesCoincidingWithPoint(Point2D point2D, ref List curveList)
{
curveList.Clear();
int curveCount = Curves.Count;
// loop through the list of curves, check if point on line
for (var index = 0; index < curveCount; index++)
{
GeometryCurve curve = Curves[index];
// does the input point exist in this line (within aValue1 tolerance)
if (Routines2D.DoesPointExistInLine(curve.HeadPoint, curve.EndPoint, point2D, GeometryConstants.Accuracy))
{
curveList.Add(curve); // add to list
}
}
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return LocalizationManager.GetTranslatedText(this, "GeometryData");
}
///
/// Removes the boundary curves from the given list of curves.
/// The boundaries themselves are determined from the given geometry
///
/// The curves.
/// The geometry (as string).
private static void RemoveBoundaryCurves(List curves, GeometryPointString geometry)
{
double minX = geometry.GetMinX();
double maxX = geometry.GetMaxX();
double minZ = geometry.GetMinZ();
foreach (GeometryCurve curve in curves.ToArray())
{
if (IsBoundaryCurve(curve, minX, maxX, minZ))
{
curves.Remove(curve);
}
}
}
///
/// get all geometrypoints from all geometrycurves
///
///
///
private static GeometryPointString GetAllPointsFromCurveList(List curveList)
{
var result = new GeometryPointString();
foreach (GeometryCurve curve in curveList)
{
result.CalcPoints.Add(curve.EndPoint);
result.CalcPoints.Add(curve.HeadPoint);
}
return result;
}
///
/// Gets next connected top curve in list of curves
///
///
///
///
///
private GeometryCurve GetNextTopCurve(GeometryCurve curve, List boundaryCurves,
List excludedCurves)
{
// if current curve ends on right limit then that must have been the last one so stop the search
if (Math.Abs(curve.HeadPoint.X - Right) < GeometryConstants.Accuracy || Math.Abs(curve.EndPoint.X - Right) < GeometryConstants.Accuracy)
{
return null;
}
foreach (GeometryCurve geometryCurve in boundaryCurves)
{
if (geometryCurve != curve && !excludedCurves.Contains(geometryCurve))
{
if (AreConnected(curve, geometryCurve))
{
return geometryCurve;
}
}
}
return null;
}
///
/// create a copy of the curves
///
///
///
private List GetCurvesCopy(List bCurves)
{
var outerloopCurvesCopy = new List(bCurves);
return outerloopCurvesCopy;
}
///
/// Create a surface line from points in curves
/// Precondition is that the curves start at the left boundary and are connected left to right
/// (not neccesarily neat head-end)
///
///
///
private void CreateSurfaceLinePointString(List curves)
{
surfaceLine.CalcPoints.Clear();
if (curves.Count == 0)
{
return;
}
var reversed = false;
// The headpoint of the first curve must be on the left boundary otherwise the
// surface line will be in the wrong order. So make sure.
if (!(Math.Abs(curves[0].HeadPoint.X - Left) < GeometryConstants.Accuracy))
{
curves[0].Reverse();
reversed = true;
}
foreach (GeometryCurve curve in curves)
{
if (!surfaceLine.CalcPoints.Contains(curve.HeadPoint))
{
surfaceLine.CalcPoints.Add(curve.HeadPoint);
}
if (!surfaceLine.CalcPoints.Contains(curve.EndPoint))
{
surfaceLine.CalcPoints.Add(curve.EndPoint);
}
}
if (reversed)
{
curves[0].Reverse();
}
}
///
/// get curves of the top side of the outerloop, vertical curves are omitted
///
///
///
private List GetTopCurves(List curves)
{
GeometryCurve topCurve;
// Remove all curves on the geometry boundary
if (GetLeftPoints().Count > 0 && GetRightPoints().Count > 0)
{
foreach (GeometryCurve curve in curves.ToArray())
{
if (IsBoundaryCurve(curve, Left, Right, Bottom))
{
curves.Remove(curve);
}
}
// Make sure you start with topcurve = curve at the left top position
topCurve = curves.Where(g => Math.Abs(g.HeadPoint.X - Left) < GeometryConstants.Accuracy ||
Math.Abs(g.EndPoint.X - Left) < GeometryConstants.Accuracy)
.OrderByDescending(c => c.HeadPoint.Z)
.FirstOrDefault();
}
else
{
GeometryPointString gString = GetAllPointsFromCurveList(curves);
RemoveBoundaryCurves(curves, gString);
double minX = gString.GetMinX();
// Make sure you start with topcurve = curve at the left top position
topCurve =
curves.Where(g => Math.Abs(g.HeadPoint.X - minX) < GeometryConstants.Accuracy ||
Math.Abs(g.EndPoint.X - minX) < GeometryConstants.Accuracy).OrderByDescending(c => c.HeadPoint.Z).FirstOrDefault();
}
var topCurvesLocal = new List();
while (topCurve != null)
{
topCurvesLocal.Add(topCurve);
topCurve = GetNextTopCurve(topCurve, curves, topCurvesLocal);
}
return topCurvesLocal;
}
///
/// Indicates whether a curve is on the boundary of the geometry
///
///
///
///
///
///
private static bool IsBoundaryCurve(GeometryCurve curve, double minX, double maxX, double minZ)
{
if (Math.Abs(curve.HeadPoint.X - minX) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.X - minX) < GeometryConstants.Accuracy)
{
return true;
}
if (Math.Abs(curve.HeadPoint.X - maxX) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.X - maxX) < GeometryConstants.Accuracy)
{
return true;
}
if (Math.Abs(curve.HeadPoint.Z - minZ) < GeometryConstants.Accuracy && Math.Abs(curve.EndPoint.Z - minZ) < GeometryConstants.Accuracy)
{
return true;
}
return false;
}
private bool AreConnected(GeometryCurve curve1, GeometryCurve curve2)
{
return (curve1.HeadPoint == curve2.HeadPoint || curve1.HeadPoint == curve2.EndPoint ||
curve1.EndPoint == curve2.HeadPoint || curve1.EndPoint == curve2.EndPoint);
}
///
/// Updates the line at the top of the geometry
///
private void UpdateSurfaceLine()
{
if (updatingSurfaceLine)
{
return;
}
updatingSurfaceLine = true;
List bCurves = GetBoundaryCurves();
if (bCurves.Count == 0)
{
surfaceLine.CalcPoints.Clear();
}
List curvesCopy = GetCurvesCopy(bCurves);
List curves = GetTopCurves(curvesCopy);
CreateSurfaceLinePointString(curves);
updatingSurfaceLine = false;
surfaceLine.SyncPoints();
}
#region properties
///
/// Gets the points.
///
///
/// The points.
///
[Validate]
public List Points { get; } = new List();
///
/// Gets the newly effected points.
///
///
/// The newly effected points.
///
public List NewlyEffectedPoints { get; } = new List();
///
/// gets the Curve data list.
///
///
/// The curves.
///
public List Curves { get; } = new List();
///
/// Gets the newly effected curves.
///
///
/// The newly effected curves.
///
public List NewlyEffectedCurves { get; } = new List();
///
/// gets the Loop data list.
///
///
/// The loops.
///
public List Loops { get; } = new List();
///
/// gets the Surface data list.
///
public List Surfaces { get; } = new List();
public void RegenerateGeometry()
{
if (isRegeneratingGeometry)
{
return;
}
isRegeneratingGeometry = true;
if (geometryGenerator == null)
{
geometryGenerator = new GeometryGenerator(this);
}
lock (Surfaces)
{
SynchronizeLoops();
RemoveDoublesFromNewlyEffectedPointsAndCurves();
Points.AddRange(NewlyEffectedPoints);
Curves.AddRange(NewlyEffectedCurves);
geometryGenerator.GenerateGeometry();
NewlyEffectedPoints.Clear();
NewlyEffectedCurves.Clear();
UpdateSurfaceLine();
SynchronizeLoops();
}
isRegeneratingGeometry = false;
}
///
/// Gets the minimum geometry points x.
///
///
/// The minimum geometry points x.
///
public double MinGeometryPointsX
{
get
{
return Points.Select(geometryPoint => geometryPoint.X).Concat(new[]
{
double.MaxValue
}).Min();
}
}
///
/// Gets the minimum geometry points z.
///
///
/// The minimum geometry points z.
///
public double MinGeometryPointsZ
{
get
{
return Points.Select(geometryPoint => geometryPoint.Z).Concat(new[]
{
double.MaxValue
}).Min();
}
}
///
/// Gets the maximum geometry points x.
///
///
/// The maximum geometry points x.
///
public double MaxGeometryPointsX
{
get
{
return Points.Select(geometryPoint => geometryPoint.X).Concat(new[]
{
double.MinValue
}).Max();
}
}
///
/// Gets the maximum geometry points z.
///
///
/// The maximum geometry points z.
///
public double MaxGeometryPointsZ
{
get
{
return Points.Select(geometryPoint => geometryPoint.Z).Concat(new[]
{
double.MinValue
}).Max();
}
}
///
/// Gets or sets the left.
///
///
/// The left.
///
public double Left { get; set; } = GeometryConstants.DefaultLeftLimitGeometry;
///
/// Gets or sets the right.
///
///
/// The right.
///
public double Right { get; set; } = GeometryConstants.DefaultRightLimitGeometry;
///
/// Gets or sets the bottom.
///
///
/// The bottom.
///
public double Bottom { get; set; } = GeometryConstants.DefaultBottomLimitGeometry;
///
/// Removes the doubles from newly effected points and curves.
///
public void RemoveDoublesFromNewlyEffectedPointsAndCurves()
{
var pdel = new List();
Point2D[] par = NewlyEffectedPoints.ToArray();
for (var i = 0; i < par.Length; i++)
{
for (int j = i; j < par.Length; j++)
{
if (i != j && par[i].LocationEquals(par[j]))
{
if (!pdel.Contains(par[j]))
{
pdel.Add(par[j]);
}
}
}
}
foreach (Point2D point in pdel)
{
NewlyEffectedPoints.Remove(point);
}
var cdel = new List();
GeometryCurve[] car = NewlyEffectedCurves.ToArray();
// First remove all "illegal" newlyeffected curves
for (var i = 0; i < car.Length; i++)
{
if (car[i].HeadPoint == null || car[i].EndPoint == null || car[i].HeadPoint.LocationEquals(car[i].EndPoint))
{
cdel.Add(car[i]);
}
}
foreach (GeometryCurve curve in cdel)
{
NewlyEffectedCurves.Remove(curve);
}
// then remove all real doubles
GeometryCurve[] car2 = NewlyEffectedCurves.ToArray();
cdel.Clear();
for (var i = 0; i < car2.Length; i++)
{
for (int j = i; j < car2.Length; j++)
{
if (i != j && car2[i].LocationEquals(car2[j]))
{
if (!cdel.Contains(car2[j]))
{
cdel.Add(car2[j]);
}
}
}
}
foreach (GeometryCurve curve in cdel)
{
NewlyEffectedCurves.Remove(curve);
}
}
///
/// Gets all points on the Left boundary.
///
/// The points on the Left boundary
public List GetLeftPoints()
{
List leftPoints = Points.Where(gp => Math.Abs(gp.X - Left) < GeometryConstants.Accuracy).ToList();
return leftPoints;
}
///
/// Gets all points on the Right boundary.
///
/// The points on the Right boundary
public List GetRightPoints()
{
List rightPoints = Points.Where(point => Math.Abs(point.X - Right) < GeometryConstants.Accuracy).ToList();
return rightPoints;
}
///
/// Gets the left curves, i.e. all curves that are on or connected to the Left boundary.
///
/// The left curves
public List GetLeftCurves()
{
var leftCurves = new List();
foreach (GeometryCurve geometryCurve in Curves)
{
if ((geometryCurve.HeadPoint.X <= Left && geometryCurve.EndPoint.X >= Left) ||
(geometryCurve.HeadPoint.X >= Left && geometryCurve.EndPoint.X <= Left))
{
leftCurves.Add(geometryCurve);
}
}
return leftCurves;
}
///
/// Gets the right curves, i.e. all curves that are on or connected to the Right boundary.
///
/// The right curves
public List GetRightCurves()
{
var rightCurves = new List();
foreach (GeometryCurve curve in Curves)
{
if ((curve.HeadPoint.X <= Right && curve.EndPoint.X >= Right) ||
(curve.HeadPoint.X >= Right && curve.EndPoint.X <= Right))
{
rightCurves.Add(curve);
}
}
return rightCurves;
}
///
/// Gets the geometry bounds.
///
///
public override GeometryBounds GetGeometryBounds()
{
return new GeometryBounds(Left, Right, Bottom,
Bottom + Math.Min(Right - Left, 20));
}
#endregion
#region Functions
#region create functions
///
/// Adjust the Geometry Bottom, Left and Right properties to the currently contained surfaces
///
public void Rebox()
{
var xMin = double.MaxValue;
var xMax = double.MinValue;
var zMin = double.MaxValue;
var zMax = double.MinValue;
foreach (Point2D point in Points)
{
xMin = Math.Min(point.X, xMin);
xMax = Math.Max(point.X, xMax);
zMin = Math.Min(point.Z, zMin);
zMax = Math.Max(point.Z, zMax);
}
Bottom = zMin;
Left = xMin;
Right = xMax;
}
#endregion
#region remove functions
///
/// Clears this instance.
///
public void Clear()
{
Points.Clear();
Curves.Clear();
Surfaces.Clear();
NewlyEffectedPoints.Clear();
NewlyEffectedCurves.Clear();
}
///
/// Removes the given data object
///
/// The IGeometryObject to remove
/// If set to true [a validate].
///
public bool Remove(IGeometryObject geometryObject, bool validate)
{
var removeFromList = false;
var objectlist = new List
{
geometryObject
};
if (geometryObject == null)
{
return false;
}
if (geometryObject.GetType() == typeof(Point2D))
{
var point = (Point2D) geometryObject;
if (Points.Remove(point))
{
// TODO: MWDAM-2132, check if code below is still needed
// if (aValidate)
// {
// HandleDelete(objectlist);
// }
//
// DataEventPublisher.DataListModified(pointDataList, point);
removeFromList = true;
}
}
else if (geometryObject.GetType() == typeof(GeometryCurve))
{
var geometryCurve = (GeometryCurve) geometryObject;
if (Curves.IndexOf(geometryCurve) > -1)
{
// TODO: MWDAM-2132, check if code below is still needed
// if (aValidate)
// {
// HandleDelete(objectlist);
// }
if (Curves.Remove(geometryCurve))
{
RemoveDeletedCurveFromIsUsedCurveLists(geometryCurve);
removeFromList = true;
// TODO: MWDAM-2132, check if code below is still needed
// DataEventPublisher.DataListModified(curveDataList, geometryCurve);
}
}
}
else if (geometryObject.GetType() == typeof(GeometryLoop))
{
var geometryLoop = (GeometryLoop) geometryObject;
if (Loops.Remove(geometryLoop))
{
// TODO: MWDAM-2132, check if code below is still needed
// DataEventPublisher.DataListModified(loopDataList, geometryLoop);
//
// if (aValidate)
// {
// HandleDelete(objectlist);
// }
removeFromList = true;
}
}
else if (geometryObject.GetType() == typeof(GeometrySurface))
{
var geometrySurface = (GeometrySurface) geometryObject;
if (Surfaces.Remove(geometrySurface))
{
removeFromList = true;
// TODO: MWDAM-2132, check if code below is still needed
// DataEventPublisher.DataListModified(surfaceDataList, geometrySurface);
}
}
// TODO: MWDAM-2132, check if code below is still needed
// DataEventPublisher.AfterChange(this);
return removeFromList;
}
///
/// Removes the deleted curve from IsUsedCurve lists.
///
/// The curve to delete.
private void RemoveDeletedCurveFromIsUsedCurveLists(GeometryCurve geometryCurve)
{
geometryGenerator.RemoveIsUsedCurve(geometryCurve);
}
///
/// deletes all the Loop from IGeometryLoop.
///
private void DeleteAllLoops()
{
Loops.Clear();
}
#endregion
#region other functions
#region calculation function
private int GetDependentCurveCount(Point2D aPoint)
{
int curveCount = Curves.Count;
var curvePointDependency = 0;
if (curveCount > 0)
{
for (var index = 0; index < curveCount; index++)
{
if (Curves[index].HeadPoint == aPoint || Curves[index].EndPoint == aPoint)
{
curvePointDependency++;
}
}
}
return curvePointDependency;
}
///
/// CheckIfIntersectStricktly
/// Determines if two lines intersect each other stricktly (so no extrapolated points).
///
/// Line 1 Point2D 1
/// Line 1 Point2D 2
/// Line 2 Point2D 1
/// Line 2 Point2D 2
/// Intersection coordinates
/// True if lines intersect each other
private bool CheckIfIntersectStricktly(Point2D beginPoint1, Point2D endPoint1,
Point2D beginPoint2, Point2D endPoint2,
ref Point2D intersect)
{
Point2D ip;
LineIntersection res = Routines2D.DetermineIf2DLinesIntersectStrickly(beginPoint1, endPoint1,
beginPoint2, endPoint2, out ip);
if (ip != null)
{
intersect = ip;
}
return res == LineIntersection.Intersects;
}
///
/// CheckIfIntersect
/// Determines if two lines intersect each other stricktly (so no extrapolated points).
///
/// Line 1 Point2D 1
/// Line 1 Point2D 2
/// Line 2 Point2D 1
/// Line 2 Point2D 2
/// Intersection coordinates
/// True if lines intersect each other
public bool CheckIfIntersect(double[] aL1P1, double[] aL1P2, double[] aL2P1, double[] aL2P2,
ref double[] aIntersect)
{
var p1 = new Point2D(aL1P1[0], aL1P1[1]);
var p2 = new Point2D(aL1P2[0], aL1P2[1]);
var p3 = new Point2D(aL2P1[0], aL2P1[1]);
var p4 = new Point2D(aL2P2[0], aL2P2[1]);
var ip = new Point2D();
bool res = CheckIfIntersectStricktly(p1, p2, p3, p4, ref ip);
if (res)
{
aIntersect[0] = ip.X;
aIntersect[1] = ip.Z;
}
return res;
}
///
/// Gets the height of the surface(s) intersected at the given x.
///
/// The x.
///
public double GetSurfaceHeight(double x)
{
double surfaceHeight = -Double.MaxValue;
double[] intersectionPoints = IntersectLayers(x, -9999);
for (var i = 0; i < intersectionPoints.Length; i++)
{
if (intersectionPoints[i] > surfaceHeight)
{
surfaceHeight = intersectionPoints[i];
}
}
return surfaceHeight;
}
///
/// All the Intersection of layers in respect with a given vertical are detemined here.
///
/// Startingpoint of the Vertical (X)
/// Startingpoint of the Vertical (Y)
/// List of Z intersection coordinates
private double[] IntersectLayers(double aXCoord, double aZCoord)
{
if (Surfaces == null)
{
throw new Exception("Empty Surfaces in IntersectLayers");
}
var beginPoint2 = new Point2D
{
X = aXCoord,
Z = aZCoord
};
var endPoint2 = new Point2D
{
X = aXCoord,
Z = 99999
};
var referencePoint = new Point2D();
var intersections = new List();
for (var surfaceIndexLocal = 0; surfaceIndexLocal < Surfaces.Count; surfaceIndexLocal++)
{
List outerLoopCurveList = Surfaces[surfaceIndexLocal].OuterLoop.CurveList;
for (var curveIndexLocal = 0; curveIndexLocal < outerLoopCurveList.Count; curveIndexLocal++)
{
//Check for each curve if it intersects with x coordinate
Point2D beginPoint1 = outerLoopCurveList[curveIndexLocal].GetHeadPoint(CurveDirection.Forward);
Point2D endPoint1 = outerLoopCurveList[curveIndexLocal].GetEndPoint(CurveDirection.Forward);
if (Math.Max(beginPoint1.X, endPoint1.X) >= aXCoord &&
Math.Min(beginPoint1.X, endPoint1.X) <= aXCoord)
{
if (CheckIfIntersectStricktly(beginPoint1, endPoint1, beginPoint2, endPoint2,
ref referencePoint))
{
if (referencePoint.Z > aZCoord && !intersections.Contains(referencePoint.Z))
{
intersections.Add(referencePoint.Z);
}
}
}
}
}
return intersections.ToArray();
}
///
/// Returns a list of boundary curves. These are curves which are used in only one surface so they have to be on a boundary (inner or outer)
///
///
private List GetBoundaryCurves()
{
var curves = new List();
var loops = new List();
foreach (GeometrySurface surface in Surfaces)
{
loops.Add(surface.OuterLoop);
// Todo Ask Rob/Tom: when a real "doughnut" type surface (so hole in the center) is permitted, adding the innerloops here will
// result in a wrong list of curves (because it will include the inner loop curves defining the hole) for its actual purpose:
// the determination of the surfaceline. When there is always a surface defined within the "dougnut" (so no real hole),
// this code will work and the innerloop must even be added to prevent finding internal boundaries. So this depends on the specs!
loops.AddRange(surface.InnerLoops);
}
foreach (GeometryLoop loop in loops)
{
foreach (GeometryCurve curve in loop.CurveList)
{
if (curves.Contains(curve))
{
// Second appearance, remove
curves.Remove(curve);
}
else
{
curves.Add(curve);
}
}
}
return curves;
}
#endregion
#endregion
#endregion
public Point2D CreatePoint(Point2D requestedPoint, bool snapToExistingPoint)
{
Point2D newPoint = DetermineNewPointAndFlags(requestedPoint, snapToExistingPoint, out bool flag1, out bool flag2);
if (!flag2 && snapToExistingPoint)
{
int count = Curves.Count;
for (int index = 0; index < count; ++index)
{
GeometryCurve curve = Curves[index];
if (Routines2D.DoesPointExistInLine(curve.HeadPoint, curve.EndPoint, newPoint, 0.25))
{
Routines2D.GetPointOnLineClosestTo(newPoint.X, newPoint.Z, curve.HeadPoint.X, curve.HeadPoint.Z,
curve.EndPoint.X, curve.EndPoint.Z, out Point2D aResultPoint);
newPoint.X = aResultPoint.X;
newPoint.Z = aResultPoint.Z;
break;
}
}
}
if (!NewlyEffectedPoints.Contains(newPoint) && !flag1)
NewlyEffectedPoints.Add(newPoint);
return newPoint;
}
private Point2D DetermineNewPointAndFlags(Point2D requestedPoint, bool snapToExistingPoint, out bool flag1, out bool flag2)
{
Point2D newPoint = null;
flag1 = false;
flag2 = false;
if (snapToExistingPoint)
newPoint = GetPoint(requestedPoint, 0.001);
if (newPoint != null)
{
requestedPoint.X = newPoint.X;
requestedPoint.Z = newPoint.Z;
if (!Points.Contains(requestedPoint))
newPoint = null;
else
flag1 = true;
}
if (newPoint == null)
{
newPoint = new Point2D(requestedPoint.X, requestedPoint.Z);
Create((IGeometryObject) newPoint);
}
else
flag2 = true;
return newPoint;
}
public IGeometryObject Create(IGeometryObject aData)
{
if (aData == null)
return (IGeometryObject) null;
if (aData.GetType() == typeof (Point2D))
{
Point2D point = (Point2D) aData;
Points.Add(point);
}
else if (aData.GetType() == typeof (GeometryCurve))
{
GeometryCurve geometryCurve = (GeometryCurve) aData;
Curves.Add(geometryCurve);
}
else if (aData.GetType() == typeof (GeometryLoop))
Loops.Add((GeometryLoop) aData);
else if (aData.GetType() == typeof (GeometrySurface))
Surfaces.Add((GeometrySurface) aData);
return aData;
}
public Point2D GetPoint(Point2D point2D, double snapDistance)
{
for (int index = 0; index < Points.Count; ++index)
{
if (Routines2D.DetermineIfPointsCoincide(point2D.X, point2D.Z, Points[index].X, Points[index].Z, snapDistance))
return new Point2D(Points[index].X, Points[index].Z);
}
return null;
}
public bool DeletePoint(Point2D aPoint)
{
int num = 0;
bool flag = false;
List source = new List();
if (Curves.Count > 0)
{
source.AddRange(Curves.Where((Func) (c => c.HeadPoint == aPoint || c.EndPoint == aPoint)));
if (num + source.Count == 2)
{
Point2D line1Point1 = new Point2D();
Point2D line2Point1 = new Point2D();
line1Point1.Init(source[0].HeadPoint != aPoint ? source[0].HeadPoint : source[0].EndPoint);
line2Point1.Init(source[1].HeadPoint != aPoint ? source[1].HeadPoint : source[1].EndPoint);
double angle = Routines2D.FindAngle(line1Point1, aPoint, line2Point1, aPoint);
if (angle.IsGreaterThanOrEqualTo(179.0) && angle.IsLessThanOrEqualTo(181.0))
{
FixCurvesWherePointIsOnBothConnectedCurvesInLineWithEachOther(aPoint, source);
}
}
Remove(aPoint, false);
if (source.Exists((curve => curve.SurfaceAtLeft != null || curve.SurfaceAtRight != null)))
flag = true;
foreach (GeometryCurve aCurve in source)
DeleteCurve(aCurve, true);
return flag;
}
Remove(aPoint, false);
return false;
}
private void FixCurvesWherePointIsOnBothConnectedCurvesInLineWithEachOther(Point2D aPoint, List source)
{
for (int index = 0; index < Curves.Count - 1; ++index)
{
if (Curves[index] == source[0])
{
if (Curves[index].EndPoint != source[1].EndPoint && aPoint == source[0].HeadPoint && aPoint == source[1].HeadPoint)
Curves[index].HeadPoint = source[1].EndPoint;
else if (Curves[index].EndPoint != source[1].EndPoint && aPoint == source[1].HeadPoint)
Curves[index].EndPoint = source[1].EndPoint;
else if (Curves[index].HeadPoint != source[1].HeadPoint && aPoint == Curves[index].EndPoint)
Curves[index].EndPoint = source[1].HeadPoint;
else if (Curves[index].HeadPoint == source[1].EndPoint)
Curves[index].HeadPoint = source[1].HeadPoint;
Remove(aPoint, false);
Remove(source[1], false);
}
}
}
public GeometryCurve CreateCurve(List points, Point2D aPoint1, Point2D aPoint2)
{
if (HandleEmptyPointsGeometryCurve(points, aPoint1, aPoint2, out GeometryCurve geometryCurve1))
{
return geometryCurve1;
}
foreach (GeometryCurve curve in this.Curves)
{
if (curve.HeadPoint == aPoint1 && curve.EndPoint == aPoint2 || curve.HeadPoint == aPoint2 && curve.EndPoint == aPoint1)
{
return curve;
}
}
GeometryCurve curve1 = new GeometryCurve();
geometryGenerator.SetIsUsed(curve1, CurveDirection.Forward, false);
geometryGenerator.SetIsUsed(curve1, CurveDirection.Reverse, false);
curve1.HeadPoint = aPoint1;
curve1.EndPoint = aPoint2;
Create((IGeometryObject) curve1);
NewlyEffectedCurves.Add(curve1);
return curve1;
}
private bool HandleEmptyPointsGeometryCurve(List points, Point2D aPoint1, Point2D aPoint2, out GeometryCurve geometryCurve1)
{
if (aPoint1 == null && aPoint2 == null)
{
if (points.Count < 1)
{
geometryCurve1 = null;
return true;
}
Point2D geometryPoint1 = null;
if (points.Count == 1)
{
Point2D point = points[0];
Point2D aPoint = new Point2D(point.X, point.Z);
List aCurveList = new List();
GetCurvesCoincidingInputPoint(aPoint, ref aCurveList);
if (aCurveList.Count <= 0)
{
geometryCurve1 = null;
return true;
}
geometryGenerator.SplitCurvesAtCoincidentPoint(CreatePoint(point, true), aCurveList);
}
else
{
for (int index = 0; index < points.Count - 1; ++index)
{
Point2D geometryPoint2 = index != 0 ? geometryPoint1 : CreatePoint(points[index], true);
geometryPoint1 = CreatePoint(points[index + 1], true);
bool flag = false;
foreach (GeometryCurve curve in Curves)
{
if (curve.HeadPoint == geometryPoint2 && curve.EndPoint == geometryPoint1 ||
curve.HeadPoint == geometryPoint1 && curve.EndPoint == geometryPoint2)
{
flag = true;
}
}
if (!flag)
{
GeometryCurve geometryCurve = new GeometryCurve();
geometryGenerator.SetIsUsed(geometryCurve, CurveDirection.Forward, false);
geometryGenerator.SetIsUsed(geometryCurve, CurveDirection.Reverse, false);
geometryCurve.HeadPoint = geometryPoint2;
geometryCurve.EndPoint = geometryPoint1;
Create((IGeometryObject) geometryCurve);
NewlyEffectedCurves.Add(geometryCurve);
}
}
}
// #Bka: this is a direct call instead of a delayed invoke. Can lead to problems (endless spinning)
RegenerateGeometry();
geometryCurve1 = Curves.Count > 0 ? Curves[0] : (GeometryCurve) null;
return true;
}
geometryCurve1 = null;
return false;
}
private void GetCurvesCoincidingInputPoint(Point2D aPoint, ref List aCurveList)
{
aCurveList.Clear();
int count = Curves.Count;
for (int index = 0; index < count; ++index)
{
GeometryCurve curve = Curves[index];
if (Routines2D.DoesPointExistInLine(curve.HeadPoint, curve.EndPoint, aPoint, 0.001))
aCurveList.Add(curve);
}
}
}