CCW 算法说明

Explanation of ccw algorithm

本文关键字:说明 算法 CCW      更新时间:2023-10-16

我在理解 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))
}

我可以理解相交函数中的代码,但我并不真正理解 ccw 函数中的代码。

为什么不使用交叉乘积?

函数内部的代码ccw以一种相当临时的方式编写,但它确实使用了有时非常非正式地称为交叉乘积的 2D 版本。对于两个向量(dx1, dy1)(dx2, dy2),乘积定义为标量值等于

CP = dx1 * dy2 - dx2 * dy1;

(在形式正确的术语中,CP实际上是向量(dx1, dy1, 0)(dx2, dy2, 0)的经典 3D 交叉乘积的符号大小。显然,该值只是一个标量((积,其中一个向量被其垂直方向所取代。

如果 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位于P1P2之间时,该函数总是返回1,表示逆时针排序。嗯,我想这只是代码作者假设的约定。

最后,如果两个向量指向同一方向,即当P0位于P1-P2段之外时,则决策基于向量长度(第四if(。如果P1接近P0 P2,则报告顺时针顺序。否则,如果P2更接近,则报告逆时针顺序。这也只是代码作者假设的约定。

而且,从代码的其余部分来看,它不是关于两的交集。它是关于两个部分的交集。