有了一个点列表,我如何确定它们是否是顺时针顺序的?

例如:

point[0] = (5,0)
point[1] = (6,4)
point[2] = (4,5)
point[3] = (1,5)
point[4] = (1,0)

会说它是逆时针的(对某些人来说是逆时针的)


当前回答

找出y最小的顶点(如果有平手,则x最大)。假设顶点是A,列表中的前一个顶点是B,列表中的下一个顶点是c。现在计算AB和AC的叉乘的符号。


引用:

如何确定一个简单多边形的方向?在 常见问题:计算机。图形。算法。 维基百科的曲线定位。

其他回答

求出这些点的质心。

假设有直线从这个点到你们的点。

求line0 line1的两条直线夹角

而不是直线1和直线2

...

...

如果这个角是单调递增的,而不是逆时针递增的,

如果是单调递减,则是顺时针递减

Else(它不是单调的)

你不能决定,所以这是不明智的

从其中一个顶点开始,计算每条边对应的角度。

第一个和最后一个将是零(所以跳过它们);对于其余部分,角度的正弦值将由归一化与(点[n]-点[0])和(点[n-1]-点[0])的单位长度的叉乘给出。

如果这些值的和是正的,那么你的多边形是逆时针方向绘制的。

c#代码实现lhf的答案:

// https://en.wikipedia.org/wiki/Curve_orientation#Orientation_of_a_simple_polygon
public static WindingOrder DetermineWindingOrder(IList<Vector2> vertices)
{
    int nVerts = vertices.Count;
    // If vertices duplicates first as last to represent closed polygon,
    // skip last.
    Vector2 lastV = vertices[nVerts - 1];
    if (lastV.Equals(vertices[0]))
        nVerts -= 1;
    int iMinVertex = FindCornerVertex(vertices);
    // Orientation matrix:
    //     [ 1  xa  ya ]
    // O = | 1  xb  yb |
    //     [ 1  xc  yc ]
    Vector2 a = vertices[WrapAt(iMinVertex - 1, nVerts)];
    Vector2 b = vertices[iMinVertex];
    Vector2 c = vertices[WrapAt(iMinVertex + 1, nVerts)];
    // determinant(O) = (xb*yc + xa*yb + ya*xc) - (ya*xb + yb*xc + xa*yc)
    double detOrient = (b.X * c.Y + a.X * b.Y + a.Y * c.X) - (a.Y * b.X + b.Y * c.X + a.X * c.Y);

    // TBD: check for "==0", in which case is not defined?
    // Can that happen?  Do we need to check other vertices / eliminate duplicate vertices?
    WindingOrder result = detOrient > 0
            ? WindingOrder.Clockwise
            : WindingOrder.CounterClockwise;
    return result;
}

public enum WindingOrder
{
    Clockwise,
    CounterClockwise
}

// Find vertex along one edge of bounding box.
// In this case, we find smallest y; in case of tie also smallest x.
private static int FindCornerVertex(IList<Vector2> vertices)
{
    int iMinVertex = -1;
    float minY = float.MaxValue;
    float minXAtMinY = float.MaxValue;
    for (int i = 0; i < vertices.Count; i++)
    {
        Vector2 vert = vertices[i];
        float y = vert.Y;
        if (y > minY)
            continue;
        if (y == minY)
            if (vert.X >= minXAtMinY)
                continue;

        // Minimum so far.
        iMinVertex = i;
        minY = y;
        minXAtMinY = vert.X;
    }

    return iMinVertex;
}

// Return value in (0..n-1).
// Works for i in (-n..+infinity).
// If need to allow more negative values, need more complex formula.
private static int WrapAt(int i, int n)
{
    // "+n": Moves (-n..) up to (0..).
    return (i + n) % n;
}

The cross product measures the degree of perpendicular-ness of two vectors. Imagine that each edge of your polygon is a vector in the x-y plane of a three-dimensional (3-D) xyz space. Then the cross product of two successive edges is a vector in the z-direction, (positive z-direction if the second segment is clockwise, minus z-direction if it's counter-clockwise). The magnitude of this vector is proportional to the sine of the angle between the two original edges, so it reaches a maximum when they are perpendicular, and tapers off to disappear when the edges are collinear (parallel).

因此,对于多边形的每个顶点(点),计算两条相邻边的叉乘大小:

Using your data:
point[0] = (5, 0)
point[1] = (6, 4)
point[2] = (4, 5)
point[3] = (1, 5)
point[4] = (1, 0)

把边连续地标为 edgeA是从point0到point1的段 点1到点2之间的edgeB ... edgeE在point4和point0之间。

那么顶点A (point0)在两者之间 edgeE[从点4到点0] 从point0到' point1'

这两条边本身就是向量,它们的x坐标和y坐标可以通过减去它们的起点和终点的坐标来确定:

edgeE = point0 - point4 = (1,0) - (5,0) = (- 4,0) and edgeA = point1 - point0 = (6,4) - (1,0) = (5,4) and

这两个相邻边的外积是用下面矩阵的行列式来计算的,这个矩阵是通过将两个向量的坐标放在表示三个坐标轴的符号(i, j, & k)下面来构造的。第三个(零)值坐标在那里,因为外积概念是一个三维结构,所以我们将这些2-D向量扩展到3-D,以便应用外积:

 i    j    k 
-4    0    0
 1    4    0    

假设所有的叉乘都产生一个垂直于两个向量相乘平面的向量,上面矩阵的行列式只有一个k(或z轴)分量。 计算k轴或z轴分量大小的公式为 A1 *b2 - a2*b1 = -4* 4 - 0* 1 = -16

这个值的大小(-16)是两个原始向量夹角的正弦值,乘以两个向量大小的乘积。 实际上,它值的另一个公式是 A X B(叉乘)= |A| * |B| * sin(AB)。

为了得到角度的大小你需要用这个值(-16)除以两个向量大小的乘积。

|A| * |B| = 4 *根号(17)= 16.4924…

所以sin(AB) = -16 / 16.4924 = -.97014…

这是一个度量顶点后的下一段是否向左或向右弯曲,以及弯曲的程度。不需要取arcsin函数。我们只关心它的大小,当然还有它的符号(正的还是负的)!

对闭合路径周围的其他4个点都这样做,并将每个顶点的计算值相加。

如果最终的和是正的,就顺时针,负的,逆时针。

一个计算上更简单的方法,如果你已经知道多边形内的一个点:

从原始多边形中选择任意线段,按此顺序选择点及其坐标。 加上一个已知的“内部”点,形成一个三角形。 根据以上三点计算CW或CCW。