我实现了两种算法:一种是@UriGoren发布的(只使用整数计算,做了一些小改进),另一种是@RoryDaulton的。我用Java编写了这些算法。由于我的多边形是闭合的,所以这两个算法都认为第二个角是凹的,而实际上它是凸的。因此,我进行了修改以避免这种情况。我的方法还使用了一个基础索引(可以是0或非0值)。
以下是我的测试顶点:
int []x = {0,100,200,200,100,0,0};
int []y = {50,0,50,200,50,200,50};
int []x = {0,100,200,100,0,0};
int []y = {50,0,50,200,200,50};
现在,让我们来谈谈算法:
private boolean isConvex1(int[] x, int[] y, int base, int n)
{
final double TWO_PI = 2 * Math.PI;
if (n <= 3) return true;
if (x[base] == x[n-1] && y[base] == y[n-1])
n--;
int old_x = x[n-2], old_y = y[n-2];
int new_x = x[n-1], new_y = y[n-1];
double new_direction = Math.atan2(new_y - old_y, new_x - old_x), old_direction;
double angle_sum = 0.0, orientation=0;
for (int i = 0; i < n; i++)
{
old_x = new_x; old_y = new_y; old_direction = new_direction;
int p = base++;
new_x = x[p]; new_y = y[p];
new_direction = Math.atan2(new_y - old_y, new_x - old_x);
if (old_x == new_x && old_y == new_y)
return false;
double angle = new_direction - old_direction;
if (angle <= -Math.PI)
angle += TWO_PI;
else if (angle > Math.PI)
angle -= TWO_PI;
if (i == 0)
{
if (angle == 0.0) return false;
orientation = angle > 0 ? 1 : -1;
}
else
if (orientation * angle <= 0)
return false;
angle_sum += angle;
}
return Math.abs(Math.round(angle_sum / TWO_PI)) == 1;
}
现在来自Uri Goren的最新消息
private boolean isConvex2(int[] x, int[] y, int base, int n)
{
if (n < 4)
return true;
boolean sign = false;
if (x[base] == x[n-1] && y[base] == y[n-1]) // if its a closed polygon, ignore last vertex
n--;
for(int p=0; p < n; p++)
{
int i = base++;
int i1 = i+1; if (i1 >= n) i1 = base + i1-n;
int i2 = i+2; if (i2 >= n) i2 = base + i2-n;
int dx1 = x[i1] - x[i];
int dy1 = y[i1] - y[i];
int dx2 = x[i2] - x[i1];
int dy2 = y[i2] - y[i1];
int crossproduct = dx1*dy2 - dy1*dx2;
if (i == base)
sign = crossproduct > 0;
else
if (sign != (crossproduct > 0))
return false;
}
return true;
}