コード例 #1
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        /// <summary>
        /// Computes an intersection of the line and the ray
        /// </summary>
        public static bool LineRay(Vector2 lineOrigin, Vector2 lineDirection, Vector2 rayOrigin, Vector2 rayDirection,
                                   out IntersectionLineRay2 intersection)
        {
            Vector2 rayOriginToLineOrigin = lineOrigin - rayOrigin;
            float   denominator           = VectorE.PerpDot(lineDirection, rayDirection);
            float   perpDotA = VectorE.PerpDot(lineDirection, rayOriginToLineOrigin);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                float perpDotB = VectorE.PerpDot(rayDirection, rayOriginToLineOrigin);
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    intersection = IntersectionLineRay2.None();
                    return(false);
                }
                // Collinear
                intersection = IntersectionLineRay2.Ray(rayOrigin);
                return(true);
            }

            // Not parallel
            float rayDistance = perpDotA / denominator;

            if (rayDistance > -Geometry.Epsilon)
            {
                intersection = IntersectionLineRay2.Point(rayOrigin + rayDirection * rayDistance);
                return(true);
            }
            intersection = IntersectionLineRay2.None();
            return(false);
        }
コード例 #2
0
        /// <summary>
        /// Computes an intersection of the lines
        /// </summary>
        public static bool IntersectLineLine(Vector2 originA, Vector2 directionA, Vector2 originB, Vector2 directionB,
                                             out Vector2 intersection)
        {
            float   denominator = VectorE.PerpDot(directionA, directionB);
            Vector2 originBToA  = originA - originB;
            float   a           = VectorE.PerpDot(directionA, originBToA);
            float   b           = VectorE.PerpDot(directionB, originBToA);

            if (Mathf.Abs(denominator) < Epsilon)
            {
                // Parallel
                if (Mathf.Abs(a) > Epsilon || Mathf.Abs(b) > Epsilon)
                {
                    // Not collinear
                    intersection = Vector2.zero;
                    return(false);
                }
                // Collinear
                intersection = originA;
                return(true);
            }

            float distanceA = b / denominator;

            intersection = originA + distanceA * directionA;
            return(true);
        }
コード例 #3
0
        /// <summary>
        /// Returns the value of an angle. Assumes clockwise order of the polygon.
        /// </summary>
        /// <param name="previous">Previous vertex</param>
        /// <param name="current">Current vertex</param>
        /// <param name="next">Next vertex</param>
        public static float GetAngle(Vector2 previous, Vector2 current, Vector2 next)
        {
            Vector2 toPrevious = (previous - current).normalized;
            Vector2 toNext     = (next - current).normalized;

            return(VectorE.Angle360(toNext, toPrevious));
        }
コード例 #4
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        /// <summary>
        /// Computes an intersection of the lines
        /// </summary>
        public static bool LineLine(Vector2 originA, Vector2 directionA, Vector2 originB, Vector2 directionB,
                                    out IntersectionLineLine2 intersection)
        {
            Vector2 originBToA  = originA - originB;
            float   denominator = VectorE.PerpDot(directionA, directionB);
            float   perpDotB    = VectorE.PerpDot(directionB, originBToA);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                float perpDotA = VectorE.PerpDot(directionA, originBToA);
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    intersection = IntersectionLineLine2.None();
                    return(false);
                }
                // Collinear
                intersection = IntersectionLineLine2.Line(originA);
                return(true);
            }

            // Not parallel
            intersection = IntersectionLineLine2.Point(originA + directionA * (perpDotB / denominator));
            return(true);
        }
コード例 #5
0
        /// <summary>
        /// Finds closest points on the lines
        /// </summary>
        public static void ClosestPointsOnLines(Vector2 originA, Vector2 directionA, Vector2 originB, Vector2 directionB,
                                                out Vector2 pointA, out Vector2 pointB)
        {
            Vector2 originBToA  = originA - originB;
            float   denominator = VectorE.PerpDot(directionA, directionB);
            float   perpDotB    = VectorE.PerpDot(directionB, originBToA);

            if (Mathf.Abs(denominator) < Epsilon)
            {
                // Parallel
                if (Mathf.Abs(perpDotB) > Epsilon ||
                    Mathf.Abs(VectorE.PerpDot(directionA, originBToA)) > Epsilon)
                {
                    // Not collinear
                    pointA = originA;
                    pointB = originB + directionB * Vector2.Dot(directionB, originBToA);
                    return;
                }

                // Collinear
                pointA = pointB = originA;
                return;
            }

            // Not parallel
            pointA = pointB = originA + directionA * (perpDotB / denominator);
        }
