给定球体上的随机点

时间:2011-04-03 19:15:51

标签: javascript random 3d geometry

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

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的幂余弦”。

2 个答案:

答案 0 :(得分:29)

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

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

因此立方体面中心的相对体积(如(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];
}

答案 1 :(得分:23)

我认为更简单的算法是

  1. [-1,1]x[-1,1]x[-1,1]多维数据集
  2. 中选择一个随机点
  3. 如果x*x + y*y + z*z > 1从1
  4. 重复
  5. xyz划分为Math.sqrt(x*x + y*y + z*z)
  6. 换句话说,只需在球体内选择一个随机点并在球体上投射。不要太担心“循环”,因为一个点在球体之外的概率约为0.4764,平均而言,循环将需要少于两次迭代。

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

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

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

    enter image description here

    两个球体上都有1000个随机点:左边的球体使用均匀的随机点,右边的球体通过从十个随机候选中选取每个点来做出选择,以最大化已经选择的点的距离。 / p>