如何判断对象是在连接路径上顺时针还是逆时针运动?


19

假设我们有一个锯齿状的形状:

形状0

两个生物沿着它的轮廓移动。

然后,我们通过拉出拐角来完全平滑形状。

我们得到这个:

光滑

现在很容易看到Orange正在移动CW,而绿色正在移动CCW。如何在不使形状变平滑的情况下知道它们向哪个方向移动?

新图片

在此处输入图片说明


这是我的2美分:i.imgur.com/zrBdw.png
肯德尔·弗雷

Answers:


27

画一条线到无穷远处,计算出您穿过形状的次数(偶数或奇数),而不计算生物所在的线段。然后检查该生物是在该行的左边还是右边。

例

在此示例中,我们将形状交叉两次(均匀),然后转到左侧。该结果直接来自此表:

   # Crosses | even  | odd
  Direction  |       |
-------------+-------+------
    left     | CCW   |  CW
    right    |  CW   | CCW

用伪代码:

x, y = position of creature
vx, vy = direction of creature movement
crossings = 0
for each x1, y1, x2, y2 in shape segments:
    if (x1 < x and x <= x2) or (x2 < x and x <= x1):
        if y - y1 > (x - x1) * (y2 - y1) / (x2 - x1):
            ++crossings
if (crossings & 1) == (vx < 0):
    return CW
else
    return CCW

你包括继续前进的线生物吗?
Ali1S232

@Gajoo:不,因此在第6行使用>而不是> =。我将对此添加注释。但是请注意,您可以包括该行,并且只需反转表内容即可。
sam hocevar

1
我在根据这种方法给出答案和给出答案之间折腾。我很高兴在这里有两种方法。从概念上讲,这是一种更简单且非常优雅的方法,但需要执行线段相交测试,要使其健壮性可能很困难。
特雷弗·鲍威尔

@TrevorPowell是的。寻找最远的边缘可能会造成混淆。我首先根据边缘的最远顶点进行检查,然后通过从形状的中心并通过两个边缘的中心(共享顶点的两个)绘制一条线,然后查看其中一条线是否与另一条边缘交叉穿越这些边缘之一后变为无穷大。它的工作好吗
wolfdawn

5

这取决于您从形状数据结构中可获得的信息,但是沿形状轮廓移动CW的生物将始终在其右侧具有形状的内部,而沿CCW移动的生物将在其轮廓上具有该形状的内部。它的左边。


一个简单得多的解决方案,也是我的第一个想法。
Amplify91

您怎么知道形状的哪个方向?我的意思是沿着形状内部的一条边在您的左侧或右侧。你怎么知道这是哪条路?
Ali1S232

一个非常优雅的解决方案,但通常情况并非如此。想象一下,将甜甜圈压平在桌子上制成二维形状。您可以沿着该形状的边缘行走,将形状的内部保持在左侧,并根据开始的位置顺时针或逆时针旋转。
马克·托马斯

4
  1. 计算形状的中心点。
  2. 从中心选取形状最远的边缘。
    • (拾取最远的边缘可确保您不会从形状的倒凹部分开始,这将导致整个形状的顺时针/逆时针确定向后)
  3. 确定沿该边缘的哪个方向是顺时针方向
    • (一个简单的实现方法是比较从形状中心到选定边缘的每个末端的角度。角度之间的差异的符号将告诉您顺时针还是逆时针)
  4. 从您在步骤2中选择的边缘开始,迭代形状的所有边缘,建立边缘列表。对于每个边,按顺时针顺序存储其两个顶点。
    • (如果形状没有随时间变化,则可以存储此边缘列表以备后用,因此不必在每一帧中执行前四个步骤)
    • (您可能已经有一个边列表。如果这样,则可以将此顺时针顶点顺序存储在同一列表中。)
  5. 要确定实体是顺时针还是逆时针移动:
    • 确定实体沿哪个边移动。
    • 在步骤4中确定的那个边的顺时针开始->结束顶点上,相对于该向量对实体的运动方向进行点积运算。
    • 如果点积的结果是大于零的值,则该实体沿顺时针方向移动。小于零表示逆时针旋转。

非常聪明的答案
wolfdawn,2012年

我有一个小问题?假设他的形状的顶点是从CWW的最左点开始编号的,那么根据您的回答,如何确定从6-> 7或9-> 10(从零开始)的移动是顺时针方向移动的?
Ali1S232

您从最远的边缘开始,然后找出该边缘上的顺时针方向。假设边A是从顶点“ a”到“ b”的顺时针方向。然后,如果我们移到边B(具有顶点“ b”和“ c”),我们知道B从“ b”到“ c”是顺时针方向。同样,边沿C将从'c'到'd'为顺时针方向。一旦我们从一条边上知道了正确的顺时针方向(步骤1-3),就可以沿着形状的边沿该顺时针方向继续,我们就可以为每个边推导出正确的“顺时针”方向,而无需实际查看其边沿的位置,这样凹就可以了
特雷弗·鲍威尔

如何判断边A是从'a'到'b'的顺时针方向还是从'b'到'a'的顺时针方向?我想你错过了那部分。
Ali1S232

@Gajoo这是第3步的括号。也许不是括号,因为这确实是整个过程的关键步骤。
特雷弗·鲍威尔

2

您需要知道定义多边形的方式,顶点围绕多边形的方式。

如果您不知道,可以通过计算多边形的面积来解决:

float Polygon::area() {
    float result = 0.0f;

    for(int a = 0; a < vertexCount; a ++) {
        int b = (a+1) % vertexCount;
        result += vertices[a].x * vertices[b].y;
        result -= vertices[a].y * vertices[b].x;
    }

    return result * .5f;
}

结果的符号(正或负)将告诉您它是顺时针还是逆时针。您需要尝试一下,看看它适合您的方向,因为这取决于您的坐标系。

如果形状是顺时针:

  • 绕着形状前进的生物顺时针旋转,并且
  • 一个生物围绕形状向后逆时针旋转

如果形状是逆时针:

  • 围绕该形状向前移动的生物正在逆时针方向旋转,并且
  • 一个生物围绕形状向后顺时针旋转

0

看来Trevor已经解决了这个问题,但这是我的解决方案:

  1. 计算形状覆盖的面积,这意味着

    area = 0
    foreach (edge in shape)
        area += edge.begin.x * edge.end.y - edge.begin.y * edge.end.x
  2. 使用如上所述计算的面积,您可以轻松判断形状本身是否为顺时针方向。仅当面积小于零时才是顺时针方向。

  3. 检查对象是否以与顶点有序相同的方向或相反的方向移动。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.