在圆环内随机生成点


策划给了个需求,给定一个圆环,内径r1,外径r2,要在圆环内随机产生点,在这些点位置上生成法术场。那么如何在圆环内随机产生这些点呢?

在圆内随机生成点

首先考虑在圆内生成随机点。
最简单的方法是在一个R*R的正方形内随机选取一个点,判断随机生成的点是否在圆内即可。python代码如下:

import random
def generateRandomPoint(r):
    while True:
        x = random.uniform(-r, r)
        y = random.uniform(-r, r)
        if x * x + y * y <= r * r:
            return x,y

还有一个简单的方法是:
先随机x的值, 根据 x 2 + y 2 < = r 2 x^2+y^2<=r^2 x2+y2<=r2,随机y的范围。
python代码如下:

import math
import random
def generateRandomPoint3(r):
    x = random.uniform(-r, r)
    square = math.sqrt(r*r-x*x)
    y = random.uniform(-square, square)
    return x,y

还有一个方法是根据半径和角度确定坐标
r ∈ [ o , R ] θ ∈ [ 0 , 2 π ] x = r ∗ cos ⁡ ( θ ) y = r ∗ sin ⁡ ( θ ) r\in[o,R] \\ \theta\in[0,2\pi] \\ x = r * \cos(\theta) \\ y = r * \sin(\theta) r[o,R]θ[0,2π]x=rcos(θ)y=rsin(θ)
python代码

import math
def generateRandomPoint1(r):
    random_r = random.uniform(0, r)
    random_theta = random.uniform(0, 2 * math.pi)
    return random_r * math.cos(random_theta), random_r * math.sin(random_theta)

但是很明显,上面生成的点的数据不是均匀分布的。
原因:
我们期望随机生成的点在圆上是均匀分布的。假设在半径为1的圆内生成点。假设一开始半径是0.5,生成角度在 [ 0 , 2 π ] [0,2\pi] [0,2π]的点的密度明显要大于半径1.0,生成角度在 [ 0 , 2 π ] [0,2\pi] [0,2π]的点。
在这里插入图片描述
即圆的半径 2 π r 2\pi r 2πr增长和半径 r r r正相关,即半径越大,需要的点也是线性增长的。即pdf也是线性增长的。由于pdf的面积大小是1,我们的半径长度是1,即
在这里插入图片描述
PDF表示概率密度函数(给出了变量落在某值xi邻域内(或者某个区间内)的概率变化快慢,概率密度函数的值不是概率,而是概率的变化率,概率密度函数下面的面积才是概率。见2
那么如何根据一个均匀分布的随机生成函数random.uniform来产生我们需要的定点呢?

生成CDF(累计分布函数)

C D F ( x ) = ∫ P D F = ∫ 2 x = x 2 CDF(x)=\int PDF=\int 2x = x^2 CDF(x)=PDF=2x=x2

交换x,y

C D F : y = x 2 s w a p : x = y 2 s o l v e : y = x C D F − 1 = y = x CDF:y=x^2\\ swap:x=y^2\\ solve:y=\sqrt x \\ CDF^{-1}=y=\sqrt x CDF:y=x2swap:x=y2solve:y=x CDF1=y=x

使用均匀分布函数带入

C D F − 1 ( r a n d o m ( ) ) = r a n d o m ( ) CDF^{-1}(random())=\sqrt {random()} CDF1(random())=random()

python代码

import math
def generateRandomPoint2(r):
    random_r = math.sqrt(random.uniform(0, r))
    random_theta = random.uniform(0, 2 * math.pi)
    return random_r * math.cos(random_theta), random_r * math.sin(random_theta)

在圆环内随机生成点

最简单的方法是在一个R*R的正方形内随机选取一个点,判断随机生成的点是否在圆环内即可。python代码如下:

def generateRandomPointFromAnnulus(r1,r2):
    """
    在圆环内随机取点, r1<=r2
    :param r1: 内径
    :param r2: 外径
    :return:
    """
    assert r1<= r2
    while True:
        x = random.uniform(-r2, r2)
        y = random.uniform(-r2, r2)
        if x * x + y * y <= r2 * r2 and x * x + y * y >= r1 * r1:
            return x,y

第二种方法是随机先随机得到x的值,然后算出y的范围,随机y的值,python代码如下:

import math
def generateRandomPointFromAnnulus1(r1,r2):
    """
    在圆环内随机取点, r1<=r2
    :param r1: 内径
    :param r2: 外径
    :return:
    """
    assert r1<= r2
    x = random.uniform(r1, r2)
    y = random.uniform(math.sqrt(x*x-r1*r1), math.sqrt(r2*r2-x*x))
    return x if random.uniform(-1,1) > 0 else -x, y if random.uniform(-1,1) > 0 else -y

类似求圆的概率密度函数,分布函数

生成CDF(累计分布函数)

和圆不一样,概率密度函数是从 [ r m i n , r m a x ] [r_{min},r_{max}] [rmin,rmax],而不是 [ 0 , r m a x ] [0,r_{max}] [0,rmax]

C D F ( x ) = ∫ r m i n r m a x r d r = π r 2 − π r m i n 2 π r m a x 2 − π r m i n 2 = A ( r 2 − r m i n 2 ) A = 1 / ( r m a x ∗ r m a x − r m i n ∗ r m i n ) CDF(x)=\int_{r_{min}}^{r_{max}} r dr= \frac{\pi r^2-\pi r_{min}^2}{\pi r_{max}^2-\pi r_{min}^2} = A(r^2 - r_{min}^2)\\ A = 1/(r_{max}*r_{max} - r_{min}*r_{min}) CDF(x)=rminrmaxrdr=πrmax2πrmin2πr2πrmin2=A(r2rmin2)A=1/(rmaxrmaxrminrmin)

交换x,y

C D F : y = A ( x 2 − r m i n 2 ) s w a p : x = A ( y 2 − r m i n 2 ) s o l v e : y = x A + r m i n 2 C D F − 1 = y = x A + r m i n 2 CDF:y=A(x^2 - r_{min}^2)\\ swap:x=A(y^2 - r_{min}^2)\\ solve:y=\sqrt {\frac {x}{A} + r_{min}^2} \\ CDF^{-1}=y=\sqrt {\frac {x}{A} + r_{min}^2} CDF:y=A(x2rmin2)swap:x=A(y2rmin2)solve:y=Ax+rmin2 CDF1=y=Ax+rmin2

使用均匀分布函数带入

C D F − 1 ( r a n d o m ( ) ) = r a n d o m ( ) A + r m i n 2 CDF^{-1}(random())=\sqrt {\frac {random()}{A} + r_{min}^2} CDF1(random())=Arandom()+rmin2

python代码

import math
def generateRandomPointFromAnnulus2(r1,r2):
    """
    在圆环内随机取点, r1<=r2
    :param r1: 内径
    :param r2: 外径
    :return:
    """
    assert r1<= r2
    a = 1 / (r2*r2-r1*r1)
    random_r = math.sqrt(random.uniform(0, 1) / a  + r1 * r1)
    random_theta = random.uniform(0, 2 * math.pi)
    return random_r * math.cos(random_theta), random_r * math.sin(random_theta)
  • 8
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值