コード例 #6
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        /// <summary>
        /// Tests if the point lies on the segment
        /// </summary>
        /// <param name="side">
        /// -1 if the point is to the left of the segment,
        /// 0 if it is on the line,
        /// 1 if it is to the right of the segment
        /// </param>
        public static bool PointSegment(Vector2 point, Vector2 segmentA, Vector2 segmentB, out int side)
        {
            Vector2 fromAToB         = segmentB - segmentA;
            float   sqrSegmentLength = fromAToB.sqrMagnitude;

            if (sqrSegmentLength < Geometry.Epsilon)
            {
                // The segment is a point
                side = 0;
                return(point == segmentA);
            }
            // Normalized direction gives more stable results
            Vector2 segmentDirection = fromAToB.normalized;
            Vector2 toPoint          = point - segmentA;
            float   perpDot          = VectorE.PerpDot(toPoint, segmentDirection);

            if (perpDot < -Geometry.Epsilon)
            {
                side = -1;
                return(false);
            }
            if (perpDot > Geometry.Epsilon)
            {
                side = 1;
                return(false);
            }
            side = 0;
            float pointProjection = Vector2.Dot(segmentDirection, toPoint);

            return(pointProjection > -Geometry.Epsilon &&
                   pointProjection < Mathf.Sqrt(sqrSegmentLength) + Geometry.Epsilon);
        }
コード例 #7
0
        /// <summary>
        /// Returns the distance between the closest points on the line and the ray
        /// </summary>
        public static float LineRay(Vector2 lineOrigin, Vector2 lineDirection, Vector2 rayOrigin, Vector2 rayDirection)
        {
            Vector2 rayOriginToLineOrigin = lineOrigin - rayOrigin;
            float   denominator           = VectorE.PerpDot(lineDirection, rayDirection);
            float   perpDotA = VectorE.PerpDot(lineDirection, rayOriginToLineOrigin);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                float perpDotB = VectorE.PerpDot(rayDirection, rayOriginToLineOrigin);
                // Parallel
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    float dotA        = Vector2.Dot(lineDirection, rayOriginToLineOrigin);
                    float distanceSqr = rayOriginToLineOrigin.sqrMagnitude - dotA * dotA;
                    return(Mathf.Sqrt(distanceSqr));
                }
                // Collinear
                return(0);
            }

            // Not parallel
            float rayDistance = perpDotA / denominator;

            if (rayDistance < -Geometry.Epsilon)
            {
                // No intersection
                Vector2 linepoint = lineOrigin - lineDirection * Vector2.Dot(lineDirection, rayOriginToLineOrigin);
                return(Vector2.Distance(rayOrigin, linepoint));
            }
            // Point intersection
            return(0);
        }
コード例 #8
0
        /// <summary>
        /// Returns the distance between the closest points on the line and the ray
        /// </summary>
        public static float LineRay(Vector2 lineOrigin, Vector2 lineDirection, Vector2 rayOrigin, Vector2 rayDirection)
        {
            Vector2 rayOriginToLineOrigin = lineOrigin - rayOrigin;
            float   denominator           = VectorE.PerpDot(lineDirection, rayDirection);
            float   perpDotA = VectorE.PerpDot(lineDirection, rayOriginToLineOrigin);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                float perpDotB = VectorE.PerpDot(rayDirection, rayOriginToLineOrigin);
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    float rayOriginProjection = Vector2.Dot(lineDirection, rayOriginToLineOrigin);
                    float distanceSqr         = rayOriginToLineOrigin.sqrMagnitude - rayOriginProjection * rayOriginProjection;
                    // distanceSqr can be negative
                    return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                }
                // Collinear
                return(0);
            }

            // Not parallel
            float rayDistance = perpDotA / denominator;

            if (rayDistance < -Geometry.Epsilon)
            {
                // No intersection
                float   rayOriginProjection = Vector2.Dot(lineDirection, rayOriginToLineOrigin);
                Vector2 linePoint           = lineOrigin - lineDirection * rayOriginProjection;
                return(Vector2.Distance(linePoint, rayOrigin));
            }
            // Point intersection
            return(0);
        }
コード例 #9
0
        /// <summary>
        /// Computes an intersection of the lines
        /// </summary>
        public static IntersectionType LineLine(Vector2 originA, Vector2 directionA, Vector2 originB, Vector2 directionB,
                                                out float distanceA, out float distanceB)
        {
            Vector2 originBToA  = originA - originB;
            float   denominator = VectorE.PerpDot(directionA, directionB);
            float   perpDotA    = VectorE.PerpDot(directionA, originBToA);
            float   perpDotB    = VectorE.PerpDot(directionB, originBToA);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    distanceA = 0;
                    distanceB = 0;
                    return(IntersectionType.None);
                }
                // Collinear
                distanceA = 0;
                distanceB = 0;
                return(IntersectionType.Line);
            }

            // Not parallel
            distanceA = perpDotB / denominator;
            distanceB = perpDotA / denominator;
            return(IntersectionType.Point);
        }
コード例 #10
0
        /// <summary>
        /// Computes an intersection of the lines
        /// </summary>
        public static bool IntersectLineLine(Vector2 originA, Vector2 directionA, Vector2 originB, Vector2 directionB,
                                             out IntersectionLineLine2 intersection)
        {
            intersection = new IntersectionLineLine2();
            Vector2 originBToA  = originA - originB;
            float   denominator = VectorE.PerpDot(directionA, directionB);
            float   perpDotB    = VectorE.PerpDot(directionB, originBToA);

            if (Mathf.Abs(denominator) < Epsilon)
            {
                // Parallel
                float perpDotA = VectorE.PerpDot(directionA, originBToA);
                if (Mathf.Abs(perpDotA) > Epsilon || Mathf.Abs(perpDotB) > Epsilon)
                {
                    // Not collinear
                    intersection.type = IntersectionType.None;
                    return(false);
                }
                // Collinear
                intersection.type  = IntersectionType.Line;
                intersection.point = originA;
                return(true);
            }

            // Not parallel
            intersection.type  = IntersectionType.Point;
            intersection.point = originA + directionA * (perpDotB / denominator);
            return(true);
        }
コード例 #11
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        /// <summary>
        /// Tests if the point lies on the ray
        /// </summary>
        public static bool PointRay(Vector2 point, Vector2 rayOrigin, Vector2 rayDirection)
        {
            Vector2 toPoint = point - rayOrigin;
            float   perpDot = VectorE.PerpDot(toPoint, rayDirection);

            return(-Geometry.Epsilon < perpDot && perpDot < Geometry.Epsilon &&
                   Vector2.Dot(rayDirection, toPoint) > -Geometry.Epsilon);
        }
コード例 #12
0
        /// <summary>
        /// Tests if the point lies on the ray
        /// </summary>
        public static bool IntersectPointRay(Vector2 point, Vector2 origin, Vector2 direction)
        {
            Vector2 toPoint = point - origin;
            float   perpDot = VectorE.PerpDot(toPoint, direction);

            return(-Epsilon < perpDot && perpDot < Epsilon &&
                   Vector2.Dot(toPoint, direction) > -Epsilon);
        }
コード例 #13
0
        /// <summary>
        /// Returns the bisector of an angle. Assumes clockwise order of the polygon.
        /// </summary>
        /// <param name="previous">Previous vertex</param>
        /// <param name="current">Current vertex</param>
        /// <param name="next">Next vertex</param>
        /// <param name="degrees">Value of the angle in degrees. Always positive.</param>
        public static Vector2 GetAngleBisector(Vector2 previous, Vector2 current, Vector2 next, out float degrees)
        {
            Vector2 toPrevious = (previous - current).normalized;
            Vector2 toNext     = (next - current).normalized;

            degrees = VectorE.Angle360(toNext, toPrevious);
            Assert.IsFalse(float.IsNaN(degrees));
            return(toNext.RotateCW(degrees / 2));
        }
コード例 #14
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        /// <summary>
        /// Computes an intersection of the line and the segment
        /// </summary>
        public static bool LineSegment(Vector2 lineOrigin, Vector2 lineDirection, Vector2 segmentA, Vector2 segmentB,
                                       out IntersectionLineSegment2 intersection)
        {
            Vector2 segmentAToOrigin = lineOrigin - segmentA;
            Vector2 segmentDirection = segmentB - segmentA;
            float   denominator      = VectorE.PerpDot(lineDirection, segmentDirection);
            float   perpDotA         = VectorE.PerpDot(lineDirection, segmentAToOrigin);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                // Normalized direction gives more stable results
                float perpDotB = VectorE.PerpDot(segmentDirection.normalized, segmentAToOrigin);
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    intersection = IntersectionLineSegment2.None();
                    return(false);
                }
                // Collinear
                bool segmentIsAPoint = segmentDirection.sqrMagnitude < Geometry.Epsilon;
                if (segmentIsAPoint)
                {
                    intersection = IntersectionLineSegment2.Point(segmentA);
                    return(true);
                }

                bool codirected = Vector2.Dot(lineDirection, segmentDirection) > 0;
                if (codirected)
                {
                    intersection = IntersectionLineSegment2.Segment(segmentA, segmentB);
                }
                else
                {
                    intersection = IntersectionLineSegment2.Segment(segmentB, segmentA);
                }
                return(true);
            }

            // Not parallel
            float segmentDistance = perpDotA / denominator;

            if (segmentDistance > -Geometry.Epsilon && segmentDistance < 1 + Geometry.Epsilon)
            {
                intersection = IntersectionLineSegment2.Point(segmentA + segmentDirection * segmentDistance);
                return(true);
            }
            intersection = IntersectionLineSegment2.None();
            return(false);
        }
コード例 #15
0
        /// <summary>
        /// Tests if the point lies on the segment
        /// </summary>
        public static bool IntersectPointSegment(Vector2 point, Vector2 segmentA, Vector2 segmentB)
        {
            Vector2 direction = segmentB - segmentA;
            Vector2 toPoint   = point - segmentA;
            float   perpDot   = VectorE.PerpDot(toPoint, direction);

            if (-Epsilon < perpDot && perpDot < Epsilon)
            {
                float dotToPoint = Vector2.Dot(toPoint, direction);
                return(dotToPoint > -Epsilon &&
                       dotToPoint < Vector2.Dot(direction, direction) + Epsilon);
            }
            return(false);
        }
