【问题标题】:Algorithm to calculate the positions of random circles so they don't overlap计算随机圆位置的算法,使它们不重叠
【发布时间】:2012-06-12 21:16:26
【问题描述】:

我有以下问题。

我有一个很大的区域,其中填充了随机数量的不同大小的圆圈。如果在随机位置插入一个随机半径的新圆,我想为它找到一个附近的位置,这样它就不会与其他任何位置重叠。如果圆圈保持接近,这是最佳选择。

圆圈的数量和大小是有限的,但是是随机的。该区域将非常大(可能是 2500x2500),因此建议 here 的像素数组是不可能的。回答相同问题的人提出了一个网格,其中的单元格是圆圈的大小。这将解决我的问题,使用尽可能大的圆圈大小的单元格,但我希望圆圈尽可能靠近,所以它不能完全满足我的需求。

一个非常基本的方法包括检测新圆放置时的碰撞,并将其从与之碰撞的圆移开。之后,再次检查碰撞并重复该过程。这显然不是很优雅,而且很容易出现无限循环(比你想象的更频繁)。

目标是为新插入的圆找到最接近的位置,使其不与其他任何人重叠。

P.D.
一件非常好的事情,但不同的事情,而不是我的主要目标,是根据需要重新排列尽可能多的圆圈,而不是仅仅重新定位一个,就好像它们在相互“推动”一样。我更喜欢距离而不是移动的圈数。也就是说,我宁愿多圈移动一点,而不是一圈远离它的原始位置。

【问题讨论】:

    标签: algorithm random geometry pack


    【解决方案1】:

    我会做以下事情:定义 x,y 的网格 对于网格,计算到所有圆的最小距离减去圆的半径。 在生成的地图上,您可以选择比 X 更亮的任何像素,这意味着您可以在那里放置一个半径为 X 的圆而不会重叠。 这是显示结果地图的代码和图像。 如果你想让它更快,你可以使用低分辨率版本的地图。

    import numpy as np,numpy.random
    import matplotlib.pyplot as plt,matplotlib,scipy.optimize
    
    maxx=2500
    maxy=2500
    maxrad=60 #max radius of the circle
    ncirc=100 # number of circles
    np.random.seed(1)
    
    #define centers of circles
    xc,yc=np.random.uniform(0,maxx,ncirc),np.random.uniform(0,maxy,ncirc)
    rads=np.random.uniform(0,maxrad,ncirc)
    #define circle radii
    
    xgrid,ygrid=np.mgrid[0:maxx,0:maxy]
    im=xgrid*0+np.inf
    
    for i in range(ncirc):
        im = np.minimum(im, ((xgrid - xc[i])**2 + (ygrid - yc[i])**2)**.5 - rads[i])
    # im now stores the minimum radii of the circles which can 
    # be placed at a given position without overlap
    
    #plotting 
    fig=plt.figure(1)
    plt.clf()
    plt.imshow(im.T,extent=(0, maxx, 0, maxy))
    plt.colorbar()
    ax = plt.gca()
    for i in range(ncirc):
         ax.add_patch(matplotlib.patches.Circle((xc[i], yc[i]), rads[i],
              facecolor='none', edgecolor='red'))
    plt.xlim(0, maxx)
    plt.ylim(0, maxy)
    plt.draw()
    

    地图看起来像 voronoi 图,但不清楚是否可以利用。

    更新:经过一番思考,有一种可能更快的解决方案适用于大量圈子。 首先创建该区域的网格(比如 2500x2500)。用 1 填充圆圈内的所有像素,其他所有像素都用 0 填充。然后,您需要将此地图与圆形内核与您要放置的圆的所需半径进行卷积。生成的地图的像素必须为 0,可用于放置像素。这种方法的优点是它可以适用于非常大的网格和圈数,并且可以通过fft轻松完成卷积。

    这是第一个掩码的插图,以及与半径为 128 像素的圆形内核卷积后的掩码。右掩码中的所有零像素都是半径为 128 的新圆的可能位置。

    【讨论】:

    • 这很有趣,虽然我不确定我是否非常了解您的更新......不过,它让我想到了快速使用网格的方法。如果我成功了,我会回答自己。
    • @sega_sai 你能解释一下如何“用循环内核卷积映射”吗?
    • 使用即 scipy.signal.convolve 和输入数组和一个 0 和 1 的二维数组,其中 1 在一个圆圈内
    【解决方案2】:

    您的问题提出了一个基于force-based layout algorithm 的解决方案,该解决方案在排斥力和吸引力之间取得了明智的平衡。 This answer 指向您可能使用的库,我希望 Google 会为您找到其他库。

    【讨论】:

    • 这对于我的目的来说是一个很好的解决方案,尽管它的复杂性 (O(n^3)) 有点令人生畏。我将检查这些库以寻找有效的实现。谢谢。
    【解决方案3】:

    尝试动态网格,从最大的圆圈开始,然后在将圆圈放置到最终位置后,在圆圈的每个边缘上画线。现在您的网格将由许多不同大小的框组成,您所要做的就是找到一个适合您的新圆的边界框的框,放置它,然后绘制定义您现在更小的框的线条。继续,直到你放置了所有的圈子。

    你总是可以在一个正方形区域内的一个角落位置放置圆圈,这样当你画线时,首先你只需要画两条线,其次你总是在放置后保持最大的空间开放。

    【讨论】:

    • 这是个好主意。问题是每次放置一个圆圈时,都会施加比必要更多的限制,最终它们可能会变得太多。我将进行一些测试,看看它的行为如何。谢谢。
    • 你是对的,但是任何基于网格的算法都将成为近似值,因为在圆形项目周围放置边界框总是会留下未使用的空间。我认为基于网格的算法可能最适合速度,但如果您正在寻找准确性,甚至是最佳拟合,那么任何网格答案都可能不是要走的路,或者至少不是一阶网格。
    猜你喜欢
    • 1970-01-01
    • 2013-08-06
    • 1970-01-01
    • 2020-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    相关资源
    最近更新 更多