相交 - 点是否在线段上 (向量叉乘和点乘方式判断)

1) 如果点在以线段ab为对角线的矩形外, 肯定不在线段上

2) 点p和线段端点a或b重叠时, 在线段上

3) ap和ab的夹角为0度,则点在线段上; 否则不在线段上

 

 

叉乘判断

//点是否在线段上
public static bool IsPointOnSegment(Vector2 p, Vector2 a, Vector2 b)
{
    //点在以线段ab为对角线的矩形外
    if ((p.x - a.x) * (p.x - b.x) > 0 || (p.y - a.y) * (p.y - b.y) > 0)
        return false;

    var ap = p - a;
    var ab = b - a;
    var cross = V2Cross(ref ap, ref ab); //|ap|*|ab|*sin(a), sin(0)=0
    //叉乘结果如果为0, 说明平行或共线
    if (Mathf.Approximately(cross, 0))
        return true;

    return false;
}

 

点乘判断

速度比叉乘慢一点,因为多了几次平方计算

//点是否在线段上
public static bool IsPointOnSegment2(Vector2 p, Vector2 a, Vector2 b)
{
    //点在以线段ab为对角线的矩形外
    if ((p.x - a.x) * (p.x - b.x) > 0 || (p.y - a.y) * (p.y - b.y) > 0)
        return false;

    var ap = p - a;
    var ab = b - a;
    float dot = Vector2.Dot(ap, ab); //|ap|*|ab|*cos(夹角), cos(0)=1
    float sqrDot = dot * dot;
    if (Mathf.Approximately(sqrDot, ap.sqrMagnitude * ab.sqrMagnitude))
        return true;

    return false;
}

 

点和线段的位置关系

1-1) 共线(p在中间)

1-2) 共线(p在两侧)

 

2) 不共线

  

 

效果

 

测试代码

using System;
using UnityEngine;

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

    public Transform m_P;

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

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

            case 2:
                for (int i = 0; i < m_InvokeCount; ++i)
                    m_IsIntersect = Shape2DHelper.IsPointOnSegment2(m_P.position, m_A.position, m_B.position);
                break;
            }

            CheckTimeCost(t1, 2);        
        }
    }

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

}

 

参考

【数学基础】玩法常用几何计算汇总 - 知乎 (zhihu.com)

点是否在线段上 - 湫叶 - 博客园 (cnblogs.com)

 

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