コード例 #16
0
        /// <summary>
        /// Tests if the point lies on the segment
        /// </summary>
        public static bool PointSegment(Vector2 point, Vector2 segmentA, Vector2 segmentB)
        {
            Vector2 segmentDirection = segmentB - segmentA;
            Vector2 toPoint          = point - segmentA;
            float   perpDot          = VectorE.PerpDot(toPoint, segmentDirection);

            if (-Geometry.Epsilon < perpDot && perpDot < Geometry.Epsilon)
            {
                float dotToPoint = Vector2.Dot(segmentDirection, toPoint);
                return(dotToPoint > -Geometry.Epsilon &&
                       dotToPoint < segmentDirection.sqrMagnitude + Geometry.Epsilon);
            }
            return(false);
        }
コード例 #17
0
        /// <summary>
        /// Calculates the signed area of the input polygon.
        /// </summary>
        /// <param name="polygon">Vertices of the polygon.</param>
        public static float GetSignedArea(IList <Vector2> polygon)
        {
            if (polygon.Count < 3)
            {
                return(0);
            }
            float a = 0;

            for (int i = 0; i < polygon.Count; i++)
            {
                a += VectorE.PerpDot(polygon.GetLooped(i - 1), polygon[i]);
            }
            return(a / 2);
        }
コード例 #18
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        private static bool PointSegment(Vector2 point, Vector2 segmentA, Vector2 segmentDirection, float sqrSegmentLength)
        {
            float segmentLength = Mathf.Sqrt(sqrSegmentLength);

            segmentDirection /= segmentLength;
            Vector2 toPoint = point - segmentA;
            float   perpDot = VectorE.PerpDot(toPoint, segmentDirection);

            if (-Geometry.Epsilon < perpDot && perpDot < Geometry.Epsilon)
            {
                float pointProjection = Vector2.Dot(segmentDirection, toPoint);
                return(pointProjection > -Geometry.Epsilon &&
                       pointProjection < segmentLength + Geometry.Epsilon);
            }
            return(false);
        }
コード例 #19
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        /// <summary>
        /// Tests if the point lies on the line
        /// </summary>
        /// <param name="side">
        /// -1 if the point is to the left of the line,
        /// 0 if it is on the line,
        /// 1 if it is to the right of the line
        /// </param>
        public static bool PointLine(Vector2 point, Vector2 lineOrigin, Vector2 lineDirection, out int side)
        {
            float perpDot = VectorE.PerpDot(point - lineOrigin, lineDirection);

            if (perpDot < -Geometry.Epsilon)
            {
                side = -1;
                return(false);
            }
            if (perpDot > Geometry.Epsilon)
            {
                side = 1;
                return(false);
            }
            side = 0;
            return(true);
        }
コード例 #20
0
        /// <summary>
        /// Tests if the point lies on the line
        /// </summary>
        /// <param name="side">
        /// -1 if the point is to the left of the line,
        /// 0 if it is on the line,
        /// 1 if it is to the right of the line
        /// </param>
        public static bool IntersectPointLine(Vector2 point, Vector2 origin, Vector2 direction, out int side)
        {
            float perpDot = VectorE.PerpDot(point - origin, direction);

            if (perpDot < -Epsilon)
            {
                side = -1;
                return(false);
            }
            if (perpDot > Epsilon)
            {
                side = 1;
                return(false);
            }
            side = 0;
            return(true);
        }
コード例 #21
0
ファイル: Intersect2D.cs プロジェクト: Elizafur/FPS-Transfer
        /// <summary>
        /// Tests if the point lies on the ray
        /// </summary>
        /// <param name="side">
        /// -1 if the point is to the left of the ray,
        /// 0 if it is on the line,
        /// 1 if it is to the right of the ray
        /// </param>
        public static bool PointRay(Vector2 point, Vector2 rayOrigin, Vector2 rayDirection, out int side)
        {
            Vector2 toPoint = point - rayOrigin;
            float   perpDot = VectorE.PerpDot(toPoint, rayDirection);

            if (perpDot < -Geometry.Epsilon)
            {
                side = -1;
                return(false);
            }
            if (perpDot > Geometry.Epsilon)
            {
                side = 1;
                return(false);
            }
            side = 0;
            return(Vector2.Dot(rayDirection, toPoint) > -Geometry.Epsilon);
        }
