【问题标题】:Explanation of ccw algorithmccw算法解释
【发布时间】:2014-10-11 13:54:49
【问题描述】:

我在理解 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 函数里面的代码我不是很懂。

为什么不用叉积?

【问题讨论】:

  • 使用什么的叉积?你不能cross 2d 向量。它仅在 3D 和 7D 空间中定义,AFAIK。
  • @Drop 在二维向量数学中,“叉积”常用于指垂直点积。

标签: c++ ccw


【解决方案1】:

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

的标量值
CP = dx1 * dy2 - dx2 * dy1;

(在形式上正确的术语中,CP 实际上是向量(dx1, dy1, 0)(dx2, dy2, 0) 的经典3D 叉积的有符号幅度。)显然,该值只是一个scalar (dot) 乘积,其中一个向量被它的垂线代替。

如果CP 的值为正,则从(dx1, dy1)(dx2, dy2) 的最短径向扫描为逆时针方向。负数CP 表示顺时针扫掠。 CP 中的零表示共线向量。 (所有这些都假设 Y 轴向上,X 轴向右。)

显然,CP &gt; 0 条件等价于dx1 * dy2 &gt; dx2 * dy1 条件,CP &lt; 0 等价于dx1 * dy2 &lt; dx2 * dy1。这正是您的ccw 函数通过前两个ifs 检查的内容。

剩余的ifs 正在处理共线情况。

如果向量指向相反的方向(由第三个if检测到),即当P0位于P1P2之间时,函数总是返回1,表示逆时针方向订购。好吧,我猜这只是代码作者假设的约定。

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

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

【讨论】:

  • 嗯。这可能是由于语言混乱(此处为德语),但dx1 * dy2 - dx2 * dy1 不是行列式,R2 中的广义交叉产物将是线性函数 R2->R2: [x y] -> [-y x]?? ?
  • @hop:我不否认将dx1 * dy2 - dx2 * dy1 称为“交叉产品”这一事实在术语上是不正确的。但我确实不时在非正式的conetxts中遇到它。 dx1 * dy2 - dx2 * dy1 的值实际上是经典(3D)叉积向量的有符号幅度。这可能是非正式用法的起源。
  • 假设向量在 xy 平面上,它基本上是在计算 3D 中的叉积。它在 wiki 中也有解释 en.wikipedia.org/wiki/Graham_scan
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-11
  • 1970-01-01
相关资源
最近更新 更多