交点 - 两圆交点 - 圆方程组方式

圆心为(xc, yc), 半径为r的圆:

 

两圆方程组联立后,求方程组的解

1) 圆1方程 - 圆2方程:

 

2) 把x=a*y+b代入圆1方程:

 

3) 利用一元二次方程求根公式,求出x, y

a, b, A, B, C, D1, E1, F1这些都可根据圆心和半径求出,所以x, y也能求出来了。

 

特殊情况

对于圆心连线与y轴平型时,即:x1==x2,

会出现分母为0的情况,遇到这样的情况,可以用下面的方式:

1) 圆1方程-圆2方程后,求y

 

2) 把y=a*x+b代入圆1方程: 

 

3) 利用一元二次方程求根公式,求出x, y

 

效果

 

//求两圆交点 - 圆方程方式
public static bool IsTwoCircleIntersect2(Vector2 c1, float r1, Vector2 c2, float r2, out Vector2 p1, out Vector2 p2)
{
    p1 = Vector2.zero;
    p2 = Vector2.zero;

    float D1 = -2 * c1.x;
    float E1 = -2 * c1.y;
    float F1 = c1.x * c1.x + c1.y * c1.y - r1 * r1;

    float D2 = -2 * c2.x;
    float E2 = -2 * c2.y;
    float F2 = c2.x * c2.x + c2.y * c2.y - r2 * r2;

    if (Mathf.Abs(c1.x - c2.x) < Mathf.Abs(c1.y - c2.y)) //1)圆心连线与x轴平行的情况, 2)以x,y差值大的方向来计算精度更高
    {
        float a = (D2 - D1) / (E1 - E2);
        float b = (F2 - F1) / (E1 - E2);

        float A = a * a + 1;
        float B = 2 * a * b + E1 * a + D1;
        float C = b * b + E1 * b + F1;

        float B4AC = B * B - 4 * A * C;
        if (B4AC < 0)
            return false;

        float tempSqrt = Mathf.Sqrt(B4AC);
        float temp2A = 2 * A;

        float x1 = (-B + tempSqrt) / temp2A;
        float y1 = a * x1 + b;

        p1 = new Vector2(x1, y1);

        if (B4AC > 0) //2个交点
        {
            float x2 = (-B - tempSqrt) / temp2A;
            float y2 = a * x2 + b;
            p2 = new Vector2(x2, y2);
        }
        else //1个交点
        {
            p2 = p1;
        }
    }
    else
    {
        float a = (E2 - E1) / (D1 - D2);
        float b = (F2 - F1) / (D1 - D2);

        float A = a * a + 1;
        float B = 2 * a * b + D1 * a + E1;
        float C = b * b + D1 * b + F1;

        float B4AC = B * B - 4 * A * C;
        if (B4AC < 0)
            return false;

        float tempSqrt = Mathf.Sqrt(B4AC);
        float temp2A = 2 * A;

        float y1 = (-B + tempSqrt) / temp2A;
        float x1 = a * y1 + b;

        p1 = new Vector2(x1, y1);

        if (B4AC > 0) //2个交点
        {
            float y2 = (-B - tempSqrt) / temp2A;
            float x2 = a * y2 + b;
            p2 = new Vector2(x2, y2);
        }
        else //1个交点
        {
            p2 = p1;
        }
    }

    return true;
}

 

测试代码

using System;
using UnityEditor;
using UnityEngine;

public class CircleTest : CollideTestBase
{

    public Transform m_C1; //圆1中心点
    [Range(0.1f, 99)]
    public float m_R1 = 0.5f; //圆1半径

    public Transform m_C2; //圆2中心点
    [Range(0.1f, 99)]
    public float m_R2 = 0.5f; //圆2半径

    public Vector2 m_Point1; //交点1
    public Vector2 m_Point2; //交点2

    private Vector3 m_PointSize = new Vector3(0.02f, 0.02f, 0.01f);

    void Update()
    {
        m_IsIntersect = false;
        m_Point1 = Vector3.zero;
        m_Point2 = Vector3.zero;
        if (m_C1 && m_R1 > 0 && m_C2 && m_R2 > 0)
        {
            var t1 = DateTime.Now;
            switch (m_ApiType)
            {
            case 1:
                for (int i = 0; i < m_InvokeCount; ++i)
                    m_IsIntersect = Shape2DHelper.IsCircleIntersect2(m_C1.position, m_R1, m_C2.position, m_R2, out m_Point1, out m_Point2);
                break;
            }

            CheckTimeCost(t1, 1);
        }
    }

    private void OnDrawGizmos()
    {
        if (m_C1 && m_R1 > 0 && m_C2 && m_R2 > 0)
        {
            if (m_IsIntersect)
            {
                Gizmos.color = Color.red;
                DrawCircle(m_C1.position, m_R1);
                DrawCircle(m_C2.position, m_R2);
                Gizmos.DrawLine(m_C1.position, m_C2.position);

                Gizmos.color = Color.green;
                DrawPoint(m_Point1, ref m_PointSize);
                DrawPoint(m_Point2, ref m_PointSize);

                Gizmos.DrawLine(m_Point1, m_Point2);
                Gizmos.DrawLine(m_Point1, m_C1.position);
                Gizmos.DrawLine(m_Point2, m_C2.position);

                Gizmos.color = Color.white;
            }
            else
            {
                DrawCircle(m_C1.position, m_R1);
                DrawCircle(m_C2.position, m_R2);
                Gizmos.DrawLine(m_C1.position, m_C2.position);
            }
        }
    }

    private static void DrawCircle(Vector2 c, float r)
    {
        int segmentCount = 30;
        float radDelta = Mathf.PI * 2 / segmentCount;
        float rad = 0;
        var lastPoint = new Vector2(r * Mathf.Cos(rad), r * Mathf.Sin(rad));
        for (int i = 1; i <= segmentCount; ++i)
        {
            rad += radDelta;
            var curPoint = new Vector2(r * Mathf.Cos(rad), r * Mathf.Sin(rad));
            Gizmos.DrawLine(c + lastPoint, c + curPoint);
            lastPoint = curPoint;
        }
    }

    private static void DrawPoint(Vector2 point, ref Vector3 pointSize)
    {
        float handleSize = HandleUtility.GetHandleSize(point) * 0.08f;
        pointSize.Set(handleSize, handleSize, 0.01f);
        Gizmos.DrawCube(point, pointSize);
    }

}

 

圆的相交情况参考

1) 没有交点

 

2) 一个交点

 

3) 两个交点

 

参考

求两个圆交点的坐标-解析表达式推导及编程_两个圆的交点坐标公式-CSDN博客

两个圆的交点怎么求? - 知乎 (zhihu.com)

怎样求解一元二次方程(四种)-百度经验 (baidu.com)

圆的一般方程_百度百科 (baidu.com)

 

c语言--求两圆交点_c语言两圆交点-CSDN博客

求两圆相交的交点的方法 - 简书 (jianshu.com)

计算几何之圆与圆的交点 - 知乎 (zhihu.com)

www.icxbk.com

 

posted @ 2023-11-17 00:52  yanghui01  阅读(188)  评论(0编辑  收藏  举报