【问题标题】:How to find a random point in a quadrangle?如何在四边形中找到一个随机点?
【发布时间】:2011-03-04 17:49:33
【问题描述】:

我必须能够为飞行模拟的航路点设置随机位置。数学挑战很简单:

“在四边形中找到一个随机位置,该点位于任何位置的概率均等。”

视觉上是这样的:

一个例子 ABCD 四边形是: 答:[21417.78 37105.97] 乙:[38197.32 24009.74] C:[1364.19 2455.54] D:[1227.77 37378.81]

提前感谢您提供的任何帮助。 :-)

编辑 谢谢大家的回复。我会在周末看看这个,然后奖励接受的答案。顺便说一句,我应该提到四边形可以是凸的或凹的。对不起。

【问题讨论】:

  • 发布了包括我自己在内的三个答案,都建议采用蛮力“选择然后检查”方法,我想知道您的问题是否真的是如何检查给定点是否在指定的四边形内,这是我们都强调的部分。
  • 四边形是否保证是凸的?
  • 更新:那是另一个想法。找到了一个出色的 SO 解决方案,可以轻松适应您的问题。
  • 也可以试试 MathOverflow mathoverflow.net
  • @jdk:MathOverflow 的琐碎

标签: c# geometry computational-geometry


【解决方案1】:

将您的四边形分成两个三角形,然后使用this excellent SO answer 在其中一个中快速找到一个随机点。

更新:

从Akusete 借用这个很棒的link 在三角形中选择一个随机点。


(来自 MathWorld - Wolfram 网络资源:wolfram.com)

给定一个有一个顶点的三角形 v1 位置的原点和其他 和 v2,选择
(来自 MathWorld - Wolfram 网络资源:wolfram.com)
A1 和 A2 是一致的 在区间 [0,1] 中变化,这给出 点均匀分布在 四边形(左图)。这 不在三角形内部的点 然后可以被丢弃,或者 转化为对应的 三角形内的点(右 图)。

【讨论】:

  • 但是,您将如何从两者中选择一个三角形?他们可能有不同的领域,从而使结果产生偏差。 (好吧,这并不难,但没有它你的答案是错误的)
  • @Kobi 好点,但是你可以选择按三角形面积加权,保证结果公平
  • @Akusete - 感谢您的链接! +1!
  • 更一般地说,您可以通过三角剖分在任何多边形内选择一个均匀分布的随机点,选择一个概率与其面积成正比的三角形,然后在其中选择一个均匀随机点三角形。
  • 我不明白反对票,所以我会投你赞成票。您的答案很复杂,也许不切实际,但看起来既有趣又正确。
【解决方案2】:

这是一个有趣的问题,并且可能有非常有趣的答案,但如果你只想让它工作,让我为你提供一些简单的东西。

算法如下:

  1. 在包围四边形的矩形内随机选取一个点。
  2. 如果它不在四边形(或任何形状)内,请重复。
  3. 利润!

编辑

根据 Bart K. 的建议,我更新了第一步以提及边界框。

【讨论】:

  • 简单有它自己的美。感谢您的回复。
  • 只选择一个随机点可能需要很长时间,尤其是当四边形的点彼此非常接近时。您可以(从统计上)通过选择一个 (x,y) 至少在四边形边界框内的点来缩小范围。
  • @Bart:你是对的。我应该说该点应该在一个与所需形状有界限但更规则的形状内(在这种情况下是一个矩形)。一点随机性是好的,但生成我们事先知道无效的数字是没有意义的。我现在将对其进行编辑,感谢您。
  • @Steve,请注意,即使在(x 和 y 对齐的)边界框中生成一个数字,在找到一个点之前仍然需要相当长的时间:以下面的四边形为例:(0,1) (0,0) (1,0) (100000000000000000000,100000000000000000000) 或面积远小于我发布的示例。当然,这取决于 OP 可能期望什么类型的四边形,也许您的建议是完全有效的,我在这里描述的这种极端情况不会发生。
  • @Bart:你又一次正确了。病态的情况,比如你的瘦四边形创建了一个巨大的、大部分是空的边界框,肯定会导致我认可的算法性能不佳。如果 OP 正在处理随机形状,那么这种边缘情况的概率应该很小,但是如果生成它们的过程有偏差或者(甚至更糟)对外部控制开放,那么您至少需要添加一个限制器重试次数。您还可以将四边形的面积与边界框的面积进行比较,(续)
【解决方案3】:

因此,这取决于您希望如何分发。

如果您希望在 2d 视图空间中随机采样点,那么 Jacob 的答案非常棒。如果您希望这些点有点像透视图(在您的示例图像中,右上角的密度比左下角的密度更大),那么您可以使用双线性插值。

双线性插值非常简单。在 [0..1] 范围内生成两个随机数 s 和 t。然后,如果您的输入点是 p0,p1,p2,p3,则双线性插值是:

bilerp(s,t) = t*(s*p3+(1-s)*p2) + (1-t)*(s*p1+(1-s)*p0)

主要区别在于您是希望您的分布在二维空间(雅各布方法)中是均匀的还是在参数空间中是均匀的。

【讨论】:

    【解决方案4】:

    您可以在边界框内随机创建点,只有在您找到一个位于多边形内的点后才会停止。

    所以:

    1. 找到包含多边形所有点的框。
    2. 在先前找到的框的边界内创建一个随机点。使用随机函数生成 x 和 y 值。
    3. 检查该点是否在多边形内(查看here 或here 的方法)
    4. 如果该点在多边形停靠点内,则完成,如果不是,请转到第 2 步

    【讨论】:

    • 感谢您解决我跳过的部分 - 如何检测点是否在内部 - 并提供一对有趣的链接。
    【解决方案5】:

    我相信有两种合适的方法可以解决这个问题。

    其他发帖者首先提到的是找到包围矩形的最小边界框,然后在该框中生成点,直到找到位于矩形内的点。

      Find Bounding box (x,y,width, height)
      Pick Random Point x1,y1 with ranges [x to x+width] and [y to y+height]
      while (x1 or y1 is no inside the quadrangle){
           Select new x1,y1
      }
    

    假设你的四边形面积是 Q,边界框是 A,你需要生成 N 对点的概率是 1-(Q/A)^N,它以指数方式接近 0。

    我会推荐上述方法,尤其是在二维方面。生成点和测试非常快。

    如果您想要终止的 garentee,那么您可以创建一个仅在四边形内生成点的算法(简单),但您必须确保点的概率分布即使在四边形中也是如此。

    http://mathworld.wolfram.com/TrianglePointPicking.html

    给出了很好的解释

    【讨论】:

      【解决方案6】:

      我会将您的四边形分成多个图形,其中每个图形都是一个正多边形,一侧(或两侧)平行于其中一个轴。例如,对于上图,我将首先找到适合四边形内部的最大矩形,该矩形必须平行于 X/Y 轴。然后在剩下的区域,我会拟合三角形,这样的三角形将与矩形的每一边相邻。

      那么写一个函数就简单了:

      1) 随机获取一个数字。 2) 在图中找一个随机点。

      如果#1 中选择的图形是一个矩形,应该很容易在其中找到一个随机点。棘手的部分是编写一个可以在三角形内找到随机点的例程

      【讨论】:

      • 正如其他人指出的那样,您需要按区域权衡图形选择。
      【解决方案7】:

      所以,这次要解决如何确定一个点是否在四边形内:

      四个边可以表示为y = mx + b 形式的线。检查点是在四条线的上方还是下方,综合起来就可以判断是在里面还是在外面。

      【讨论】:

      • 这看起来很合理。如果它 仍然 太慢,一个可能的优化是找到 by 四边形的矩形并进行快速的第一次测试以查看该点是否在其中。四个比较,很便宜。如果它在,停止。否则,进行测试 y=mx+b 测试。这种潜在的优化实际上可能会更慢,所以一定要对其进行基准测试。
      • 找出由四边形包围的矩形本身似乎是一个挑战。
      【解决方案8】:

      您是否允许在四边形边界的矩形内反复尝试任何地方,直到在四边形内得到一些东西?这甚至可能比一些花哨的算法更快,以确保您在四边形中挑选一些东西?

      顺便说一句,在那个问题陈述中,我认为“查找”一词的使用令人困惑。您无法真正找到满足条件的随机值;随机发生器只是把它给你。您要做的是在随机发生器上设置参数,为您提供符合特定条件的值。

      【讨论】:

        【解决方案9】:

        “蛮力”方法只是循环遍历,直到获得有效坐标。在伪代码中:

        left   = min(pa.x, pb.x, pc.x, pd.x)
        right  = max(pa.x, pb.x, pc.x, pd.x)
        bottom = min(pa.y, pb.y, pc.y, pd.y)
        top    = max(pa.y, pb.y, pc.y, pd.y)
        do {
            x = left   + fmod(rand, right-left)
            y = bottom + fmod(rand, top-bottom)
        } while (!isin(x, y, pa, pb, pc, pd));
        

        您可以使用从网上提取的股票函数来获取“isin”。我意识到这不是世界上执行速度最快的事情,但我认为它会奏效。

        【讨论】:

          猜你喜欢
          • 2010-09-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-28
          • 2011-12-04
          • 1970-01-01
          相关资源
          最近更新 更多