J'ai besoin d'un algorithme qui puisse me donner des positions autour d'une sphère pour N points (moins de 20, probablement) qui les étend vaguement. Il n'y a pas besoin de "perfection", mais j'en ai juste besoin pour qu'aucun d'entre eux ne soit groupé.
Quelques autres questions que j'ai rencontrées ont parlé de la distribution uniforme randomisée, ce qui ajoute un niveau de complexité qui ne m'inquiète pas. Je suis désolé, mais c’est une question aussi stupide, mais je voulais montrer que j’ai vraiment regardé haut et que j’ai encore fait court.
Donc, ce que je recherche, c’est un pseudocode simple pour répartir uniformément N points autour d’une unité de sphère, qui retourne en coordonnées sphériques ou cartésiennes. Encore mieux s’il peut même se distribuer avec un peu de randomisation (imaginez des planètes autour d’une étoile, bien réparties, mais avec une marge de liberté).
Dans cet exemple de codenode[k]
n'est que le kème nœud. Vous générez un tableau N points et node[k]
est le kième (de 0 à N-1). Si c’est tout ce qui vous dérange, espérons que vous pourrez l’utiliser maintenant.
(en d'autres termes, k
est un tableau de taille N défini avant le début du fragment de code et contenant une liste des points).
Alternativement , construisant sur l'autre réponse ici (et en utilisant Python):
> cat ll.py
from math import asin
nx = 4; ny = 5
for x in range(nx):
lon = 360 * ((x+0.5) / nx)
for y in range(ny):
midpt = (y+0.5) / ny
lat = 180 * asin(2*((y+0.5)/ny-0.5))
print lon,lat
> python2.7 ll.py
45.0 -166.91313924
45.0 -74.0730322921
45.0 0.0
45.0 74.0730322921
45.0 166.91313924
135.0 -166.91313924
135.0 -74.0730322921
135.0 0.0
135.0 74.0730322921
135.0 166.91313924
225.0 -166.91313924
225.0 -74.0730322921
225.0 0.0
225.0 74.0730322921
225.0 166.91313924
315.0 -166.91313924
315.0 -74.0730322921
315.0 0.0
315.0 74.0730322921
315.0 166.91313924
Si vous tracez cela, vous verrez que l'espacement vertical est plus grand près des pôles, de sorte que chaque point se situe dans à peu près la même superficie totale (près des pôles, il y a moins d'espace "horizontalement", donc cela donne plus "verticalement").
Ce n'est pas la même chose que tous les points ayant à peu près la même distance de leurs voisins (c'est ce dont vos liens parlent, je pense), mais cela peut suffire à ce que vous voulez et améliore simplement la création d'une grille uniforme lat/lon .
L'algorithme de sphère de Fibonacci est idéal pour cela. C'est rapide et donne des résultats qui en un coup d'oeil tromperont facilement l'oeil humain. Vous pouvez voir un exemple de traitement qui affichera le résultat au fil du temps, à mesure que des points sont ajoutés. Voici un autre excellent exemple interactif réalisé par @gman. Et voici une rapide python avec une option de randomisation simple:
import math, random
def fibonacci_sphere(samples=1,randomize=True):
rnd = 1.
if randomize:
rnd = random.random() * samples
points = []
offset = 2./samples
increment = math.pi * (3. - math.sqrt(5.));
for i in range(samples):
y = ((i * offset) - 1) + (offset / 2);
r = math.sqrt(1 - pow(y,2))
phi = ((i + rnd) % samples) * increment
x = math.cos(phi) * r
z = math.sin(phi) * r
points.append([x,y,z])
return points
1000 échantillons vous donnent ceci:
C’est ce que l’on appelle des points d’emballage sur une sphère et il n’existe pas de solution générale (connue) parfaite. Cependant, il existe de nombreuses solutions imparfaites. Les trois plus populaires semblent être:
n
d’eux) à l’intérieur du cube entourant la sphère, puis vous les rejetez en dehors de la sphère. Traitez les points restants comme des vecteurs et normalisez-les. Ce sont vos "échantillons" - choisissez n
en utilisant une méthode (aléatoire, gourmande, etc.).A beaucoup plus d'informations sur ce problème peuvent être trouvées ici
Vous avez dit que vous ne pouviez pas utiliser la méthode de la spirale dorée et c'est dommage car c'est vraiment très bon. Je voudrais vous en donner une compréhension complète afin que vous puissiez peut-être comprendre comment éviter que cela ne soit "groupé".
Il existe donc un moyen rapide et non aléatoire de créer un réseau approximativement correct. comme discuté ci-dessus, aucun réseau ne sera parfait, mais cela peut être "assez bon". Il est comparé à d’autres méthodes, par ex. at BendWavy.org mais il a juste un joli et joli look ainsi qu'une garantie d'un espacement uniforme dans la limite.
Pour comprendre cet algorithme, je vous invite tout d'abord à examiner l'algorithme 2D en spirale du tournesol. Ceci est basé sur le fait que le nombre le plus irrationnel est le nombre d'or (1 + sqrt(5))/2
Et si l'on émet des points par l'approche "placez-vous au centre, tournez un nombre d'or de tours entiers, puis émettez un autre point dans cette direction. , "on construit naturellement une spirale qui, quand on arrive à des nombres de points de plus en plus élevés, refuse néanmoins de disposer de" barres "bien définies sur lesquelles les points s'alignent.(Note 1.)
L'algorithme pour l'espacement uniforme sur un disque est,
from numpy import pi, cos, sin, sqrt, arange
import matplotlib.pyplot as pp
num_pts = 100
indices = arange(0, num_pts, dtype=float) + 0.5
r = sqrt(indices/num_pts)
theta = pi * (1 + 5**0.5) * indices
pp.scatter(r*cos(theta), r*sin(theta))
pp.show()
et cela donne des résultats qui ressemblent à (n = 100 et n = 1000):
La chose étrange clé est la formule r = sqrt(indices / num_pts)
; comment suis-je arrivé à celui-là? (Note 2.)
Eh bien, j'utilise la racine carrée ici parce que je veux que ceux-ci aient un espacement uniforme autour de la sphère. C’est la même chose que de dire que dans la limite des grands [~ # ~] n [~ # ~] je veux une petite région [~ # ~] r [~ # ~] ( r , r + d r ), Θ ∈ ( θ , θ + d θ ) contient un nombre de points proportionnel à sa surface, ce qui correspond à r d r d θ . Maintenant, si nous prétendons que nous parlons d’une variable aléatoire ici, cela a une interprétation directe qui dit que la densité de probabilité conjointe pour ( [~ # ~] r [~ # ~] , Θ ) est simplement cr pour une constante c . La normalisation sur le disque de l'unité force alors c = 1/π.
Maintenant, laissez-moi vous présenter un truc. Il provient de la théorie des probabilités où il est connu sous le nom échantillonnage du CDF inverse : supposons que vous vouliez générer une variable aléatoire avec une densité de probabilité f ( z ) et vous avez une variable aléatoire [~ # ~] u [~ # ~] ~ Uniforme (0, 1), comme dans random()
dans la plupart des langages de programmation. Comment est-ce que tu fais ça?
Maintenant, le tour en spirale du nombre d'or espacera les points dans un motif bien uniforme pour θ alors intégrons cela à l'extérieur; pour le cercle unitaire, il nous reste [~ # ~] f [~ # ~] ( r ) = r 2. Donc, la fonction inverse est [~ # ~] f [~ # ~] -1( u ) = u 1/2, et donc nous générerions des points aléatoires sur la sphère en coordonnées polaires avec r = sqrt(random()); theta = 2 * pi * random()
.
Maintenant au lieu de au hasard échantillonner cette fonction inverse, nous sommes uniformément l'échantillonner, et la bonne chose à propos de l'échantillonnage uniforme est que nos résultats sur la façon dont les points sont répartis dans la limite de grande [~ # ~] n [~ # ~] == se comportera comme si nous l'avions échantillonné de manière aléatoire. Cette combinaison est le truc. Au lieu de random()
, nous utilisons (arange(0, num_pts, dtype=float) + 0.5)/num_pts
, De sorte que, par exemple, si nous voulons échantillonner 10 points, ils sont r = 0.05, 0.15, 0.25, ... 0.95
. Nous échantillonnons uniformément r pour obtenir un espacement égal des surfaces, et nous utilisons l'incrément de tournesol pour éviter de terribles "barres" de points dans la sortie.
Les changements que nous devons faire pour doter la sphère de points consistent simplement à désactiver les coordonnées polaires pour les coordonnées sphériques. Bien entendu, la coordonnée radiale n’entre pas dans ceci parce que nous sommes sur une sphère unité. Pour garder les choses un peu plus cohérentes ici, même si j'ai été formé en physicien, j'utiliserai les coordonnées des mathématiciens où 0 ≤ φ ≤ π est la latitude descendant du pôle et 0 ≤ θ ≤ 2π est la longitude. La différence avec ce qui précède est donc que nous remplaçons la variable r par φ .
Notre élément de surface, qui était r d r d θ , devient maintenant le péché pas beaucoup plus compliqué ( φ ) d φ d θ . Donc, notre densité de joint pour un espacement uniforme est sin ( φ )/4π. Intégrant dehors θ , nous trouvons f ( φ ) = sin ( φ )/2, donc [~ # ~] f [~ # ~] ( φ ) = (1 - cos ( φ ))/2. En inversant cela, nous pouvons voir qu’une variable aléatoire uniforme ressemblerait à acos (1 - 2 u ), mais nous échantillonnons de manière uniforme au lieu d’aléatoire, nous utilisons donc φ k = acos (1 - 2 ( k + 0,5)/ [~ # ~] n [~ # ~] ). Et le reste de l'algorithme ne fait que projeter cela sur les coordonnées x, y et z:
from numpy import pi, cos, sin, arccos, arange
import mpl_toolkits.mplot3d
import matplotlib.pyplot as pp
num_pts = 1000
indices = arange(0, num_pts, dtype=float) + 0.5
phi = arccos(1 - 2*indices/num_pts)
theta = pi * (1 + 5**0.5) * indices
x, y, z = cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi);
pp.figure().add_subplot(111, projection='3d').scatter(x, y, z);
pp.show()
Encore une fois pour n = 100 et n = 1000, les résultats sont les suivants:
Ces "barres" sont formées par des approximations rationnelles d'un nombre, et les meilleures approximations rationnelles d'un nombre proviennent de son expression de fraction continue, z + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))
où z
est un entier et n_1, n_2, n_3, ...
est une suite finie ou infinie d’entiers positifs:
def continued_fraction(r):
while r != 0:
n = floor(r)
yield n
r = 1/(r - n)
Puisque la partie de fraction 1/(...)
est toujours comprise entre zéro et un, un grand entier dans la fraction continue permet une approximation rationnelle particulièrement bonne: "un divisé par quelque chose entre 100 et 101" est meilleur que "un divisé par quelque chose entre 1 et 2. " Le nombre le plus irrationnel est donc celui qui est 1 + 1/(1 + 1/(1 + ...))
et n'a pas d'approximations rationnelles particulièrement bonnes; on peut résoudre φ = 1 + 1/ φ en multipliant par φ pour obtenir la formule du nombre d'or.
Pour ceux qui ne connaissent pas bien NumPy, toutes les fonctions sont "vectorisées", de sorte que sqrt(array)
est identique à ce que les autres langages peuvent écrire map(sqrt, array)
. Il s’agit donc d’une application composant par composant sqrt
. Il en va de même pour la division par un scalaire ou l'addition de scalaires - ceux-ci s'appliquent à tous les composants en parallèle.
La preuve est simple une fois que vous savez que c'est le résultat. Si vous demandez quelle est la probabilité que z < [~ # ~] z [~ # ~] < z + d z , cela revient à demander quelle est la probabilité que z < [~ # ~] f [~ # ~] -1( [~ # ~] u [~ # ~] ) < z + d z , applique [~ # ~] f [~ # ~] == == ==) == aux trois expressions, notant qu'il s'agit d'une fonction à croissance monotone, d'où [ ~ # ~] f [~ # ~] ( z ) < [~ # ~] u [~ # ~] < [~ # ~] f [~ # ~] ( z + d z ), développez le côté droit pour trouver [~ # ~] f [~ # ~] ( z ) + f ( z ) d z , et depuis [~ # ~] u [~ # ~] est uniforme, cette probabilité est juste f ( z ) d z comme promis.
Ce que vous recherchez s'appelle un revêtement sphérique. Le problème de recouvrement sphérique est très difficile et les solutions sont inconnues, à l'exception d'un petit nombre de points. Ce qui est certain, c’est que pour n points d’une sphère, il existe toujours deux points de distance d = (4-csc^2(\pi n/6(n-2)))^(1/2)
ou plus proches.
Si vous voulez une méthode probabiliste pour générer des points uniformément répartis sur une sphère, rien de plus simple: générez des points dans l’espace uniformément par distribution gaussienne (il est intégré à Java, il n’est pas difficile de trouver le code pour d’autres langues). Donc, dans un espace tridimensionnel, vous avez besoin de quelque chose comme
Random r = new Random();
double[] p = { r.nextGaussian(), r.nextGaussian(), r.nextGaussian() };
Puis projetez le point sur la sphère en normalisant sa distance à l’origine
double norm = Math.sqrt( (p[0])^2 + (p[1])^2 + (p[2])^2 );
double[] sphereRandomPoint = { p[0]/norm, p[1]/norm, p[2]/norm };
La distribution gaussienne dans n dimensions est symétrique sphérique, de sorte que la projection sur la sphère est uniforme.
Bien entendu, rien ne garantit que la distance entre deux points d'une collection de points générés uniformément sera délimitée ci-dessous. Vous pouvez donc utiliser le rejet pour imposer les conditions que vous pourriez avoir: il est probablement préférable de générer l'ensemble de la collection, puis rejeter toute la collection si nécessaire. (Ou utilisez "rejet précoce" pour rejeter toute la collection que vous avez générée jusqu'à présent; ne gardez pas certains points et n'en déposez pas d'autres.) Vous pouvez utiliser la formule pour d
donnée ci-dessus, moins le temps mort, pour déterminer la distance minimale entre les points en dessous de laquelle vous rejetterez un ensemble de points. Vous devrez calculer n choisissez 2 distances et la probabilité de rejet dépendra du jeu; il est difficile de dire comment, alors lancez une simulation pour avoir une idée des statistiques pertinentes.
Cette réponse est basée sur la même "théorie" qui est bien décrite par cette réponse
J'ajoute cette réponse comme:
- Aucune des autres options ne correspond au besoin d'uniformité (ou pas manifestement). (En notant que pour que la planète ressemble à un comportement de distribution particulièrement voulu dans la demande initiale, vous rejetez simplement de la liste finie des k points uniformément créés aléatoirement (au hasard le nombre d'index dans les k éléments de retour).)
- L’autre impl. Le plus proche vous a forcé à choisir le "N" par "axe angulaire", par opposition à "une seule valeur de N" entre les deux angular axes (qui avec un faible nombre de N, il est très difficile de savoir ce qui est important ou non (par exemple, vous voulez des "5 points - amusez-vous))
- En outre, il est très difficile de comprendre comment différencier les autres options sans aucune image. Voici donc à quoi ressemble cette option (ci-dessous) et son implémentation prête à l'emploi. .
avec N à 20:
puis N en 80:
voici le code python3 prêt à l'emploi, où l'émulation est la même source: " http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere "trouvé par d’autres. (Le tracé que j'ai inclus, qui se déclenche lorsqu'il est exécuté en tant que "principal", provient de: http://www.scipy.org/Cookbook/Matplotlib/mplot3D )
from math import cos, sin, pi, sqrt
def GetPointsEquiAngularlyDistancedOnSphere(numberOfPoints=45):
""" each point you get will be of form 'x, y, z'; in cartesian coordinates
eg. the 'l2 distance' from the origion [0., 0., 0.] for each point will be 1.0
------------
converted from: http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere )
"""
dlong = pi*(3.0-sqrt(5.0)) # ~2.39996323
dz = 2.0/numberOfPoints
long = 0.0
z = 1.0 - dz/2.0
ptsOnSphere =[]
for k in range( 0, numberOfPoints):
r = sqrt(1.0-z*z)
ptNew = (cos(long)*r, sin(long)*r, z)
ptsOnSphere.append( ptNew )
z = z - dz
long = long + dlong
return ptsOnSphere
if __== '__main__':
ptsOnSphere = GetPointsEquiAngularlyDistancedOnSphere( 80)
#toggle True/False to print them
if( True ):
for pt in ptsOnSphere: print( pt)
#toggle True/False to plot them
if(True):
from numpy import *
import pylab as p
import mpl_toolkits.mplot3d.axes3d as p3
fig=p.figure()
ax = p3.Axes3D(fig)
x_s=[];y_s=[]; z_s=[]
for pt in ptsOnSphere:
x_s.append( pt[0]); y_s.append( pt[1]); z_s.append( pt[2])
ax.scatter3D( array( x_s), array( y_s), array( z_s) )
ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')
p.show()
#end
testé à faible taux (N dans 2, 5, 7, 13, etc.) et semble fonctionner 'Nice'
Essayer:
function sphere ( N:float,k:int):Vector3 {
var inc = Mathf.PI * (3 - Mathf.Sqrt(5));
var off = 2 / N;
var y = k * off - 1 + (off / 2);
var r = Mathf.Sqrt(1 - y*y);
var phi = k * inc;
return Vector3((Mathf.Cos(phi)*r), y, Mathf.Sin(phi)*r);
};
La fonction ci-dessus doit être exécutée en boucle avec le nombre total de boucles et l'itération en cours de la boucle N.
Il est basé sur un motif de graines de tournesol, sauf que les graines de tournesol sont incurvées dans un demi-dôme, puis dans une sphère.
Voici une photo, sauf que je place la caméra à mi-chemin à l'intérieur de la sphère, de sorte qu'elle a l'air 2D au lieu de 3D car la caméra est à la même distance de tous les points. http://3.bp.blogspot.com/-9lbPHLccQHA/USXf88_bvVI/AAAAAAAAADY/j7qhQsSZsA8/s640/sphere.jpg
Healpix résout un problème étroitement lié (pixelisation de la sphère avec des pixels de surface égale):
http://healpix.sourceforge.net/
C'est probablement exagéré, mais peut-être qu'après l'avoir examiné, vous vous rendrez compte que certaines des autres propriétés de Nice vous intéressent. C'est beaucoup plus qu'une simple fonction qui génère un nuage de points.
J'ai atterri ici pour essayer de le retrouver; le nom "healpix" n'évoque pas exactement les sphères ...
OU ... pour placer 20 points, calculez les centres des faces icosahédronales. Pour 12 points, trouvez les sommets de l'icosaèdre. Pour 30 points, le milieu des bords de l’icosaèdre. vous pouvez faire la même chose avec le tétraèdre, le cube, le dodécaèdre et les octaèdres: un ensemble de points se trouve sur les sommets, un autre au centre de la face et un autre au centre des arêtes. Ils ne peuvent pas être mélangés, cependant.
edit: Ceci ne répond pas à la question que le PO voulait poser, le laissant ici au cas où les gens le jugeraient utile.
Nous utilisons la règle de probabilité de multiplication, combinée à des infinis-minimaux. Cela donne 2 lignes de code pour obtenir le résultat souhaité:
longitude: φ = uniform([0,2pi))
azimuth: θ = -arcsin(1 - 2*uniform([0,1]))
(défini dans le système de coordonnées suivant :)
Votre langue a généralement une primitive de nombre aléatoire uniforme. Par exemple, dans python, vous pouvez utiliser random.random()
pour renvoyer un nombre compris dans l'intervalle [0,1)
. Vous pouvez multiplier ce nombre par k pour obtenir un nombre aléatoire. la plage [0,k)
. Ainsi, en python, uniform([0,2pi))
signifierait random.random()*2*math.pi
.
Preuve
Maintenant, nous ne pouvons pas attribuer θ de manière uniforme, sinon nous nous regrouperions aux pôles. Nous souhaitons attribuer des probabilités proportionnelles à la surface du coin sphérique (le θ dans ce diagramme est en fait):
Un angular déplacement dφ à l'équateur entraînera un déplacement de dφ * r. Quel sera ce déplacement à un azimut arbitraire θ? Eh bien, le rayon de l'axe z est r*sin(θ)
, donc la longueur de l'arc de cette "latitude" coupant le coin est dφ * r*sin(θ)
. Ainsi, nous calculons la distribution cumulative de la zone à échantillonner, en intégrant la zone de la tranche du pôle sud au pôle nord.
(où choses = dφ*r
)
Nous allons maintenant essayer d’obtenir l’inverse du CDF: http://en.wikipedia.org/wiki/Inverse_transform_sampling
Nous normalisons d’abord en divisant notre quasi-CDF par sa valeur maximale. Cela a pour effet d'annuler les d et r.
azimuthalCDF: cumProb = (sin(θ)+1)/2 from -pi/2 to pi/2
inverseCDF: θ = -sin^(-1)(1 - 2*cumProb)
Ainsi:
let x by a random float in range [0,1]
θ = -arcsin(1-2*x)
avec un petit nombre de points, vous pouvez exécuter une simulation:
from random import random,randint
r = 10
n = 20
best_closest_d = 0
best_points = []
points = [(r,0,0) for i in range(n)]
for simulation in range(10000):
x = random()*r
y = random()*r
z = r-(x**2+y**2)**0.5
if randint(0,1):
x = -x
if randint(0,1):
y = -y
if randint(0,1):
z = -z
closest_dist = (2*r)**2
closest_index = None
for i in range(n):
for j in range(n):
if i==j:
continue
p1,p2 = points[i],points[j]
x1,y1,z1 = p1
x2,y2,z2 = p2
d = (x1-x2)**2+(y1-y2)**2+(z1-z2)**2
if d < closest_dist:
closest_dist = d
closest_index = i
if simulation % 100 == 0:
print simulation,closest_dist
if closest_dist > best_closest_d:
best_closest_d = closest_dist
best_points = points[:]
points[closest_index]=(x,y,z)
print best_points
>>> best_points
[(9.921692138442777, -9.930808529773849, 4.037839326088124),
(5.141893371460546, 1.7274947332807744, -4.575674650522637),
(-4.917695758662436, -1.090127967097737, -4.9629263893193745),
(3.6164803265540666, 7.004158551438312, -2.1172868271109184),
(-9.550655088997003, -9.580386054762917, 3.5277052594769422),
(-0.062238110294250415, 6.803105171979587, 3.1966101417463655),
(-9.600996012203195, 9.488067284474834, -3.498242301168819),
(-8.601522086624803, 4.519484132245867, -0.2834204048792728),
(-1.1198210500791472, -2.2916581379035694, 7.44937337008726),
(7.981831370440529, 8.539378431788634, 1.6889099589074377),
(0.513546008372332, -2.974333486904779, -6.981657873262494),
(-4.13615438946178, -6.707488383678717, 2.1197605651446807),
(2.2859494919024326, -8.14336582650039, 1.5418694699275672),
(-7.241410895247996, 9.907335206038226, 2.271647103735541),
(-9.433349952523232, -7.999106443463781, -2.3682575660694347),
(3.704772125650199, 1.0526567864085812, 6.148581714099761),
(-3.5710511242327048, 5.512552040316693, -3.4318468250897647),
(-7.483466337225052, -1.506434920354559, 2.36641535124918),
(7.73363824231576, -8.460241422163824, -1.4623228616326003),
(10, 0, 0)]
Prenez les deux facteurs les plus importants de votre N
, si N==20
, Les deux facteurs les plus importants sont {5,4}
Ou plus généralement {a,b}
. Calculer
dlat = 180/(a+1)
dlong = 360/(b+1})
Placez votre premier point sur {90-dlat/2,(dlong/2)-180}
, votre second sur {90-dlat/2,(3*dlong/2)-180}
, votre 3ème sur {90-dlat/2,(5*dlong/2)-180}
, jusqu'à ce que vous ayez fait le tour du monde une fois. Nous en arrivons à environ {75,150}
lorsque vous passez à côté de {90-3*dlat/2,(dlong/2)-180}
.
Évidemment, je travaille cela en degrés sur la surface de la terre sphérique, avec les conventions habituelles pour traduire +/- en N/S ou E/W. Et bien évidemment, cela vous donne une distribution totalement non aléatoire, mais elle est uniforme et les points ne sont pas regroupés.
Pour ajouter un certain degré d’aléatoire, vous pouvez générer 2 normalement distribués (avec une moyenne 0 et un dév std de {dlat/3, dlong/3}) et les ajouter à vos points uniformément distribués.
# create uniform spiral grid
numOfPoints = varargin[0]
vxyz = zeros((numOfPoints,3),dtype=float)
sq0 = 0.00033333333**2
sq2 = 0.9999998**2
sumsq = 2*sq0 + sq2
vxyz[numOfPoints -1] = array([(sqrt(sq0/sumsq)),
(sqrt(sq0/sumsq)),
(-sqrt(sq2/sumsq))])
vxyz[0] = -vxyz[numOfPoints -1]
phi2 = sqrt(5)*0.5 + 2.5
rootCnt = sqrt(numOfPoints)
prevLongitude = 0
for index in arange(1, (numOfPoints -1), 1, dtype=float):
zInc = (2*index)/(numOfPoints) -1
radius = sqrt(1-zInc**2)
longitude = phi2/(rootCnt*radius)
longitude = longitude + prevLongitude
while (longitude > 2*pi):
longitude = longitude - 2*pi
prevLongitude = longitude
if (longitude > pi):
longitude = longitude - 2*pi
latitude = arccos(zInc) - pi/2
vxyz[index] = array([ (cos(latitude) * cos(longitude)) ,
(cos(latitude) * sin(longitude)),
sin(latitude)])