コード例 #22
0
        /// <summary>
        /// Tests if the point lies on the ray
        /// </summary>
        /// <param name="side">
        /// -1 if the point is to the left of the ray,
        /// 0 if it is on the line,
        /// 1 if it is to the right of the ray
        /// </param>
        public static bool IntersectPointRay(Vector2 point, Vector2 origin, Vector2 direction, out int side)
        {
            Vector2 toPoint = point - origin;
            float   perpDot = VectorE.PerpDot(toPoint, direction);

            if (perpDot < -Epsilon)
            {
                side = -1;
                return(false);
            }
            if (perpDot > Epsilon)
            {
                side = 1;
                return(false);
            }
            side = 0;
            return(Vector2.Dot(toPoint, direction) > -Epsilon);
        }
コード例 #23
0
        /// <summary>
        /// Tests if the point lies on the segment
        /// </summary>
        /// <param name="side">
        /// -1 if the point is to the left of the segment,
        /// 0 if it is on the line,
        /// 1 if it is to the right of the segment
        /// </param>
        public static bool PointSegment(Vector2 point, Vector2 segmentA, Vector2 segmentB, out int side)
        {
            Vector2 segmentDirection = segmentB - segmentA;
            Vector2 toPoint          = point - segmentA;
            float   perpDot          = VectorE.PerpDot(toPoint, segmentDirection);

            if (perpDot < -Geometry.Epsilon)
            {
                side = -1;
                return(false);
            }
            if (perpDot > Geometry.Epsilon)
            {
                side = 1;
                return(false);
            }
            side = 0;
            float dotToPoint = Vector2.Dot(segmentDirection, toPoint);

            return(dotToPoint > -Geometry.Epsilon &&
                   dotToPoint < segmentDirection.sqrMagnitude + Geometry.Epsilon);
        }
コード例 #24
0
        /// <summary>
        /// Tests if the point lies on the segment
        /// </summary>
        /// <param name="side">
        /// -1 if the point is to the left of the segment,
        /// 0 if it is on the line,
        /// 1 if it is to the right of the segment
        /// </param>
        public static bool IntersectPointSegment(Vector2 point, Vector2 segmentA, Vector2 segmentB, out int side)
        {
            Vector2 direction = segmentB - segmentA;
            Vector2 toPoint   = point - segmentA;
            float   perpDot   = VectorE.PerpDot(toPoint, direction);

            if (perpDot < -Epsilon)
            {
                side = -1;
                return(false);
            }
            if (perpDot > Epsilon)
            {
                side = 1;
                return(false);
            }
            side = 0;
            float dotToPoint = Vector2.Dot(toPoint, direction);

            return(dotToPoint > -Epsilon &&
                   dotToPoint < Vector2.Dot(direction, direction) + Epsilon);
        }
コード例 #25
0
        /// <summary>
        /// Returns the distance between the closest points on the lines defined by origin and direction
        /// </summary>
        public static float DistanceToLine(Vector2 originA, Vector2 directionA, Vector2 originB, Vector2 directionB)
        {
            if (Mathf.Abs(VectorE.PerpDot(directionA, directionB)) < Epsilon)
            {
                // Parallel
                Vector2 originBToA = originA - originB;
                if (Mathf.Abs(VectorE.PerpDot(directionA, originBToA)) > Epsilon ||
                    Mathf.Abs(VectorE.PerpDot(directionB, originBToA)) > Epsilon)
                {
                    // Not collinear
                    float dotA        = Vector2.Dot(directionA, originBToA);
                    float distanceSqr = originBToA.sqrMagnitude - dotA * dotA;
                    return(distanceSqr < 0 ? 0 : Mathf.Sqrt(distanceSqr));
                }

                // Collinear
                return(0);
            }

            // Not parallel
            return(0);
        }
コード例 #26
0
        /// <summary>
        /// Returns the distance between the closest points on the line and the segment
        /// </summary>
        public static float LineSegment(Vector2 lineOrigin, Vector2 lineDirection, Vector2 segmentA, Vector2 segmentB)
        {
            Vector2 segmentAToOrigin = lineOrigin - segmentA;
            Vector2 segmentDirection = segmentB - segmentA;
            float   denominator      = VectorE.PerpDot(lineDirection, segmentDirection);
            float   perpDotA         = VectorE.PerpDot(lineDirection, segmentAToOrigin);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                // Normalized direction gives more stable results
                float perpDotB = VectorE.PerpDot(segmentDirection.normalized, segmentAToOrigin);
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    float segmentAProjection = Vector2.Dot(lineDirection, segmentAToOrigin);
                    float distanceSqr        = segmentAToOrigin.sqrMagnitude - segmentAProjection * segmentAProjection;
                    // distanceSqr can be negative
                    return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                }
                // Collinear
                return(0);
            }

            // Not parallel
            float segmentDistance = perpDotA / denominator;

            if (segmentDistance < -Geometry.Epsilon || segmentDistance > 1 + Geometry.Epsilon)
            {
                // No intersection
                Vector2 segmentPoint           = segmentA + segmentDirection * Mathf.Clamp01(segmentDistance);
                float   segmentPointProjection = Vector2.Dot(lineDirection, segmentPoint - lineOrigin);
                Vector2 linePoint = lineOrigin + lineDirection * segmentPointProjection;
                return(Vector2.Distance(linePoint, segmentPoint));
            }
            // Point intersection
            return(0);
        }
