18

编辑:我用答案更新了程序,效果很好!

我正在制作一个程序(请随意尝试),让用户绘制多边形,然后对其进行三角剖分。他们可以单击添加顶点并按 Enter 进行三角测量。无论如何,只要我告诉它这些点是以顺时针还是逆时针方式绘制的,该算法就可以正常工作(现在我将它设置为仅适用于顺时针多边形)。几天来我一直试图弄清楚这一点,但不知道如何确定这些点是顺时针还是逆时针。尝试使用前面提到的程序绘制形状以获得更好的想法,您可以更好地体验我正在谈论的内容,而不是我试图解释它。

以下是点的定义方式:

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var vertices = [];

// Called on click
function addPoint(mouseX, mouseY) {
    vertices.push(new Point(mouseX, mouseY));
}

这是一个顺时针多边形的图像:

顺时针多边形

这是逆时针多边形的图像:

逆时针多边形

如果您能帮我弄清楚如何确定点的“顺时针方向”,我将不胜感激!

4

5 回答 5

29

Compute the polygon area using the shoelace formula, but without the absolute value sign. If the result is positive, the points are ordered counterclockwise, and if negative - clockwise.

function polygonArea() { 
    var area = 0;
    for (var i = 0; i < vertices.length; i++) {
        j = (i + 1) % vertices.length;
        area += vertices[i].x * vertices[j].y;
        area -= vertices[j].x * vertices[i].y;
    }
    return area / 2;
}
var clockwise = polygonArea() > 0;
于 2013-01-24T16:52:27.100 回答
1

一般的想法是看一下多边形的凸包并从那里猜测方向。但是,我认为你不需要建造整个船体来找到方向,而只需要建造一个属于它的部分。

所以:

  • 找到多边形的两个点,使所有其他点都在这条线的一侧。
  • 如果所有点都在左侧(只需检查其中一个点),则为逆时针。如果它们在右侧,则为顺时针方向。

示例

上图:4-5 让右图,5-11 让右图,... 下图:6-7 让左图,7-14 让图上左边, ...

Warning: While "walking" on your polygon, do not restart the numeration, otherwise it will be wrong. On the top figure, 4-(n-1) let the figure on the left!

于 2013-01-24T16:40:56.387 回答
1

Your intuitive definition of clockwisedness is not well defined. For example, If I draw a horseshoe:

   /---a-b--\
  /   _d_c_  \
 /  /       \ \
 | |        | |
 | |        | |
  \ \       / /
   \ \     / /
    --     --

If 0 = a < b < b < d and I look at a and b I would conclude from your description that the shape has been drawn clockwise, but if 0 = c < d < a < b I would conclude that the shape has been drawn anticlockwise. Since both of these scenarios involve the same direction in which the points were drawn, just from different starting points, I can only conclude that your definition is lacking.

The horseshoe I drew isn't the best; the idea is that it is almost a circle with just a small hole at the bottom, to allow the other side to be drawn in the opposite direction.

If you are interested in defining things more strictly, then I suggest something along the following lines:

Considering any finite simple polygon as separating the plane into two distinct areas (one finite and one infinite), we can always consider the finite area to be the interior of the polygon. In such a scenario we define a vertex ordering to be clockwise iff the order of the points runs with the exterior along its right-hand side. This is called curve orientation.

Once you have this more solid definition, implementation can be as simple as counting the winding number. Take the midpoint of any ordered pair, say 0 and 1, take a line segment to the right of the ordered pair (at any angle, say perpendicular), and count how many intersections it has with other line segments: The curve is clockwise iff the number is odd.

This is simple to implement, linear in time O(n), and adds constant space O(1).

于 2013-01-24T16:43:19.787 回答
1

如果有人使用three.js,ShapeUtils它会附带一个内置isClockWise方法,该方法在内部使用该area方法来确定计算区域的符号。

isClockWise: function ( pts ) {

    return ShapeUtils.area( pts ) < 0;

}

ShapeUtils.isClockWise方法可以在这里找到。

area: function ( contour ) {

    var n = contour.length;
    var a = 0.0;

    for ( var p = n - 1, q = 0; q < n; p = q ++ ) {

        a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;

    }

    return a * 0.5;

},

ShapeUtils.area方法可以在这里找到。

于 2017-01-23T15:34:06.917 回答
0

这是一个专门用于 OpenLayers 的函数函数。如您所见,顺时针多边形的条件是面积<0 ,此参考确认它。

function IsClockwise(feature)
{
if(feature.geometry==null)return -1;
var vertices=feature.geometry.getVertices();
var area=0;
for (var i = 0; i < (vertices.length); i++) 
    {
    j = (i + 1) % vertices.length;
    area += vertices[i].x * vertices[j].y;
    area -= vertices[j].x * vertices[i].y;
    // console.log(area);
    }
return (area < 0);
}
于 2014-11-18T10:45:12.377 回答