1 float cross(const Point &point0, const Point &point1) 2 { 3 return point0.first * point1.second - point0.second * point1.first; 4 } 5 6 bool isLineIntersect(const Point &point0, const Point &point1, const Point &point2, const Point &point3) 7 { 8 auto value0 = cross( 9 std::make_pair(point1.first - point0.first, point1.second - point0.second), 10 std::make_pair(point3.first - point0.first, point3.second - point0.second)); 11 auto value1 = cross( 12 std::make_pair(point1.first - point0.first, point1.second - point0.second), 13 std::make_pair(point2.first - point0.first, point2.second - point0.second)); 14 auto value2 = cross( 15 std::make_pair(point3.first - point2.first, point3.second - point2.second), 16 std::make_pair(point0.first - point2.first, point0.second - point2.second)); 17 auto value3 = cross( 18 std::make_pair(point3.first - point2.first, point3.second - point2.second), 19 std::make_pair(point1.first - point2.first, point1.second - point2.second)); 20 return value0 < 0 != value1 < 0 && value2 < 0 != value3 < 0; 21 }
原理很简单,
通过向量叉积可以得到垂直于2个向量的向量.
通过两条线段互相分割, 叉积符号是否不同就可以判断线段是否相交.
例如线段, p0p1, p2p3.
先用p0p1分割p2p3:
p0p1 * p0p2
p0p1 * p0p3
再用p2p3分割p0p1:
p2p3 * p2p0
p2p3 * p2p1
如果
p0p1 * p0p2 < 0 !=p0p1 * p0p3 < 0 &&
p2p3 * p2p0 < 0 != p2p3 * p2p1 < 0
成立则线段相交.
这个问题困扰了我很多年, 我尝试着研究, 因为学识太浅, 无法理解其中的奥秘.
直到我明白了向量计算的含义才焕然大悟.
向量叉积是垂直于2个向量的向量,
在2D坐标系里, 通过2D向量得到叉积是一个3D向量,
这个3D向量垂直于2个2D向量, 脑补一下, 这个3D向量必然平行于z轴.
平行z轴有正负2个方向, 这个方向取决于坐标系是左手还是右手. 向量叉乘是顺时针还是逆时针.
说的有点隐晦, 当理解向量计算之后, 判断线段相交只是一个很简单的问题.
时间: 2024-11-09 06:56:27