相交 - 点是否在线段上 (向量叉乘和点乘方式判断)
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)