Random 如何生成随机凸多边形?

Random 如何生成随机凸多边形?,random,geometry,Random,Geometry,我正试图设计一种生成随机二维凸多边形的方法。它必须具有以下属性: 坐标应该是整数 多边形应该位于具有角(0,0)和(C,C)的正方形内,其中C是给定的 多边形的顶点数应接近给定的N 例如,生成具有10个顶点且位于正方形[0..100]x[0..100]内的随机多边形 这项任务之所以困难,是因为坐标应该是整数 我尝试的方法是在给定的正方形中生成随机点集,并计算这些点的凸包。但是,与N相比,生成的凸包的顶点非常少 有什么想法吗?这还不完全,但它可能会给你一些想法 如果N

我正试图设计一种生成随机二维凸多边形的方法。它必须具有以下属性:

  • 坐标应该是整数
  • 多边形应该位于具有角(0,0)和(C,C)的正方形内,其中C是给定的
  • 多边形的顶点数应接近给定的N
例如,生成具有10个顶点且位于正方形[0..100]x[0..100]内的随机多边形

这项任务之所以困难,是因为坐标应该是整数

我尝试的方法是在给定的正方形中生成随机点集,并计算这些点的凸包。但是,与N相比,生成的凸包的顶点非常少


有什么想法吗?

这还不完全,但它可能会给你一些想法

如果N<3,则退出。生成具有N个顶点的单位圆,并将其随机旋转[0..90]度

从原点向外随机挤出每个顶点,并使用每对相邻顶点与原点之间的叉积符号确定凸度。这是一个在速度和质量之间进行权衡的步骤


设置顶点后,从原点查找具有最大幅值的顶点。将每个顶点除以该大小以规格化多边形,然后将其放大(C/2)。转换为(C/2,C/2)并转换回整数。

一个简单的算法是:

  • 从随机线开始(两个顶点和两条边的多边形)
  • 取多边形的随机边E
  • 在此边上创建新的随机点P
  • 取一条垂直于E的线L穿过点P。通过计算线T和由E相邻的两条边定义的线之间的交点,计算凸度未破坏时P的最大偏移量
  • 在该范围内随机偏移点P
  • 如果点数不够,则从2开始重复

  • 您的初始方法是正确的-计算凸包是满足随机性、凸性和整体性的唯一方法

    我能想到的优化算法以获得“更多点”的唯一方法是将它们组织成一个圆圈,而不是完全随机的。你的点应该更靠近正方形的“边缘”,而不是靠近中心。在中心,概率应该是~0,因为多边形必须是凸的


    一个简单的选择是为你的点设置一个最小半径,可能是C/2或C*0.75。计算C正方形的中心,如果某个点太近,将其从中心移开,直到达到最小距离。

    这是我知道的生成每个凸多边形的概率相等的最快算法。输出正好有N个顶点,并且运行时间为O(N logn),因此它可以非常快速地生成大型多边形

    • 生成两个列表,
      X
      Y
      ,其中包含0和C之间的N个随机整数。确保没有重复项
    • 排序
      X
      Y
      并存储它们的最大和最小元素
    • 将其他元素(不是最大值或最小值)随机分为两组:
      X1
      X2
      ,以及
      Y1
      Y2
    • 在这些列表的开始和结束处重新插入最小和最大元素(
      minX
      X1
      X2
      的开始处,
      maxX
      在结束处,等等)
    • 找到连续的差异(
      X1[i+1]-X1[i]
      ),颠倒第二组(
      X2[i]-X2[i+1]
      )的顺序。将这些存储在列表中
      XVec
      YVec
    • 随机(洗牌)
      YVec
      并将每对
      XVec[i]
      YVec[i]
      视为二维向量
    • 按角度对这些向量进行排序,然后将它们端到端地放置以形成多边形
    • 将多边形移动到原始的最小和最大坐标
    此处提供了动画和Java实现:

    该算法基于Pavel Valtr的一篇论文:“《离散与计算几何》13.1(1995):637-643.

    如果有人对Python端口感兴趣,下面是

    随机导入
    从数学导入atan2
    def到凸形轮廓(顶点计数,
    x_生成器=random.random,
    y_生成器=随机。随机):
    """
    Sander Verdonschot的Valtr端口算法。
    参考:
    http://cglab.ca/~sander/misc/convxgeneration/ValtrAlgorithm.java
    >>>轮廓=至凸形轮廓(20)
    >>>透镜(轮廓)==20
    真的
    """
    xs=[x_生成器()用于范围内的u(顶点数)]
    ys=[y_生成器()用于范围内的u(顶点数)]
    xs=已排序(xs)
    ys=已排序(ys)
    最小x,*xs,最大x=xs
    最小y,*ys,最大y=ys
    向量x=_到_向量x坐标(x,min,max)
    vectors_ys=_至_vectors_坐标(ys,min_y,max_y)
    随机。随机(向量)
    def到_矢量_角度(矢量):
    x、 y=向量
    返回atan2(y,x)
    向量=排序(zip(向量x,向量y),
    键=到(矢量角度)
    点x=点y=0
    最小多边形x=最小多边形y=0
    点数=[]
    对于向量x,向量中的向量y:
    点。附加((点x,点y))
    点x+=向量x
    点y+=向量y
    最小多边形=最小(最小多边形,点)
    min_polygon_y=min(min_polygon_y,point_y)
    shift_x,shift_y=min_x-min_多边形,min_y-min_多边形
    返回[(点x+移位x,点y+移位y)
    对于点x,点y在点中]
    定义向量坐标(坐标、最小坐标、最大坐标):
    最后一个最小值=最后一个最大值=最小坐标
    结果=[]
    对于坐标中的坐标:
    如果_to_random_boolean():
    结果.追加(坐标-最后一分钟)
    最后一分钟=坐标
    其他: