在舞台上寻找一个自由区域

时间:2009-01-28 10:48:48

标签: actionscript-3 algorithm geometry

我在舞台上的随机位置绘制矩形,我不希望它们重叠。 因此,对于每个矩形,我需要找到一个空白区域来放置它。

我考虑过尝试一个随机位置,用

验证它是否是免费的
private function containsRect(r:Rectangle):Boolean {
    var free:Boolean = true;
    for (var i:int = 0; i < numChildren; i++)
        free &&= getChildAt(i).getBounds(this).containsRect(r);
    return free;
}

如果它返回false,则尝试使用另一个随机位置。

问题在于,如果没有可用空间,我将永远陷入尝试随机位置。

有一个优雅的解决方案吗?

7 个答案:

答案 0 :(得分:3)

您可以通过转换简化操作。如果你正在寻找一个放置LxH矩形的有效位置,你可以将所有先前的矩形L单位向右增长,H单位向下,然后搜索一个不与任何那些相交的单个点。这个点将是放置新矩形的有效位置的右下角。

接下来应用扫描线扫描算法来查找任何矩形未覆盖的区域。如果您想要均匀分布,则应选择随机y坐标(假设您向下扫描),按自由区域分布加权。然后从您选择的扫描线中的开放段中均匀地选择随机x坐标。

答案 1 :(得分:3)

让S成为舞台的一部分。设A是我们想要绘制的最小矩形的区域。设N = S / A

一种可能的确定性方法:

在空白舞台上绘制矩形时,会将舞台划分为最多4个可适合下一个矩形的区域。当您绘制下一个矩形时,一个或两个区域被分成最多4个子区域(每个),可以适合矩形等。您将永远不会创建多于N个区域,其中S是舞台的区域,并且A是最小矩形的区域。保留一个区域列表(未排序很好),每个区域由其四个角点表示,每个区域用其区域标记,并使用区域加权reservoir sampling,水库大小为1来选择一个概率区域与其面积成比例,最多一次通过列表。然后在该区域的随机位置放置一个矩形。 (从区域左下角部分选择一个随机点,允许您绘制一个矩形,该点为左下角,而不会碰到顶部或右侧墙壁。)

如果您不是从空白阶段开始,那么只需在O(N)中构建可用区域列表(例如,通过以任何顺序重新绘制空白舞台上的所有现有矩形),然后再搜索第一个指向绘制一个新的矩形。

注意:您可以将储存器大小更改为k,以便一步完成选择下一个k矩形。

注2:您也可以在树中存储可用区域,每个边缘权重等于子树区域上区域的区域总和。然后,为了选择O(logN)中的区域,我们递归地选择具有根区域/ S的概率区域的根,或者具有概率边缘权重/ S的每个子树。但是,当重新平衡树时更新权重将是令人讨厌的。

     运行时间:O(N)
      空格:O(N)

    一种可能的随机方法:

    在舞台上随机选择一个点。如果您可以绘制一个或多个包含该点的矩形(不只是一个点的左下角),则返回包含该点的随机定位矩形。可以毫无偏见地定位矩形以及一些细微之处,但我会留给你。

    最糟糕的是,有一个空间对我们的矩形来说足够大,而且舞台的其余部分都已填满。所以这种方法成功概率&gt; 1 / N,或概率失败&lt; 1-1 / N。重复N次。我们现在以概率&lt; (1-1 / N)^ N&lt;的1 / e。失败我们的意思是我们的矩形有一个空间,但我们没有找到它。通过成功,我们意味着我们找到了一个存在的空间。为了获得合理的成功概率,我们重复Nlog(N)次1 / N失败概率,或N²次1 / e ^ N失败概率。

    总结:尝试随机点,直到我们找到一个空格,在NlogN(或N²)尝试后停止,在这种情况下我们可以确信不存在空格。

        运行时:O(NlogN)表示成功的概率很高, O(N²)表示成功的概率非常高   空格:O(1)

答案 2 :(得分:1)

我不确定这会有多优雅,但您可以设置最大尝试次数。也许100?

当然,您可能仍有一些空间可用,但无论如何您都可以触发“完成”事件。这就像当补间库将对象捕捉到目标点时,因为它“足够接近”。

HTH

答案 3 :(得分:1)

可以确定是否有足够的空间,可以检查当前一组矩形胶带占用的面积。如果遗留的区域数量小于新矩形的面积,那么您可以立即放弃并拯救。我不知道您可以获得哪些信息,或者是否以常规模式放置矩形,但如果是这样,您可以更改检查以查看是否显然没有足够的可用空间。

这对你来说可能不是最合适的方法,但这是我头脑中的第一件事!

答案 4 :(得分:0)

假设您在尝试绘制矩形之前定义了矩形的尺寸,我认为这样的事情可能有效:

在候选矩形的舞台上建立可能的中心点网格。因此,对于6x4矩形,您的第一个点将是(3,2),然后是(3 + 6 * x,2 + 4 * y)。如果可以在四个相邻点之间绘制一个矩形,则可能存在空间。

for (x = 0, x < stage.size / rect.width - 1, x++)
    for (y = 0, y < stage.size / rect.height - 1, y++)
        if can_draw_rectangle_at([x,y], [x+rect.width, y+rect.height])
            return true;

这并没有告诉你哪里你可以画它(虽然应该可以建立一个可能的绘图区域的列表),只是你可以。

答案 5 :(得分:0)

我认为用你所拥有的唯一有效的方法是维护一个开放位置的2D布尔数组。具有足够大小的数组,使得绘图位置仍然是随机的。

绘制新矩形时,将相应的矩形块清零。然后检查空闲区域是恒定的^ H ^ H ^ H ^ H ^ H ^ H ^ H时间。糟糕,这意味着查找是O(nm)时间,其中n是长度,m是宽度。必须有一个基于范围的解决方案,argh。

Edit2:显然答案是here,但在我看来,在Actionscript上实现这一点可能有点多,特别是如果你不热衷于几何体。

答案 6 :(得分:0)

这是我使用的算法

  1. 放下N个随机点,其中N是您想要的矩形数
  2. 迭代地增加在每个点N处创建的矩形的尺寸,直到它们接触另一个矩形。
  3. 如果您想拥有最小允许的矩形大小,可以约束初始点的放置方式。

    如果你想要所有用矩形覆盖的空间,你可以逐渐将随机点添加到剩余的“自由”空间,直到没有任何区域被覆盖。