Algorithm 如何有效地确定多边形是凸多边形、非凸多边形还是复杂多边形?
从手册页中:Algorithm 如何有效地确定多边形是凸多边形、非凸多边形还是复杂多边形?,algorithm,geometry,polygon,computational-geometry,xlib,Algorithm,Geometry,Polygon,Computational Geometry,Xlib,从手册页中: 如果形状复杂,则路径可能自相交。请注意,路径中的连续重合点不被视为自相交 如果形状为凸,则对于多边形内的每对点,连接它们的线段不与路径相交。如果客户端知道,指定凸面可以提高性能。如果为非凸路径指定凸,则图形结果未定义 如果形状为非凸,则路径不自相交,但形状并非完全凸。如果客户知道,指定非凸而不是复杂可以提高性能。如果为自交路径指定非凸,则图形结果未定义 我在fillXFillPolygon中遇到性能问题,正如手册页所示,我要采取的第一步是指定多边形的正确形状。为了安全起见,我目
- 如果
复杂,则路径可能自相交。请注意,路径中的连续重合点不被视为自相交形状
- 如果
为凸,则对于多边形内的每对点,连接它们的线段不与路径相交。如果客户端知道,指定凸面可以提高性能。如果为非凸路径指定凸,则图形结果未定义形状
- 如果
为非凸,则路径不自相交,但形状并非完全凸。如果客户知道,指定非凸而不是复杂可以提高性能。如果为自交路径指定非凸,则图形结果未定义形状
XFillPolygon
中遇到性能问题,正如手册页所示,我要采取的第一步是指定多边形的正确形状。为了安全起见,我目前正在使用Complex
有没有有效的算法来确定多边形(由一系列坐标定义)是凸的、非凸的还是复杂的?这里有一个测试来检查多边形是否凸 考虑沿多边形的每一组三个点。如果每个角度小于等于180度,则有一个凸多边形。当你计算出每个角度时,也要保持一个180度的总角度。对于凸多边形,总计为360 此测试以O(n)时间运行
另外,请注意,在大多数情况下,这种计算只需执行一次即可节省—大多数情况下,您需要处理一组多边形,这些多边形不会一直变化。您可以使事情比礼品包装算法简单得多。。。这是一个很好的答案,当你有一组点,没有任何特定的边界,需要找到凸包
相比之下,考虑多边形不是自相交的情况,它由一组列表中的点组成,其中连续点形成边界。在这种情况下,确定多边形是否为凸多边形要容易得多(而且您也不必计算任何角度):
对于多边形的每一对连续边(每三组点),计算由指向点的边按递增顺序定义的向量的叉积的z分量。取这些向量的叉积: given p[k], p[k+1], p[k+2] each with coordinates x, y:
dx1 = x[k+1]-x[k]
dy1 = y[k+1]-y[k]
dx2 = x[k+2]-x[k+1]
dy2 = y[k+2]-y[k+1]
zcrossproduct = dx1*dy2 - dy1*dx2
如果叉积的z分量全部为正或全部为负,则多边形为凸多边形。否则多边形是非凸的
如果有N个点,确保计算N个叉积,例如,确保使用三元组(p[N-2],p[N-1],p[0])和(p[N-1],p[0],p[1])
如果多边形是自相交的,则即使其定向角都在同一方向上,在这种情况下,上述方法不会产生正确的结果。要测试多边形是否为凸多边形,多边形的每个点都应与每条线平齐或在每条线后平齐 下面是一个示例图片:
以下Java函数/方法是中所述算法的实现
public boolean isConvex()
{
如果(_顶点.size()<4)
返回true;
布尔符号=假;
int n=_顶点.size();
对于(int i=0;i0;
else if(符号!=(zcrossproduct>0))
返回false;
}
返回true;
}
只要顶点按顺序排列(顺时针或逆时针),并且没有自交边(即,它仅适用于)该算法就可以工作 将Uri的代码改编成matlab。希望这能有所帮助 请注意,Uri的算法只适用于简单多边形!所以,一定要先测试多边形是否简单
% M [ x1 x2 x3 ...
% y1 y2 y3 ...]
% test if a polygon is convex
function ret = isConvex(M)
N = size(M,2);
if (N<4)
ret = 1;
return;
end
x0 = M(1, 1:end);
x1 = [x0(2:end), x0(1)];
x2 = [x0(3:end), x0(1:2)];
y0 = M(2, 1:end);
y1 = [y0(2:end), y0(1)];
y2 = [y0(3:end), y0(1:2)];
dx1 = x2 - x1;
dy1 = y2 - y1;
dx2 = x0 - x1;
dy2 = y0 - y1;
zcrossproduct = dx1 .* dy2 - dy1 .* dx2;
% equality allows two consecutive edges to be parallel
t1 = sum(zcrossproduct >= 0);
t2 = sum(zcrossproduct <= 0);
ret = t1 == N || t2 == N;
end
%M[x1 x2 x3。。。
%y1 y2 y3…]
%测试多边形是否为凸多边形
函数ret=isConvex(M)
N=尺寸(M,2);
如果(N=0);
t2=sum(zcrossproduct此方法适用于简单多边形(无自交边),假设顶点按顺序排列(顺时针或逆时针)
对于顶点数组:
vertices = [(0,0),(1,0),(1,1),(0,1)]
// concave
int []x = {0,100,200,200,100,0,0};
int []y = {50,0,50,200,50,200,50};
// convex
int []x = {0,100,200,100,0,0};
int []y = {50,0,50,200,200,50};
下面的python
实现检查所有交叉乘积的z
组件是否具有相同的符号
def zCrossProduct(a,b,c):
return (a[0]-b[0])*(b[1]-c[1])-(a[1]-b[1])*(b[0]-c[0])
def isConvex(vertices):
if len(vertices)<4:
return True
signs= [zCrossProduct(a,b,c)>0 for a,b,c in zip(vertices[2:],vertices[1:],vertices)]
return all(signs) or not any(signs)
def ZCROSS产品(a、b、c):
返回(a[0]-b[0])*(b[1]-c[1])-(a[1]-b[1])*(b[0]-c[0])
def isConvex(顶点):
如果zip中a、b、c的len(顶点)为0(顶点[2:],顶点[1:],顶点)]
返回所有(标志)或不返回任何(标志)
当你搜索“确定凸多边形”时,这个问题现在是Bing或Google的第一项。然而,没有一个答案是足够好的
这个(现已删除)的工作原理是检查一组无序的点是否可以变成凸多边形,但这不是OP要求的。他要求提供一种方法来检查给定的多边形是否是凸多边形。(计算机科学中的“多边形”通常被定义为[如中所示]作为二维点的有序数组,连续点与一个边以及最后一个点连接到第一个点。)此外,这种情况下的礼品包装算法对于n
点的时间复杂度为O(n^2)
,其中
TWO_PI = 2 * pi
def is_convex_polygon(polygon):
"""Return True if the polynomial defined by the sequence of 2D
points is 'strictly convex': points are valid, side lengths non-
zero, interior angles are strictly between zero and a straight
angle, and the polygon does not intersect itself.
NOTES: 1. Algorithm: the signed changes of the direction angles
from one side to the next side must be all positive or
all negative, and their sum must equal plus-or-minus
one full turn (2 pi radians). Also check for too few,
invalid, or repeated points.
2. No check is explicitly done for zero internal angles
(180 degree direction-change angle) as this is covered
in other ways, including the `n < 3` check.
"""
try: # needed for any bad points or direction changes
# Check for too few points
if len(polygon) < 3:
return False
# Get starting information
old_x, old_y = polygon[-2]
new_x, new_y = polygon[-1]
new_direction = atan2(new_y - old_y, new_x - old_x)
angle_sum = 0.0
# Check each point (the side ending there, its angle) and accum. angles
for ndx, newpoint in enumerate(polygon):
# Update point coordinates and side directions, check side length
old_x, old_y, old_direction = new_x, new_y, new_direction
new_x, new_y = newpoint
new_direction = atan2(new_y - old_y, new_x - old_x)
if old_x == new_x and old_y == new_y:
return False # repeated consecutive points
# Calculate & check the normalized direction-change angle
angle = new_direction - old_direction
if angle <= -pi:
angle += TWO_PI # make it in half-open interval (-Pi, Pi]
elif angle > pi:
angle -= TWO_PI
if ndx == 0: # if first time through loop, initialize orientation
if angle == 0.0:
return False
orientation = 1.0 if angle > 0.0 else -1.0
else: # if other time through loop, check orientation is stable
if orientation * angle <= 0.0: # not both pos. or both neg.
return False
# Accumulate the direction-change angle
angle_sum += angle
# Check that the total number of full turns is plus-or-minus 1
return abs(round(angle_sum / TWO_PI)) == 1
except (ArithmeticError, TypeError, ValueError):
return False # any exception means not a proper convex polygon
if orientation * angle < 0.0: # not both pos. or both neg.
# A square
assert is_convex_polygon( ((0,0), (1,0), (1,1), (0,1)) )
# This LOOKS like a square, but it has an extra point on one of the edges.
assert is_convex_polygon( ((0,0), (0.5,0), (1,0), (1,1), (0,1)) )
// concave
int []x = {0,100,200,200,100,0,0};
int []y = {50,0,50,200,50,200,50};
// convex
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) // Rory Daulton
{
final double TWO_PI = 2 * Math.PI;
// points is 'strictly convex': points are valid, side lengths non-zero, interior angles are strictly between zero and a straight
// angle, and the polygon does not intersect itself.
// NOTES: 1. Algorithm: the signed changes of the direction angles from one side to the next side must be all positive or
// all negative, and their sum must equal plus-or-minus one full turn (2 pi radians). Also check for too few,
// invalid, or repeated points.
// 2. No check is explicitly done for zero internal angles(180 degree direction-change angle) as this is covered
// in other ways, including the `n < 3` check.
// needed for any bad points or direction changes
// Check for too few points
if (n <= 3) return true;
if (x[base] == x[n-1] && y[base] == y[n-1]) // if its a closed polygon, ignore last vertex
n--;
// Get starting information
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;
// Check each point (the side ending there, its angle) and accum. angles for ndx, newpoint in enumerate(polygon):
for (int i = 0; i < n; i++)
{
// Update point coordinates and side directions, check side length
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; // repeated consecutive points
// Calculate & check the normalized direction-change angle
double angle = new_direction - old_direction;
if (angle <= -Math.PI)
angle += TWO_PI; // make it in half-open interval (-Pi, Pi]
else if (angle > Math.PI)
angle -= TWO_PI;
if (i == 0) // if first time through loop, initialize orientation
{
if (angle == 0.0) return false;
orientation = angle > 0 ? 1 : -1;
}
else // if other time through loop, check orientation is stable
if (orientation * angle <= 0) // not both pos. or both neg.
return false;
// Accumulate the direction-change angle
angle_sum += angle;
// Check that the total number of full turns is plus-or-minus 1
}
return Math.abs(Math.round(angle_sum / TWO_PI)) == 1;
}
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;
}