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".
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:
I think that an easier algorithm is
[-1,1]x[-1,1]x[-1,1]
cubex*x + y*y + z*z > 1
repeat from 1x
,y
andz
byMath.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:
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.