Beispiel #1
0
        public static float Intersect(Rect rect, LocalSegment3 segment)
        {
            Vector3 closestPointOnSegment_unused, closestPointOnRect_unused;

            return(Intersect(rect, segment,
                             out closestPointOnRect_unused, out closestPointOnSegment_unused));
        }
Beispiel #2
0
        // https://stackoverflow.com/a/18543221 for line-plane intersection.

        /// <summary>
        /// Returns true if the line segment intersects with the plane, or false otherwise.
        ///
        /// Specify output parameters to receive more detailed information about the
        /// intersection, such as the point at which it occurs and whether the line lies on
        /// the plane.
        /// </summary>
        public static bool Intersect(LocalPlane plane, LocalSegment3 line)
        {
            Vector3 pointOnPlane_unused;
            float   amountAlongSegment_unused;
            bool    isLineCoplanar_unused;

            return(Intersect(plane, line,
                             out pointOnPlane_unused,
                             out amountAlongSegment_unused,
                             out isLineCoplanar_unused));
        }
Beispiel #3
0
        /// <summary>
        /// Returns true if the line segment intersects with the plane, or false otherwise.
        ///
        /// If intersectInfiniteLine is specified, returns true if the line defined by the
        /// line segment intersects with the plane, or false otherwise.
        ///
        /// If this method returns true, no out parameters are set to NaN, and reasonable
        /// defaults are chosen in edge-cases (such as a coplanar line). If this method
        /// returns false, some or all output parameters may have no reasonable value and
        /// are set to NaN.
        ///
        /// pointOnPlane is the point along the line defined by the segment that intersects
        /// with the plane. If the line segment is parallel to the plane and _on_ the plane,
        /// pointOnPlane will be set to the center of the line segment as a convenience.
        /// Otherwise, it will be set to a Vector3 containing all NaNs.
        ///
        /// amountAlongSegment is the normalized amount from A to B along the line segment
        /// that intersects with the plane. The line segment intersects with the plane only
        /// if this value is between 0 and 1 (inclusive). If the line segment is parallel to
        /// the plane and _on_ the plane, amountAlongSegment will be set to 0.5f. Otherwise,
        /// amountAlongSegment will be set to NaN.
        ///
        /// isLineCoplanar is true if the line defined by the line segment is wholly on
        /// the plane, or false otherwise.
        /// </summary>
        public static bool Intersect(LocalPlane plane, LocalSegment3 line,
                                     out Vector3 pointOnPlane,
                                     out float amountAlongSegment,
                                     out bool isLineCoplanar,
                                     bool intersectInfiniteLine = false)
        {
            var planePosition = plane.position;
            var planeNormal   = plane.normal;

            var a = line.a;
            var b = line.b;

            var u     = b - a;
            var uDotN = planeNormal.Dot(u);

            if (uDotN.Abs() > float.Epsilon)
            {
                isLineCoplanar = false;

                var w = a - planePosition;
                amountAlongSegment = -(planeNormal.Dot(w)) / uDotN;
                pointOnPlane       = a + u * amountAlongSegment;

                return(intersectInfiniteLine ||
                       (amountAlongSegment >= 0f && amountAlongSegment <= 1f));
            }
            else
            {
                var pa = a - planePosition;
                if (planeNormal.Dot(pa).Abs() < float.Epsilon)
                {
                    isLineCoplanar = true;
                }
                else
                {
                    isLineCoplanar = false;
                }

                if (isLineCoplanar)
                {
                    pointOnPlane       = (a + b) / 2f;
                    amountAlongSegment = 0.5f;
                    return(true);
                }
                else
                {
                    pointOnPlane       = new Vector3(float.NaN, float.NaN, float.NaN);
                    amountAlongSegment = float.NaN;
                    return(false);
                }
            }
        }
