我正在寻找一种算法,可以在一个带有平底(圆盘)的圆锥内生成点。
我有一个标准化的轴沿着它创建锥体(为了我们的目的,我们只是说它是y轴所以(0,1,0)和锥体的角度(假设它是45度) 。
我可以在网上找到的唯一资源在锥形内生成矢量,但它们基于对球体进行采样,因此在底部会得到一种“雪锥”效果,而不是底部的磁盘。
使用以下伪代码完成:
// Sample phi uniformly on [0, 2PI]
float phi = rand(0, 1) * 2 * PI
// Sample u uniformly from [cos(angle), 1]
float u = rand(0, 1) * (1 - cos(angle * PI/180)) + cos(angle * PI/180)
vec3 = vec3(sqrt(1 - u^2) * cos(phi), u, sqrt(1 - u^2) * sin(phi)))
下图是我的目标。能够在表面或内部生成样本也很不错:
答案 0 :(得分:4)
我可以使用积分和概率分布详细解释我的解决方案,但是在这个网站上缺少MathJax使得这很困难。我将把我的解释保持在一个简单的层面,但应该很清楚。我也会让解决方案比你要求的更加通用:我们想要一个高度为a
的右圆锥和基座b
的半径内的随机点,我们希望这个点具有均匀的采样超过那个锥体的体积。这种方法直接选择锥体中的随机点而不进行任何拒绝测试。
首先让我们考虑较大锥体内的小锥体h
,两个锥体具有相同的顶点和平行底座。这两个锥体当然是类似的数字,方形立方法则表示较小锥体的体积随其高度的立方变化。该高度从0
到a
不等,我们希望它的立方体在该范围内均匀。因此,我们选择h
随统一随机变量的立方根而变化,我们得到(在Python 3代码中),
h = a * (random()) ** (1/3)
我们接下来考虑圆形区域,它是较小的高度锥h
的基础。该基数的半径为(b / a) * h
,类似的三角形。现在想想在较大的圆形区域内的半径r
的较小圆形区域,两个圆在同一平面内并且具有相同的中心。较小圆的面积随其半径的平方而变化,因此为了在其范围内获得均匀的面积,我们采用均匀随机变量的平方根。我们得到
r = (b / a) * h * sqrt(random())
我们现在想要在半径为t
的较小圆周上的点的角度r
(对于 theta )。弧度的角度显然不依赖于其他因素,所以我们只使用一个均匀的随机变量得到
t = 2 * pi * random()
我们现在使用这三个随机变量h
,r
和t
来选择起始锥内的点。如果锥体的顶点位于原点并且锥体的轴线沿着正y轴,那么基部的中心是(0,a,0)并且基部圆周上的点是( b,a,0),你可以选择
x = r * cos(t)
y = h
z = r * sin(t)
当您询问“在表面上”生成样本时,您没有说明您是指锥体的侧面(或“侧面”?),只是基座或整个表面。你的第二张图片似乎只是侧面,但我会为这三张图片提供代码。
只有一方
我们再次在较大的锥体内使用较小的高度锥h
。它的表面积随其高度的平方而变化,因此我们采用均匀随机变量的平方根。如果我们的点在表面上,则其底部的圆是固定的,并且角度也是均匀的。所以我们得到
h = a * sqrt(random())
r = (b / a) * h
t = 2 * pi * random()
使用上面用于锥体内部的x
,y
和z
相同的代码来获取锥体侧面上的最终随机点。< / p>
仅限基数
这很像在内部选择一个点,除了高度预定为等于整个锥体的高度。我们得到以下有些简化的代码:
h = a
r = b * sqrt(random())
t = 2 * pi * random()
再次使用前面的代码作为最终x
,y
和z
。
整个表面
在这里,我们可以首先随机决定是将点放在基点还是表面上,然后将点放在上面两种方式之一中。高度a
和基础半径b
的圆锥底部的面积为pi * b * b
,而圆锥面的表面积为pi * b * sqrt(a*a + b*b)
。我们使用基数与这些区域总数的比率来选择使用哪个地下区域:
if random() < b / (b + sqrt(a*a + b*b)):
return point_on_base(a, b)
else:
return point_on_side(a, b)
将上面的代码用于side和base以完成该代码。
以下是10,000个随机点的简单matplotlib 3D散点图,首先在锥体内,然后在其侧面上。请注意,我的顶角为45°,因为您的文字说明但与图片不同。从其他角度观察这些似乎证实它们在体积或面积上是均匀的。