using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Deltares.DamPiping.ExitPointDeterminator { public enum LineIntersection { NoIntersection, Intersects, Parallel, } public static class Routines2D { // private const float cCoincideTolerance = 0.0001f; // private const double cEpsilon = 0.0001; // public static double Compute2DDistance(double aX1, double aY1, double aX2, double aY2) { double num1 = aX1 - aX2; double num2 = aY1 - aY2; return Math.Sqrt(num1 * num1 + num2 * num2); } // public static PointLocation RelativePointPositionToLine(double aLine1X, double aLine1Y, double aLine2X, double aLine2Y, double aPointX, double aPointY) // { // double num = Routines2D.CrossProduct(aLine2X - aLine1X, aLine2Y - aLine1Y, aPointX - aLine1X, aPointY - aLine1Y); // if (Math.Abs(num) < 0.0001) // return PointLocation.On; // return num < 0.0 ? PointLocation.Right : PointLocation.Left; // } // public static LineIntersection DetermineIf2DLinesIntersectStrickly(Point2D point1, Point2D point2, Point2D point3, Point2D point4, ref Point2D intersectionPoint) { return Routines2D.DetermineIf2DLinesIntersectStrickly(point1, point2, point3, point4, out intersectionPoint, 0.0001); } public static LineIntersection DetermineIf2DLinesIntersectStrickly(Point2D point1, Point2D point2, Point2D point3, Point2D point4, out Point2D intersectionPoint, double tolerance) { LineIntersection lineIntersection = Routines2D.DetermineIf2DLinesIntersectWithExtrapolation(Routines2D.CalculateNormalLineConstants(point1, point2), Routines2D.CalculateNormalLineConstants(point3, point4), out intersectionPoint); switch (lineIntersection) { case LineIntersection.Intersects: if (!Routines2D.DoesPointExistInLine(point1, point2, intersectionPoint, tolerance) || !Routines2D.DoesPointExistInLine(point3, point4, intersectionPoint, tolerance)) { intersectionPoint = (Point2D)null; lineIntersection = LineIntersection.NoIntersection; break; } break; case LineIntersection.Parallel: if (!Routines2D.DoLinesAtLeastPartialyOverlap(point1, point2, point3, point4, tolerance)) { if (Routines2D.DetermineIfPointsCoincide(point1, point3, tolerance) || Routines2D.DetermineIfPointsCoincide(point1, point4, tolerance)) { intersectionPoint = point1; lineIntersection = LineIntersection.Intersects; } if (Routines2D.DetermineIfPointsCoincide(point2, point3, tolerance) || Routines2D.DetermineIfPointsCoincide(point2, point4, tolerance)) { intersectionPoint = point2; lineIntersection = LineIntersection.Intersects; break; } break; } break; } return lineIntersection; } public static bool DoLinesAtLeastPartialyOverlap(Point2D point1, Point2D point2, Point2D point3, Point2D point4, double tolerance) { bool flag = Routines2D.AreLinesParallel(point1, point2, point3, point4, tolerance); if (!flag) return false; if (Math.Abs(point1.X - point2.X) < double.Epsilon) { double num1 = Math.Max(point1.Y, point2.Y); double num2 = Math.Min(point1.Y, point2.Y); double num3 = Math.Max(point3.Y, point4.Y); double num4 = Math.Min(point3.Y, point4.Y); if (num1 <= num4 || num2 >= num3) flag = false; } else { double num1 = Math.Max(point1.X, point2.X); double num2 = Math.Min(point1.X, point2.X); double num3 = Math.Max(point3.X, point4.X); double num4 = Math.Min(point3.X, point4.X); if (num1 <= num4 || num2 >= num3) flag = false; } return flag; } public static bool AreLinesParallel(Point2D point1, Point2D point2, Point2D point3, Point2D point4) { return Routines2D.AreLinesParallel(point1, point2, point3, point4, 0.0001); } public static bool AreLinesParallel(Point2D point1, Point2D point2, Point2D point3, Point2D point4, double tolerance) { Vector3D vector3D1 = new Vector3D(point2.X, point2.Y, 0.0) - new Vector3D(point1.X, point1.Y, 0.0); Vector3D vector3D2 = new Vector3D(point4.X, point4.Y, 0.0) - new Vector3D(point3.X, point3.Y, 0.0); vector3D1.Normalize(); vector3D2.Normalize(); return Routines2D.AreLinesParallel(new Point2D(vector3D1.X, vector3D1.Y), new Point2D(vector3D2.X, vector3D2.Y), tolerance); } public static LineIntersection DetermineIf2DLinesIntersectWithExtrapolation(Point2D aPoint1, Point2D aPoint2, Point2D aPoint3, Point2D aPoint4, ref Point2D aIntersectionPoint) { return Routines2D.DetermineIf2DLinesIntersectWithExtrapolation(Routines2D.CalculateNormalLineConstants(aPoint1, aPoint2), Routines2D.CalculateNormalLineConstants(aPoint3, aPoint4), out aIntersectionPoint); } public static bool DetermineIfPointsCoincide(Point2D point1, Point2D point2, double tolerance) { return Math.Abs(point1.X - point2.X) < tolerance && Math.Abs(point1.Y - point2.Y) < tolerance; } public static bool DoesPointExistInLine(Point2D linePoint1, Point2D linePoint2, Point2D point, double tolerance) { double x1 = linePoint1.X; double y1 = linePoint1.Y; double x2 = linePoint2.X; double y2 = linePoint2.Y; if (linePoint1.X == linePoint2.X && linePoint1.Y == linePoint2.Y) return Routines2D.Compute2DDistance(point.X, point.Y, x1, y1) < tolerance; double num1 = Math.Max(x1, x2); double num2 = Math.Min(x1, x2); double num3 = Math.Max(y1, y2); double num4 = Math.Min(y1, y2); double num5 = num2 - tolerance; double num6 = num4 - tolerance; double num7 = num1 + tolerance; double num8 = num3 + tolerance; double x3 = point.X; double y3 = point.Y; if (x3 <= num5 || x3 >= num7 || (y3 <= num6 || y3 >= num8)) return false; double num9 = y1 - y2; double num10 = x2 - x1; double num11 = -(num9 * x1 + num10 * y1); return Math.Abs((num9 * x3 + num10 * y3 + num11) / Routines2D.Compute2DDistance(x1, y1, x2, y2)) < tolerance; } // public static double LinInpolY(double aXStart, double aYStart, double aXEnd, double aYEnd, double aXInterpolation) // { // if (Math.Abs(aXEnd - aXStart) < 1E-15) // return (aYEnd + aYStart) * 0.5; // return GeneralMathRoutines.LinearInterpolate(aYStart, aYEnd, (aXInterpolation - aXStart) / (aXEnd - aXStart)); // } // // public static double CalculateSquaredDistance(Point2D point, Point2D segmentPoint1, Point2D segmentPoint2) // { // Point2D point2D1 = segmentPoint2 - segmentPoint1; // Point2D point2D2 = point - segmentPoint1; // Func func = (Func)((first, second) => first.X * second.X + first.Y * second.Y); // double num1 = func(point2D2, point2D1); // double num2 = func(point2D1, point2D1); // Point2D point2D3; // if (num1 <= 0.0) // point2D3 = point - segmentPoint1; // else if (num2 <= num1) // { // point2D3 = point - segmentPoint2; // } // else // { // double num3 = num1 / num2; // Point2D point2D4 = segmentPoint1 + num3 * point2D1; // point2D3 = point - point2D4; // } // return func(point2D3, point2D3); // } // // public static double CalculateSquaredDistance(Point2D segment1Point1, Point2D segment1Point2, Point2D segment2Point1, Point2D segment2Point2) // { // return ((IEnumerable)new double[4] // { // Routines2D.CalculateSquaredDistance(segment1Point1, segment2Point1, segment2Point2), // Routines2D.CalculateSquaredDistance(segment1Point2, segment2Point1, segment2Point2), // Routines2D.CalculateSquaredDistance(segment2Point1, segment1Point1, segment1Point2), // Routines2D.CalculateSquaredDistance(segment2Point2, segment1Point1, segment1Point2) // }).Min(); // } // // public static double CalculateDistanceToLine(double pointX, double pointY, double segmentStartX, double segmentStartY, double segmentEndX, double segmentEndY) // { // return Math.Sqrt(Routines2D.CalculateSquaredDistance(new Point2D(pointX, pointY), new Point2D(segmentStartX, segmentStartY), new Point2D(segmentEndX, segmentEndY))); // } // // public static void FindParallelLine(double x1, double y1, double x2, double y2, double distance, out double resultX1, out double resultY1, out double resultX2, out double resultY2) // { // if (Math.Abs(distance) > 0.0) // { // double num1 = x2 - x1; // double num2 = y2 - y1; // double num3 = Routines2D.Compute2DDistance(x1, y1, x2, y2); // double num4 = distance / num3; // double num5 = num4 * num1; // double num6 = num4 * num2; // x1 -= num6; // x2 -= num6; // y1 += num5; // y2 += num5; // } // resultX1 = x1; // resultX2 = x2; // resultY1 = y1; // resultY2 = y2; // } // // public static PointInPolygon CheckIfPointIsInPolygon(List polygon, double x, double y) // { // PointInPolygon pointInPolygon = PointInPolygon.OutsidePolygon; // if (polygon.Count > 0) // polygon.Add(polygon[0]); // double count = (double)polygon.Count; // if (count > 2.0) // { // double x1 = polygon[0].X - x; // double y1 = polygon[0].Y - y; // if (Math.Abs(x1) < 1E-10 && Math.Abs(y1) < 1E-10) // return PointInPolygon.OnPolygonEdge; // double num1 = Math.Atan2(y1, x1); // double num2 = 0.0; // for (int index = 1; (double)index < count; ++index) // { // double x2 = polygon[index].X - x; // double y2 = polygon[index].Y - y; // if (Math.Abs(x2) < 1E-10 && Math.Abs(y2) < 1E-10) // return PointInPolygon.OnPolygonEdge; // double num3 = Math.Atan2(y2, x2); // double num4 = num3 - num1; // if (num4 < -1.0 * Math.PI) // num4 += 2.0 * Math.PI; // if (num4 > Math.PI) // num4 -= 2.0 * Math.PI; // if (Math.PI - num4 < 1E-10 || Math.PI + num4 < 1E-10) // return PointInPolygon.OnPolygonEdge; // num2 += num4; // num1 = num3; // } // pointInPolygon = num2 > 19.0 * Math.PI / 10.0 || num2 < -19.0 * Math.PI / 10.0 ? PointInPolygon.InsidePolygon : PointInPolygon.OutsidePolygon; // } // return pointInPolygon; // } // // public static void GetPointOnLineClosestTo(double aPointX, double aPointY, double aLine1X, double aLine1Y, double aLine2X, double aLine2Y, out double aResultX, out double aResultY) // { // double x = Routines2D.Compute2DDistance(aLine1X, aLine1Y, aLine2X, aLine2Y); // double num = (Math.Pow(Routines2D.Compute2DDistance(aLine1X, aLine1Y, aPointX, aPointY), 2.0) - Math.Pow(Routines2D.Compute2DDistance(aLine2X, aLine2Y, aPointX, aPointY), 2.0) + Math.Pow(x, 2.0)) / (2.0 * x); // if (num <= 0.0) // { // aResultX = aLine1X; // aResultY = aLine1Y; // } // else if (num >= x) // { // aResultX = aLine2X; // aResultY = aLine2Y; // } // else // { // aResultX = aLine1X + num / x * (aLine2X - aLine1X); // aResultY = aLine1Y + num / x * (aLine2Y - aLine1Y); // } // } // // public static List IntersectCircleline(double aX, double aY, double aR, double aX1, double aX2, double aY1, double aY2) // { // double num1 = aX2 - aX1; // double x1 = aX1 - aX; // double num2 = aY2 - aY1; // double x2 = aY1 - aY; // List point2DList = new List(); // if (Math.Abs(num1) > 1E-08 || Math.Abs(num2) > 1E-08) // { // double num3 = num1 * num1 + num2 * num2; // double num4 = 2.0 * (num1 * x1 + num2 * x2); // double num5 = x1 * x1 + x2 * x2 - aR * aR; // double d = num4 * num4 - 4.0 * num3 * num5; // if (d > 1E-08) // { // double num6 = (-num4 + Math.Sqrt(d)) / (2.0 * num3); // if (num6 >= -1E-08 && num6 <= 1.00000001) // point2DList.Add(new Point2D(aX1 + num6 * num1, aY1 + num6 * num2)); // double num7 = (-num4 - Math.Sqrt(d)) / (2.0 * num3); // if (num7 >= -1E-08 && num7 <= 1.00000001) // point2DList.Add(new Point2D(aX1 + num7 * num1, aY1 + num7 * num2)); // } // else if (Math.Abs(d) <= 1E-08) // { // double num6 = -num4 / (2.0 * num3); // if (num6 >= -1E-08 && num6 <= 1.00000001) // point2DList.Add(new Point2D(aX1 + num6 * num1, aY1 + num6 * num2)); // } // } // else if (Math.Abs(Math.Pow(x1, 2.0) + Math.Pow(x2, 2.0) - Math.Pow(aR, 2.0)) < 1E-08) // point2DList.Add(new Point2D(aX1, aY1)); // return point2DList; // } // // public static Clockwise IsClockWise(IEnumerable aPolygon) // { // Point2D[] array = aPolygon.Distinct().ToArray(); // if (array.Length < 3) // return Clockwise.NotEnoughUniquePoints; // double num1 = 0.0; // for (int index = 0; index < array.Length - 1; ++index) // { // double num2 = (array[index + 1].X - array[index].X) * (array[index + 1].Y + array[index].Y); // num1 += num2; // } // double num3 = (array[0].X - array[array.Length - 1].X) * (array[0].Y + array[array.Length - 1].Y); // int num4 = Math.Sign(num1 + num3); // if (num4 == 0) // return Clockwise.PointsOnLine; // return (double)num4 <= 0.0 ? Clockwise.AntiClockwise : Clockwise.IsClockwise; // } // // public static double ComputeTriangleArea(double aX1, double aY1, double aX2, double aY2, double aX3, double aY3) // { // return 0.5 * ((aX3 - aX1) * (aY2 - aY1) - (aY3 - aY1) * (aX2 - aX1)); // } // // public static bool AreEqual(double x1, double x2, double tolerance) // { // return Math.Abs(x1 - x2) < tolerance; // } // // public static bool AreEqual(Point2D p1, Point2D p2, int tolerance) // { // if (Routines2D.AreEqual(p1.X, p2.X, (double)tolerance)) // return Routines2D.AreEqual(p1.Y, p2.Y, (double)tolerance); // return false; // } // // public static bool AreEqual(int x1, int x2, int tolerance) // { // return Math.Abs(x1 - x2) < tolerance; // } // // public static bool DetermineIfPointsCoincide(double aX1, double aY1, double aX2, double aY2, double aTolerance) // { // if (Math.Abs(aX2 - aX1) < aTolerance) // return Math.Abs(aY2 - aY1) < aTolerance; // return false; // } // // public static double Determine2DPolygonArea(List closedPolygon) // { // int count = closedPolygon.Count; // double num = 0.0; // if (!Routines2D.DetermineIfPointsCoincide(closedPolygon[0], closedPolygon[count - 1], 9.99999974737875E-05)) // { // closedPolygon.Add(closedPolygon[0]); // count = closedPolygon.Count; // } // for (int index = 0; index < count - 1; ++index) // num += Routines2D.CrossProduct(closedPolygon[index].X, closedPolygon[index].Y, closedPolygon[index + 1].X, closedPolygon[index + 1].Y); // return num / 2.0; // } // // public static Point2D DeterminePolygonCentroid(List closedPolygon) // { // int count = closedPolygon.Count; // if (!Routines2D.DetermineIfPointsCoincide(closedPolygon[0], closedPolygon[count - 1], 9.99999974737875E-05)) // closedPolygon.Add(closedPolygon[0]); // else // --count; // double num1 = Routines2D.Determine2DPolygonArea(closedPolygon); // if (num1 > 0.0) // { // double num2 = 0.0; // double num3 = 0.0; // for (int index = 0; index < count; ++index) // { // double num4 = Routines2D.CrossProduct(closedPolygon[index].X, closedPolygon[index].Y, closedPolygon[index + 1].X, closedPolygon[index + 1].Y); // num2 += (closedPolygon[index].X + closedPolygon[index + 1].X) * num4; // num3 += (closedPolygon[index].Y + closedPolygon[index + 1].Y) * num4; // } // return new Point2D(num2 / (6.0 * num1), num3 / (6.0 * num1)); // } // double num5 = 0.0; // double num6 = 0.0; // for (int index = 0; index < count; ++index) // { // num5 += closedPolygon[index].X; // num6 += closedPolygon[index].Y; // } // return new Point2D(num5 / (double)count, num6 / (double)count); // } // // public static MinMax GetMinMax(List aPointList, ref double aMin, ref double aMax, MinMaxCordinate aMinMaxCoordinate) // { // if (aPointList.Count < 2) // return MinMax.Error; // aMin = aPointList.Min((Func)(x => // { // if (aMinMaxCoordinate != MinMaxCordinate.X) // return x.Y; // return x.X; // })); // aMax = aPointList.Max((Func)(x => // { // if (aMinMaxCoordinate != MinMaxCordinate.X) // return x.Y; // return x.X; // })); // return MinMax.Calculated; // } // // public static double GetAngle(double x1, double y1, double x2, double y2) // { // double aValue1_1 = y2 - y1; // double aValue1_2 = x2 - x1; // if (aValue1_2.IsNearEqual(1E-08)) // return 90.0; // if (aValue1_1.IsNearEqual(1E-08)) // return 0.0; // return Math.Atan(aValue1_1 / aValue1_2) * 180.0 / Math.PI; // } // // public static bool IsPointInRectangularBounds(double aXLeft, double aXRight, double aYTop, double aYBottom, Point2D aPoint) // { // bool flag1 = aPoint.X.IsGreaterThanOrEqualTo(aXLeft) && aPoint.X.IsLessThanOrEqualTo(aXRight); // bool flag2 = aPoint.Y.IsGreaterThanOrEqualTo(aYBottom) && aPoint.Y.IsLessThanOrEqualTo(aYTop); // if (flag1) // return flag2; // return false; // } // // public static double GetMinimumDistanceAmongPoints(List pointList) // { // if (pointList.Count < 2) // return 0.0; // List doubleList = new List(); // for (int index1 = 0; index1 < pointList.Count; ++index1) // { // for (int index2 = index1 + 1; index2 < pointList.Count; ++index2) // doubleList.Add(Routines2D.Compute2DDistance(pointList[index1].X, pointList[index1].Y, pointList[index2].X, pointList[index2].Y)); // } // doubleList.Sort(); // return doubleList[0]; // } // // public static Point2D RotateAroundPoint(Point2D rotatePoint, Point2D rotateCenter, double theta) // { // double num1 = rotatePoint.X - rotateCenter.X; // double num2 = rotatePoint.Y - rotateCenter.Y; // return new Point2D() // { // X = Math.Cos(theta) * num1 - Math.Sin(theta) * num2 + rotateCenter.X, // Y = Math.Sin(theta) * num1 + Math.Cos(theta) * num2 + rotateCenter.Y // }; // } // // public static bool IsBetween(double x, double x1, double x2) // { // if (x1 <= x && x2 >= x) // return true; // if (x1 >= x) // return x2 <= x; // return false; // } // private static double CrossProduct(double pointAx, double pointAy, double pointBx, double pointBy) { return pointAx * pointBy - pointBx * pointAy; } private static Vector3D CalculateNormalLineConstants(Point2D aPoint1, Point2D aPoint2) { return new Vector3D() { X = aPoint2.Y - aPoint1.Y, Y = -(aPoint2.X - aPoint1.X), Z = (aPoint2.Y - aPoint1.Y) * aPoint1.X - (aPoint2.X - aPoint1.X) * aPoint1.Y }; } private static bool AreLinesParallel(Point2D aLine1Constant, Point2D aLine2Constant, double tolerance) { double x1 = aLine1Constant.X; double y1 = aLine1Constant.Y; double x2 = aLine2Constant.X; double y2 = aLine2Constant.Y; return Math.Abs(Routines2D.CrossProduct(x1, x2, y1, y2)) < tolerance; } private static LineIntersection DetermineIf2DLinesIntersectWithExtrapolation(Vector3D aLine1Constant, Vector3D aLine2Constant, out Point2D aIntersectionPoint) { aIntersectionPoint = new Point2D(0.0, 0.0); double x1 = aLine1Constant.X; double y1 = aLine1Constant.Y; double z1 = aLine1Constant.Z; double x2 = aLine2Constant.X; double y2 = aLine2Constant.Y; double z2 = aLine2Constant.Z; if (Routines2D.AreLinesParallel(new Point2D(x1, x2), new Point2D(y1, y2), 0.0001)) { aIntersectionPoint = (Point2D)null; return LineIntersection.Parallel; } double num1 = (y2 * z1 - y1 * z2) / (x1 * y2 - x2 * y1); double num2 = (z1 * x2 - z2 * x1) / (x2 * y1 - x1 * y2); aIntersectionPoint.X = num1; aIntersectionPoint.Y = num2; return LineIntersection.Intersects; } } }