// 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; namespace Deltares.DamEngine.Data.Geometry; /// /// Helper class for Line objects /// public class LineHelper { /// /// Calculate intersection between two lines (strict interpolation) /// /// /// /// /// public bool GetStrictIntersectionPoint(Line line1, Line line2, ref GeometryPoint intersectPoint) { var point1 = new Point2D(line1.BeginPoint.X, line1.BeginPoint.Z); var point2 = new Point2D(line1.EndPoint.X, line1.EndPoint.Z); var point3 = new Point2D(line2.BeginPoint.X, line2.BeginPoint.Z); var point4 = new Point2D(line2.EndPoint.X, line2.EndPoint.Z); Point2D ip; LineIntersection res = Routines2D.DetermineIf2DLinesIntersectStrickly(point1, point2, point3, point4, out ip); if (ip != null) { intersectPoint.X = ip.X; intersectPoint.Z = ip.Z; } return res == LineIntersection.Intersects; } /// /// This method uses constant extrapolation from the start point to the negative X direction and /// from the end point to the positive X direction. Then the method tries to find intersection /// points with the circle on that line. /// /// Circle's middle point X value /// Circle's middle point Z value /// Circle's radius /// Point collection which defines a line. Extrapolation is performed at the start and end points. /// Intersections of this line extrapolated to the negative and positive X with the circle. public List ExtendedSurfaceIntersectionPointsWithCircle(double xMid, double zMid, double radius, IList pointss) { List points = pointss.Where(p => !double.IsNaN(p.X)).ToList(); if (points.Count >= 2) { double requiredMinSurfacePointX = xMid - radius; double requiredMaxSurfacePointX = xMid + radius; if (requiredMinSurfacePointX < points[0].X) { points.Insert(0, new Point2D { X = requiredMinSurfacePointX, Z = points[0].Z }); } if (requiredMaxSurfacePointX > points[points.Count - 1].X) { points.Insert(points.Count, new Point2D { X = requiredMaxSurfacePointX, Z = points[points.Count - 1].Z }); } } return IntersectionPointsWithCircle(xMid, zMid, radius, points); } /// /// Intersections the points with circle. /// /// The x mid. /// The z mid. /// The radius. /// The points. /// public List IntersectionPointsWithCircle(double xMid, double zMid, double radius, IList points) { var result = new List(); if (points.Count >= 2) { for (var pointIndex = 0; pointIndex < points.Count - 1; pointIndex++) { Point2D start = points[pointIndex]; Point2D end = points[pointIndex + 1]; bool outOfReach = ((Math.Max(start.X, end.X) < xMid - radius) || (Math.Min(start.X, end.X) > xMid + radius) || (Math.Max(start.Z, end.Z) < zMid - radius) || (Math.Min(start.Z, end.Z) > zMid + radius)); if (!outOfReach) { var line = new Line { BeginPoint = start, EndPoint = end }; result.AddRange(Intersect_Circle_line(xMid, zMid, radius, line)); } } } return result; } public GeometryPoint GetIntersectionPointWithExtrapolation(GeometryPoint p1, GeometryPoint p2, GeometryPoint p3, GeometryPoint p4) { return IntersectionPointWithExtrapolation(p1, p2, p3, p4); } /// /// Intersects the circle line. /// /// The xm. /// The ym. /// The r. /// The line. /// private List Intersect_Circle_line(double xm, double ym, double r, Line line) { return Routines2D.IntersectCircleline(xm, ym, r, line.BeginPoint.X, line.EndPoint.X, line.BeginPoint.Z, line.EndPoint.Z); } /// /// Determines the intersection point of two lines, allowing the intersection point being extrapolated. /// /// /// /// /// /// Intersection point or null (parallel lines) private GeometryPoint IntersectionPointWithExtrapolation(GeometryPoint p1, GeometryPoint p2, GeometryPoint p3, GeometryPoint p4) { GeometryPoint intersectPoint = null; var point1 = new Point2D(p1.X, p1.Z); var point2 = new Point2D(p2.X, p2.Z); var point3 = new Point2D(p3.X, p3.Z); var point4 = new Point2D(p4.X, p4.Z); Routines2D.DetermineIf2DLinesIntersectWithExtrapolation(point1, point2, point3, point4, out Point2D ip); if (ip != null) { intersectPoint = new GeometryPoint(ip.X, ip.Z); } return intersectPoint; } }