我在理解 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;
}
Run Code Online (Sandbox Code Playgroud)
此代码用于查看两条线是否相交:
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))
}
Run Code Online (Sandbox Code Playgroud)
intersect函数里面的代码我能看懂,但是ccw函数里面的代码我不是很懂。
为什么不使用交叉产品?
ccw函数内部的代码是以一种相当特别的方式编写的,但它确实使用了有时非常非正式地称为 2D 版本的cross product。对于两个向量(dx1, dy1),(dx2, dy2)该乘积被定义为一个标量值,等于
CP = dx1 * dy2 - dx2 * dy1;
Run Code Online (Sandbox Code Playgroud)
(在形式上正确的术语中,CP实际上是向量和的经典 3D 叉积的有符号幅度。)显然,该值只是一个标量(点)积,其中一个向量被其垂直替换。(dx1, dy1, 0)(dx2, dy2, 0)
如果 的值为CP正,则最短的径向扫描从(dx1, dy1)到(dx2, dy2)逆时针方向。负CP表示顺时针扫描。零CP表示共线向量。(所有这些都假设 Y 轴向上,X 轴向右。)
显然,CP > 0condition 等价于dx1 * dy2 > dx2 * dy1condition 并且CP < 0等价于dx1 * dy2 < dx2 * dy1。这正是您的ccw函数通过前两个ifs检查的内容。
其余的ifs 正在处理共线情况。
如果向量指向相反的方向(由第三个 检测到if),即当P0位于P1和之间时P2,函数总是返回1,表示逆时针顺序。好吧,我想这只是代码作者假定的约定。
最后,如果两个向量指向相同的方向,即当P0位于P1-P2线段之外时,决定基于向量长度(第四个if)。如果P1比接近P2到P0,报道顺时针排序。否则,如果P2更近,则报告逆时针排序。这也只是代码作者假定的约定。
而且,从其余的代码来看,这不是关于两条线的交集。它是关于两个线段的交集。