Example #1
0
        /// <summary>
        ///     Finds the points of intersection between a line and a circle. The results are two lambdas along the line, one
        ///     for each point, or NaN if there is no intersection.</summary>
        public static void LineWithCircle(ref EdgeD line, ref CircleD circle,
                                          out double lambda1, out double lambda2)
        {
            // The following expressions come up a lot in the solution, so simplify using them.
            double dx = line.End.X - line.Start.X;
            double dy = line.End.Y - line.Start.Y;
            double ax = -line.Start.X + circle.Center.X;
            double ay = -line.Start.Y + circle.Center.Y;

            // Solve simultaneously for l:
            // Eq of a line:    x = sx + l * dx
            //                  y = sy + l * dy
            // Eq of a circle:  (x - cx)^2 + (y - cy)^2 = r^2
            //
            // Eventually we get a standard quadratic equation in l with the
            // following coefficients:
            double a = dx * dx + dy * dy;
            double b = -2 * (ax * dx + ay * dy);
            double c = ax * ax + ay * ay - circle.Radius * circle.Radius;

            // Now just solve the quadratic eqn...
            double D = b * b - 4 * a * c;

            if (D < 0)
            {
                lambda1 = lambda2 = double.NaN;
            }
            else
            {
                double sqrtD = Math.Sqrt(D);
                lambda1 = (-b + sqrtD) / (2 * a);
                lambda2 = (-b - sqrtD) / (2 * a);
            }
        }
Example #2
0
        /// <summary>
        ///     Finds the points of intersection between a ray and an arc. The resulting lambdas along the ray are sorted in
        ///     ascending order, so the "first" intersection is always in lambda1 (if any). Lambda may be NaN if there is no
        ///     intersection (or no "second" intersection).</summary>
        public static void RayWithArc(ref EdgeD ray, ref ArcD arc,
                                      out double lambda1, out double lambda2)
        {
            RayWithCircle(ref ray, ref arc.Circle, out lambda1, out lambda2);
            var sweepdir = Math.Sign(arc.AngleSweep);

            if (!double.IsNaN(lambda1))
            {
                var dir = ((ray.Start + lambda1 * (ray.End - ray.Start)) - arc.Circle.Center).Theta();
                if (!(GeomUt.AngleDifference(arc.AngleStart, dir) * sweepdir > 0 && GeomUt.AngleDifference(arc.AngleStart + arc.AngleSweep, dir) * sweepdir < 0))
                {
                    lambda1 = double.NaN;
                }
            }
            if (!double.IsNaN(lambda2))
            {
                var dir = ((ray.Start + lambda2 * (ray.End - ray.Start)) - arc.Circle.Center).Theta();
                if (!(GeomUt.AngleDifference(arc.AngleStart, dir) * sweepdir > 0 && GeomUt.AngleDifference(arc.AngleStart + arc.AngleSweep, dir) * sweepdir < 0))
                {
                    lambda2 = double.NaN;
                }
            }
            if (double.IsNaN(lambda1) && !double.IsNaN(lambda2))
            {
                lambda1 = lambda2;
                lambda2 = double.NaN;
            }
        }
