public void TestSignedAngle()
 {
     {
         Vector3 v1    = Vector3.up;
         Vector2 v2    = Vector3.left;
         float   angle = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.forward);
         Assert.AreApproximatelyEqual(angle, 90f);
         float angle2 = Vector2.SignedAngle(v1, v2);
         Assert.AreApproximatelyEqual(angle, angle2);
         float angle3 = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.back);
         Assert.AreApproximatelyEqual(angle, -angle3);
     }
     {
         Vector3 v1    = Vector3.up;
         Vector2 v2    = Vector3.right;
         float   angle = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.forward);
         Assert.AreApproximatelyEqual(angle, -90f);
         float angle2 = Vector2.SignedAngle(v1, v2);
         Assert.AreApproximatelyEqual(angle, angle2);
         float angle3 = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.back);
         Assert.AreApproximatelyEqual(angle, -angle3);
     }
     {
         Vector3 v1    = Vector3.up;
         Vector2 v2    = new Vector3(-0.0001f, 1, 0);
         float   angle = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.forward);
         Assert.AreApproximatelyEqual(angle, 0.00572958f);
         float angle3 = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.back);
         Assert.AreApproximatelyEqual(angle, -angle3);
     }
     {
         Vector3 v1    = Vector3.up;
         Vector2 v2    = new Vector3(0.0001f, 1, 0);
         float   angle = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.forward);
         Assert.AreApproximatelyEqual(angle, -0.00572958f);
         float angle3 = UnityVectorExtensions.SignedAngle(v1, v2, Vector3.back);
         Assert.AreApproximatelyEqual(angle, -angle3);
     }
 }
