交点 - 两线段(直线)交点 - 直线方程组方式

 

//求两直线交点 - 直线方程组方式
public static bool IsTwoLineIntersect(Vector2 A, Vector2 B, Vector2 C, Vector2 D, out Vector2 point)
{
    point = Vector2.zero;

    /** 1 解线性方程组, 求线段交点. **/
    //a*x+b*y=e
    float a = (B.y - A.y); //AB.y
    float b = (A.x - B.x); //BA.x
    float e = A.x * B.y - A.y * B.x; //A×B
    //c*x+d*y=f
    float c = (C.y - D.y); //DC.y
    float d = (D.x - C.x); //CD.x
    float f = D.x * C.y - D.y * C.x; //D×C

    float detDown = a * d - b * c; //AB×CD

    // 叉乘结果为0, 则平行或共线, 不相交
    if (Mathf.Approximately(detDown, 0)) //float.Epsilon
        return false;

    // 克莱姆法则解出方程组, (x, y)即为交点
    float invDetDown = 1 / detDown;
    float x = (d * e - b * f) * invDetDown;
    float y = (a * f - c * e) * invDetDown;

    point = new Vector2(x, y);
    return true;
}

 

//求两线段交点 - 直线方程组方式
public static bool IsTwoSegmentIntersect3(Vector2 A, Vector2 B, Vector2 C, Vector2 D, out Vector2 point)
{
    if (IsTwoLineIntersect(A, B, C, D, out point))
    {
        float x = point.x;
        float y = point.y;

        if ((x - A.x) * (x - B.x) <= 0 && (y - A.y) * (y - B.y) <= 0 // 交点在线段1上
        && (x - C.x) * (x - D.x) <= 0 && (y - C.y) * (y - D.y) <= 0) // 且交点也在线段2上
        {
            return true;
        }
    }

    point = Vector2.zero;
    return false;
}

 

效果

投影法慢很多

 

测试代码

using System;
using UnityEditor;
using UnityEngine;

public class SegmentTest : CollideTestBase
{
    //线段1的顶点A, B
    public Transform m_A; 
    public Transform m_B;

    //线段2的顶点C, D
    public Transform m_C;
    public Transform m_D;

    public Vector2 m_Point; //显示交点用

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

    void Update()
    {
        m_IsIntersect = false;
        m_Point = Vector2.zero;
        if (m_A && m_B && m_C && m_D)
        {
            var t1 = DateTime.Now;
            switch (m_ApiType)
            {
            case 1:
                for (int i = 0; i < m_InvokeCount; ++i)
                    m_IsIntersect = Shape2DHelper.IsTwoSegmentIntersect(m_A.position, m_B.position, m_C.position, m_D.position);
                break;

            case 2:
                for (int i = 0; i < m_InvokeCount; ++i)
                    m_IsIntersect = Shape2DHelper.IsTwoSegmentIntersect2(m_A.position, m_B.position, m_C.position, m_D.position, out m_Point);
                break;

            case 3:
                for (int i = 0; i < m_InvokeCount; ++i)
                    m_IsIntersect = Shape2DHelper.IsTwoSegmentIntersect3(m_A.position, m_B.position, m_C.position, m_D.position, out m_Point);
                break;
            }

            CheckTimeCost(t1, 3);
        }
    }

    private void OnDrawGizmos()
    {
        if (m_A && m_B && m_C && m_D)
        {
            if (m_IsIntersect)
            {
                Gizmos.color = Color.red;
                Gizmos.DrawLine(m_A.position, m_B.position);
                Gizmos.DrawLine(m_C.position, m_D.position);

                Gizmos.color = Color.green;
                float handleSize = HandleUtility.GetHandleSize(m_Point) * 0.1f;
                m_CubeSize.Set(handleSize, handleSize, 0.01f);
                Gizmos.DrawCube(m_Point, m_CubeSize);

                Gizmos.color = Color.white;
            }
            else
            {
                Gizmos.DrawLine(m_A.position, m_B.position);
                Gizmos.DrawLine(m_C.position, m_D.position);
            }
        }
    }

}

 

参考

求两条线段交点zz - 马语者 - 博客园 (cnblogs.com)

 

posted @ 2023-11-23 22:51  yanghui01  阅读(24)  评论(0编辑  收藏  举报