math - 锥形内均匀采样(按体积)

标签 math 3d geometry distribution

我正在寻找一种算法,该算法可以在具有平坦底部(磁盘)的圆锥体内生成点。

我有创建圆锥的标准化轴(出于我们的目的,我们只说它是y轴,所以(0,1,0)以及圆锥的角度(假设是45度)。

我在网上可以找到的唯一资源是在圆锥体内生成 vector ,但是它们是基于对球体进行采样的,因此在底部,您会得到一种“雪锥”效果,而不是在底部有一个圆盘。

这是通过以下伪代码完成的:

// 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)))

下图是我要的。能够在表面或内部生成样本的能力也会很好:

enter image description here

最佳答案

我可以使用积分和概率分布来详细说明我的解决方案,但是此站点上缺少MathJax使得这样做变得困难。我将保持简单的解释,但是应该清楚。我还将使该解决方案比您要求的更为通用:我们想要在高度a和基本b半径的右圆形圆锥内的随机点,并且希望在该圆锥的体积上进行均匀采样的点。此方法无需任何拒绝测试即可直接在圆锥中选择一个随机点。

首先,让我们考虑一下在较大圆锥体内的高度为h的较小圆锥,这两个圆锥具有相同的顶点和平行的底面。这两个圆锥体当然是相似的图形,并且方形立方体定律说,较小圆锥体的体积随其高度的立方体而变化。该高度从0a不等,我们希望它的立方体在该范围内是均匀的。因此,我们选择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()

现在,我们使用这三个随机变量hrt在起始圆锥体内选择我们的点。如果圆锥体的顶点位于原点并且圆锥体的轴沿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()

对上面用于锥体内部的xyz使用相同的代码,以获取锥体侧面上的最终随机点。

仅基础

这类似于在内部选择一个点,不同之处在于高度的预定值等于整个圆锥的高度。我们得到以下稍微简化的代码:
h = a
r = b * sqrt(random())
t = 2 * pi * random()

同样,对最终的xyz使用先前的代码。

整个表面

在这里,我们可以首先随机决定是将我们的点放置在基座上还是放置在表面上,然后以上面两种方式之一将其放置。高度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)

使用我上面的代码作为补充,以完成该代码。

这是10,000个随机点的简单matplotlib 3D散点图,首先在圆锥内部,然后在其侧面。请注意,正如您的文字所示,我使顶点角度为45°,但与您的图片不同。从其他角度查看这些似乎可以确认它们在体积或面积上是一致的。

enter image description here

enter image description here

关于math - 锥形内均匀采样(按体积),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41749411/

相关文章:

javascript - 给定正多边形的一条边,找出剩余的边

algorithm - 计算具有 100% 平滑度的平滑顶点法线的一般方法

ios - iOS 应用程序中的 3D 对象

algorithm - 最大线性维度 2d 点集

c# - .Net 中的零舍入错误类?

c# - 找到垂直线及其与矩形的交点

两个限制之间缩放数字的数学方程不是从 0 开始?

python - 3D旋转以连 catch 和圆柱体

algorithm - 平面中的最大共线点

actionscript-3 - 如何将非直线分成偶数段?