コード例 #27
0
        /// <summary>
        /// Returns the distance between the closest points on the lines
        /// </summary>
        public static float LineLine(Vector2 originA, Vector2 directionA, Vector2 originB, Vector2 directionB)
        {
            if (Mathf.Abs(VectorE.PerpDot(directionA, directionB)) < Geometry.Epsilon)
            {
                // Parallel
                Vector2 originBToA = originA - originB;
                if (Mathf.Abs(VectorE.PerpDot(directionA, originBToA)) > Geometry.Epsilon ||
                    Mathf.Abs(VectorE.PerpDot(directionB, originBToA)) > Geometry.Epsilon)
                {
                    // Not collinear
                    float originBProjection = Vector2.Dot(directionA, originBToA);
                    float distanceSqr       = originBToA.sqrMagnitude - originBProjection * originBProjection;
                    // distanceSqr can be negative
                    return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                }

                // Collinear
                return(0);
            }

            // Not parallel
            return(0);
        }
コード例 #28
0
        /// <summary>
        /// Finds closest points on the line and the ray
        /// </summary>
        public static void ClosestPointsLineRay(Vector2 lineOrigin, Vector2 lineDirection, Vector2 rayOrigin, Vector2 rayDirection,
                                                out Vector2 linePoint, out Vector2 rayPoint)
        {
            Vector2 rayOriginToLineOrigin = lineOrigin - rayOrigin;
            float   denominator           = VectorE.PerpDot(lineDirection, rayDirection);
            float   perpDotA = VectorE.PerpDot(lineDirection, rayOriginToLineOrigin);

            if (Mathf.Abs(denominator) < Epsilon)
            {
                float perpDotB = VectorE.PerpDot(rayDirection, rayOriginToLineOrigin);
                // Parallel
                if (Mathf.Abs(perpDotA) > Epsilon || Mathf.Abs(perpDotB) > Epsilon)
                {
                    // Not collinear
                    float dotA = Vector2.Dot(lineDirection, rayOriginToLineOrigin);
                    linePoint = lineOrigin - dotA * lineDirection;
                    rayPoint  = rayOrigin;
                    return;
                }
                // Collinear
                linePoint = rayPoint = rayOrigin;
                return;
            }

            // Not parallel
            float rayDistance = perpDotA / denominator;

            if (rayDistance < -Epsilon)
            {
                // No intersection
                linePoint = lineOrigin - lineDirection * Vector2.Dot(lineDirection, rayOriginToLineOrigin);
                rayPoint  = rayOrigin;
                return;
            }
            // Point intersection
            linePoint = rayPoint = rayOrigin + rayDirection * rayDistance;
        }