Example #3
0
        /// <summary>
        ///     Checks for intersections between a ray and a bounding box. Returns true if there is at least one intersection.</summary>
        public static bool RayWithBoundingBox(ref EdgeD ray, ref BoundingBoxD box)
        {
            double dx = ray.End.X - ray.Start.X;
            double dy = ray.End.Y - ray.Start.Y;
            double k, c;  // temporaries

            // Check intersection with horizontal bounds
            if (dy != 0)
            {
                // Upper line
                k = (box.Ymax - ray.Start.Y) / dy;
                if (k >= 0)
                {
                    c = ray.Start.X + k * dx;
                    if (c >= box.Xmin && c <= box.Xmax)
                    {
                        return(true);
                    }
                }
                // Lower line
                k = (box.Ymin - ray.Start.Y) / dy;
                if (k >= 0)
                {
                    c = ray.Start.X + k * dx;
                    if (c >= box.Xmin && c <= box.Xmax)
                    {
                        return(true);
                    }
                }
            }
            // Check intersection with vertical bounds
            if (dx != 0)
            {
                // Rightmost line
                k = (box.Xmax - ray.Start.X) / dx;
                if (k >= 0)
                {
                    c = ray.Start.Y + k * dy;
                    if (c >= box.Ymin && c <= box.Ymax)
                    {
                        return(true);
                    }
                }
                // Leftmost line
                k = (box.Xmin - ray.Start.X) / dx;
                if (k >= 0)
                {
                    c = ray.Start.Y + k * dy;
                    if (c >= box.Ymin && c <= box.Ymax)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Example #4
0
        /// <summary>
        ///     Calculates the intersection of a ray with a segment. Returns the result as the lambdas of the intersection
        ///     point along the ray and the segment. If there is no intersection returns double.NaN in both lambdas.</summary>
        public static void RayWithSegment(ref EdgeD ray, ref EdgeD segment, out double rayL, out double segmentL)
        {
            Intersect.LineWithLine(ref ray, ref segment, out rayL, out segmentL);

            if (!double.IsNaN(rayL) && ((rayL < 0) || (segmentL < 0) || (segmentL > 1)))
            {
                rayL = segmentL = double.NaN;
            }
        }
Example #5
0
        private void AssertRayWithCircle(double frX, double frY, double toX, double toY, double cX, double cY, double cR, double expL1, double expL2)
        {
            EdgeD   ray = new EdgeD(frX, frY, toX, toY);
            CircleD cir = new CircleD(cX, cY, cR);
            double  l1, l2;

            Intersect.RayWithCircle(ref ray, ref cir, out l1, out l2);
            Assert.AreEqual(expL1, l1, 0.001);
            Assert.AreEqual(expL2, l2, 0.001);
        }
Example #6
0
        private void AssertLineWithCircle(double frX, double frY, double toX, double toY, double cX, double cY, double cR, double expL1, double expL2)
        {
            EdgeD   lin = new EdgeD(frX, frY, toX, toY);
            CircleD cir = new CircleD(cX, cY, cR);
            double  l1, l2;

            Intersect.LineWithCircle(ref lin, ref cir, out l1, out l2);
            Assert.AreEqual(MinTO(expL1, expL2), MinTO(l1, l2), 0.001);
            Assert.AreEqual(MaxTO(expL1, expL2), MaxTO(l1, l2), 0.001);
        }
Example #7
0
        /// <summary>
        ///     Finds intersections between a ray and a rectangle. Returns the lambdas of intersections, if any, or NaN
        ///     otherwise. Guarantees that lambda1 &lt; lambda2, and if only one of them is NaN then it's lambda2. Lambda is
        ///     such that ray.Start + lambda * (ray.End - ray.Start) gives the point of intersection.</summary>
        public static void RayWithRectangle(ref EdgeD ray, ref RectangleD rect, out double lambda1, out double lambda2)
        {
            double lambda, dummy;
            bool   done1 = false;

            lambda1 = lambda2 = double.NaN;

            for (int i = 0; i < 4; i++)
            {
                EdgeD segment;
                switch (i)
                {
                case 0: segment = new EdgeD(rect.Left, rect.Top, rect.Right, rect.Top); break;

                case 1: segment = new EdgeD(rect.Right, rect.Top, rect.Right, rect.Bottom); break;

                case 2: segment = new EdgeD(rect.Right, rect.Bottom, rect.Left, rect.Bottom); break;

                case 3: segment = new EdgeD(rect.Left, rect.Bottom, rect.Left, rect.Top); break;

                default: throw new InternalErrorException("fsvxhfhj");     // unreachable
                }

                Intersect.RayWithSegment(ref ray, ref segment, out lambda, out dummy);

                if (!double.IsNaN(lambda))
                {
                    if (!done1)
                    {
                        lambda1 = lambda;
                        done1   = true;
                    }
                    else if (lambda != lambda1)
                    {
                        if (lambda > lambda1)
                        {
                            lambda2 = lambda;
                        }
                        else
                        {
                            lambda2 = lambda1;
                            lambda1 = lambda;
                        }
                        return;
                    }
                }
            }
        }
Example #8
0
        /// <summary>
        ///     Finds the point of intersection of two lines. The result is in terms of lambda along each of the lines. Point
        ///     of intersection is defined as "line.Start + lambda * line", for each line. If the lines don't intersect, the
        ///     lambdas are set to NaN.</summary>
        public static void LineWithLine(ref EdgeD line1, ref EdgeD line2, out double line1Lambda, out double line2Lambda)
        {
            // line1 direction vector
            double l1dx = line1.End.X - line1.Start.X;
            double l1dy = line1.End.Y - line1.Start.Y;
            // line2 direction vector
            double l2dx = line2.End.X - line2.Start.X;
            double l2dy = line2.End.Y - line2.Start.Y;

            double denom = l1dx * l2dy - l1dy * l2dx;

            if (denom == 0)
            {
                line1Lambda = double.NaN;
                line2Lambda = double.NaN;
            }
            else
            {
                line1Lambda = (l2dx * (line1.Start.Y - line2.Start.Y) - l2dy * (line1.Start.X - line2.Start.X)) / denom;
                line2Lambda = (l1dx * (line1.Start.Y - line2.Start.Y) - l1dy * (line1.Start.X - line2.Start.X)) / denom;
            }
        }
Example #9
0
        /// <summary>
        ///     Finds the points of intersection between a ray and a circle. The resulting lambdas along the ray are sorted in
        ///     ascending order, so the "first" intersection is always in lambda1 (if any). Lambda may be NaN if there is no
        ///     intersection (or no "second" intersection).</summary>
        public static void RayWithCircle(ref EdgeD ray, ref CircleD circle,
                                         out double lambda1, out double lambda2)
        {
            LineWithCircle(ref ray, ref circle, out lambda1, out lambda2);

            // Sort the two values in ascending order, with NaN last,
            // while resetting negative values to NaNs
            if (lambda1 < 0)
            {
                lambda1 = double.NaN;
            }
            if (lambda2 < 0)
            {
                lambda2 = double.NaN;
            }
            if (lambda1 > lambda2 || double.IsNaN(lambda1))
            {
                double temp = lambda1;
                lambda1 = lambda2;
                lambda2 = temp;
            }
        }
Example #10
0
 /// <summary>
 ///     Finds the point of intersection of two lines. If the lines don't intersect, the resulting point coordinates
 ///     are NaN.</summary>
 public static PointD LineWithLine(EdgeD line1, EdgeD line2)
 {
     LineWithLine(ref line1, ref line2, out var line1Lambda, out var line2Lambda);
     return(line1.Start + line1Lambda * (line1.End - line1.Start));
 }
Example #11
0
 /// <summary>
 ///     Finds the points of intersection between a line and a circle. The results are two lambdas along the line, one
 ///     for each point, or NaN if there is no intersection.</summary>
 public static void LineWithCircle(EdgeD line, CircleD circle,
                                   out double lambda1, out double lambda2)
 {
     LineWithCircle(ref line, ref circle, out lambda1, out lambda2);
 }
Example #12
0
 /// <summary>Returns true if this bounding box intersects with the specified ray.</summary>
 public bool IntersectsWithRay(EdgeD ray)
 {
     return(Intersect.RayWithBoundingBox(ref ray, ref this));
 }
Example #13
0
 /// <summary>Returns a new BoundingBox bounding the specified edge.</summary>
 public static BoundingBoxD FromEdge(EdgeD edge)
 {
     return(FromPoint(ref edge.Start, ref edge.End));
 }
Example #14
0
 /// <summary>
 ///     Returns a value indicating whether one of the triangle edges is equal to <paramref name="e"/>. Edge equality
 ///     is direction-insensitive.</summary>
 public bool HasEdge(EdgeD e) => e == Edge12 || e == Edge23 || e == Edge31;