173 votes

Répartir uniformément n points sur une sphère

J'ai besoin d'un algorithme qui peut me donner des positions autour d'une sphère pour N points (moins de 20, probablement) qui les répartit vaguement. Il n'y a pas besoin de "perfection", mais j'ai juste besoin que aucun d'entre eux ne soit regroupé.

  • Cette question a fourni un bon code, mais je n'ai pas trouvé un moyen de le rendre uniforme, car cela semblait être à 100% aléatoire.
  • Cet article de blog recommandait deux façons permettant de saisir le nombre de points sur la sphère, mais l'algorithme de Saff et Kuijlaars est exactement en pseudo-code que je pourrais transcrire, et l'exemple de code que j'ai trouvé contenait "node[k]", ce que je n'ai pas vu expliqué et a ruiné cette possibilité. Le deuxième exemple de blog était la Spirale de la Section Dorée, qui m'a donné des résultats étranges et regroupés, sans moyen clair de définir un rayon constant.
  • Cet algorithme de cette question semble pouvoir fonctionner, mais je ne peux pas assembler ce qui se trouve sur cette page en pseudo-code ou quoi que ce soit d'autre.

Quelques autres fils de discussion auxquels j'ai participé ont parlé de distribution uniforme aléatoire, ce qui ajoute un niveau de complexité qui ne me préoccupe pas. Je m'excuse que ce soit une question si stupide, mais je voulais montrer que j'avais vraiment cherché intensément et n'avais toujours pas trouvé.

Donc, ce que je cherche, c'est un simple pseudo-code pour distribuer de manière uniforme N points autour d'une sphère unité, renvoyant soit des coordonnées sphériques soit cartésiennes. Encore mieux s'il peut distribuer uniformément avec un peu de randomisation (pensez aux planètes autour d'une étoile, assez espacées, mais avec de la marge de manœuvre).

0 votes

Que voulez-vous dire par "avec un peu de randomisation" ? Voulez-vous dire des perturbations dans un sens quelconque ?

42 votes

OP est confus. Ce qu'il recherche, c'est placer des points sur une sphère de telle sorte que la distance minimale entre deux points soit la plus grande possible. Cela donnera l'impression que les points sont "uniformément répartis" sur toute la sphère. Cela n'a absolument rien à voir avec la création d'une distribution aléatoire uniforme sur une sphère, ce qui est le sujet de nombreux liens mentionnés, et de nombreuses réponses ci-dessous en parlent.

1 votes

20 n'est pas beaucoup de points à placer sur une sphère si vous ne voulez pas qu'ils aient l'air juste aléatoires.

198voto

Fnord Points 227

L'algorithme de la sphère Fibonacci est excellent pour cela. Il est rapide et donne des résultats qui, en un coup d'œil, tromperont facilement l'œil humain. Vous pouvez voir un exemple réalisé avec processing qui montrera le résultat au fil du temps au fur et à mesure que des points sont ajoutés. Voici un autre excellent exemple interactif réalisé par @gman. Et voici une implémentation simple en python.

import math

def fibonacci_sphere(samples=1000):

    points = []
    phi = math.pi * (math.sqrt(5.) - 1.)  # golden angle en radians

    for i in range(samples):
        y = 1 - (i / float(samples - 1)) * 2  # y va de 1 à -1
        radius = math.sqrt(1 - y * y)  # rayon à y

        theta = phi * i  # incrément d'angle d'or

        x = math.cos(theta) * radius
        z = math.sin(theta) * radius

        points.append((x, y, z))

    return points

1000 échantillons vous donnent ceci :

entrer la description de l'image ici

0 votes

Une variable n est appelée lors de la définition de phi: phi = ((i + rnd) % n) * increment. Est-ce que n = échantillons?

0 votes

@AndrewStaroscik Oui! Quand j'ai écrit le code pour la première fois, j'ai utilisé "n" comme variable et j'ai changé le nom plus tard mais je n'ai pas fait preuve de diligence. Merci d'avoir remarqué ça!

0 votes

C'est génial, mais comment utiliser cela et entrer la distance souhaitée entre les points ? Par exemple, supposons que je veuille utiliser ceci pour emballer une sphère de rayon 2 autour d'une sphère. Quelle variable devrais-je changer pour obtenir une séparation de 2 entre les points ? Merci !

88voto