Example #2
0
            // Convert from screen coords to normalized FOV angular coords
            private Rect ScreenToFOV(Rect rScreen, float fov, float fovH, float aspect)
            {
                Rect      r     = new Rect(rScreen);
                Matrix4x4 persp = Matrix4x4.Perspective(fov, aspect, 0.0001f, 2f).inverse;

                Vector3 p     = persp.MultiplyPoint(new Vector3(0, (r.yMin * 2f) - 1f, 0.5f)); p.z = -p.z;
                float   angle = UnityVectorExtensions.SignedAngle(Vector3.forward, p, Vector3.left);

                r.yMin = ((fov / 2) + angle) / fov;

                p      = persp.MultiplyPoint(new Vector3(0, (r.yMax * 2f) - 1f, 0.5f)); p.z = -p.z;
                angle  = UnityVectorExtensions.SignedAngle(Vector3.forward, p, Vector3.left);
                r.yMax = ((fov / 2) + angle) / fov;

                p      = persp.MultiplyPoint(new Vector3((r.xMin * 2f) - 1f, 0, 0.5f));  p.z = -p.z;
                angle  = UnityVectorExtensions.SignedAngle(Vector3.forward, p, Vector3.up);
                r.xMin = ((fovH / 2) + angle) / fovH;

                p      = persp.MultiplyPoint(new Vector3((r.xMax * 2f) - 1f, 0, 0.5f));  p.z = -p.z;
                angle  = UnityVectorExtensions.SignedAngle(Vector3.forward, p, Vector3.up);
                r.xMax = ((fovH / 2) + angle) / fovH;
                return(r);
            }
        private bool IsTargetOffscreen(CameraState state)
        {
            if (state.HasLookAt)
            {
                Vector3 dir = state.ReferenceLookAt - state.CorrectedPosition;
                dir = Quaternion.Inverse(state.CorrectedOrientation) * dir;
                if (state.Lens.Orthographic)
                {
                    if (Mathf.Abs(dir.y) > state.Lens.OrthographicSize)
                    {
                        return(true);
                    }
                    if (Mathf.Abs(dir.x) > state.Lens.OrthographicSize * state.Lens.Aspect)
                    {
                        return(true);
                    }
                }
                else
                {
                    float fov   = state.Lens.FieldOfView / 2;
                    float angle = UnityVectorExtensions.Angle(dir.ProjectOntoPlane(Vector3.right), Vector3.forward);
                    if (angle > fov)
                    {
                        return(true);
                    }

                    fov   = Mathf.Rad2Deg * Mathf.Atan(Mathf.Tan(fov * Mathf.Deg2Rad) * state.Lens.Aspect);
                    angle = UnityVectorExtensions.Angle(dir.ProjectOntoPlane(Vector3.up), Vector3.forward);
                    if (angle > fov)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Example #4
0
        private Rect ScreenToFOV(Rect rScreen, float fov, float fovH, float aspect)
        {
            Rect      result  = new Rect(rScreen);
            Matrix4x4 inverse = Matrix4x4.Perspective(fov, aspect, 0.01f, 10000f).inverse;
            Vector3   to      = inverse.MultiplyPoint(new Vector3(0f, result.yMin * 2f - 1f, 0.1f));

            to.z = -to.z;
            float num = UnityVectorExtensions.SignedAngle(Vector3.forward, to, Vector3.left);

            result.yMin = (fov / 2f + num) / fov;
            to          = inverse.MultiplyPoint(new Vector3(0f, result.yMax * 2f - 1f, 0.1f));
            to.z        = -to.z;
            num         = UnityVectorExtensions.SignedAngle(Vector3.forward, to, Vector3.left);
            result.yMax = (fov / 2f + num) / fov;
            to          = inverse.MultiplyPoint(new Vector3(result.xMin * 2f - 1f, 0f, 0.1f));
            to.z        = -to.z;
            num         = UnityVectorExtensions.SignedAngle(Vector3.forward, to, Vector3.up);
            result.xMin = (fovH / 2f + num) / fovH;
            to          = inverse.MultiplyPoint(new Vector3(result.xMax * 2f - 1f, 0f, 0.1f));
            to.z        = -to.z;
            num         = UnityVectorExtensions.SignedAngle(Vector3.forward, to, Vector3.up);
            result.xMax = (fovH / 2f + num) / fovH;
            return(result);
        }
        /// <summary>Positions the virtual camera according to the transposer rules.</summary>
        /// <param name="deltaTime">Used for damping.  If less than 0, no damping is done.</param>
        /// <param name="up">Current camera up</param>
        /// <param name="desiredCameraOffset">Where we want to put the camera relative to the follow target</param>
        /// <param name="outTargetPosition">Resulting camera position</param>
        /// <param name="outTargetOrient">Damped target orientation</param>
        protected void TrackTarget(
            float deltaTime, Vector3 up, Vector3 desiredCameraOffset,
            out Vector3 outTargetPosition, out Quaternion outTargetOrient)
        {
            var  targetOrientation = GetReferenceOrientation(up);
            var  dampedOrientation = targetOrientation;
            bool prevStateValid    = deltaTime >= 0 && VirtualCamera.PreviousStateIsValid;

            if (prevStateValid)
            {
                if (m_AngularDampingMode == AngularDampingMode.Quaternion &&
                    m_BindingMode == BindingMode.LockToTarget)
                {
                    float t = VirtualCamera.DetachedFollowTargetDamp(1, m_AngularDamping, deltaTime);
                    dampedOrientation = Quaternion.Slerp(
                        m_PreviousReferenceOrientation, targetOrientation, t);
                }
                else
                {
                    var relative = (Quaternion.Inverse(m_PreviousReferenceOrientation)
                                    * targetOrientation).eulerAngles;
                    for (int i = 0; i < 3; ++i)
                    {
                        if (Mathf.Abs(relative[i]) < 0.01f) // correct for precision drift
                        {
                            relative[i] = 0;
                        }
                        else if (relative[i] > 180)
                        {
                            relative[i] -= 360;
                        }
                    }
                    relative          = VirtualCamera.DetachedFollowTargetDamp(relative, AngularDamping, deltaTime);
                    dampedOrientation = m_PreviousReferenceOrientation * Quaternion.Euler(relative);
                }
            }
            m_PreviousReferenceOrientation = dampedOrientation;

            var targetPosition  = FollowTargetPosition;
            var currentPosition = m_PreviousTargetPosition;
            var previousOffset  = prevStateValid ? m_PreviousOffset : desiredCameraOffset;
            var offsetDelta     = desiredCameraOffset - previousOffset;

            if (offsetDelta.sqrMagnitude > 0.01f)
            {
                var q = UnityVectorExtensions.SafeFromToRotation(
                    m_PreviousOffset.ProjectOntoPlane(up),
                    desiredCameraOffset.ProjectOntoPlane(up), up);
                currentPosition = targetPosition + q * (m_PreviousTargetPosition - targetPosition);
            }
            m_PreviousOffset = desiredCameraOffset;

            // Adjust for damping, which is done in camera-offset-local coords
            var positionDelta = targetPosition - currentPosition;

            if (prevStateValid)
            {
                Quaternion dampingSpace;
                if (desiredCameraOffset.AlmostZero())
                {
                    dampingSpace = VcamState.RawOrientation;
                }
                else
                {
                    dampingSpace = Quaternion.LookRotation(dampedOrientation * desiredCameraOffset, up);
                }
                var localDelta = Quaternion.Inverse(dampingSpace) * positionDelta;
                localDelta    = VirtualCamera.DetachedFollowTargetDamp(localDelta, Damping, deltaTime);
                positionDelta = dampingSpace * localDelta;
            }
            currentPosition += positionDelta;

            outTargetPosition = m_PreviousTargetPosition = currentPosition;
            outTargetOrient   = dampedOrientation;
        }
        // Make sure this is calld only once per frame
        private float GetTargetHeading(float currentHeading, Quaternion targetOrientation)
        {
            if (m_BindingMode == BindingMode.SimpleFollowWithWorldUp)
            {
                return(0);
            }
            if (FollowTarget == null)
            {
                return(currentHeading);
            }

            var headingDef = m_Heading.m_Definition;

            if (headingDef == Heading.HeadingDefinition.Velocity && mTargetRigidBody == null)
            {
                headingDef = Heading.HeadingDefinition.PositionDelta;
            }

            Vector3 velocity = Vector3.zero;

            switch (headingDef)
            {
            case Heading.HeadingDefinition.PositionDelta:
                velocity = FollowTargetPosition - mLastTargetPosition;
                break;

            case Heading.HeadingDefinition.Velocity:
                velocity = mTargetRigidBody.velocity;
                break;

            case Heading.HeadingDefinition.TargetForward:
                velocity = FollowTargetRotation * Vector3.forward;
                break;

            default:
            case Heading.HeadingDefinition.WorldForward:
                return(0);
            }

            // Process the velocity and derive the heading from it.
            Vector3 up = targetOrientation * Vector3.up;

            velocity = velocity.ProjectOntoPlane(up);
            if (headingDef != Heading.HeadingDefinition.TargetForward)
            {
                int filterSize = m_Heading.m_VelocityFilterStrength * 5;
                if (mHeadingTracker == null || mHeadingTracker.FilterSize != filterSize)
                {
                    mHeadingTracker = new HeadingTracker(filterSize);
                }
                mHeadingTracker.DecayHistory();
                if (!velocity.AlmostZero())
                {
                    mHeadingTracker.Add(velocity);
                }
                velocity = mHeadingTracker.GetReliableHeading();
            }
            if (!velocity.AlmostZero())
            {
                return(UnityVectorExtensions.SignedAngle(
                           targetOrientation * Vector3.forward, velocity, up));
            }

            // If no reliable heading, then stay where we are.
            return(currentHeading);
        }
        /// <summary>Positions the virtual camera according to the transposer rules.</summary>
        /// <param name="curState">The current camera state</param>
        /// <param name="deltaTime">Used for damping.  If less than 0, no damping is done.</param>
        public override void MutateCameraState(ref CameraState curState, float deltaTime)
        {
            InitPrevFrameStateInfo(ref curState, deltaTime);

            // Update the heading
            if (FollowTarget != m_PreviousTarget)
            {
                m_PreviousTarget = FollowTarget;
#if CINEMACHINE_PHYSICS
                m_TargetRigidBody = (m_PreviousTarget == null) ? null : m_PreviousTarget.GetComponent <Rigidbody>();
#endif
                m_LastTargetPosition = (m_PreviousTarget == null) ? Vector3.zero : m_PreviousTarget.position;
                mHeadingTracker      = null;
            }
            m_LastHeading = HeadingUpdater(this, deltaTime, curState.ReferenceUp);
            float heading = m_LastHeading;
            if (IsValid)
            {
                // Calculate the heading
                if (m_BindingMode != BindingMode.SimpleFollowWithWorldUp)
                {
                    heading += m_Heading.m_Bias;
                }
                Quaternion headingRot = Quaternion.AngleAxis(heading, Vector3.up);

                Vector3 rawOffset = EffectiveOffset;
                Vector3 offset    = headingRot * rawOffset;

                // Track the target, with damping
                TrackTarget(deltaTime, curState.ReferenceUp, offset, out Vector3 pos, out Quaternion orient);

                // Place the camera
                offset = orient * offset;
                curState.ReferenceUp = orient * Vector3.up;

                // Respect minimum target distance on XZ plane
                var targetPosition = FollowTargetPosition;
                pos += GetOffsetForMinimumTargetDistance(
                    pos, offset, curState.RawOrientation * Vector3.forward,
                    curState.ReferenceUp, targetPosition);
                curState.RawPosition = pos + offset;

                if (deltaTime >= 0 && VirtualCamera.PreviousStateIsValid)
                {
                    var lookAt = targetPosition;
                    if (LookAtTarget != null)
                    {
                        lookAt = LookAtTargetPosition;
                    }
                    var dir0 = m_LastCameraPosition - lookAt;
                    var dir1 = curState.RawPosition - lookAt;
                    if (dir0.sqrMagnitude > 0.01f && dir1.sqrMagnitude > 0.01f)
                    {
                        curState.PositionDampingBypass = UnityVectorExtensions.SafeFromToRotation(
                            dir0, dir1, curState.ReferenceUp).eulerAngles;
                    }
                }
                m_LastTargetPosition = targetPosition;
                m_LastCameraPosition = curState.RawPosition;
            }
        }
        // Make sure this is calld only once per frame
        private float GetTargetHeading(
            float currentHeading, Quaternion targetOrientation, float deltaTime)
        {
            if (m_BindingMode == BindingMode.SimpleFollowWithWorldUp)
            {
                return(0);
            }
            if (FollowTarget == null)
            {
                return(currentHeading);
            }

            if (m_Heading.m_HeadingDefinition == Heading.HeadingDefinition.Velocity &&
                mTargetRigidBody == null)
            {
                Debug.Log(string.Format(
                              "Attempted to use HeadingDerivationMode.Velocity to calculate heading for {0}. No RigidBody was present on '{1}'. Defaulting to position delta",
                              GetFullName(VirtualCamera.VirtualCameraGameObject), FollowTarget));
                m_Heading.m_HeadingDefinition = Heading.HeadingDefinition.PositionDelta;
            }

            Vector3 velocity = Vector3.zero;

            switch (m_Heading.m_HeadingDefinition)
            {
            case Heading.HeadingDefinition.PositionDelta:
                velocity = FollowTarget.position - mLastTargetPosition;
                break;

            case Heading.HeadingDefinition.Velocity:
                velocity = mTargetRigidBody.velocity;
                break;

            case Heading.HeadingDefinition.TargetForward:
                velocity = FollowTarget.forward;
                break;

            default:
            case Heading.HeadingDefinition.WorldForward:
                return(0);
            }

            // Process the velocity and derive the heading from it.
            int filterSize = m_Heading.m_VelocityFilterStrength * 5;

            if (mHeadingTracker == null || mHeadingTracker.FilterSize != filterSize)
            {
                mHeadingTracker = new HeadingTracker(filterSize);
            }
            mHeadingTracker.DecayHistory();
            Vector3 up = targetOrientation * Vector3.up;

            velocity = velocity.ProjectOntoPlane(up);
            if (!velocity.AlmostZero())
            {
                mHeadingTracker.Add(velocity);
            }

            velocity = mHeadingTracker.GetReliableHeading();
            if (!velocity.AlmostZero())
            {
                return(UnityVectorExtensions.SignedAngle(targetOrientation * Vector3.forward, velocity, up));
            }

            // If no reliable heading, then stay where we are.
            return(currentHeading);
        }
Example #9
0
        private float GetTargetHeading(float currentHeading, Vector3 up, float deltaTime)
        {
            if (VirtualCamera.Follow == null)
            {
                return(currentHeading);
            }

            if (m_RecenterToTargetHeading.m_HeadingDefinition
                == Recentering.HeadingDerivationMode.Velocity &&
                mTargetRigidBody == null)
            {
                Debug.Log(string.Format(
                              "Attempted to use HeadingDerivationMode.Velocity to calculate heading for {0}. No RigidBody was present on '{1}'. Defaulting to position delta",
                              GetFullName(VirtualCamera.VirtualCameraGameObject), VirtualCamera.Follow));
                m_RecenterToTargetHeading.m_HeadingDefinition = Recentering.HeadingDerivationMode.PositionDelta;
            }

            Vector3 velocity = Vector3.zero;

            switch (m_RecenterToTargetHeading.m_HeadingDefinition)
            {
            case Recentering.HeadingDerivationMode.PositionDelta:
                velocity = VirtualCamera.Follow.position - mLastTargetPosition;
                break;

            case Recentering.HeadingDerivationMode.Velocity:
                velocity = mTargetRigidBody.velocity;
                break;

            default:
            case Recentering.HeadingDerivationMode.TargetForward:
                return(VirtualCamera.Follow.rotation.eulerAngles.y);

            case Recentering.HeadingDerivationMode.WorldForward:
                return(0);
            }

            // Process the velocity and derive the heading from it.
            int filterSize = m_RecenterToTargetHeading.m_VelocityFilterStrength * 5;

            if (mHeadingTracker == null || mHeadingTracker.FilterSize != filterSize)
            {
                mHeadingTracker = new HeadingTracker(filterSize);
            }
            mHeadingTracker.DecayHistory();
            velocity = velocity.ProjectOntoPlane(up);
            if (!velocity.AlmostZero())
            {
                mHeadingTracker.Add(velocity);
            }

            velocity = mHeadingTracker.GetReliableHeading();
            if (!velocity.AlmostZero())
            {
                Vector3 fwd = (-GetBackVector(up)).ProjectOntoPlane(up);
                return(UnityVectorExtensions.SignedAngle(fwd, velocity, up));
            }

            // If no reliable heading, then stay where we are.
            return(currentHeading);
        }
Example #10
0
        Vector3 DoTracking(Vector3 currentPosition, Vector3 up, float deltaTime)
        {
            if (VirtualCamera.Follow == null)
            {
                return(currentPosition);
            }

            if (VirtualCamera.Follow != PreviousTarget)
            {
                PreviousTarget      = VirtualCamera.Follow;
                mTargetRigidBody    = VirtualCamera.Follow.GetComponent <Rigidbody>();
                mLastTargetPosition = VirtualCamera.Follow.position;
                mHeadingTracker     = null;
            }

            // Heading
            if (!m_HeadingIsSlave)
            {
                UpdateHeading(deltaTime, up, true);
            }
            mLastTargetPosition = VirtualCamera.Follow.position;

            // Where to put the camera
            Vector3 localTarget = EffectiveOffset(up);

            localTarget = Quaternion.AngleAxis(m_XAxis.Value + m_HeadingBias, up) * localTarget;

            // Adjust for damping, which is done in local coords
            if (deltaTime > 0)
            {
                if (m_DampingStyle == DampingStyle.Polar)
                {
                    // Get the offset in polar
                    Vector3 localCurrent     = currentPosition - VirtualCamera.Follow.position;
                    Vector3 currentOnPlane   = localCurrent.ProjectOntoPlane(up);
                    Vector3 currentPerpPlane = localCurrent - currentOnPlane;
                    Vector3 targetOnPlane    = localTarget.ProjectOntoPlane(up);
                    Vector3 targetPerpPlane  = localTarget - targetOnPlane;
                    Vector3 delta            = new Vector3(
                        UnityVectorExtensions.SignedAngle(currentOnPlane, targetOnPlane, up),
                        Vector3.Dot(targetPerpPlane - currentPerpPlane, up),
                        (targetOnPlane.magnitude - currentOnPlane.magnitude));

                    // Apply damping
                    Vector3 trackingSpeeds = TrackingSpeeds;
                    for (int i = 0; i < 3; ++i)
                    {
                        delta[i] *= deltaTime / Mathf.Max(trackingSpeeds[i], deltaTime);
                    }

                    localTarget  = currentOnPlane;
                    localTarget += (localTarget.normalized * delta.z);
                    localTarget += currentPerpPlane + (delta.y * up);
                    localTarget  = Quaternion.AngleAxis(delta.x, up) * localTarget;
                }
                else
                {
                    Vector3    worldOffset           = currentPosition - (VirtualCamera.Follow.position + localTarget);
                    Quaternion localToWorldTransform = Quaternion.LookRotation(
                        VirtualCamera.Follow.rotation * Vector3.forward, up);
                    Vector3 localOffset    = Quaternion.Inverse(localToWorldTransform) * worldOffset;
                    Vector3 trackingSpeeds = TrackingSpeeds;
                    for (int i = 0; i < 3; ++i)
                    {
                        localOffset[i] *= deltaTime / Mathf.Max(trackingSpeeds[i], deltaTime);
                    }
                    return(currentPosition - (localToWorldTransform * localOffset));
                }
            }

            // Return the adjusted rig position
            return(VirtualCamera.Follow.position + localTarget);
        }
    public void FindIntersectionTests()
    {
        {
            var l1_p1            = new Vector2(0, 1);
            var l1_p2            = new Vector2(0, -1);
            var l2_p1            = new Vector2(-1, 0);
            var l2_p2            = new Vector2(1, 0);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 2);
            Assert.IsTrue(AreApproximatelyEqual(intersection, Vector2.zero));
        }
        {
            var l1_p1            = new Vector2(0, 1);
            var l1_p2            = new Vector2(0, 0);
            var l2_p1            = new Vector2(-1, 0);
            var l2_p2            = new Vector2(1, 0);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 2);
            Assert.IsTrue(AreApproximatelyEqual(intersection, Vector2.zero));
        }
        {
            var l1_p1            = new Vector2(0, 2);
            var l1_p2            = new Vector2(0, 1);
            var l2_p1            = new Vector2(-1, 0);
            var l2_p2            = new Vector2(1, 0);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 1);
            Assert.IsTrue(AreApproximatelyEqual(intersection, Vector2.zero));
        }
        {
            var l1_p1            = new Vector2(0, 2);
            var l1_p2            = new Vector2(0, 1);
            var l2_p1            = new Vector2(1, 2);
            var l2_p2            = new Vector2(1, 1);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 0);
            Assert.IsTrue(float.IsInfinity(intersection.x) && float.IsInfinity(intersection.y));
        }
        {
            var l1_p1            = new Vector2(1, 2);
            var l1_p2            = new Vector2(1, 1);
            var l2_p1            = new Vector2(1, -2);
            var l2_p2            = new Vector2(1, -1);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 3);
            Assert.IsTrue(float.IsInfinity(intersection.x) && float.IsInfinity(intersection.y));
        }
        {
            var l1_p1            = new Vector2(1, 2);
            var l1_p2            = new Vector2(1, -2);
            var l2_p1            = new Vector2(1, 3);
            var l2_p2            = new Vector2(1, 1);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(float.IsInfinity(intersection.x) && float.IsInfinity(intersection.y));
        }
        {
            var l1_p1            = new Vector2(1, 2);
            var l1_p2            = new Vector2(1, -2);
            var l2_p1            = new Vector2(1, 2);
            var l2_p2            = new Vector2(1, -2);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(float.IsInfinity(intersection.x) && float.IsInfinity(intersection.y));
        }
        {
            var l1_p1            = new Vector2(1, 2);
            var l1_p2            = new Vector2(1, -2);
            var l2_p1            = new Vector2(1, -2);
            var l2_p2            = new Vector2(1, 2);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(float.IsInfinity(intersection.x) && float.IsInfinity(intersection.y));
        }
        {
            var l1_p1            = new Vector2(0, 1);
            var l1_p2            = new Vector2(0, 1);
            var l2_p1            = new Vector2(1, 0);
            var l2_p2            = new Vector2(1, 0);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(float.IsInfinity(intersection.x) && float.IsInfinity(intersection.y));
        }
        {
            var l1_p1            = new Vector2(0, 0);
            var l1_p2            = new Vector2(2, 0);
            var l2_p1            = new Vector2(0, 1);
            var l2_p2            = new Vector2(1, 0);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 2);
            Assert.IsTrue(AreApproximatelyEqual(intersection, l2_p2));
        }
        {
            var l1_p1            = new Vector2(0, 0);
            var l1_p2            = new Vector2(2, 0);
            var l2_p1            = new Vector2(1, 0);
            var l2_p2            = new Vector2(0, 1);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 2);
            Assert.IsTrue(AreApproximatelyEqual(intersection, l2_p1));
        }

        // Parallel segments touching at one point
        {
            var l1_p1            = new Vector2(0, 3);
            var l1_p2            = new Vector2(0, 5);
            var l2_p1            = new Vector2(0, 5);
            var l2_p2            = new Vector2(0, 9);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(AreApproximatelyEqual(intersection, l2_p1));
        }
        {
            var l1_p1            = new Vector2(0, 5);
            var l1_p2            = new Vector2(0, 3);
            var l2_p1            = new Vector2(0, 5);
            var l2_p2            = new Vector2(0, 9);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(AreApproximatelyEqual(intersection, l2_p1));
        }
        {
            var l1_p1            = new Vector2(0, 3);
            var l1_p2            = new Vector2(0, 5);
            var l2_p1            = new Vector2(0, 9);
            var l2_p2            = new Vector2(0, 5);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(AreApproximatelyEqual(intersection, l2_p2));
        }
        {
            var l1_p1            = new Vector2(0, 5);
            var l1_p2            = new Vector2(0, 3);
            var l2_p1            = new Vector2(0, 9);
            var l2_p2            = new Vector2(0, 5);
            int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                          out Vector2 intersection);
            Assert.IsTrue(intersectionType == 4);
            Assert.IsTrue(AreApproximatelyEqual(intersection, l2_p2));
        }
    }
