对于我正在制作的简单粒子系统,我需要给出一个宽度和高度的椭圆,计算一个位于该椭圆中的随机点X,Y。
现在我不是数学方面最好的,所以我想在这里询问是否有人能指出我正确的方向。
也许正确的方法是在宽度范围内选择随机浮点数,将其取为X并从中计算Y值?
答案 0 :(得分:23)
在半径为1的圆内生成一个随机点。这可以通过在区间phi
中采用随机角度[0, 2*pi)
和随机值rho
来实现。区间[0, 1)
和计算
x = sqrt(rho) * cos(phi)
y = sqrt(rho) * sin(phi)
公式中的平方根确保了圆内的均匀分布。
将x
和y
缩放到椭圆的尺寸
x = x * width/2.0
y = y * height/2.0
答案 1 :(得分:12)
使用rejection sampling:在椭圆周围的矩形中选择一个随机点。通过检查(x-x0)^ 2 / a ^ 2 +(y-y0)^ 2 / b ^ 2-1的符号来测试该点是否在椭圆内。如果该点不在内部,请重复此操作。 (这假设椭圆与坐标轴对齐。类似的解决方案在一般情况下有效,但当然更复杂。)
答案 2 :(得分:1)
您可以使用极坐标进行笛卡尔坐标转换:
x = cos(angle) * radius
y = sin(angle) * radius
稍作修改
x = cos(angle) * width
y = sin(angle) * height
您没有指定语言,但这是使用Processing的快速演示:
float ellipseWidth = 150,ellipseHeight = 100;
float angle,radius,x,y;
void setup(){
size(400,400);
smooth();
noStroke();
ellipseMode(CENTER);
background(0);
fill(255);
}
void draw(){
//choose a random angle on the ellipse
angle = random(TWO_PI);
//convert from polar to cartesian, using both width and height as radii
x = cos(angle) * ellipseWidth;
y = sin(angle) * random(ellipseHeight);//random 'lengths' vertically
//draw
translate(200,200);//move to centre
ellipse(x,y,5,5);
}
您可以看到它运行here
HTH
答案 3 :(得分:1)
通过仔细考虑极性形式的定义,可以在不使用拒绝采样的情况下生成椭圆内的点。从wikipedia开始,椭圆的极坐标由
给出直观地说,我们应该在半径越大的地方更频繁地采样极角θ。在数学上更多,我们的随机变量θ的PDF应该是p(θ)dθ= dA / A,其中dA是角度θ与宽度dθ的单个区段的面积。使用极角区域方程dA = 1/2 r 2 dθ,椭圆区域为πab,则PDF变为
要从此PDF中随机抽样,一种直接方法是inverse CDF technique。这需要计算累积密度函数(CDF),然后反转此函数。使用Wolfram Alpha获得不定积分,然后反转它得到
的逆CDF其中u在0和1之间运行。因此,为了对随机角度θ进行采样,您只需在0和1之间生成一个均匀的随机数u,并将其替换为逆CDF的等式。
要获得随机半径,可以使用适用于圆的相同技术(例如,参见Generate a random point within a circle (uniformly))。
以下是一些实现此算法的示例Python代码:
import numpy
import matplotlib.pyplot as plt
import random
# Returns theta in [-pi/2, 3pi/2]
def generate_theta(a, b):
u = random.random() / 4.0
theta = numpy.arctan(b/a * numpy.tan(2*numpy.pi*u))
v = random.random()
if v < 0.25:
return theta
elif v < 0.5:
return numpy.pi - theta
elif v < 0.75:
return numpy.pi + theta
else:
return -theta
def radius(a, b, theta):
return a * b / numpy.sqrt((b*numpy.cos(theta))**2 + (a*numpy.sin(theta))**2)
def random_point(a, b):
random_theta = generate_theta(a, b)
max_radius = radius(a, b, random_theta)
random_radius = max_radius * numpy.sqrt(random.random())
return numpy.array([
random_radius * numpy.cos(random_theta),
random_radius * numpy.sin(random_theta)
])
a = 2
b = 1
points = numpy.array([random_point(a, b) for _ in range(2000)])
plt.scatter(points[:,0], points[:,1])
plt.show()