交点 - 两线段交点 - 投影法
1) 线段ab的法线上投影
点b的投影为|ob2|,线段cd的端点的投影为:|od2|,|oc2|
1-a) |od2|-|ob2|>0,|oc2|-|ob2|<0
1-b) |od2|-|ob2|>0,|oc2|-|ob2|<0
1-c) |od2|-|ob2|>0,|oc2|-|ob2|>0,肯定不相交
2) 线段cd的法线上投影
点d的投影为|od1|,线段ab的端点的投影为:|oa1|,|ob1|
2-a) |oa1|-|od1|<0,|ob1|-|od1|>0
2-b) |oa1|-|od1|<0,|ob1|-|od1|>0
2-c) |oa1|-|od1|>0,|ob1|-|od1|>0,肯定不相交
所以,同时满足1-a)和2-a)才相交,否则不相交
//两线段交点 - 投影法 public static bool IsTwoSegmentIntersect2(Vector2 a, Vector2 b, Vector2 c, Vector2 d, out Vector2 p) { p = Vector2.zero; var ab = b - a; var cd = d - c; var cross = V2Cross(ref ab, ref cd); //|ab|*|cd|*sin(夹角) if (Mathf.Approximately(cross, 0)) //两线段平行或共线 return false; var abNM = new Vector2(-ab.y, ab.x); //向量ab的法线(左), 非单位向量 float distB2 = Vector2.Dot(b, abNM); //多乘了|ab|的 float distD2 = Vector2.Dot(d, abNM) - distB2; float distC2 = Vector2.Dot(c, abNM) - distB2; if (distD2 * distC2 > 0) return false; var cdNM = new Vector2(-cd.y, cd.x); //向量cd的法线(左) float distD1 = Vector2.Dot(d, cdNM); float distA1 = Vector2.Dot(a, cdNM) - distD1; float distB1 = Vector2.Dot(b, cdNM) - distD1; if (distA1 * distB1 > 0) return false; //计算交点坐标 float len = distD2 / cross; p = d - cd * len; return true; }
参考
【数学基础】玩法常用几何计算汇总 - 知乎 (zhihu.com)