Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random Point on a given Sphere

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".

like image 681
Squis Avatar asked Apr 03 '11 19:04

Squis


People also ask

How do you select a random point on a sphere?

random points can be picked on a unit sphere in the Wolfram Language using the function RandomPoint[Sphere[], n]. have a uniform distribution on the surface of a unit sphere. This method can also be extended to hypersphere point picking.

How do you find the points of a sphere?

The general equation of a sphere is: (x - a)² + (y - b)² + (z - c)² = r², where (a, b, c) represents the center of the sphere, r represents the radius, and x, y, and z are the coordinates of the points on the surface of the sphere.

How do you generate random points in a polygon?

The first step is to decompose the polygon into triangles. You can use the relative areas of the triangles to determine the probability that a random point is in each triangle. Finally, you can generate random points in the union of the triangles.

How do you evenly distribute points on a sphere?

Mapping the Fibonacci lattice (aka Golden Spiral, aka Fibonacci Sphere) onto the surface of a sphere is an extremely fast and effective approximate method to evenly distribute points on a sphere.


2 Answers

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.

like image 27
6502 Avatar answered Sep 30 '22 17:09

6502


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];
}
like image 163
Neil Lamoureux Avatar answered Sep 30 '22 19:09

Neil Lamoureux