r_outer
)的中心位于(0, 0)
,内圆边界(半径为r_inner
)的中心位于(x_inner, y_inner)
。D
表示外部圆盘,H1
表示平面上的非中心内孔,H2
表示半径为r_inner
、以(0, 0)
为中心的中心圆盘。D-H2
中取样(这很容易均匀地进行)。然后我们犯了两个错误:
A=H1-H2
,我们可能会从中取样,但这些样本不应该在结果中。B=H2-H1
,我们永远不会从中取样,尽管我们应该取样。A
和B
是全等的:给定平面上的任何点(x, y)
,如果且仅当(x_inner-x, y_inner-y)
在H1
中时,(x, y)
在H2
中。因此,如果(x, y)
在A
中,则(x_inner-x, y_inner-y)
在B
中。映射(x, y) -> (x_inner-x, y_inner-y)
表示围绕点(0.5*x_inner, 0.5*y_inner)
旋转180度。所以有一个简单的技巧:从D-H2
生成,如果我们最终得到了H1-H2
中的某些东西,则旋转以获取相应的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
以下是生成示例图的代码:
import matplotlib.pyplot as plt
samples = [sample(5, 2, 1.0, 2.0) for _ in range(10000)]
xs, ys = zip(*samples)
plt.scatter(xs, ys, s=0.1)
plt.axis("equal")
plt.show()
您真的需要精确取样吗?因为使用接受/拒绝算法应该可以正常工作。我假设大橙色圆位于(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)
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
1.
我选择一个随机角度(a)和沿着 r 的一个点(l):a = Pi,l = 1;
2.
接下来是一个随机比率:rt = 2;
3.
??? - Max Yarix_inner
= 10,y_inner
= 10,r_inner
= 10,x_outer
= 0,y_outer
= 0,r_outer
= 50;
结果得到的 x_result
和 y_result
超过了50的范围(甚至达到200+)。 - Max Yari(Θ,σ)
(抱歉,没有ρ)将是(σ cosΘ - xc)² + (σ sinΘ - yc)² = σ² - 2(cosΘ xc + sinΘ yc)σ + xc² + yc² = R²
σ
的二次方程,可以轻松用 Θ
求解。然后您可以在 0, 2π
中绘制一个角,并在 r
和 σ
之间绘制半径。但是这样做并不能得到均匀分布,因为 σ
的范围是 Θ
的函数,并且存在极向偏差。通过计算适当的转移函数可能可以解决这个问题,但这需要一些技术支持,可能无法在分析上处理。