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