/// <summary>
 /// Computes an intersection of the circles
 /// </summary>
 /// <returns>True if the circles intersect or one circle is contained within the other</returns>
 public static bool IntersectCircleCircle(Circle circleA, Circle circleB, out IntersectionCircleCircle intersection)
 {
     return(IntersectCircleCircle(circleA.center, circleA.radius, circleB.center, circleB.radius, out intersection));
 }
        /// <summary>
        /// Computes an intersection of the circles
        /// </summary>
        /// <returns>True if the circles intersect or one circle is contained within the other</returns>
        public static bool IntersectCircleCircle(Vector2 centerA, float radiusA, Vector2 centerB, float radiusB,
                                                 out IntersectionCircleCircle intersection)
        {
            intersection = new IntersectionCircleCircle();

            Vector2 fromBtoA            = centerA - centerB;
            float   distanceFromBtoASqr = fromBtoA.sqrMagnitude;

            if (distanceFromBtoASqr < EpsilonSqr)
            {
                if (Mathf.Abs(radiusA - radiusB) < Epsilon)
                {
                    // Circles are coincident
                    intersection.type = IntersectionType.Circle;
                    return(true);
                }
                // One circle is inside the other
                intersection.type = IntersectionType.None;
                return(true);
            }

            float sumOfRadii    = radiusA + radiusB;
            float sumOfRadiiSqr = sumOfRadii * sumOfRadii;

            if (distanceFromBtoASqr > sumOfRadiiSqr)
            {
                // No intersections, circles are separate
                intersection.type = IntersectionType.None;
                return(false);
            }
            if (Mathf.Abs(distanceFromBtoASqr - sumOfRadiiSqr) < EpsilonSqr)
            {
                // One intersection outside
                intersection.type   = IntersectionType.Point;
                intersection.pointA = centerB + fromBtoA * (radiusB / sumOfRadii);
                return(true);
            }

            float differenceOfRadii    = radiusA - radiusB;
            float differenceOfRadiiSqr = differenceOfRadii * differenceOfRadii;

            if (distanceFromBtoASqr < differenceOfRadiiSqr)
            {
                // One circle is contained within the other
                intersection.type = IntersectionType.None;
                return(true);
            }
            if (Mathf.Abs(distanceFromBtoASqr - differenceOfRadiiSqr) < EpsilonSqr)
            {
                // One intersection inside
                intersection.type   = IntersectionType.Point;
                intersection.pointA = centerB - fromBtoA * (radiusB / differenceOfRadii);
                return(true);
            }

            // Two intersections
            intersection.type = IntersectionType.TwoPoints;

            float   radiusASqr       = radiusA * radiusA;
            float   distanceToMiddle = 0.5f * (radiusASqr - radiusB * radiusB) / distanceFromBtoASqr + 0.5f;
            Vector2 middle           = centerA - fromBtoA * distanceToMiddle;

            float discriminant = radiusASqr / distanceFromBtoASqr - distanceToMiddle * distanceToMiddle;

            if (discriminant < 0)
            {
                discriminant = 0;
            }
            Vector2 offset = fromBtoA.Perp() * Mathf.Sqrt(discriminant);

            intersection.pointA = middle + offset;
            intersection.pointB = middle - offset;
            return(true);
        }
Example #3
0
        /// <summary>
        /// Computes an intersection of the circles
        /// </summary>
        /// <returns>True if the circles intersect or one circle is contained within the other</returns>
        public static bool CircleCircle(Vector2 centerA, float radiusA, Vector2 centerB, float radiusB,
                                        out IntersectionCircleCircle intersection)
        {
            Vector2 fromBtoA            = centerA - centerB;
            float   distanceFromBtoASqr = fromBtoA.sqrMagnitude;

            if (distanceFromBtoASqr < Geometry.Epsilon)
            {
                if (Mathf.Abs(radiusA - radiusB) < Geometry.Epsilon)
                {
                    // Circles are coincident
                    intersection = IntersectionCircleCircle.Circle();
                    return(true);
                }
                // One circle is inside the other
                intersection = IntersectionCircleCircle.None();
                return(true);
            }

            // For intersections on the circle's edge magnitude is more stable than sqrMagnitude
            float distanceFromBtoA = Mathf.Sqrt(distanceFromBtoASqr);

            float sumOfRadii = radiusA + radiusB;

            if (Mathf.Abs(distanceFromBtoA - sumOfRadii) < Geometry.Epsilon)
            {
                // One intersection outside
                intersection = IntersectionCircleCircle.Point(centerB + fromBtoA * (radiusB / sumOfRadii));
                return(true);
            }
            if (distanceFromBtoA > sumOfRadii)
            {
                // No intersections, circles are separate
                intersection = IntersectionCircleCircle.None();
                return(false);
            }

            float differenceOfRadii    = radiusA - radiusB;
            float differenceOfRadiiAbs = Mathf.Abs(differenceOfRadii);

            if (Mathf.Abs(distanceFromBtoA - differenceOfRadiiAbs) < Geometry.Epsilon)
            {
                // One intersection inside
                intersection = IntersectionCircleCircle.Point(centerB - fromBtoA * (radiusB / differenceOfRadii));
                return(true);
            }
            if (distanceFromBtoA < differenceOfRadiiAbs)
            {
                // One circle is contained within the other
                intersection = IntersectionCircleCircle.None();
                return(true);
            }

            // Two intersections
            float   radiusASqr       = radiusA * radiusA;
            float   distanceToMiddle = 0.5f * (radiusASqr - radiusB * radiusB) / distanceFromBtoASqr + 0.5f;
            Vector2 middle           = centerA - fromBtoA * distanceToMiddle;

            float   discriminant = radiusASqr / distanceFromBtoASqr - distanceToMiddle * distanceToMiddle;
            Vector2 offset       = fromBtoA.RotateCCW90() * Mathf.Sqrt(discriminant);

            intersection = IntersectionCircleCircle.TwoPoints(middle + offset, middle - offset);
            return(true);
        }