为了账号安全,请及时绑定邮箱和手机立即绑定

从 Sphere Loc 和 Radius 获取 Sphere 表面上的随机 XYZ

从 Sphere Loc 和 Radius 获取 Sphere 表面上的随机 XYZ

PHP
肥皂起泡泡 2023-03-11 15:31:51
我试图根据 XYZ 中的球体中心和 PHP 中的半径来获取球体表面上的随机 XYZ 坐标。目前,我的系统纯粹是随机的,希望在行星中心有一个位置。我不擅长数学,所以请多多包涵(计算障碍和阅读障碍)。现在我只是随机混乱如下(注意 randint 是一个自定义函数,它检查rand_int,mt_rand并rand使用最新的。            $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 ) );但我有行星 radius$pradius和行星 XYZ 中心阵列 $poo poo(x, y, z),我想我可以获得随机表面 XYZ,只是不确定。我看过其他语言,但无法理解要移植的任何内容。更新基于答案中提供的两种方法,我想出了以下两个功能。但是两者都无法正常运行。以下函数仅在小行星(北极)的顶部产生陨石坑(点),即使它应该从其半径处的小行星中心计算。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 ); } 
查看完整描述

1 回答

?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

您当前正在从边长为 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. 通过等于 r/d 的因子缩放来自步骤 1 的向量,其中 d 是在步骤 2 中确定的向量长度。对于我们的示例,我们将通过因子 r/d = 100/(50sqrt(2) ) = 2/平方根(2) = 平方根(2)。这给出 -50sqrt(2), 0, 50sqrt(2)。

  4. 现在,将步骤 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)

方法二:


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)


查看完整回答
反对 回复 2023-03-11
  • 1 回答
  • 0 关注
  • 90 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信