2

How can I calculate points around a sphere? I need this for my particles explosion. I don't want the particle's points to be all random. I need them in a spherical pattern. For 2d circle explosion I was using this:

float n=many;
float rad = 1;
for (int i = 0; i < n; i++)
{
        float fi = 2*PI*i/n;
        float x1 = rad*sin(fi + PI)+x ;
        float y1 = rad*cos(fi + PI)+y ;
        addparticlesmart(x,y,(x1-x),(y1-y), 0.01f),r,g,b,a,0.02f);
}
Bart
  • 19,692
  • 7
  • 68
  • 77
SteveL
  • 3,331
  • 4
  • 32
  • 57
  • 4
    http://www.cs.cmu.edu/~mws/rpos.html – Bart Mar 20 '12 at 13:20
  • The easiest way IMO is to generate Gaussian-distributed _x_, _y_, _z_ values, and normalize the vector to the desired radius. – leftaroundabout Mar 20 '12 at 13:24
  • @Bart: this does _not_ give a uniform distribution on the sphere (where each area element will get the same density) – leftaroundabout Mar 20 '12 at 13:26
  • 1
    possible duplicate of [Uniform random (Monte-Carlo) distribution on unit sphere](http://stackoverflow.com/questions/1841014/uniform-random-monte-carlo-distribution-on-unit-sphere) – High Performance Mark Mar 20 '12 at 13:27
  • This was just asked a few days ago: [Evenly distributing n points on a sphere](http://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere/9606368#9606368) – BlueRaja - Danny Pflughoeft Mar 20 '12 at 14:50
  • The OP clearly states "I don't want the particle's points to be all random" which implies that these random methods thought to be similar to this question are in fact quite dissimilar. To illustrate this, his example for the 2D case demonstrates a high degree of non-randomness. – andand Mar 20 '12 at 21:23

3 Answers3

6

Complete conversion from spherical to Cartesian coordinates:

Cartesian coordinates: (x,y,z)
Spherical coordinates: (r,φ,θ) with r∈[0,∞), φ∈[0,2π), θ∈[0,π]

Then:
x = r*cos(φ)*sin(θ)
y = r*sin(φ)*sin(θ)
z = r*cos(θ)
Stefan Marinov
  • 570
  • 4
  • 14
  • Right, but you also need to consider the differentials of the coordinate mapping to produce proper probability densities on the sphere. – leftaroundabout Mar 20 '12 at 13:28
  • I was just pointing out the mathematics behind it. The actual implementation, to be similar to the asker's one for the two-dimensinal case, is actually quite simple: you just put everything in another for where you compute `θ` similarly (btw `z` as well as it isn't affected from the value of `φ`, using the notation I provided). Then you can modify the code in the given `for` accordingly, i.e. multiply by `sin(θ)`. What you have to consider is up to what you exactly need, of course. – Stefan Marinov Mar 20 '12 at 13:36
5

You have a few options.

Lat / Lon - Loop over latitude from -π/2 to + π/2 and longitude from 0 to 2π at whatever interval you like. Then convert from spherical to cartesian coordinates. While this is easy to code, it has the disadvantage that the points tend to cluster at the poles.

Tessellation - You can pick a regular polyhedron, preferably with triangular faces, (an icosahedron is my favorite for this purpose) and recursively find the bisector of each edge of each face. You then divide that face into four triangular faces, normalizing the bisector points so they lie on the surface of the sphere. Though the points are not quite uniformly distributed over the sphere (which can be seen if you don't use an icosahedron as the base polyhedron) it appears to be much more evenly distributed than the lat / lon approach. It has as a disadvantage, being somewhat more difficult to code. A more detailed description is available here.

Random points - I know you said you didn't like the idea of picking random points, but I'll include it here for completeness. There is a good treatment of it at Wolfram's site.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
andand
  • 17,134
  • 11
  • 53
  • 79
  • I saw the wolfram site. But I see no connection between calculating theta and phi and connecting that to the center point and radius in order to produce random points in the sphere. I don't know how to convert that to code. I have my theta and I have my phi. How do I get the coordinates for a point on a sphere with x,y,z coordinates and R radius? – John Demetriou Oct 09 '17 at 07:43
  • 1
    @JohnDemetriou That's a different issue. You need to transform between Cartesian and Spherial coordinates (https://www.google.com/search?q=cartesian+to+spherical&oq=cartesian+to+sph&gs_l=psy-ab.3.0.0l10.5531.6540.0.7737.3.3.0.0.0.0.330.874.2-2j1.3.0....0...1.1.64.psy-ab..0.3.872....0.4Swcsyj5ArA) and vice versa. – andand Oct 09 '17 at 15:07
  • 1
    @JohnDemetriou For completeness ... here are topics for converting Spherical to Cartesian coordinates (https://www.google.com/search?q=spherical+to+cartesian&oq=spheric&gs_l=psy-ab.3.0.0i20i263i264k1j0i67k1l6j0l3.87228.88833.0.90803.7.7.0.0.0.0.289.784.0j2j2.4.0....0...1.1.64.psy-ab..3.4.782...46j35i39k1j0i20i264k1j0i46k1.0.Tv9yinF4kYc). – andand Oct 09 '17 at 15:13
3

If you can use the new c++11 standard, it is easy to create gaussian distributed random numbers. Then you can use the fact that three 1-dimensional gaussian numbers makes one 3-dimensional gaussian coordinate, which is uniformly distributed on a sphere of constant radius (the radius is gaussian distributed). If you want the coordinates only on a specific radius you have to normalize your coordinates. Here's how you can do it:

#include <iostream>
#include <random>
#include <cmath>


using namespace std;

int main (int argC, char* argV[])
{
    //Create random generator
    mt19937 rnd;
    //Create Gaussian distribution
    normal_distribution<double> normDist ( 0.0, 1.0 );
    //Seed random generator
    rnd.seed(time(NULL));

    const double sphereRadius = 1;

    //Create 3 Gauss Random Numbers
    double rndArray[3];
    double rndSqrSum = 0;
    for ( uint i = 0; i < 3; i++ )
    {
        rndArray[i] = normDist( rnd );
        rndSqrSum += rndArray[i] * rndArray[i];
    }

    //Calculate Faktor to get a Sphere of radius sphereRadius
    double faktor = sphereRadius / sqrt( rndSqrSum ) ;

    //The random Coordinates then are:
    double x = rndArray[0]*faktor;
    double y = rndArray[1]*faktor;
    double z = rndArray[2]*faktor;

    cout << "Koordinates are: " << endl << "x: " << x << endl << "y: " << y << endl << "z: " << z << endl << "Radius is: " << sqrt(x*x+y*y+z*z) << endl;

}

For your application probably not needed but useful though, this method can be used for arbitrary dimensions, eg. 20 dimensional problems.

Haatschii
  • 9,021
  • 10
  • 58
  • 95