import math, random
from typing import List, Tuple
def generate_polygon(center: Tuple[float, float], avg_radius: float,
irregularity: float, spikiness: float,
num_vertices: int) -> List[Tuple[float, float]]:
"""
Start with the center of the polygon at center, then creates the
polygon by sampling points on a circle around the center.
Random noise is added by varying the angular spacing between
sequential points, and by varying the radial distance of each
point from the centre.
Args:
center (Tuple[float, float]):
a pair representing the center of the circumference used
to generate the polygon.
avg_radius (float):
the average radius (distance of each generated vertex to
the center of the circumference) used to generate points
with a normal distribution.
irregularity (float):
variance of the spacing of the angles between consecutive
vertices.
spikiness (float):
variance of the distance of each vertex to the center of
the circumference.
num_vertices (int):
the number of vertices of the polygon.
Returns:
List[Tuple[float, float]]: list of vertices, in CCW order.
"""
# Parameter check
if irregularity < 0 or irregularity > 1:
raise ValueError("Irregularity must be between 0 and 1.")
if spikiness < 0 or spikiness > 1:
raise ValueError("Spikiness must be between 0 and 1.")
irregularity *= 2 * math.pi / num_vertices
spikiness *= avg_radius
angle_steps = random_angle_steps(num_vertices, irregularity)
# now generate the points
points = []
angle = random.uniform(0, 2 * math.pi)
for i in range(num_vertices):
radius = clip(random.gauss(avg_radius, spikiness), 0, 2 * avg_radius)
point = (center[0] + radius * math.cos(angle),
center[1] + radius * math.sin(angle))
points.append(point)
angle += angle_steps[i]
return points
def random_angle_steps(steps: int, irregularity: float) -> List[float]:
"""Generates the division of a circumference in random angles.
Args:
steps (int):
the number of angles to generate.
irregularity (float):
variance of the spacing of the angles between consecutive vertices.
Returns:
List[float]: the list of the random angles.
"""
# generate n angle steps
angles = []
lower = (2 * math.pi / steps) - irregularity
upper = (2 * math.pi / steps) + irregularity
cumsum = 0
for i in range(steps):
angle = random.uniform(lower, upper)
angles.append(angle)
cumsum += angle
# normalize the steps so that point 0 and point n+1 are the same
cumsum /= (2 * math.pi)
for i in range(steps):
angles[i] /= cumsum
return angles
def clip(value, lower, upper):
"""
Given an interval, values outside the interval are clipped to the interval
edges.
"""
return min(upper, max(value, lower))
@MateuszKonieczny这是从一组顶点创建多边形图像的代码。
vertices = generate_polygon(center=(250, 250),
avg_radius=100,
irregularity=0.35,
spikiness=0.2,
num_vertices=16)
black = (0, 0, 0)
white = (255, 255, 255)
img = Image.new('RGB', (500, 500), white)
im_px_access = img.load()
draw = ImageDraw.Draw(img)
# either use .polygon(), if you want to fill the area with a solid colour
draw.polygon(vertices, outline=black, fill=white)
# or .line() if you want to control the line thickness, or use both methods together!
draw.line(vertices + [vertices[0]], width=2, fill=black)
img.show()
# now you can save the image (img), or do whatever else you want with it.
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
下面是一些示例结果:
所生成的多边形可以是凸的或x 1e 4f 1x,但是对于更大数量的期望边,它们几乎肯定是凹的。多边形也从单位正方形内随机生成的点生成,因此,边数较多的多边形通常看起来像是具有“方形”边界(例如上面的右下角的50边多边形示例)。要修改此常规边界形状,您可以更改随机选择初始x和y点的方式(即,从高斯分布等)。
function CreateRandomPoly()
figure();
colors = {'r','g','b','k'};
for i=1:5
[x,y]=CreatePoly();
c = colors{ mod(i-1,numel(colors))+1};
plotc(x,y,c);
hold on;
end
end
function [x,y]=CreatePoly()
numOfPoints = randi(30);
theta = randi(360,[1 numOfPoints]);
theta = theta * pi / 180;
theta = sort(theta);
rho = randi(200,size(theta));
[x,y] = pol2cart(theta,rho);
xCenter = randi([-1000 1000]);
yCenter = randi([-1000 1000]);
x = x + xCenter;
y = y + yCenter;
end
function plotc(x,y,varargin)
x = [x(:) ; x(1)];
y = [y(:) ; y(1)];
plot(x,y,varargin{:})
end
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
6条答案
按热度按时间txu3uszq1#
我采用了@MitchWheat和@ templatypedef在圆上采样点的想法,并将其进一步扩展。
在我的应用程序中,我需要能够控制多边形有多奇怪,即从正多边形开始,随着参数的增加,它们变得越来越混乱。绕着圆走一圈,每次走一个随机的Angular 步长,在每一步中,在一个随机的半径上放置一个点,在方程中,我生成的Angular 步长为x1c 0d1x
其中theta_i和r_i给予每个点相对于中心U的Angular 和半径(min,max)从均匀分布中抽取随机数,并且N(mu,sigma)从高斯分布中提取随机数,并修剪(x,最小值,max)将一个值限定在一个范围内。这给了我们两个非常好的参数来控制多边形的狂野程度- epsilon,我称之为不规则性控制这些点是否均匀分布在圆的周围,sigma,我称之为,尖峰度,控制这些点与半径为r_ave的圆的偏差,如果你把这两个参数都设为0,你会得到完全规则的多边形,如果你把它们调大,多边形会变得更疯狂。
我用python很快地把它做出来,得到了这样的东西:
下面是完整的python代码:
@MateuszKonieczny这是从一组顶点创建多边形图像的代码。
pw136qt22#
利用MATLAB类
DelaunayTri
和TriRep
以及它们用于处理三角形网格的各种方法,有一种简洁的方法可以完成您想要的任务。下面的代码按照以下步骤创建一个任意的simple polygon:下面是生成的函数:
下面是一些示例结果:
所生成的多边形可以是凸的或x 1e 4f 1x,但是对于更大数量的期望边,它们几乎肯定是凹的。多边形也从单位正方形内随机生成的点生成,因此,边数较多的多边形通常看起来像是具有“方形”边界(例如上面的右下角的50边多边形示例)。要修改此常规边界形状,您可以更改随机选择初始
x
和y
点的方式(即,从高斯分布等)。ymzxtsji3#
对于凸2D多边形(完全超出我的想象):
1.生成一个随机半径R
1.在半径为R的圆周上生成N个随机点
1.围绕圆移动,并在圆上的相邻点之间绘制直线。
bxgwgixi4#
正如@ templatypedef和@MitchWheat所说,生成
N
个随机Angular 和半径很容易做到这一点。对Angular 进行排序很重要,否则它将不是一个简单的多边形。注意,我使用了一个简洁的技巧来绘制闭合曲线--我在这里描述过。顺便说一下,多边形可能是凹的。请注意,所有这些多边形都是星星的。生成一个更一般的多边形根本不是一个简单的问题。只是为了给予你尝一尝这个问题的滋味-检查http://www.cosy.sbg.ac.at/~held/projects/rpg/rpg.html和http://compgeom.cs.uiuc.edu/~jeffe/open/randompoly.html。
lfapxunr5#
这里是一个工作端口的Matlab的迈克Ounsworth解决方案。我没有优化它的matlab。我可能会更新解决方案后。
8gsdolmq6#
有了现成的计算几何库,一种简单有效的方法是:
变凹度凹船体
带(高斯)平滑的凹面船体