从球体定位和半径获取球体表面上的随机XYZ



我正在尝试根据 X Y Z 中的球体中心和 PHP 中的半径在球体表面上获取随机 X Y Z 坐标。目前,我的系统纯粹是随机的,希望在行星中心有一个位置。我在数学上无能,所以请耐心等待(计算障碍和阅读障碍(。

现在我只是随机混乱如下(注意 randint 是一个自定义函数,用于检查rand_intmt_randrand并使用最新的。

$nx = randint( abs( $poo['x'] - $max_distance_x ), abs( $poo['x'] + $max_distance_x ) );
$ny = randint( abs( $poo['y'] - $max_distance_y ), abs( $poo['y'] + $max_distance_y ) );
$nz = randint( abs( $poo['z'] - $max_distance_z ), abs( $poo['z'] + $max_distance_z ) );

但是我有行星半径$pradius,行星XYZ中心阵列$poopoo(x, y, z),我想我可以得到随机表面X Y Z,只是不确定。我看过其他语言,但很难理解要移植的任何内容。

更新

基于答案中提供的两种方法,我想出了以下两个函数。但是两者都无法正常运行。

以下函数仅在小行星(北极(的顶部产生陨石坑(点(,即使它应该从小行星中心在其半径处计算。

function basic_spheroid_point( $cx, $cy, $cz, $r ) {
$x = randint(-$r, $r);
$y = randint(-$r, $r);
$z = randint(-$r, $r);
$dx = $x - $cx;
$dy = $y - $cy;
$dz = $z - $cz;
$dd = sqrt( ( $dx * $dx ) + ( $dy * $dy ) + ( $dz * $dz ) );
if ( $dd > $r )
return basic_spheroid_point( $cx, $cy, $cz, $r );
$dx = $r * $dx / $dd;
$dy = $r * $dy / $dd;
$dz = $r * $dz / $dd;
return array( $cx + $dx, $cy + $dy, $cz + $dz );
}

此功能在地球的北极聚集了陨石坑,尽管也有全球覆盖的陨石坑,因此它部分工作。

function uniform_spheroid_point($cx, $cy, $cz, $r) {
$ap = randint( 0, 359 );
$aq = randint( 0, 359 );
$dx = $r* cos( $ap ) * cos( $aq );
$dy = $r * sin( $aq );
$dz = $r * sin( $ap ) * cos( $aq );
return array( $cx + $dx, $cy + $dy, $cz + $dz );
} 

您当前正在从边长为 2*max_distance_x、2*max_distance_y 和 2*max_distance_z 的平行六面体的内部随机选择一个点。让我们假设它们都相同,并且等效于要随机选择点的球体表面的半径 r。然后,您的方法将从边长为 2r 的立方体中随机选择。基本上,当以这种方式选择时,您的随机点实际上都不会位于半径为 r 的球体表面上。

但是 - 给定立方体中的一个点,您可以做的是:

  1. 计算从中心点到随机点("增量"(的向量。例如,如果您的中心点为 100,100,100,半径为 100,并且您随机选择点 50,100,150,则您要查找的向量为 -50,0,50。

  2. 计算步骤 1 中矢量的长度。这使用两点之间距离的公式,扩展以考虑点的三个坐标:sqrt(dx^2 + dy^2 +dz^2(。例如,我们的距离是 sqrt((-50(^2 + 0^2 + 50^2( = sqrt(2500 + 0 + 2500( = 50sqrt(2(。

  3. 将步骤
  4. 1 中的向量缩放等于 R/D 的因子,其中 d 是步骤 2 中确定的向量的长度。对于我们的示例,我们将向量缩放 r/d = 100/(50sqrt(2(( = 2/sqrt(2( = sqrt(2( 的因子。这给出了 -50sqrt(2(, 0, 50sqrt(2(。

  5. 现在,将步骤 3 中的缩放向量添加到中心点,以获得半径为 r 的球体表面上的点。在我们的例子中,球体表面上的点是 100-50sqrt(2(、100、100+50sqrt(2(。

现在唯一的问题是,有些点比其他点更有可能被选中。原因是球体表面上的某些点比其他点有更多的立方体。具体来说,位于边界立方体上的球体点在其外部没有更远的点,但球体上与连接立方体中心及其角之一的直线相交的点在球体外部具有大量空间(。要获得真正均匀的点分布,您需要排除随机选择的任何不在球体内部或表面上的点。如果这样做,您将通过上述方法获得点的均匀分布。因为立方体的体积是8r^3,球体的体积是4/3pir^3,而因为4/3pi~4,所以每次抽奖都有大约50%的机会得到一个你必须扔掉的点。平均而言,您希望每两场平局获得一分。您通常不需要很多随机抽奖才能获得一个好的抽奖,但它在技术上是无限的。

如果你想确保每次随机抽奖都是好的,我可能会建议从0到360度随机均匀地选择两个角度。然后,使用这些角度来标识球体上的一个点。因此,例如,假设您首先绘制角度 p,然后绘制角度 q。角度 p 可以确定从中获取该点的平原。此平面将以圆形横截面与球体相交。然后,角度 q 可以确定此相交圆上的哪个点作为随机点返回。假设这些角度给出点(x', y', z'(。井。。。

y' = r*sin(q) … since nothing else determines the y coordinate except q
x' = r*cos(p)*cos(q)
z' = r*sin(p)*cos(q)

这样做的优点是不需要拒绝任何随机样本,缺点是需要相对更昂贵的三角运算。

编辑:每种方法的伪代码

方法一:

RandomPointOnSphere(centerX, centerY, centerZ, radius)
1. x = random(-radius, radius)
2. y = random(-radius, radius)
3. z = random(-radius, radius)
4. dx = x - centerX
5. dy = y - centerY
6. dz = z - centerZ
7. dd = sqrt(dx*dx + dy*dy + dz*dz)
8. if dd > radius then return RandomPointOnSphere(centerX, centerY, centerZ, radius)
9. dx = radius * dx / dd
10. dy = radius * dy / dd
11. dz = radius * dz / dd
12. return (centerX + dx, centerY + dy, centerZ + dz)

方法2:

RandomPointOnSphere(centerX, centerY, centerZ, radius)
1. angleP = random(0, 359)
2. angleQ = random(0, 359)
3. dx = radius* cos(angleP) * cos(angleQ)
4. dy = radius * sin(angleQ)
5. dz = radius * sin(angleP) * cos(angleQ)
6. return (centerX + dx, centerY + dy, centerZ + dz)

最新更新