Advertisement
FocusedWolf

LineIntersection

Jun 24th, 2015
5,006
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 13.39 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5.  
  6. namespace Code
  7. {
  8.     //Originally: http://www.artiom.pro/2013/06/c-find-intersections-of-two-line-by.html
  9.  
  10.     public class LineEquation
  11.     {
  12.         public LineEquation(Point start, Point end)
  13.         {
  14.             Start = start;
  15.             End = end;
  16.  
  17.             A = End.Y - Start.Y;
  18.             B = Start.X - End.X;
  19.             C = A * Start.X + B * Start.Y;
  20.         }
  21.  
  22.         public Point Start { get; private set; }
  23.         public Point End { get; private set; }
  24.  
  25.         public double A { get; private set; }
  26.         public double B { get; private set; }
  27.         public double C { get; private set; }
  28.  
  29.         public Point? GetIntersectionWithLine(LineEquation otherLine)
  30.         {
  31.             double determinant = A * otherLine.B - otherLine.A * B;
  32.  
  33.             if (determinant.IsZero()) //lines are parallel
  34.                 return default(Point?);
  35.  
  36.             //Cramer's Rule
  37.  
  38.             double x = (otherLine.B * C - B * otherLine.C) / determinant;
  39.             double y = (A * otherLine.C - otherLine.A * C) / determinant;
  40.  
  41.             Point intersectionPoint = new Point(x, y);
  42.  
  43.             return intersectionPoint;
  44.         }
  45.  
  46.         public Point? GetIntersectionWithLineSegment(LineEquation otherLine)
  47.         {
  48.             Point? intersectionPoint = GetIntersectionWithLine(otherLine);
  49.  
  50.             if (intersectionPoint.HasValue &&
  51.                 intersectionPoint.Value.IsBetweenTwoPoints(otherLine.Start, otherLine.End))
  52.                 return intersectionPoint;
  53.  
  54.             return default(Point?);
  55.         }
  56.  
  57.         //i didnt review this one for correctness
  58.         public LineEquation GetIntersectionWithLineForRay(Rect rectangle)
  59.         {
  60.             LineEquation intersectionLine;
  61.  
  62.             if (Start == End)
  63.                 return null;
  64.  
  65.             IEnumerable<LineEquation> lines = rectangle.LineSegments();
  66.             intersectionLine = new LineEquation(new Point(0, 0), new Point(0, 0));
  67.             var intersections = new Dictionary<LineEquation, Point>();
  68.             foreach (LineEquation equation in lines)
  69.             {
  70.                 Point? intersectionPoint = GetIntersectionWithLineSegment(equation);
  71.  
  72.                 if (intersectionPoint.HasValue)
  73.                     intersections[equation] = intersectionPoint.Value;
  74.             }
  75.  
  76.             if (!intersections.Any())
  77.                 return null;
  78.  
  79.             var intersectionPoints = new SortedDictionary<double, Point>();
  80.             foreach (var intersection in intersections)
  81.             {
  82.                 if (End.IsBetweenTwoPoints(Start, intersection.Value) ||
  83.                     intersection.Value.IsBetweenTwoPoints(Start, End))
  84.                 {
  85.                     double distanceToPoint = Start.DistanceToPoint(intersection.Value);
  86.                     intersectionPoints[distanceToPoint] = intersection.Value;
  87.                 }
  88.             }
  89.  
  90.             if (intersectionPoints.Count == 1)
  91.             {
  92.                 Point endPoint = intersectionPoints.First().Value;
  93.                 intersectionLine = new LineEquation(Start, endPoint);
  94.  
  95.                 return intersectionLine;
  96.             }
  97.  
  98.             if (intersectionPoints.Count == 2)
  99.             {
  100.                 Point start = intersectionPoints.First().Value;
  101.                 Point end = intersectionPoints.Last().Value;
  102.                 intersectionLine = new LineEquation(start, end);
  103.  
  104.                 return intersectionLine;
  105.             }
  106.  
  107.             return null;
  108.         }
  109.  
  110.         public override string ToString()
  111.         {
  112.             return "[" + Start + "], [" + End + "]";
  113.         }
  114.     }
  115.  
  116.     public static class DoubleExtensions
  117.     {
  118.         //SOURCE: https://github.com/mathnet/mathnet-numerics/blob/master/src/Numerics/Precision.cs
  119.         //        https://github.com/mathnet/mathnet-numerics/blob/master/src/Numerics/Precision.Equality.cs
  120.         //        http://referencesource.microsoft.com/#WindowsBase/Shared/MS/Internal/DoubleUtil.cs
  121.         //        http://stackoverflow.com/questions/2411392/double-epsilon-for-equality-greater-than-less-than-less-than-or-equal-to-gre
  122.        
  123.         /// <summary>
  124.         /// The smallest positive number that when SUBTRACTED from 1D yields a result different from 1D.
  125.         /// The value is derived from 2^(-53) = 1.1102230246251565e-16, where IEEE 754 binary64 &quot;double precision&quot; floating point numbers have a significand precision that utilize 53 bits.
  126.         ///
  127.         /// This number has the following properties:
  128.         ///     (1 - NegativeMachineEpsilon) &lt; 1 and
  129.         ///     (1 + NegativeMachineEpsilon) == 1
  130.         /// </summary>
  131.         public const double NegativeMachineEpsilon = 1.1102230246251565e-16D; //Math.Pow(2, -53);
  132.  
  133.         /// <summary>
  134.         /// The smallest positive number that when ADDED to 1D yields a result different from 1D.
  135.         /// The value is derived from 2 * 2^(-53) = 2.2204460492503131e-16, where IEEE 754 binary64 &quot;double precision&quot; floating point numbers have a significand precision that utilize 53 bits.
  136.         ///
  137.         /// This number has the following properties:
  138.         ///     (1 - PositiveDoublePrecision) &lt; 1 and
  139.         ///     (1 + PositiveDoublePrecision) &gt; 1
  140.         /// </summary>
  141.         public const double PositiveMachineEpsilon = 2D * NegativeMachineEpsilon;
  142.  
  143.         /// <summary>
  144.         /// The smallest positive number that when SUBTRACTED from 1D yields a result different from 1D.
  145.         ///
  146.         /// This number has the following properties:
  147.         ///     (1 - NegativeMachineEpsilon) &lt; 1 and
  148.         ///     (1 + NegativeMachineEpsilon) == 1
  149.         /// </summary>
  150.         public static readonly double MeasuredNegativeMachineEpsilon = MeasureNegativeMachineEpsilon();
  151.  
  152.         private static double MeasureNegativeMachineEpsilon()
  153.         {
  154.             double epsilon = 1D;
  155.  
  156.             do
  157.             {
  158.                 double nextEpsilon = epsilon / 2D;
  159.  
  160.                 if ((1D - nextEpsilon) == 1D) //if nextEpsilon is too small
  161.                     return epsilon;
  162.  
  163.                 epsilon = nextEpsilon;
  164.             }
  165.             while (true);
  166.         }
  167.  
  168.         /// <summary>
  169.         /// The smallest positive number that when ADDED to 1D yields a result different from 1D.
  170.         ///
  171.         /// This number has the following properties:
  172.         ///     (1 - PositiveDoublePrecision) &lt; 1 and
  173.         ///     (1 + PositiveDoublePrecision) &gt; 1
  174.         /// </summary>
  175.         public static readonly double MeasuredPositiveMachineEpsilon = MeasurePositiveMachineEpsilon();
  176.  
  177.         private static double MeasurePositiveMachineEpsilon()
  178.         {
  179.             double epsilon = 1D;
  180.  
  181.             do
  182.             {
  183.                 double nextEpsilon = epsilon / 2D;
  184.  
  185.                 if ((1D + nextEpsilon) == 1D) //if nextEpsilon is too small
  186.                     return epsilon;
  187.  
  188.                 epsilon = nextEpsilon;
  189.             }
  190.             while (true);
  191.         }
  192.  
  193.         const double DefaultDoubleAccuracy = NegativeMachineEpsilon * 10D;
  194.  
  195.         public static bool IsClose(this double value1, double value2)
  196.         {
  197.             return IsClose(value1, value2, DefaultDoubleAccuracy);
  198.         }
  199.  
  200.         public static bool IsClose(this double value1, double value2, double maximumAbsoluteError)
  201.         {
  202.             if (double.IsInfinity(value1) || double.IsInfinity(value2))
  203.                 return value1 == value2;
  204.  
  205.             if (double.IsNaN(value1) || double.IsNaN(value2))
  206.                 return false;
  207.  
  208.             double delta = value1 - value2;
  209.  
  210.             //return Math.Abs(delta) <= maximumAbsoluteError;
  211.  
  212.             if (delta > maximumAbsoluteError ||
  213.                 delta < -maximumAbsoluteError)
  214.                 return false;
  215.  
  216.             return true;
  217.         }
  218.  
  219.         public static bool LessThan(this double value1, double value2)
  220.         {
  221.             return (value1 < value2) && !IsClose(value1, value2);
  222.         }
  223.  
  224.         public static bool GreaterThan(this double value1, double value2)
  225.         {
  226.             return (value1 > value2) && !IsClose(value1, value2);
  227.         }
  228.  
  229.         public static bool LessThanOrClose(this double value1, double value2)
  230.         {
  231.             return (value1 < value2) || IsClose(value1, value2);
  232.         }
  233.  
  234.         public static bool GreaterThanOrClose(this double value1, double value2)
  235.         {
  236.             return (value1 > value2) || IsClose(value1, value2);
  237.         }
  238.  
  239.         public static bool IsOne(this double value)
  240.         {
  241.             double delta = value - 1D;
  242.  
  243.             //return Math.Abs(delta) <= PositiveMachineEpsilon;
  244.  
  245.             if (delta > PositiveMachineEpsilon ||
  246.                 delta < -PositiveMachineEpsilon)
  247.                 return false;
  248.  
  249.             return true;
  250.         }
  251.  
  252.         public static bool IsZero(this double value)
  253.         {
  254.             //return Math.Abs(value) <= PositiveMachineEpsilon;
  255.  
  256.             if (value > PositiveMachineEpsilon ||
  257.                 value < -PositiveMachineEpsilon)
  258.                 return false;
  259.  
  260.             return true;
  261.         }
  262.     }
  263.  
  264.     public static class PointExtensions
  265.     {
  266.         public static double DistanceToPoint(this Point point, Point point2)
  267.         {
  268.             return Math.Sqrt((point2.X - point.X) * (point2.X - point.X) + (point2.Y - point.Y) * (point2.Y - point.Y));
  269.         }
  270.  
  271.         public static double SquaredDistanceToPoint(this Point point, Point point2)
  272.         {
  273.             return (point2.X - point.X) * (point2.X - point.X) + (point2.Y - point.Y) * (point2.Y - point.Y);
  274.         }
  275.  
  276.         public static bool IsBetweenTwoPoints(this Point targetPoint, Point point1, Point point2)
  277.         {
  278.             double minX = Math.Min(point1.X, point2.X);
  279.             double minY = Math.Min(point1.Y, point2.Y);
  280.             double maxX = Math.Max(point1.X, point2.X);
  281.             double maxY = Math.Max(point1.Y, point2.Y);
  282.  
  283.             double targetX = targetPoint.X;
  284.             double targetY = targetPoint.Y;
  285.  
  286.             return minX.LessThanOrClose(targetX)
  287.                   && targetX.LessThanOrClose(maxX)
  288.                   && minY.LessThanOrClose(targetY)
  289.                   && targetY.LessThanOrClose(maxY);
  290.         }
  291.     }
  292.  
  293.     public static class RectExtentions
  294.     {
  295.         //improved name from original
  296.         public static IEnumerable<LineEquation> LineSegments(this Rect rectangle)
  297.         {
  298.             var lines = new List<LineEquation>
  299.             {
  300.                 new LineEquation(new Point(rectangle.X, rectangle.Y),
  301.                                  new Point(rectangle.X, rectangle.Y + rectangle.Height)),
  302.  
  303.                 new LineEquation(new Point(rectangle.X, rectangle.Y + rectangle.Height),
  304.                                  new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height)),
  305.  
  306.                 new LineEquation(new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height),
  307.                                  new Point(rectangle.X + rectangle.Width, rectangle.Y)),
  308.  
  309.                 new LineEquation(new Point(rectangle.X + rectangle.Width, rectangle.Y),
  310.                                  new Point(rectangle.X, rectangle.Y)),
  311.             };
  312.  
  313.             return lines;
  314.         }
  315.  
  316.         //improved from original at http://www.codeproject.com/Tips/403031/Extension-methods-for-finding-centers-of-a-rectang
  317.  
  318.         /// <summary>
  319.         /// Returns the center point of the rectangle
  320.         /// </summary>
  321.         /// <param name="r"></param>
  322.         /// <returns>Center point of the rectangle</returns>
  323.         public static Point Center(this Rect r)
  324.         {
  325.             return new Point(r.Left + (r.Width / 2D), r.Top + (r.Height / 2D));
  326.         }
  327.         /// <summary>
  328.         /// Returns the center right point of the rectangle
  329.         /// i.e. the right hand edge, centered vertically.
  330.         /// </summary>
  331.         /// <param name="r"></param>
  332.         /// <returns>Center right point of the rectangle</returns>
  333.         public static Point CenterRight(this Rect r)
  334.         {
  335.             return new Point(r.Right, r.Top + (r.Height / 2D));
  336.         }
  337.         /// <summary>
  338.         /// Returns the center left point of the rectangle
  339.         /// i.e. the left hand edge, centered vertically.
  340.         /// </summary>
  341.         /// <param name="r"></param>
  342.         /// <returns>Center left point of the rectangle</returns>
  343.         public static Point CenterLeft(this Rect r)
  344.         {
  345.             return new Point(r.Left, r.Top + (r.Height / 2D));
  346.         }
  347.         /// <summary>
  348.         /// Returns the center bottom point of the rectangle
  349.         /// i.e. the bottom edge, centered horizontally.
  350.         /// </summary>
  351.         /// <param name="r"></param>
  352.         /// <returns>Center bottom point of the rectangle</returns>
  353.         public static Point CenterBottom(this Rect r)
  354.         {
  355.             return new Point(r.Left + (r.Width / 2D), r.Bottom);
  356.         }
  357.         /// <summary>
  358.         /// Returns the center top point of the rectangle
  359.         /// i.e. the topedge, centered horizontally.
  360.         /// </summary>
  361.         /// <param name="r"></param>
  362.         /// <returns>Center top point of the rectangle</returns>
  363.         public static Point CenterTop(this Rect r)
  364.         {
  365.             return new Point(r.Left + (r.Width / 2D), r.Top);
  366.         }
  367.     }
  368. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement