带有移位孔的环内随机点

时间:2017-10-29 22:25:31

标签: python math random geometry point

首先,如果有人能给我一个适当的术语“带有移位孔的环”,我将不胜感激,请看下我在下面图片中的形状。

回到主要问题:我想在橙色区域中选择一个随机点,不需要均匀分布。对于通常环的情况,我会选择随机点(r:R)范围和随机角度,然后将它们转换为x,y并完成。但对于这种不寻常的形状......是否有一个“简单”的公式,或者我应该通过做某种形状的多边形近似来接近它?

我对一般方法感兴趣,但会欣赏python,javascript或您选择的任何编码语言的示例。

shifted annulus

4 个答案:

答案 0 :(得分:3)

你真的需要精确抽样吗?因为接受/拒绝它应该工作得很好。我假设大橙色圆圈位于(0,0)

import math
import random

def sample_2_circles(xr, yr, r, R):
    """
    R - big radius
    r, xr, yr - small radius and its position
    """
    x = xr
    y = yr
    cnd = True
    while cnd:
        # sample uniformly in whole orange circle
        phi = 2.0 * math.pi * random.random()
        rad = R * math.sqrt(random.random())
        x = rad * math.cos(phi)
        y = rad * math.sin(phi)

        # check condition - if True we continue in the loop with sampling
        cnd = ( (x-xr)**2 + (y-yr)**2 < r*r )

    return (x,y)

答案 1 :(得分:3)

这是一种简单的方法,可以在没有重新采样的情况下提供均匀分布。

为简单起见,假设外边界圆的中心(半径r_outer)位于(0, 0),内圆边界的中心(半径r_inner)位于{{ 1}}。

为外部磁盘写(x_inner, y_inner),为偏心内孔给出的平面子集D,为中心H1半径为H2的磁盘,以r_inner为中心。

现在假设我们忽略了内圈不是中心的事实,而不是从(0, 0)采样,我们从D-H1采样(这很容易统一)。然后我们犯了两个错误:

  • 我们可以从中抽取一个区域D-H2,即使这些样本不在结果中。
  • 我们从未采样过的地区A = H1 - H2,即使我们应该

但事情就是这样:区域B = H2 - H1A是一致的:在平面中给出任何B(x, y)(x, y)当且仅当H2位于(x_inner - x, y_inner - y)时,H1位于(x, y)当{且仅当A位于(x_inner - x, y_inner - y)时{} {1}}!地图B表示点(x, y) -> (x_inner - x, y_inner - y)周围的旋转180度。所以有一个简单的诀窍:从(0.5*x_inner, 0.5*y_inner)生成,如果我们在D - H2中得到一些内容,请旋转以获得相应的H1 - H2点。

这是代码。注意使用均匀分布的平方根来选择半径:这是一个标准技巧。例如,请参阅this article

H2 - H1

一个示例图,由以下内容生成:

import math
import random

def sample(r_outer, r_inner, x_inner, y_inner):
    """
    Sample uniformly from (x, y) satisfiying:

       x**2 + y**2 <= r_outer**2

       (x-x_inner)**2 + (y-y_inner)**2 > r_inner**2

    Assumes that the inner circle lies inside the outer circle;
    i.e., that hypot(x_inner, y_inner) <= r_outer - r_inner.
    """
    # Sample from a normal annulus with radii r_inner and r_outer.
    rad = math.sqrt(random.uniform(r_inner**2, r_outer**2))
    angle = random.uniform(-math.pi, math.pi)
    x, y = rad*math.cos(angle),rad*math.sin(angle)

    # If we're inside the forbidden hole, reflect.
    if math.hypot(x - x_inner, y - y_inner) < r_inner:
        x, y = x_inner - x, y_inner - y

    return x, y

uniform samples from annulus with off-center hole

答案 2 :(得分:2)

由于您没有显示自己的方程式,算法或代码,只是中心对齐圆的算法大纲,我也只是在这里给出一个算法的大纲,用于更一般的情况。 / p>

较小的圆是相似变换下的较大圆的图像。即在较大的圆中有一个固定点和一个比率(R / r,大于1),这样你可以在较小的圆上取任意点,检查从固定点到该点的矢量,并乘以该矢量通过比率,那么当从固定点开始时该矢量的结束是较大圆上的点。这种转变是一对一的。

因此,您可以在较小的圆上选择一个随机点(在0和2-pi之间选择随机的角度)并选择1之间的随机比率和圆之间的比例比R / r。然后使用具有相同固定点的相似变换,但使用随机比率来获得较小圆上的刚选择点的图像点。这是您所需区域的随机点。

这种方法相当简单。事实上,最难的数学部分是找到相似变换的固定点。但考虑到两个圆圈的中心和半径,这很容易。提示:转换将较小圆的中心带到较大圆的中心。

询问您是否需要更多细节。我的算法不会产生均匀的分布:在圆圈最接近的地方,点数会更加紧密,而在圆圈相距最远的地方,点数会更紧密。

以下是一些未经测试的Python 3.6.2代码。我会测试它并在可能的时候显示它的图形。

import math
import random

def rand_pt_between_circles(x_inner, 
                            y_inner,
                            r_inner, 
                            x_outer,
                            y_outer,
                            r_outer):
    """Return a random floating-point 2D point located between the 
    inner and the outer circles given by their center coordinates and 
    radii. No error checking is done on the parameters."""
    # Find the fixed point of the similarity transformation from the
    #   inner circle to the outer circle.
    x_fixed = x_inner - (x_outer - x_inner) / (r_outer - r_inner) * r_inner 
    y_fixed = y_inner - (y_outer - y_inner) / (r_outer - r_inner) * r_inner 

    # Find a a random transformation ratio between 1 and r_outer / r_inner
    #   and a random point on the inner circle
    ratio = 1 + (r_outer - r_inner) * random.random()
    theta = 2 * math.pi * random.random()
    x_start = x_inner + r_inner * math.cos(theta)
    y_start = y_inner + r_inner * math.sin(theta)

    # Apply the similarity transformation to the random point.
    x_result = x_fixed + (x_start - x_fixed) * ratio
    y_result = y_fixed + (y_start - y_fixed) * ratio

    return x_result, y_result

答案 3 :(得分:1)

Severin Pappadeux描述的接受/拒绝方法可能是最简单的。

对于直接逼近,您也可以在极坐标中工作,孔的中心为极点。

外部圆的极坐标方程(Θ, σ)(抱歉,没有rho)将是

(σ cosΘ - xc)² + (σ sinΘ - yc)² = σ² - 2(cosΘ xc + sinΘ yc)σ + xc² + yc² = R²

这是σ中的二次方程,您可以根据Θ轻松解决。然后,您可以在0, 2π绘制一个角度,在rσ之间绘制半径。

这不会给你一个统一的分布,因为σ的范围是Θ的函数,并且由于极性偏差。这可以通过计算合适的传递函数来解决,但这有点技术性,可能不易分析。