Ceci est connu comme l'emballage de points sur une sphère, et il n'existe pas de solution générale et parfaite (connue). Cependant, il existe de nombreuses solutions imparfaites. Les trois plus populaires semblent être:

  1. Créer une simulation. Traitez chaque point comme un électron contraint à une sphère, puis lancez une simulation pour un certain nombre d'étapes. La répulsion des électrons tendra naturellement le système vers un état plus stable, où les points sont à peu près aussi éloignés les uns des autres que possible.
  2. Rejet de l'hypercube. Cette méthode au nom fantaisiste est en réalité très simple : vous choisissez uniformément des points (beaucoup plus que n d'entre eux) à l'intérieur du cube entourant la sphère, puis rejetez les points à l'extérieur de la sphère. Traitez les points restants comme des vecteurs et normalisez-les. Ce sont vos "échantillons" - choisissez n d'entre eux en utilisant une méthode quelconque (au hasard, cupide, etc.).
  3. Approximations en spirale. Vous tracez une spirale autour d'une sphère et distribuez uniformément les points autour de la spirale. En raison des mathématiques impliquées, ces méthodes sont plus complexes à comprendre que la simulation, mais beaucoup plus rapides (et probablement nécessitant moins de code). La plus populaire semble être celle de Saff, et al.

Beaucoup plus d'informations sur ce problème peuvent être trouvées ici

0 votes

Je vais examiner la tactique en spirale qu'Andrew Cooke a postée ci-dessous, cependant, pourriez-vous s'il vous plaît clarifier la différence entre ce que je veux et ce qu'est la "distribution uniforme aléatoire" ? Est-ce juste un placement aléatoire à 100% des points sur une sphère de manière uniforme ? Merci pour votre aide. :)

4 votes

@ Befall: "distribution uniforme aléatoire" fait référence à la probabilité d'une distribution uniforme - cela signifie que lorsqu'on choisit un point aléatoire sur la sphère, chaque point a la même probabilité d'être choisi. Cela n'a rien à voir avec la distribution spatiale finale des points, et n'a donc rien à voir avec votre question.

0 votes

Ahhh, d'accord, merci beaucoup. La recherche de ma question a conduit à un tas de réponses pour les deux, et je ne pouvais pas vraiment saisir ce qui était inutile pour moi.

15voto

andrew cooke Points 20902

Dans ce code d'exemple, node[k] est simplement le noeud k. Vous générez un tableau de N points et node[k] est le k-ième (de 0 à N-1). Si c'est tout ce qui vous déroute, vous devriez pouvoir l'utiliser maintenant.

(en d'autres termes, k est un tableau de taille N qui est défini avant le début du fragment de code, et qui contient une liste de points).

Alternativement, en s'appuyant 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 important près des pôles, de sorte que chaque point est situé dans à peu près la même surface d'espace (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 avec leurs voisins (ce dont je pense que vos liens parlent), mais cela peut être suffisant pour ce que vous voulez et améliore simplement la création d'une grille lat/lon uniforme.

0 votes

Agréable, c'est bon de voir une solution mathématique. Je pensais utiliser une hélice et une séparation de longueur d'arc. Je ne suis toujours pas sûr de comment obtenir la solution optimale, ce qui est un problème intéressant.

0 votes

Avez-vous vu que j'ai édité ma réponse pour inclure une explication de node[k] en haut ? Je pense que c'est peut-être tout ce dont vous avez besoin...

0 votes

Merveilleux, merci pour l'explication. Je vais essayer plus tard, car je n'ai pas de temps actuellement, mais merci beaucoup de m'avoir aidé. Je vous ferai savoir comment ça se passe pour mes besoins. ^^

7voto

ufomorace Points 410

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 devrait fonctionner en boucle avec un total de N boucles et une itération actuelle k.

Elle est basée sur un motif de graines de tournesol, sauf que les graines de tournesol sont courbées autour d'un demi-dôme, puis encore en une sphère.

Voici une image, sauf que j'ai placé la caméra à mi-chemin à l'intérieur de la sphère.

entrez la description de l'image ici

1voto

Prenez les deux plus grands facteurs de votre N, si N==20 alors les deux plus grands facteurs sont {5,4}, ou, plus généralement {a,b}. Calculer

dlat  = 180/(a+1)
dlong = 360/(b+1})

Placez votre premier point à {90-dlat/2,(dlong/2)-180}, votre deuxième à {90-dlat/2,(3*dlong/2)-180}, votre 3ème à {90-dlat/2,(5*dlong/2)-180}, jusqu'à ce que vous ayez fait le tour du monde une fois, à ce moment-là vous devriez être à environ {75,150} quand vous allez ensuite à {90-3*dlat/2,(dlong/2)-180}.

Évidemment, je travaille en degrés sur la surface de la terre sphérique, avec les conventions habituelles pour traduire +/- en N/S ou E/O. Et évidemment, cela vous donne une distribution complètement non aléatoire, mais elle est uniforme et les points ne sont pas regroupés.

Pour ajouter un certain degré de hasard, vous pourriez générer 2 valeurs distribuées normalement (avec une moyenne de 0 et un écart type de {dlat/3, dlong/3} selon le cas) et les ajouter à vos points distribués uniformément.

5 votes

Cela aurait l'air beaucoup mieux si vous travailliez avec sin(lat) plutôt que lat. Comme c'est le cas actuellement, vous obtiendrez beaucoup de regroupements près des pôles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X