我在理解ccw(逆时针)算法时遇到了一些麻烦:
int ccw (Point P0, Point P1, Point P2) {
dx1 = P1.x - P0.x;
dx2 = P2.x - P0.x;
dy1 = P1.y - P0.y;
dy2 = P1.y - P0.y;
if (dy1 * dx2 > dy2 * dx1) return -1;
if (dx1 * dy2 > dy1 * dx2) return 1;
if ((dx1 * dx2 < 0) || (dy1 * dy2 < 0)) return 1;
if ((dx1 * dx1 + dy1 * dy1) < (dx2 * dx2 + dy2 * dy2)) return -1;
return 0;
}
此代码用于查看两条线是否相交:
bool intersect (Vector2D l1, Vector2D l2) {
return (((ccw(l1.start, l1.end, l2.start) * ccw(l1.start, l1.end, l2.end)) <= 0)
&& ((ccw(l2.start, l2.end, l1.start) * ccw(l2.start, l2.end, l1.start)) <= 0))
}
我可以理解intersect函数里面的代码,但我真的不明白ccw函数里面的代码。
为什么不使用交叉产品?
答案 0 :(得分:4)
ccw
函数中的代码是以相当临时的方式编写的,但它确实使用了有时非常非正式地称为跨产品的2D版本的代码。对于两个向量(dx1, dy1)
和(dx2, dy2)
,该产品被定义为等于
CP = dx1 * dy2 - dx2 * dy1;
(在形式上正确的术语中,CP
实际上是向量(dx1, dy1, 0)
和(dx2, dy2, 0)
的经典3D交叉积的带符号幅度。)Obovisly,该值只是一个标量( dot )乘积,其中一个向量被其垂直替换。
如果CP
的值为正,则从(dx1, dy1)
到(dx2, dy2)
的最短径向扫描逆时针旋转。负CP
表示顺时针扫描。 CP
中的零表示共线矢量。 (所有这些都假设Y轴朝上,X轴朝右。)
显然,CP > 0
条件相当于dx1 * dy2 > dx2 * dy1
条件,而CP < 0
相当于dx1 * dy2 < dx2 * dy1
。这正是您的ccw
函数在前两个if
中检查的内容。
剩余的if
正在处理共线情况。
如果向量指向相反方向(由第三个if
检测到),即当P0
位于P1
和P2
之间时,该函数始终返回1
,表示逆时针排序。好吧,我想这只是代码作者所采用的惯例。
最后,如果两个向量指向同一方向,即P0
位于P1-P2
段之外,则决策基于向量长度(第四个if
)。如果P1
比P2
更接近P0
,则会报告顺时针排序。否则,如果P2
更近,则报告逆时针排序。这也只是代码作者所采用的惯例。
并且,根据其余代码判断,它不是关于两个行的交集。它是关于两个段的交集。