コード例 #29
0
        /// <summary>
        /// Returns the distance between the closest points on the segments
        /// </summary>
        public static float SegmentSegment(Vector2 segment1A, Vector2 segment1B, Vector2 segment2A, Vector2 segment2B)
        {
            Vector2 from2ATo1A     = segment1A - segment2A;
            Vector2 direction1     = segment1B - segment1A;
            Vector2 direction2     = segment2B - segment2A;
            float   segment1Length = direction1.magnitude;
            float   segment2Length = direction2.magnitude;

            bool segment1IsAPoint = segment1Length < Geometry.Epsilon;
            bool segment2IsAPoint = segment2Length < Geometry.Epsilon;

            if (segment1IsAPoint && segment2IsAPoint)
            {
                return(Vector2.Distance(segment1A, segment2A));
            }
            if (segment1IsAPoint)
            {
                direction2.Normalize();
                return(PointSegment(segment1A, segment2A, segment2B, direction2, segment2Length));
            }
            if (segment2IsAPoint)
            {
                direction1.Normalize();
                return(PointSegment(segment2A, segment1A, segment1B, direction1, segment1Length));
            }

            direction1.Normalize();
            direction2.Normalize();
            float denominator = VectorE.PerpDot(direction1, direction2);
            float perpDot1    = VectorE.PerpDot(direction1, from2ATo1A);
            float perpDot2    = VectorE.PerpDot(direction2, from2ATo1A);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                if (Mathf.Abs(perpDot1) > Geometry.Epsilon || Mathf.Abs(perpDot2) > Geometry.Epsilon)
                {
                    // Not collinear
                    float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
                    if (segment2AProjection > -Geometry.Epsilon &&
                        segment2AProjection < segment1Length + Geometry.Epsilon)
                    {
                        float distanceSqr = from2ATo1A.sqrMagnitude - segment2AProjection * segment2AProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }

                    Vector2 from1ATo2B          = segment2B - segment1A;
                    float   segment2BProjection = Vector2.Dot(direction1, from1ATo2B);
                    if (segment2BProjection > -Geometry.Epsilon &&
                        segment2BProjection < segment1Length + Geometry.Epsilon)
                    {
                        float distanceSqr = from1ATo2B.sqrMagnitude - segment2BProjection * segment2BProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }

                    if (segment2AProjection < 0 && segment2BProjection < 0)
                    {
                        if (segment2AProjection > segment2BProjection)
                        {
                            return(Vector2.Distance(segment1A, segment2A));
                        }
                        return(Vector2.Distance(segment1A, segment2B));
                    }
                    if (segment2AProjection > 0 && segment2BProjection > 0)
                    {
                        if (segment2AProjection < segment2BProjection)
                        {
                            return(Vector2.Distance(segment1B, segment2A));
                        }
                        return(Vector2.Distance(segment1B, segment2B));
                    }
                    float   segment1AProjection = Vector2.Dot(direction2, from2ATo1A);
                    Vector2 segment2Point       = segment2A + direction2 * segment1AProjection;
                    return(Vector2.Distance(segment1A, segment2Point));
                }
                // Collinear

                bool codirected = Vector2.Dot(direction1, direction2) > 0;
                if (codirected)
                {
                    // Codirected
                    float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
                    if (segment2AProjection > -Geometry.Epsilon)
                    {
                        // 1A------1B
                        //     2A------2B
                        return(SegmentSegmentCollinear(segment1A, segment1B, segment2A));
                    }
                    else
                    {
                        //     1A------1B
                        // 2A------2B
                        return(SegmentSegmentCollinear(segment2A, segment2B, segment1A));
                    }
                }
                else
                {
                    // Contradirected
                    float segment2BProjection = Vector2.Dot(direction1, segment2B - segment1A);
                    if (segment2BProjection > -Geometry.Epsilon)
                    {
                        // 1A------1B
                        //     2B------2A
                        return(SegmentSegmentCollinear(segment1A, segment1B, segment2B));
                    }
                    else
                    {
                        //     1A------1B
                        // 2B------2A
                        return(SegmentSegmentCollinear(segment2B, segment2A, segment1A));
                    }
                }
            }

            // Not parallel
            float distance1 = perpDot2 / denominator;
            float distance2 = perpDot1 / denominator;

            if (distance1 < -Geometry.Epsilon || distance1 > segment1Length + Geometry.Epsilon ||
                distance2 < -Geometry.Epsilon || distance2 > segment2Length + Geometry.Epsilon)
            {
                // No intersection
                bool    codirected = Vector2.Dot(direction1, direction2) > 0;
                Vector2 from1ATo2B;
                if (!codirected)
                {
                    PTUtils.Swap(ref segment2A, ref segment2B);
                    direction2 = -direction2;
                    from1ATo2B = -from2ATo1A;
                    from2ATo1A = segment1A - segment2A;
                    distance2  = segment2Length - distance2;
                }
                else
                {
                    from1ATo2B = segment2B - segment1A;
                }
                Vector2 segment1Point;
                Vector2 segment2Point;

                float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
                float segment2BProjection = Vector2.Dot(direction1, from1ATo2B);

                bool segment2AIsAfter1A  = segment2AProjection > -Geometry.Epsilon;
                bool segment2BIsBefore1B = segment2BProjection < segment1Length + Geometry.Epsilon;
                bool segment2AOnSegment1 = segment2AIsAfter1A && segment2AProjection < segment1Length + Geometry.Epsilon;
                bool segment2BOnSegment1 = segment2BProjection > -Geometry.Epsilon && segment2BIsBefore1B;
                if (segment2AOnSegment1 && segment2BOnSegment1)
                {
                    if (distance2 < -Geometry.Epsilon)
                    {
                        segment1Point = segment1A + direction1 * segment2AProjection;
                        segment2Point = segment2A;
                    }
                    else
                    {
                        segment1Point = segment1A + direction1 * segment2BProjection;
                        segment2Point = segment2B;
                    }
                }
                else if (!segment2AOnSegment1 && !segment2BOnSegment1)
                {
                    if (!segment2AIsAfter1A && !segment2BIsBefore1B)
                    {
                        segment1Point = distance1 < -Geometry.Epsilon ? segment1A : segment1B;
                    }
                    else
                    {
                        // Not on segment
                        segment1Point = segment2AIsAfter1A ? segment1B : segment1A;
                    }
                    float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
                    segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
                    segment2Point           = segment2A + direction2 * segment1PointProjection;
                }
                else if (segment2AOnSegment1)
                {
                    if (distance2 < -Geometry.Epsilon)
                    {
                        segment1Point = segment1A + direction1 * segment2AProjection;
                        segment2Point = segment2A;
                    }
                    else
                    {
                        segment1Point = segment1B;
                        float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
                        segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
                        segment2Point           = segment2A + direction2 * segment1PointProjection;
                    }
                }
                else
                {
                    if (distance2 > segment2Length + Geometry.Epsilon)
                    {
                        segment1Point = segment1A + direction1 * segment2BProjection;
                        segment2Point = segment2B;
                    }
                    else
                    {
                        segment1Point = segment1A;
                        float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
                        segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
                        segment2Point           = segment2A + direction2 * segment1PointProjection;
                    }
                }
                return(Vector2.Distance(segment1Point, segment2Point));
            }

            // Point intersection
            return(0);
        }
