示例#1
0
        /// <summary>
        /// Finds, provided it exists, the intersection point with the specified <see cref="LineSegment"/>.
        /// </summary>
        ///
        /// <param name="other"><see cref="LineSegment"/> to find intersection with.</param>
        ///
        /// <returns>Returns intersection point with the specified <see cref="LineSegment"/>, or <see langword="null"/>, if
        /// the two segments do not intersect.</returns>
        ///
        /// <remarks><para>If the two segments do not intersect, the method returns <see langword="null"/>. If the two
        /// segments share multiple points, this throws an <see cref="InvalidOperationException"/>.
        /// </para></remarks>
        ///
        /// <exception cref="InvalidOperationException">Thrown if the segments overlap - if they have
        /// multiple points in common.</exception>
        ///
        public DoublePoint?GetIntersectionWith(LineSegment other)
        {
            DoublePoint?result = null;

            if ((line.Slope == other.line.Slope) || (line.IsVertical && other.line.IsVertical))
            {
                if (line.Intercept == other.line.Intercept)
                {
                    // Collinear segments. Inspect and handle.
                    // Consider this segment AB and other as CD. (start/end in both cases)
                    // There are three cases:
                    // 0 shared points: C and D both project onto the same ray of AB
                    // 1 shared point: One of A or B equals one of C or D, and the other of C/D
                    //      projects on the correct ray.
                    // Many shared points.

                    ProjectionLocation projC = LocateProjection(other.start), projD = LocateProjection(other.end);

                    if ((projC != ProjectionLocation.SegmentAB) && (projC == projD))
                    {
                        // no shared points
                        result = null;
                    }
                    else if (((start == other.start) && (projD == ProjectionLocation.RayA)) ||
                             ((start == other.end) && (projC == ProjectionLocation.RayA)))
                    {
                        // shared start point
                        result = start;
                    }
                    else if (((end == other.start) && (projD == ProjectionLocation.RayB)) ||
                             ((end == other.end) && (projC == ProjectionLocation.RayB)))
                    {
                        // shared end point
                        result = end;
                    }
                    else
                    {
                        // overlapping
                        throw new InvalidOperationException("Overlapping segments do not have a single intersection point.");
                    }
                }
            }
            else
            {
                result = GetIntersectionWith(other.line);

                if ((result.HasValue) && (other.LocateProjection(result.Value) != ProjectionLocation.SegmentAB))
                {
                    // the intersection is on the extended line of this segment
                    result = null;
                }
            }

            return(result);
        }
示例#2
0
        // Get type of point's projections to this line segment
        private ProjectionLocation LocateProjection(DoublePoint point)
        {
            // Modified from http://www.codeguru.com/forum/showthread.php?t=194400

            /*  How do I find the distance from a point to a line segment?
             *
             *  Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By).
             *  Let P be the point of perpendicular projection of C on AB.  The parameter
             *  r, which indicates P's position along AB, is computed by the dot product
             *  of AC and AB divided by the square of the length of AB:
             *
             *  (1)     AC dot AB
             *      r = ---------
             ||AB||^2
             *
             *  r has the following meaning:
             *
             *      r=0      P = A
             *      r=1      P = B
             *      r<0      P is on the backward extension of AB (and distance C-AB is distance C-A)
             *      r>1      P is on the forward extension of AB (and distance C-AB is distance C-B)
             *      0<r<1    P is interior to AB (and distance C-AB(segment) is distance C-AB(line))
             *
             *  The length of the line segment AB is computed by:
             *
             *      L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )
             *
             *  and the dot product of two 2D vectors, U dot V, is computed:
             *
             *      D = (Ux * Vx) + (Uy * Vy)
             *
             *  So (1) expands to:
             *
             *          (Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
             *      r = -------------------------------
             *               (Bx-Ax)^2 + (By-Ay)^2
             */

            // the above is modified here to compare the numerator and denominator, rather than doing the division
            DoublePoint abDelta = end - start;
            DoublePoint acDelta = point - start;

            double numerator   = acDelta.X * abDelta.X + acDelta.Y * abDelta.Y;
            double denomenator = abDelta.X * abDelta.X + abDelta.Y * abDelta.Y;

            ProjectionLocation result = (numerator < 0) ? ProjectionLocation.RayA : (numerator > denomenator) ? ProjectionLocation.RayB : ProjectionLocation.SegmentAB;

            return(result);
        }
示例#3
0
        public Point?GetIntersectionWith(LineSegment other)
        {
            Point?result = null;

            if (line.Slope == other.line.Slope || (line.IsVertical && other.line.IsVertical))
            {
                if (line.Intercept == other.line.Intercept)
                {
                    ProjectionLocation projectionLocation  = LocateProjection(other.start);
                    ProjectionLocation projectionLocation2 = LocateProjection(other.end);
                    if (projectionLocation != ProjectionLocation.SegmentAB && projectionLocation == projectionLocation2)
                    {
                        result = null;
                    }
                    else if ((start == other.start && projectionLocation2 == ProjectionLocation.RayA) || (start == other.end && projectionLocation == ProjectionLocation.RayA))
                    {
                        result = start;
                    }
                    else
                    {
                        if ((!(end == other.start) || projectionLocation2 != ProjectionLocation.RayB) && (!(end == other.end) || projectionLocation != ProjectionLocation.RayB))
                        {
                            throw new InvalidOperationException("Overlapping segments do not have a single intersection point.");
                        }
                        result = end;
                    }
                }
            }
            else
            {
                result = GetIntersectionWith(other.line);
                if (result.HasValue && other.LocateProjection(result.Value) != ProjectionLocation.SegmentAB)
                {
                    result = null;
                }
            }
            return(result);
        }