我不确定如何解决这个问题。我不确定它的任务有多复杂。我的目标是拥有一个生成任何多边形的算法。我唯一的要求是多边形不复杂(即边不相交)。我正在使用Matlab进行数学运算,但欢迎任何抽象的东西。
任何援助/指示?
编辑:
我正在考虑更多可以生成任何多边形的代码,即使这样:
答案 0 :(得分:24)
我采用了@MitchWheat和@ templatetypedef关于在圆圈上采样点的想法,并把它放得更远。
在我的应用程序中,我需要能够控制多边形的奇怪程度,即从常规多边形开始,当我调高参数时,它们变得越来越混乱。基本思路如@templatetypedef所述;每次以一个随机的角度步长绕着圆圈行走,并且在每个步骤中以随机半径放置一个点。在方程式I中,生成角度步长为
其中theta_i和r_i给出每个点相对于中心的角度和半径,U(min,max)从均匀分布中拉出一个随机数,N(mu,sigma)从高斯分布中提取一个随机数和clip(x,min,max)将值阈值化为一个范围。这给了我们两个非常好的参数来控制多边形的多么狂野 - 我称之为不规则的epsilon控制点是否在圆周上均匀地成角度空间,以及我和#sigma 39; ll调用 spikeyness ,它控制点与半径r_ave的圆度有多大差异。如果你将这两个都设置为0,那么你会获得完全规则的多边形,如果你将它们调高,那么多边形会变得更加疯狂。
我在python中快速掀起了这个并得到了这样的东西:
这里是完整的python代码:
import math, random
def generatePolygon( ctrX, ctrY, aveRadius, irregularity, spikeyness, numVerts ) :
'''Start with the centre of the polygon at ctrX, ctrY,
then creates the polygon by sampling points on a circle around the centre.
Randon noise is added by varying the angular spacing between sequential points,
and by varying the radial distance of each point from the centre.
Params:
ctrX, ctrY - coordinates of the "centre" of the polygon
aveRadius - in px, the average radius of this polygon, this roughly controls how large the polygon is, really only useful for order of magnitude.
irregularity - [0,1] indicating how much variance there is in the angular spacing of vertices. [0,1] will map to [0, 2pi/numberOfVerts]
spikeyness - [0,1] indicating how much variance there is in each vertex from the circle of radius aveRadius. [0,1] will map to [0, aveRadius]
numVerts - self-explanatory
Returns a list of vertices, in CCW order.
'''
irregularity = clip( irregularity, 0,1 ) * 2*math.pi / numVerts
spikeyness = clip( spikeyness, 0,1 ) * aveRadius
# generate n angle steps
angleSteps = []
lower = (2*math.pi / numVerts) - irregularity
upper = (2*math.pi / numVerts) + irregularity
sum = 0
for i in range(numVerts) :
tmp = random.uniform(lower, upper)
angleSteps.append( tmp )
sum = sum + tmp
# normalize the steps so that point 0 and point n+1 are the same
k = sum / (2*math.pi)
for i in range(numVerts) :
angleSteps[i] = angleSteps[i] / k
# now generate the points
points = []
angle = random.uniform(0, 2*math.pi)
for i in range(numVerts) :
r_i = clip( random.gauss(aveRadius, spikeyness), 0, 2*aveRadius )
x = ctrX + r_i*math.cos(angle)
y = ctrY + r_i*math.sin(angle)
points.append( (int(x),int(y)) )
angle = angle + angleSteps[i]
return points
def clip(x, min, max) :
if( min > max ) : return x
elif( x < min ) : return min
elif( x > max ) : return max
else : return x
@MateuszKonieczny这里是用于从顶点列表创建多边形图像的代码。
verts = generatePolygon( ctrX=250, ctrY=250, aveRadius=100, irregularity=0.35, spikeyness=0.2, numVerts=16 )
black = (0,0,0)
white=(255,255,255)
im = Image.new('RGB', (500, 500), white)
imPxAccess = im.load()
draw = ImageDraw.Draw(im)
tupVerts = map(tuple,verts)
# either use .polygon(), if you want to fill the area with a solid colour
draw.polygon( tupVerts, outline=black,fill=white )
# or .line() if you want to control the line thickness, or use both methods together!
draw.line( tupVerts+[tupVerts[0]], width=2, fill=black )
im.show()
# now you can save the image (im), or do whatever else you want with it.
答案 1 :(得分:21)
利用MATLAB类DelaunayTri
和TriRep
以及它们用于处理三角网格的各种方法,有一种巧妙的方法可以做你想要的。下面的代码遵循以下步骤来创建任意simple polygon:
生成一些等于所需边数加上软糖因子的随机点。软糖因子确保,无论三角测量的结果如何,我们都应该有足够的面,以便能够将三角形网格修剪成具有所需边数的多边形。
创建点的Delaunay三角剖分,从而得到一个convex polygon,它由一系列三角形面构成。
如果三角剖分的边界具有比期望更多的边缘,则在具有唯一顶点的边缘上选择随机三角形面(即,三角形仅与三角剖分的其余部分共享一条边)。删除此三角形面将减少边界边缘的数量。
如果三角测量边界的边缘少于所需的边缘,或者前一步骤无法找到要移除的三角形,则在边缘上选择一个随机三角形面,该边缘在三角剖分边界上只有一个边缘。删除此三角形面将增加边界边缘的数量。
如果找不到符合上述标准的三角形面,则发出警告,指出无法找到具有所需边数的多边形,并返回当前三角剖分边界的x和y坐标。否则,继续删除三角形面,直到满足所需的边数,然后返回三角剖分边界的x和y坐标。
这是结果函数:
function [x, y, dt] = simple_polygon(numSides)
if numSides < 3
x = [];
y = [];
dt = DelaunayTri();
return
end
oldState = warning('off', 'MATLAB:TriRep:PtsNotInTriWarnId');
fudge = ceil(numSides/10);
x = rand(numSides+fudge, 1);
y = rand(numSides+fudge, 1);
dt = DelaunayTri(x, y);
boundaryEdges = freeBoundary(dt);
numEdges = size(boundaryEdges, 1);
while numEdges ~= numSides
if numEdges > numSides
triIndex = vertexAttachments(dt, boundaryEdges(:,1));
triIndex = triIndex(randperm(numel(triIndex)));
keep = (cellfun('size', triIndex, 2) ~= 1);
end
if (numEdges < numSides) || all(keep)
triIndex = edgeAttachments(dt, boundaryEdges);
triIndex = triIndex(randperm(numel(triIndex)));
triPoints = dt([triIndex{:}], :);
keep = all(ismember(triPoints, boundaryEdges(:,1)), 2);
end
if all(keep)
warning('Couldn''t achieve desired number of sides!');
break
end
triPoints = dt.Triangulation;
triPoints(triIndex{find(~keep, 1)}, :) = [];
dt = TriRep(triPoints, x, y);
boundaryEdges = freeBoundary(dt);
numEdges = size(boundaryEdges, 1);
end
boundaryEdges = [boundaryEdges(:,1); boundaryEdges(1,1)];
x = dt.X(boundaryEdges, 1);
y = dt.X(boundaryEdges, 2);
warning(oldState);
end
以下是一些示例结果:
生成的多边形可以是凸面或concave,但是对于更大数量的所需边,它们几乎肯定是凹的。多边形也是从单位正方形内随机生成的点生成的,因此具有较大边数的多边形通常看起来像具有“方形”边界(例如上面右下方的50边多边形)。要修改此常规边界形状,您可以更改随机选择初始x
和y
点的方式(即从高斯分布等)。
答案 2 :(得分:10)
对于凸出的2D多边形(完全在我的头顶):
生成随机半径R
在Radius R圆周上生成N个随机点
围绕圆圈移动并在圆圈上的相邻点之间绘制直线。
答案 3 :(得分:1)
这是Mike Ounsworth解决方案的Matlab工作端口。我没有为matlab优化它。我可能会稍后更新解决方案。
function [points] = generatePolygon(ctrX, ctrY, aveRadius, irregularity, spikeyness, numVerts)
%{
Start with the centre of the polygon at ctrX, ctrY,
then creates the polygon by sampling points on a circle around the centre.
Randon noise is added by varying the angular spacing between sequential points,
and by varying the radial distance of each point from the centre.
Params:
ctrX, ctrY - coordinates of the "centre" of the polygon
aveRadius - in px, the average radius of this polygon, this roughly controls how large the polygon is, really only useful for order of magnitude.
irregularity - [0,1] indicating how much variance there is in the angular spacing of vertices. [0,1] will map to [0, 2pi/numberOfVerts]
spikeyness - [0,1] indicating how much variance there is in each vertex from the circle of radius aveRadius. [0,1] will map to [0, aveRadius]
numVerts - self-explanatory
Returns a list of vertices, in CCW order.
Website: https://stackoverflow.com/questions/8997099/algorithm-to-generate-random-2d-polygon
%}
irregularity = clip( irregularity, 0,1 ) * 2*pi/ numVerts;
spikeyness = clip( spikeyness, 0,1 ) * aveRadius;
% generate n angle steps
angleSteps = [];
lower = (2*pi / numVerts) - irregularity;
upper = (2*pi / numVerts) + irregularity;
sum = 0;
for i =1:numVerts
tmp = unifrnd(lower, upper);
angleSteps(i) = tmp;
sum = sum + tmp;
end
% normalize the steps so that point 0 and point n+1 are the same
k = sum / (2*pi);
for i =1:numVerts
angleSteps(i) = angleSteps(i) / k;
end
% now generate the points
points = [];
angle = unifrnd(0, 2*pi);
for i =1:numVerts
r_i = clip( normrnd(aveRadius, spikeyness), 0, 2*aveRadius);
x = ctrX + r_i* cos(angle);
y = ctrY + r_i* sin(angle);
points(i,:)= [(x),(y)];
angle = angle + angleSteps(i);
end
end
function value = clip(x, min, max)
if( min > max ); value = x; return; end
if( x < min ) ; value = min; return; end
if( x > max ) ; value = max; return; end
value = x;
end
答案 4 :(得分:0)
如何生成随机点,然后弄清楚以什么顺序放置它们,以使边缘不重叠呢?我还没有做太多的研究,所以可能并不总是可能的,但是我认为是...(请让我知道是否,如果可以,请指出不正确的地方)。合适的位置可能会丢失或重新生成。)我也不知道是否有一种有效的方法可以对大量点执行此操作,但至少对于少量点应该很快。