给定球体上的随机点

发布于 2024-10-29 05:59:09 字数 602 浏览 1 评论 0原文

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

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

I want to select random points on a given sphere. This page explains it quite well:

http://mathworld.wolfram.com/SpherePointPicking.html
("To obtain points such that any small area on the sphere...")

But I'm not entirely sure if I'm implementing it correctly in JavaScript, as I have little means of testing it properly:

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

I'm especially unsure about if I've understood that cos(-1) correctly, which I implemented as "The cosine to the power of -1".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

伴随着你 2024-11-05 05:59:09

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

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

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

The cube algorithm will not give an even distribution over the sphere - in particular the areas near the projections of the corners will have the densest distribution of points and near the centers of the faces of the cubes will be the lowest.

You can understand this intuitively since the volume of cube projected onto the underlying sphere is larger near the corners that near the centers of the cubes faces. In fact, the volume of a small piece (that projects on a small circle on the sphere) is proportional to the
cube of size of the vector from the origin through the center of the small circle to the point on the sphere that it intersects.

So the relative volume on a cube face center (like (1,0,0)) is 1, but for a corner (e.g., (1,1,1)) is cube of sqrt(3) or 1.73 cubed, about 5.2, so almost 5 times denser!

The spreadPoints() function might do a better job, but I'm not sure.

There are a couple of errors in you JavaScript - the use of the pow(..,-1) function instead of acos(), mix ups on the angles and missing the Math object for the random() call.,

Here is similar but correct JavaScript to do what the Wolfram links says:

/*
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];
}
花开雨落又逢春i 2024-11-05 05:59:09

我认为更简单的算法是

  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,平均而言,循环需要的迭代次数少于两次。

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

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

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

在此处输入图像描述

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

I think that an easier algorithm is

  1. Pick a random point inside the [-1,1]x[-1,1]x[-1,1] cube
  2. If x*x + y*y + z*z > 1 repeat from 1
  3. Normalize dividing x, y and z by Math.sqrt(x*x + y*y + z*z)

in other words just pick a random point inside the sphere and project on the sphere. Don't worry too much about the "loop" because the probability of a point being outside the sphere is about 0.4764 and on average the loop will require less than two iterations.

You can see this algorithm in action on this link. Note that if you use chrome there will be some banding around an equator that in my opinion is a bug in Math.random or just a low quality random generator (works fine on Firefox or Safari, but the same problem is visible also on Android browser). The banding is much more visible with an higher number of points (e.g. 10000 instead of the 1000 points I'm using now to keep animation smooth). EDIT: This bug has now been fixed on chrome and Android.

Note that if you're looking for a method to distribute points evenly over a sphere you can do something nicer by choosing ten random points as described above and then accepting only the one with the biggest 3d distance from the set of already chosen points. This is still globally random (i.e. the probablity that a disc with a prescribed radius will receive a point is the same for all discs on the sphere) but will distribute points better if you need to do a "sampling" of the sphere. This function is coded as spreadPoints() in the html file pointed by the link.

You can see the difference between the two approaches here:

enter image description here

Both spheres have 1000 random points drawn on them: the sphere on the left used uniform random points, the sphere on the right instead made the choice by picking each point among ten random candidates to maximize the distance from already chosen points.

吾性傲以野 2024-11-05 05:59:09

这应该更有效。参见 https://karlsims.com/random-inms.com/random-in-in-sphere.html 视觉解释。

function randomSpherePoint(x0,y0,z0,radius) {
   var y = Math.random() * 2 - 1;  // random y from -1 to 1
   var r = Math.sqrt(1 - y*y);     // radius on xz plane at y
   var long = Math.random() * 2 * Math.PI;  // random longitude
   return [x0 + radius * r * Math.sin(long),
           y0 + radius * y,
           z0 + radius * r * Math.cos(long)];
}

This should be slightly more efficient. See https://karlsims.com/random-in-sphere.html for a visual explanation.

function randomSpherePoint(x0,y0,z0,radius) {
   var y = Math.random() * 2 - 1;  // random y from -1 to 1
   var r = Math.sqrt(1 - y*y);     // radius on xz plane at y
   var long = Math.random() * 2 * Math.PI;  // random longitude
   return [x0 + radius * r * Math.sin(long),
           y0 + radius * y,
           z0 + radius * r * Math.cos(long)];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文