コード例 #30
0
        /// <summary>
        /// Returns the distance between the closest points on the ray and the segment
        /// </summary>
        public static float RaySegment(Vector2 rayOrigin, Vector2 rayDirection, Vector2 segmentA, Vector2 segmentB)
        {
            Vector2 segmentAToOrigin = rayOrigin - segmentA;
            Vector2 segmentDirection = segmentB - segmentA;
            float   denominator      = VectorE.PerpDot(rayDirection, segmentDirection);
            float   perpDotA         = VectorE.PerpDot(rayDirection, segmentAToOrigin);
            // Normalized direction gives more stable results
            float perpDotB = VectorE.PerpDot(segmentDirection.normalized, segmentAToOrigin);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                float   segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
                Vector2 originToSegmentB   = segmentB - rayOrigin;
                float   segmentBProjection = Vector2.Dot(rayDirection, originToSegmentB);
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    if (segmentAProjection > -Geometry.Epsilon)
                    {
                        float distanceSqr = segmentAToOrigin.sqrMagnitude - segmentAProjection * segmentAProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }
                    if (segmentBProjection > -Geometry.Epsilon)
                    {
                        float distanceSqr = originToSegmentB.sqrMagnitude - segmentBProjection * segmentBProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }

                    if (segmentAProjection > segmentBProjection)
                    {
                        return(Vector2.Distance(rayOrigin, segmentA));
                    }
                    return(Vector2.Distance(rayOrigin, segmentB));
                }
                // Collinear
                if (segmentAProjection > -Geometry.Epsilon || segmentBProjection > -Geometry.Epsilon)
                {
                    // Point or segment intersection
                    return(0);
                }
                // No intersection
                return(segmentAProjection > segmentBProjection ? -segmentAProjection : -segmentBProjection);
            }

            // Not parallel
            float rayDistance     = perpDotB / denominator;
            float segmentDistance = perpDotA / denominator;

            if (rayDistance < -Geometry.Epsilon ||
                segmentDistance < -Geometry.Epsilon || segmentDistance > 1 + Geometry.Epsilon)
            {
                // No intersection
                bool    codirected = Vector2.Dot(rayDirection, segmentDirection) > 0;
                Vector2 segmentBToOrigin;
                if (!codirected)
                {
                    PTUtils.Swap(ref segmentA, ref segmentB);
                    segmentDirection = -segmentDirection;
                    segmentBToOrigin = segmentAToOrigin;
                    segmentAToOrigin = rayOrigin - segmentA;
                    segmentDistance  = 1 - segmentDistance;
                }
                else
                {
                    segmentBToOrigin = rayOrigin - segmentB;
                }

                float segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
                float segmentBProjection = -Vector2.Dot(rayDirection, segmentBToOrigin);
                bool  segmentAOnRay      = segmentAProjection > -Geometry.Epsilon;
                bool  segmentBOnRay      = segmentBProjection > -Geometry.Epsilon;
                if (segmentAOnRay && segmentBOnRay)
                {
                    if (segmentDistance < 0)
                    {
                        Vector2 rayPoint     = rayOrigin + rayDirection * segmentAProjection;
                        Vector2 segmentPoint = segmentA;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                    else
                    {
                        Vector2 rayPoint     = rayOrigin + rayDirection * segmentBProjection;
                        Vector2 segmentPoint = segmentB;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                }
                else if (!segmentAOnRay && segmentBOnRay)
                {
                    if (segmentDistance < 0)
                    {
                        Vector2 rayPoint     = rayOrigin;
                        Vector2 segmentPoint = segmentA;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                    else if (segmentDistance > 1 + Geometry.Epsilon)
                    {
                        Vector2 rayPoint     = rayOrigin + rayDirection * segmentBProjection;
                        Vector2 segmentPoint = segmentB;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                    else
                    {
                        Vector2 rayPoint         = rayOrigin;
                        float   originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
                        Vector2 segmentPoint     = segmentA + segmentDirection * originProjection / segmentDirection.sqrMagnitude;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                }
                else
                {
                    // Not on ray
                    Vector2 rayPoint         = rayOrigin;
                    float   originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
                    float   sqrSegmentLength = segmentDirection.sqrMagnitude;
                    if (originProjection < 0)
                    {
                        return(Vector2.Distance(rayPoint, segmentA));
                    }
                    else if (originProjection > sqrSegmentLength)
                    {
                        return(Vector2.Distance(rayPoint, segmentB));
                    }
                    else
                    {
                        Vector2 segmentPoint = segmentA + segmentDirection * originProjection / sqrSegmentLength;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                }
            }
            // Point intersection
            return(0);
        }