【问题标题】:Generating points in area with at least X gap length in-between在具有至少 X 间隙长度的区域中生成点
【发布时间】:2011-11-15 14:08:08
【问题描述】:

我正在尝试提出一种在给定区域(在我的情况下为正方形)中生成 X 个随机点的方法。造成这样一个问题的一件事是,每个点都必须与所有其他点相距至少 Y 个单位。

首先想到的是(在 c# 中)检查新点与所有现有点之间的距离:

while(points.Count < pointsToGenerate)
{
     Point newPoint = NewPoint();
     bool addPoint = true;
     foreach(Point p in points)
     {
          if((p - newPoint).Length() < minDistance)
          {
              addPoint = false;
              break;
          }
     }

     if(addPoint)
     {
          points.Add(newPoint);
     }
}

现在这肯定会起作用,但是如果没有找到有效点,这将成为一个永无止境的循环。那么在此处输入一个神奇的数字 Z 作为尝试次数的限制?

if(loopCount > 100)
{
     break;
}

现在这有一些明显的问题。如果这些点是随机生成的,那么即使还有位置可以放置该点,loopCount 也可以超过 Z。它不仅可以,而且会发生!

我可以做的是为每次通过创建一个可用点列表,然后选择其中一个随机点。除了一件事外,这将完美无缺:性能。我的应用程序不需要超级性能,但面积是 1000^2。即使我将自己限制为整数,每次通过也要检查很多点!

所以,我能想出的可能还不够,因此我希望得到一些帮助。有没有更好的方法在区域 A 中生成点 Y 之间距离最小的 X 点?

谢谢!

编辑: 更好,我的意思是在性能与完美之间取得平衡的情况下通常更好。有点模糊,我知道。我还不确定生成这些点需要多少开销,所以我基本上追求比我自己的方法更优雅的方法。

~罗伯特

【问题讨论】:

  • 如果不能以 Y 间距分布 X 点,您希望发生什么?那些只有一种排列方式的情况呢?您是在生成点列表还是一组点?
  • @Eric - 如果距离不为零,那么集合/列表的区别有什么关系?
  • 计算几何方面的专家可能会使用 Voronoi 图为您提供一些巧妙的算法。我不是这样的专家,所以我将在此评论中喃喃自语。
  • 我也会咕哝着使用circle packing 来“规范化”你的问题。您可以缩小圆圈,使它们以最小距离分开,并且在每个圆圈中最多创建一个随机点。不过,我还没有仔细考虑过这个……
  • @Mr.TAMER 一个非常好的建议!我将创建一组最佳放置的点,然后选择其中的一个随机子集,但如果使用了太多点,那将创建一种人工外观的模式。在处理大量点时,使用概率会创建更好(看起来更随机)的模式,但也会产生更多开销。我不确定我的申请是否需要您的方式,但我确实喜欢它! :)

标签: algorithm computational-geometry


【解决方案1】:

要了解您的问题:您是在寻找最佳答案(即:家庭作业),还是寻找比创建随机点更好的非常好的算法?

在第一种情况下,如果您没有关于 A 区域的先验信息,恐怕这是一个非常复杂的问题。而且我相信很难找到比探索每个案例都更快的算法.

但是,如果您对 A 有一些先验信息,那么事情可能会更简单。例如,如果是凸面,您可以利用 如果您的空间是无限的,则最佳路面是六边形这一事实。这意味着您必须将点(在 X 中)放在三角形的末端

所以:

  • 计算凸包 (O(n*log(n)))
  • 计算直径(集合中最远的两个点)
  • 首先在 X 中添加一个点(直径)
  • 然后添加与六边形路面相对应的点,有利于凸包上的点

这个算法不是最优的(除非你定义了一个非常好的“有利于凸包上的那些”......)


编辑:E 先生的评论提醒我,最佳路面的东西来自circle packing。感谢他的精确度!


但是,我确实有另一种算法,看起来非常不错,甚至可能是最优的!它不需要 A 上的任何条件,而且有点贵,但不会太多。是的,我知道,这与我所说的相矛盾,但谁在乎呢!有一个好的算法就足够了。

让我们将 B 命名为到目前为止可用点的集合。而 C 是构成 B 的端点的点。开始时,B=A,如果 A 是正方形,则 C 由 4 个点(角)组成。你只需要递归:

  • 计算 B 最远的两个点。您只需要 C 中的点
  • 在 X 上随机添加一个点(直径)
  • 从 B 中删除现在不可用的点。您只需要为此更新 C。

我知道,如果你在 1000x1000 的网格中工作,C 以 4 个点开始,但在 X 上加一个点后,这意味着 C 增长到 1570 个点(大约为 (pi/2)1000)。 您必须注意,您从未放入内存 B,它很大(O(n^2),如果 A 可以放入 nn 网格中)只有 C,我相信在任何时候,大小C 是 O(n) ,仍然比 O(n^2) 好得多。并且计算直径仍然是 O(size(C)) = O(n)

【讨论】:

  • 非常有帮助,谢谢!我试图在正方形区域中获得随机点,没有复杂的形状,并且它们不会彼此靠近。你所提议的(据我所知)是用尽可能多的点以最佳方式填充形状,然后选择其中的一个随机子集作为点。虽然点之间的距离永远不会小于 Y,但这不会涵盖所有可能的位置。例如,如果您在 100*100 区域中有三个点,即使这些点不在最佳放置集中,您也可以拥有 [0,0]、[5,5] 和 [6, 20]。喜欢这个答案,它很好地解决了我的问题!
【解决方案2】:

这是我的想法,我认为您必须将该区域划分为边长等于 Y 的正方形。这样做之后,您可能会留下一个边小于 y 的矩形,除非面积 = 整数 * y2。 现在您可以生成的最大点数是正方形+矩形的数量。因此,如果 X 不止于此,您可以以失败结束该方法。

从最后一个(右下)最小的矩形开始生成点。在那里选择一个随机点,并在其顶部矩形和左侧矩形上找到一个点,使它们与第一个点相距 Y,并且仅当其直接右侧和底部正方形/矩形为时才开始在矩形/正方形中填充一个点填充。因此,您在最后填充第一个正方形。

在生成随机点时,您只需要担心与最多两个点的距离,即最右边的正方形/矩形中的一个点和最下面的正方形/矩形中的一个点。当然,如果你得到超过 X 点,你可以停下来,或者忽略随机的几个点来剩下 X 点

为了让事情更随机,你可以从四个边中的任何一个开始跳 Y 边的正方形,(这里是左上角),这样每次的起点都不一样。

【讨论】:

  • 我可能理解错了,但这不会与创建网格相同的结果,其中网格中的交叉点是一组可能的点(因为只有一到两个 (? ) 每个矩形可能有点。
  • 不,它不会,对于您在最后一个矩形中选择的每个随机点,您可以在左侧和顶部的矩形中拥有无限可能的点。该点可以是矩形内的任何点,而不是交点。
【解决方案3】:

如果限制自己使用整数是一种选择,那么有一种算法可以工作。只需跟踪每行或每列中可用的位置数,然后为新点的空缺中的每一行或每列重新计算这些值。这里的关键是选择的随机位置只在可用点中选择,而不是整个网格。

PointsRemaining = X
Points = new CoordinateCollection
Width = 1000
Height = 1000
if (Width > Hight)
    Swap(Width, Hight)
    Swapped = true
NumberOfLocationsAvailable = new int[Width]
InitializeArrayValues(NumberOfLocationsAvailable, Height)
TotalLocationsAvailable = Width * Height
While (TotalLocationsAvailable > 0 and PointsRemaining > 0)
    NextPoint = Random(0, TotalLocationsAvailable)
    NextCoordinates = FindCoordinates(NextPoint, NumberOfLocationsAvailable)
    NumberLocationsRemoved = RemoveLocationsWithinDistance(NextCoordinates, Points, NumberOfLocationsAvailable, Y)
    TotalLocationsAvailable = TotalLocationsAvailable - NumberLocationsRemoved
    Points.Add(NextCoordinates)
    PointsRemaining = PointsRemaining - 1
if (Swapped)
    Points = RotatePoints(Points)

这使RemoveLocationsWithinDistance 变得非常复杂,但这不应该困难。它将需要一个大小为 Y 的布尔值的二维方形数组。

【讨论】:

    【解决方案4】:

    如果您想要一个随机分布,您可以通过将网格离散为大小为 y 的单元格,在 O(1) 时间内回答“距离该点是否有小于 y 的点”。那么距离另一个点 Q 小于 y 的任何点 P 必须位于与 Q 相邻的 9 个单元格之一中,因此您可以只使用哈希表并进行 9 次检查。此外,每个单元格最多可以包含 2 个点。

    使用这样的数据结构,您可以进行随机抽样并拒绝以填补您的空间。只要 y 与总面积相比相对较小,您就会很快成功。

    【讨论】:

      【解决方案5】:

      您可以使用分子动力学技术。

      从一个大盒子开始,将你的点分散在一些规则的网格上,间距 > Y。

      现在将每个点视为一个球形粒子,该粒子通过一些排斥势(例如排斥性 Lennard-Jones)与其他点相互作用,并选择参数以使每个粒子的有效直径为 Y。

      给粒子随机速度,并用离散求解器求解运动方程(比如速度-Verlet,它不一定要准确)。粒子之间的排斥将使粒子 Y 分开。随着时间步长更新粒子位置,每次将框缩小一点,直到达到所需的大小。 (哦,盒子可以用周期性边界条件,或短程排斥场来处理。)

      当然,您必须确保可以将所有粒子都放入盒子中。在 2D 中,圆形的最佳包装是已知的,请参阅开普勒问题。不是听说现在3D开普勒问题也解决了吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-28
        • 2019-02-23
        • 1970-01-01
        • 2021-09-20
        相关资源
        最近更新 更多