交点 - 求两线段交点2

发布时间 2023-11-23 22:54:11作者: yanghui01

效果

 

会用到的知识

相交 - 两线段是否相交 - yanghui01 - 博客园 (cnblogs.com)

线性代数 - 已知点求直线方程 - yanghui01 - 博客园 (cnblogs.com)

交点 - 两直线交点 - yanghui01 - 博客园 (cnblogs.com)

 

//两线段是否相交
public static bool IsTwoSegmentIntersect2(Vector2 a, Vector2 b, Vector2 c, Vector2 d, out Vector2 point)
{
    //先判断是否相交
    if (Shape2DHelper.IsLineSegmentIntersect(a, b, c, d))
    {
        //因为已经确定线段相交, 那么线段所在直线的交点就是线段交点
        //已知两点求点斜式: k=-(b.y-a.y)/(a.x-b.x), t=-(a.y*b.x-a.x*b.y)/(a.x-b.x)
        float k1 = -(b.y - a.y) / (a.x - b.x);
        float t1 = -(a.y * b.x - a.x * b.y) / (a.x - b.x);

        float k2 = -(d.y - c.y) / (c.x - d.x);
        float t2 = -(c.y * d.x - c.x * d.y) / (c.x - d.x);

        float x = (t1 - t2) / (k2 - k1);
        float y = k1 * x + t1;
        point = new Vector2(x, y);
        return true;
    }

    point = Vector2.zero;
    return false;
}

该函数比IsTwoSegmentIntersect慢,主要涉及5次除法

 

测试代码

using System;
using UnityEditor;
using UnityEngine;

public class SegmentTest : MonoBehaviour
{
    //线段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; //显示交点用

    public int m_ApiType = 1;
    [Range(1, 3999999)]
    public int m_InvokeCount = 1; //用于测试大批量调用时的性能
    public bool m_AutoIcrApiType = false; //自动调用每一个函数, 看看各个函数的执行耗时

    private bool m_IsIntersect;
    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, out m_Point);
                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;
            }

            if (m_InvokeCount > 1 && m_AutoIcrApiType)
            {
                if (m_ApiType < 3)
                    m_ApiType++;
            }

            if (m_InvokeCount > 1)
            {
                var t2 = DateTime.Now;
                var dur = t2 - t1;
                if (dur.TotalMilliseconds >= 100)
                    Debug.Log($"totalMs:{dur.TotalMilliseconds}");
            }
        }
    }

    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);
            }
        }
    }

}