生成随机2D多边形的算法

s5s*_*s5s 35 random algorithm matlab polygon computational-geometry

我不知道如何解决这个问题.我不确定它的任务有多复杂.我的目标是拥有一个生成任何多边形的算法.我唯一的要求是多边形不复杂(即边不相交).我正在使用Matlab进行数学运算,但欢迎任何抽象的东西.

任何援助/指导?

编辑:

我正在考虑更多可以生成任何多边形的代码甚至是这样的:

在此输入图像描述

Mik*_*rth 27

我拿了@MitchWheat和@ templatetypedef的想法,在一个圆圈上采样点,并把它放得更远.

在我的应用程序中,我需要能够控制多边形的奇怪程度,即从常规多边形开始,当我调高参数时,它们变得越来越混乱.基本思路如@templatetypedef所述; 每次以一个随机的角度步长绕着圆圈行走,并且在每个步骤中将一个点放在随机半径上.在方程式中,我生成角度步长为 顶点的角度和半径的方程

其中theta_i和r_i给出每个点相对于中心的角度和半径,U(min,max)从均匀分布中拉出一个随机数,N(mu,sigma)从高斯分布中拉出一个随机数,并剪辑(x,min,max)将值阈值化为范围.这给了我们两个非常好的参数来控制多边形的多么狂野 - 我称之为不规则的 epsilon 控制点是否围绕圆圈均匀地成角度空间,而sigma我称之为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
Run Code Online (Sandbox Code Playgroud)

@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.
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,由于该算法的性质(它使用极坐标),无法创建某些类型的多边形。像这样的一个:https://i.stack.imgur.com/bxa3b.png (3认同)

gno*_*ice 24

通过利用MATLAB类DelaunayTri以及TriRep它们用于处理三角形网格的各种方法,有一种巧妙的方法可以做你想要的.下面的代码遵循以下步骤来创建任意简单的多边形:

  • 生成一些等于所需边数的随机点加上一个软糖因子.软糖因子确保无论三角测量的结果如何,我们都应该有足够的面以能够将三角形网格修剪成具有所需边数的多边形.

  • 创建点的Delaunay三角剖分,从而产生由一系列三角形面构造的凸多边形.

  • 如果三角剖分的边界具有比期望更多的边缘,则在具有唯一顶点的边缘上选择随机三角形面(即,三角形仅与三角剖分的其余部分共享一条边).移除此三角形小平面将减少边界边缘的数量.

  • 如果三角测量的边界具有比期望的边缘更少的边缘,或者前一步骤无法找到要移除的三角形,则在边缘上选择随机三角形面,其在三角剖分边界上仅具有其一个边缘.移除此三角形小平面将增加边界边缘的数量.

  • 如果找不到与上述标准匹配的三角形面,则发出警告,指出无法找到具有所需边数的多边形,并返回当前三角剖分边界的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
Run Code Online (Sandbox Code Playgroud)

以下是一些示例结果:

在此输入图像描述

生成的多边形可以是凸的或凹的,但是对于更大数量的所需边,它们几乎肯定是凹的.多边形也是从单位正方形内随机生成的点生成的,因此具有较大边数的多边形通常看起来像具有"方形"边界(例如上面右下方的50边多边形).要修改此一般边界形状,您可以更改初始xy点随机选择的方式(即从高斯分布等).


Mit*_*eat 12

对于凸二维多边形(完全偏离我的头顶):

  1. 生成随机半径R

  2. 在Radius R的圆周上生成N个随机点

  3. 围绕圆圈移动并在圆上相邻点之间绘制直线.

  • 我还可以补充一点,一般来说,问题是在图上找到一个不相交的汉密尔顿循环。显然,对于 n 顶点图有 (n-1)!/2 个这样的循环,这意味着 n 个随机点定义 (n-1)!/2 个不同的多边形。如果你有一个检测两条边是否相交的函数(这很容易),那么你可以随机选取一个点,随机选取另一个,测试这条边是否与现有边相交,并保留/拒绝该点等等. 通过这种方式,您可以在平面上创建一般的随机多边形。 (2认同)

And*_*ein 6

正如@templatetypedef和@MitchWheat所说,通过生成N随机角度和半径很容易实现.对角度进行排序很重要,否则它将不是简单的多边形.请注意,我使用一个巧妙的技巧绘制闭合曲线 - 我在这里描述它.顺便说一句,多边形可能是凹的.

请注意,所有这些多边形都是星形的.生成更通用的多边形根本不是一个简单的问题.只是为了让您体验一下这个问题 - 请查看 http://www.cosy.sbg.ac.at/~held/projects/rpg/rpg.htmlhttp://compgeom.cs.uiuc.edu/~ jeffe/open/randompoly.html.

在此输入图像描述

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
Run Code Online (Sandbox Code Playgroud)