Example #12
0
 public void FindIntersectionTests()
 {
     {
         var l1_p1            = new Vector2(0, 1);
         var l1_p2            = new Vector2(0, -1);
         var l2_p1            = new Vector2(-1, 0);
         var l2_p2            = new Vector2(1, 0);
         int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                       out Vector2 intersection);
         Assert.IsTrue(intersectionType == 2);
         Assert.IsTrue(Mathf.Abs(intersection.x) < 1e-8f &&
                       Mathf.Abs(intersection.y) < 1e-8f); // intersection should be Vector2.zero
     }
     {
         var l1_p1            = new Vector2(0, 1);
         var l1_p2            = new Vector2(0, 0);
         var l2_p1            = new Vector2(-1, 0);
         var l2_p2            = new Vector2(1, 0);
         int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                       out Vector2 intersection);
         Assert.IsTrue(intersectionType == 2);
         Assert.IsTrue(Mathf.Abs(intersection.x) < 1e-8f &&
                       Mathf.Abs(intersection.y) < 1e-8f); // intersection should be Vector2.zero
     }
     {
         var l1_p1            = new Vector2(0, 2);
         var l1_p2            = new Vector2(0, 1);
         var l2_p1            = new Vector2(-1, 0);
         var l2_p2            = new Vector2(1, 0);
         int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                       out Vector2 intersection);
         Assert.IsTrue(intersectionType == 1);
         Assert.IsTrue(Mathf.Abs(intersection.x) < 1e-8f &&
                       Mathf.Abs(intersection.y) < 1e-8f); // intersection should be Vector2.zero
     }
     {
         var l1_p1            = new Vector2(0, 2);
         var l1_p2            = new Vector2(0, 1);
         var l2_p1            = new Vector2(1, 2);
         var l2_p2            = new Vector2(1, 1);
         int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                       out Vector2 intersection);
         Assert.IsTrue(intersectionType == 0);
     }
     {
         var l1_p1            = new Vector2(0, 1);
         var l1_p2            = new Vector2(0, 1);
         var l2_p1            = new Vector2(1, 0);
         var l2_p2            = new Vector2(1, 0);
         int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                       out Vector2 intersection);
         Assert.IsTrue(intersectionType == 0);
     }
     {
         var l1_p1            = new Vector2(0, 0);
         var l1_p2            = new Vector2(2, 0);
         var l2_p1            = new Vector2(0, 1);
         var l2_p2            = new Vector2(1, 0);
         int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                       out Vector2 intersection);
         Assert.IsTrue(intersectionType == 1);
         Assert.IsTrue(intersection == l2_p2);
     }
     {
         var l1_p1            = new Vector2(0, 0);
         var l1_p2            = new Vector2(2, 0);
         var l2_p1            = new Vector2(1, 0);
         var l2_p2            = new Vector2(0, 1);
         int intersectionType = UnityVectorExtensions.FindIntersection(l1_p1, l1_p2, l2_p1, l2_p2,
                                                                       out Vector2 intersection);
         Assert.IsTrue(intersectionType == 2);
         Assert.IsTrue(intersection == l2_p1);
     }
 }