Beispiel #4
0
        // 2D intersection:
        // https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
        // https://ideone.com/PnPJgb

        /// <summary>
        /// Returns true if the two segments are not parallel or colinear and intersect in 2D,
        /// ignoring the segments' Z components.
        /// </summary>
        public static bool Intersect2D(LocalSegment3 segment0, LocalSegment3 segment1,
                                       out Vector2 intersectionPoint,
                                       out float amountAlongSegment0,
                                       out float amountAlongSegment1)
        {
            Vector2 p = segment0.a, q = segment0.b, r = segment1.a, s = segment1.b;

            // t = (q − p) × s / (r × s)
            // u = (q − p) × r / (r × s)

            var denom = Fake2DCross(r, s);

            if (denom == 0)
            {
                // Lines are collinear or parallel.
                amountAlongSegment0 = float.NaN;
                amountAlongSegment1 = float.NaN;
                intersectionPoint   = new Vector2(float.NaN, float.NaN);
                return(false);
            }

            var tNumer = Fake2DCross(q - p, s);
            var uNumer = Fake2DCross(q - p, r);

            amountAlongSegment0 = tNumer / denom;
            amountAlongSegment1 = uNumer / denom;

            if (amountAlongSegment0 < 0 || amountAlongSegment0 > 1 ||
                amountAlongSegment1 < 0 || amountAlongSegment1 > 1)
            {
                // Line segments do not intersect within their ranges.
                intersectionPoint = default(Vector2);
                return(false);
            }

            intersectionPoint = p + r * amountAlongSegment0;
            return(true);
        }
Beispiel #5
0
 /// <summary>
 /// Returns the closest point to point p on the segment. Also outputs the
 /// parameterization from 0 to 1 along ab that results in the closest point:
 /// closestPt(t) = a + t*(b - a).
 /// </summary>
 public static Vector3 ClosestPtPointSegment(LocalSegment3 segment, Vector3 p,
                                             out float t)
 {
     return(ClosestPtPointSegment(segment.a, segment.b, p, out t));
 }
Beispiel #6
0
        /// <summary>
        /// Returns the closest point to point p on the segment.
        /// </summary>
        public static Vector3 ClosestPtPointSegment(LocalSegment3 segment, Vector3 p)
        {
            float unusedT;

            return(ClosestPtPointSegment(segment.a, segment.b, p, out unusedT));
        }
Beispiel #7
0
 /// <summary>
 /// Returns the squared-distance of the point p from the segment.
 /// </summary>
 public static float SqrDistPointSegment(LocalSegment3 segment, Vector3 p)
 {
     return(SqrDistPointSegment(segment.a, segment.b, p));
 }
Beispiel #8
0
        /// <summary>
        /// Computes the squared distance between two 3D line segments, outputting the amount
        /// along each segment (0 to 1) corresponding to the closest points (t1 and t2), and
        /// outputting the closest points themselves (c1 and c2).
        /// </summary>
        public static float Intersect(LocalSegment3 seg1, LocalSegment3 seg2,
                                      out float t1, out float t2,
                                      out Vector3 c1, out Vector3 c2)
        {
            Vector3 d1 = seg1.b - seg1.a; // Direction vector of seg1.
            Vector3 d2 = seg2.b - seg2.a; // Direction vector of seg2.
            Vector3 r  = seg1.a - seg2.a;
            float   a  = Dot(d1, d1);     // Squared length of seg1.
            float   e  = Dot(d2, d2);     // Squared length of seg2.
            float   f  = Dot(d2, r);

            // Check if either or both segments degenerate into points.
            if (a <= float.Epsilon && e <= float.Epsilon)
            {
                // Both segments degenerate into points.
                t1 = t2 = 0f;
                c1 = seg1.a; c2 = seg2.a;
                return(Dot(c1 - c2, c1 - c2));
            }
            if (a <= float.Epsilon)
            {
                // First segment degenerates into a point.
                t1 = 0f;
                t2 = (f / e).Clamped01();
            }
            else
            {
                float c = Dot(d1, r);
                if (e <= float.Epsilon)
                {
                    // Second segment degenerates into a point.
                    t2 = 0f;
                    t1 = (-c / a).Clamped01();
                }
                else
                {
                    // General, non-degenerate case.
                    float b     = Dot(d1, d2);
                    float denom = a * e - b * b; // Always non-negative.

                    // If the segments are not parallel, compute the closest point on seg1 to seg2
                    // and clamp to seg1. Otherwise, pick an arbitrary t1 (here 0).
                    if (denom != 0f)
                    {
                        t1 = ((b * f - c * e) / denom).Clamped01();
                    }
                    else
                    {
                        t1 = 0f;
                    }
                    // Compute the point on seg2 closest to t1.
                    float t2nom = b * t1 + f; // avoid dividing e until later.

                    // If t2 in [0, 1], we're done. Otherwise, recompute t1 for the new value of
                    // t2 and clamp to [0, 1].
                    if (t2nom < 0f)
                    {
                        t2 = 0f;
                        t1 = (-c / a).Clamped01();
                    }
                    else if (t2nom > e)
                    {
                        t2 = 1f;
                        t1 = ((b - c) / a).Clamped01();
                    }
                    else
                    {
                        t2 = t2nom / e;
                    }
                }
            }

            c1 = seg1.a + d1 * t1;
            c2 = seg2.a + d2 * t2;
            return((c1 - c2).sqrMagnitude);
        }
