// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU 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 General Public License for more details. // // You should have received a copy of the GNU 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.Collections.ObjectModel; using System.Linq; using Ringtoets.Piping.Data.Properties; namespace Ringtoets.Piping.Data.Calculation { /// /// This class contains general mathematical routines for 2D lines. /// public static class Math2D { /// /// Constant which is used to precision errors in comparisons. /// private const double epsilonForComparisons = 1e-8; /// /// Determines the intersection point of a line which passes through the and /// the ; and a line which passes through the /// and the . /// /// A which the first line passes through. /// Another which the first line passes through. /// A which the second line passes through. /// Another which the second line passes through. /// An with coordinates at the point where the lines intersect. Or null when no /// intersection point exists (lines are parallel). /// /// Taken from: https://www.topcoder.com/community/data-science/data-science-tutorials/geometry-concepts-line-intersection-and-its-applications/ /// Based on https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection /// /// Thrown when equals or /// equals , which makes it impossible to determine /// a line through the points. public static Point2D LineIntersectionWithLine(Point2D line1Point1, Point2D line1Point2, Point2D line2Point1, Point2D line2Point2) { if (line1Point1.Equals(line1Point2) || line2Point1.Equals(line2Point2)) { throw new ArgumentException(Resources.Math2D_LineIntersectionWithLine_Line_points_are_equal); } var aLine = line1Point2.Y - line1Point1.Y; var bLine = line1Point1.X - line1Point2.X; var cLine = aLine*line1Point1.X + bLine*line1Point1.Y; var aOtherLine = line2Point2.Y - line2Point1.Y; var bOtherLine = line2Point1.X - line2Point2.X; var cOtherLine = aOtherLine*line2Point1.X + bOtherLine*line2Point1.Y; var determinant = aLine*bOtherLine - aOtherLine*bLine; if (Math.Abs(determinant) < epsilonForComparisons) { return null; } return new Point2D { X = (bOtherLine*cLine - bLine*cOtherLine)/determinant, Y = (aLine*cOtherLine - aOtherLine*cLine)/determinant }; } /// /// Determines the intersection points of a of with a vertical line /// which is plotted at x=. /// /// A collection of segments that possibly intersect with the /// vertical line at x=. /// The x coordinate of the vertical line. /// A of with all intersection points of the /// with the vertical line at x=. /// Segments which have length=0 or which are vertical, will not return an intersection point. public static IEnumerable SegmentsIntersectionWithVerticalLine(IEnumerable segments, double verticalLineX) { var intersectionPointY = new Collection(); foreach (Segment2D segment in segments.Where(s => s.ContainsX(verticalLineX))) { Point2D intersectionPoint = LineIntersectionWithVerticalLine(segment.FirstPoint, segment.SecondPoint, verticalLineX); if (intersectionPoint != null) { intersectionPointY.Add(intersectionPoint); } } return intersectionPointY; } /// /// Determines the intersection point of a line through the points and /// with a vertical line at x=. If /// equals , then no intersection point /// will be returned. /// /// A which the line passes through. /// Another which the line passes through. /// The x coordinate of the vertical line. /// The intersection point between the line through and /// and the vertical line at x=; or null if /// the line through and is vertical or /// the points are equal. private static Point2D LineIntersectionWithVerticalLine(Point2D point1, Point2D point2, double x) { var verticalLineFirstPoint = new Point2D { X = x, Y = 0 }; var verticalLineSecondPoint = new Point2D { X = x, Y = 1 }; try { return LineIntersectionWithLine(point1, point2, verticalLineFirstPoint, verticalLineSecondPoint); } catch (ArgumentException) { return null; } } } }