【问题标题】:Random Point on a given Sphere给定球体上的随机点
【发布时间】:2011-07-28 18:12:06
【问题描述】:

我想在给定球体上选择随机点。这个页面解释得很好:

http://mathworld.wolfram.com/SpherePointPicking.html (“要获得点,使得球体上的任何小区域......”)

但我不完全确定我是否在 JavaScript 中正确实现它,因为我几乎没有办法正确测试它:

var u = random();
var v = random();
var angle1 = 2 * Math.PI * u;
var angle2 = Math.pow(Math.cos (2 * v - 1), -1);
X = X0 + (radius * Math.sin(angle1) * Math.cos(angle2));
Y = Y0 + (radius * Math.sin(angle1) * Math.sin(angle1));
Z = Z0 + (radius * Math.cos(angle1));

我特别不确定我是否正确理解了 cos(-1),我将其实现为“-1 的余弦”。

【问题讨论】:

  • "cos^-1" 表示“反余弦”,又名“arccos”(或“acos”)。
  • 您可以通过确保 sqrt(x^2+y^2+z^2)(没有 x0/y0/z0 偏移)等于半径 +/- 浮点的小公差来部分测试答案错误。

标签: javascript random 3d geometry


【解决方案1】:

立方体算法不会在球体上给出均匀分布 - 特别是角投影附近的区域将具有最密集的点分布,而靠近立方体面的中心的区域将是最低的。

您可以直观地理解这一点,因为投影到底层球体上的立方体体积在靠近立方体面中心的角落附近更大。事实上,一小块(投影在球体上的一个小圆圈上)的体积与 从原点到小圆的中心到球体上相交点的向量大小的立方。

所以立方体面中心(如 (1,0,0))的相对体积为 1,但对于角点(如 (1,1,1))是 sqrt(3) 的立方体或 1.73 的立方体,大约 5.2,所以密度几乎是 5 倍!

spreadPoints() 函数可能会做得更好,但我不确定。

您的 JavaScript 中有几个错误 - 使用 pow(..,-1) 函数而不是 acos(),混淆了角度,并且缺少用于 random() 调用的 Math 对象。,

这里是类似但正确的 JavaScript 来执行 Wolfram 链接所说的:

/*
Returns a random point of a sphere, evenly distributed over the sphere.
The sphere is centered at (x0,y0,z0) with the passed in radius.
The returned point is returned as a three element array [x,y,z]. 
*/
function randomSpherePoint(x0,y0,z0,radius){
   var u = Math.random();
   var v = Math.random();
   var theta = 2 * Math.PI * u;
   var phi = Math.acos(2 * v - 1);
   var x = x0 + (radius * Math.sin(phi) * Math.cos(theta));
   var y = y0 + (radius * Math.sin(phi) * Math.sin(theta));
   var z = z0 + (radius * Math.cos(phi));
   return [x,y,z];
}

【讨论】:

    【解决方案2】:

    我认为更简单的算法是

    1. [-1,1]x[-1,1]x[-1,1] 立方体内随机选择一个点
    2. 如果 x*x + y*y + z*z > 1 从 1 开始重复
    3. xyz 归一化除以Math.sqrt(x*x + y*y + z*z)

    换句话说,只需在球体内选择一个随机点并投射到球体上。不要太担心“循环”,因为一个点在球外的概率约为 0.4764,平均而言循环需要少于两次迭代。

    您可以在on this link 看到此算法的实际应用。 请注意,如果您使用 chrome,赤道周围会出现一些条带,我认为这是 Math.random 中的一个错误,或者只是一个低质量的随机生成器(在 Firefox 或 Safari 上工作正常,但同样的问题也可见在安卓浏览器上)。随着点数的增加,条带更加明显(例如,10000 而不是我现在用来保持动画流畅的 1000 点)。 编辑:这个错误现已在 chrome 和 Android 上得到修复.

    请注意,如果您正在寻找一种将点均匀分布在球体上的方法,您可以通过如上所述选择十个随机点,然后只接受与已选择的集合中 3d 距离最大的点来做一些更好的事情点。这仍然是全局随机的(即,具有规定半径的圆盘将接收一个点的概率对于球体上的所有圆盘都是相同的)但如果您需要对球体进行“采样”,则会更好地分配点。该函数在链接指向的html文件中编码为spreadPoints()

    您可以在这里看到这两种方法之间的区别:

    两个球体上都绘制了 1000 个随机点:左侧的球体使用统一的随机点,右侧的球体通过从 10 个随机候选点中选择每个点来最大化与已选择点的距离。

    【讨论】:

    • 这真的是最优算法吗?我希望一个不会丢掉这么多积分的人会更好?
    • 最优性不是标量值,您必须选择标准。问题中的算法需要更复杂的计算,而此处显示的算法计算更简单,但循环平均运行不到两次,但每次迭代需要三个随机数。是更好还是更糟? ......因为它经常发生在计算回复是“取决于”。
    猜你喜欢
    • 1970-01-01
    • 2019-08-28
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2018-03-31
    • 1970-01-01
    • 2012-02-08
    相关资源
    最近更新 更多