Beispiel #9
0
        public static float Intersect(Rect rect, LocalSegment3 segment,
                                      out Vector3 closestPointOnRect,
                                      out Vector3 closestPointOnSegment)
        {
            float closestSqrDist = float.PositiveInfinity;

            closestPointOnRect = closestPointOnSegment = default(Vector3);

            Vector3 segmentA_rect;
            bool    aProjectsInside = rect.ContainsProjectedPoint(segment.a, out segmentA_rect);
            Vector3 segmentB_rect;
            bool    bProjectsInside = rect.ContainsProjectedPoint(segment.b, out segmentB_rect);

            // Test if the segment intersects with the rect plane and is inside the rect.
            var     plane_rect = rect.ToLocalPlane();
            var     segment_rect = new LocalSegment3(segmentA_rect, segmentB_rect);
            Vector3 pointOnPlane_rect; float amountAlongSegment; bool isLineCoplanar;
            var     intersectsPlane = Intersect(plane_rect, segment_rect,
                                                out pointOnPlane_rect, out amountAlongSegment,
                                                out isLineCoplanar);

            if (intersectsPlane)
            {
                var absPointOnPlane_rect = pointOnPlane_rect.Abs();
                var absRadii             = rect.radii.Abs();
                if (absPointOnPlane_rect.x <= absRadii.x && absPointOnPlane_rect.y <= absRadii.y)
                {
                    closestPointOnRect    = rect.matrix.MultiplyPoint3x4(pointOnPlane_rect);
                    closestPointOnSegment = segment.Evaluate(amountAlongSegment);
                    return(0f);
                }
            }

            // Must test the rect segments and plane-projection distances to find the closest
            // pair of points and return their squared-distance.

            // Segment point A <> plane, when A projects inside rect.
            if (aProjectsInside)
            {
                var testPointRect = rect.matrix.MultiplyPoint3x4(segmentA_rect.WithZ(0f));
                var testSqrDist   = (testPointRect - segment.a).sqrMagnitude;
                if (testSqrDist < closestSqrDist)
                {
                    closestSqrDist        = testSqrDist;
                    closestPointOnRect    = testPointRect;
                    closestPointOnSegment = segment.a;
                }
            }

            // Segment point B <> plane, when B projects inside rect.
            if (bProjectsInside)
            {
                var testPointRect = rect.matrix.MultiplyPoint3x4(segmentB_rect.WithZ(0f));
                var testSqrDist   = (testPointRect - segment.b).sqrMagnitude;
                if (testSqrDist < closestSqrDist)
                {
                    closestSqrDist        = testSqrDist;
                    closestPointOnRect    = testPointRect;
                    closestPointOnSegment = segment.b;
                }
            }

            if (!aProjectsInside || !bProjectsInside)
            {
                // Closest point segment <> {AB, BC, CD, DA}.
                foreach (var rectSegment in rect.segments)
                {
                    Vector3 testClosestPointRectSegment;
                    Vector3 testClosestPointSegment;
                    float   unusedT1, unusedT2;
                    var     testSqrDist = Intersect(rectSegment, segment,
                                                    out unusedT1, out unusedT2,
                                                    out testClosestPointRectSegment,
                                                    out testClosestPointSegment);

                    // Debug
                    //RuntimeGizmos.RuntimeGizmoDrawer drawer;
                    //if (RuntimeGizmos.RuntimeGizmoManager.TryGetGizmoDrawer(out drawer)) {
                    //  drawer.DrawLine(testClosestPointRectSegment, testClosestPointSegment);
                    //}

                    if (testSqrDist < closestSqrDist)
                    {
                        closestSqrDist        = testSqrDist;
                        closestPointOnRect    = testClosestPointRectSegment;
                        closestPointOnSegment = testClosestPointSegment;
                    }
                }
            }

            return(closestSqrDist);
        }
Beispiel #10
0
 public static float Intersect(LocalSegment3 segment, Rect rect,
                               out Vector3 closestPointOnSegment,
                               out Vector3 closestPointOnRect)
 {
     return(Intersect(rect, segment, out closestPointOnRect, out closestPointOnSegment));
 }
Beispiel #11
0
        //[ThreadStatic]
        //private static LocalSegment3[] _rectEdgesBuffer = new LocalSegment3[4];

        public static float Intersect(LocalSegment3 segment, Rect rect)
        {
            return(Intersect(rect, segment));
        }