Distribución uniforme de n puntos en una esfera


Necesito un algoritmo que pueda darme posiciones alrededor de una esfera para N puntos (menos de 20, probablemente) que los extienda vagamente. No hay necesidad de "perfección", pero solo la necesito para que ninguno de ellos esté agrupado.

  • Esta pregunta proporcionó un buen código, pero no pude encontrar una manera de hacer este uniforme, ya que parecía 100% aleatorio.
  • Esta entrada de blog recomendado tenía dos maneras que permiten la entrada de número de puntos en la esfera, pero el El algoritmo Saff y Kuijlaarsestá exactamente en psuedocode que podría transcribir, y el ejemplo de código que encontré contenía "nodo[k]", que no pude ver explicado y arruinó esa posibilidad. El segundo ejemplo del blog fue la Espiral de la Sección Dorada, que me dio resultados extraños, agrupados, sin una forma clara de definir un radio constante.
  • Este algoritmo de esta pregunta parece que podría funcionar, pero no puedo armar lo que hay en eso página en psuedocode o algo así.

Algunos otros hilos de preguntas que encontré hablaron de distribución uniforme aleatoria, lo que agrega un nivel de complejidad que no me preocupa. Me disculpo porque esta es una pregunta tan tonta, pero quería mostrar que realmente he buscado mucho y todavía me quedo corto.

Entonces, lo que estoy buscando es un pseudocódigo simple para distribuir uniformemente N puntos alrededor de una esfera unitaria, que retorna en coordenadas esféricas o cartesianas. Aún mejor si incluso puede distribuirse con un poco de aleatorización (piense en planetas alrededor de una estrella, decentemente dispersos, pero con espacio para el margen de maniobra).

Author: Amir, 2012-03-07

14 answers

En este código de ejemplo node[k] es sólo el nodo kth. Está generando una matriz N puntos y node[k] es el kth (de 0 a N-1). Si eso es todo lo que te está confundiendo, espero que puedas usarlo ahora.

(en otras palabras, k es una matriz de tamaño N que se define antes de que comience el fragmento de código, y que contiene una lista de los puntos).

Alternativamente, construyendo sobre la otra respuesta aquí (y usando 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 graficas eso, verás que el espaciado vertical es mayor cerca de los polos de modo que cada punto está situado en aproximadamente el mismo área total del espacio (cerca de los polos hay menos espacio "horizontalmente", por lo que da más "verticalmente").

Esto no es lo mismo que todos los puntos que tienen aproximadamente la misma distancia a sus vecinos (que es de lo que creo que sus enlaces están hablando), pero puede ser suficiente para lo que desea y mejora simplemente haciendo una cuadrícula lat/lon uniforme.

 10
Author: andrew cooke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-12 20:28:24

El algoritmo de la esfera de Fibonacci es excelente para esto. Es rápido y da resultados que a simple vista engañarán fácilmente al ojo humano. Puede ver un ejemplo hecho con processing que mostrará el resultado con el tiempo a medida que se agregan puntos. Aquí hay otro gran ejemplo interactivo hecho por @gman. Y aquí hay una versión rápida de python con una opción de aleatorización 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 muestras te dan esto:

introduzca la descripción de la imagen aquí

 90
Author: Fnord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-13 21:33:14

Esto se conoce como puntos de empaque en una esfera, y no hay una solución general (conocida) perfecta. Sin embargo, hay muchas soluciones imperfectas. Los tres más populares parecen ser:

  1. Crea una simulación. Trate cada punto como un electrón restringido a una esfera, luego ejecute una simulación para un cierto número de pasos. La repulsión de los electrones tenderá naturalmente al sistema a un estado más estable, donde los puntos están tan lejos unos de otros como pueden conseguir.
  2. Rechazo de hipercubos. Este método de sonido de fantasía es realmente muy simple: elige uniformemente puntos (mucho más que n de ellos) dentro del cubo que rodea la esfera, luego rechaza los puntos fuera de la esfera. El tratamiento de los restantes puntos como vectores, y normalizar ellos. Estas son sus "muestras" - elija n de ellas usando algún método (aleatoriamente, codicioso, etc.).
  3. Aproximaciones espirales. Trazas una espiral alrededor de una esfera, y uniformemente-distribuir los puntos alrededor de la espiral. Debido a las matemáticas involucradas, estas son más complicadas de entender que la simulación, pero mucho más rápidas (y probablemente implican menos código). El más popular parece ser por Saff, et al .

A lot se puede encontrar más información sobre este problema aquí

 74
Author: BlueRaja - Danny Pflughoeft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-20 18:30:47

El método de la espiral dorada

Dijiste que no podías hacer funcionar el método de la espiral dorada y eso es una pena porque es muy, muy bueno. Me gustaría darte una comprensión completa de ello para que tal vez puedas entender cómo mantener esto lejos de ser "agrupado."

Así que aquí hay una forma rápida y no aleatoria de crear una red que es aproximadamente correcta; como se discutió anteriormente, ninguna red será perfecta, pero esto puede ser "lo suficientemente bueno". Se compara con otros métodos, por ejemplo, en BendWavy.org pero solo tiene un aspecto agradable y bonito, así como una garantía sobre el espaciado uniforme en el límite.

Primer: espirales de girasol en el disco unitario

Para entender este algoritmo, primero los invito a mirar el algoritmo espiral de girasol 2D. Esto se basa en el hecho de que el número más irracional es la proporción áurea (1 + sqrt(5))/2 y si uno emite puntos por el enfoque " stand at the center, turn a golden ratio of whole turns, then emit otro punto en esa dirección," uno construye naturalmente una espiral que, a medida que se llega a un número cada vez mayor de puntos, sin embargo se niega a tener "barras" bien definidas en las que los puntos se alinean. (Nota 1.)

El algoritmo para el espaciado uniforme en un disco es,

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()

Y produce resultados que parecen (n=100 y n=1000):

introduzca la descripción de la imagen aquí

Espaciando los puntos radialmente

La clave extraña es la fórmula r = sqrt(indices / num_pts); cómo ¿llegué a esa? (Nota 2.)

Bueno, estoy usando la raíz cuadrada aquí porque quiero que estos tengan espaciado de área uniforme alrededor de la esfera. Eso es lo mismo que decir que en el límite de grandes N quiero un poco de región R ∈ (r, r + dr), Θ ∈ (θ, θ + dq) para contener un número de puntos proporcional a su área, que es r dr dq. Ahora si pretendemos que estamos hablando de una variable aleatoria aquí, esto tiene una interpretación directa como diciendo que la densidad de probabilidad conjunta para (R, Θ ) es solo c r para alguna constante c. La normalización en el disco unitario entonces fuerza c = 1/π.

Ahora permítanme presentar un truco. Viene de la teoría de la probabilidad donde se conoce como muestreo de la CDF inversa : supongamos que desea generar una variable aleatoria con una densidad de probabilidad f(z ) y tienes una variable aleatoria U ~ Uniforme(0, 1), al igual que sale de random() en la mayoría de los lenguajes de programación. ¿Cómo haces esto?

  1. Primero, convierte tu densidad en una función de distribución acumulativa F(z ), que, recuerde, aumenta monótonamente de 0 a 1 con derivada f(z ).
  2. Luego calcule la función inversa de la CDF F-1(z).
  3. Usted encontrará que Z = F-1(U) es distribuido de acuerdo a la densidad deseada. (Nota 3).

Ahora el golden ratio espiral truco espacios de los puntos en un muy bien incluso el patrón para q así que vamos a integrar a cabo; por el círculo unidad nos quedamos con F(r) = r2. Así que la función inversa es F-1(u) = u1/2, y por lo tanto no podemos generar puntos al azar en la esfera en coordenadas polares con r = sqrt(random()); theta = 2 * pi * random().

Ahora en lugar de aleatoriamente muestreando esta función inversa estamos uniformemente muestreándola, y lo bueno del muestreo uniforme es que nuestros resultados sobre cómo se distribuyen los puntos en el límite de grandes N se comportarán como si lo hubiéramos muestreado aleatoriamente. Esta combinación es el truco. En lugar de random() usamos (arange(0, num_pts, dtype=float) + 0.5)/num_pts, de modo que, digamos, si queremos muestrear 10 puntos son r = 0.05, 0.15, 0.25, ... 0.95. Muestreamos uniformemente r para obtener un espacio de igual área, y usamos el incremento de girasol para evitar "barras" horribles de puntos en la salida.

Ahora haciendo el girasol en una esfera

Los cambios que necesitamos hacer para salpicar la esfera con puntos simplemente implican cambiar las coordenadas polares por coordenadas esféricas. La coordenada radial, por supuesto, no entra en esto porque estamos en una esfera unitaria. Para mantener las cosas un poco más consistentes aquí, a pesar de que fui entrenado como físico, usaré las coordenadas de los matemáticos donde 0 ≤ φ ≤ π es latitud que desciende del polo y 0 ≤ θ ≤ 2π es longitud. Así que la diferencia desde arriba es que básicamente estamos reemplazando la variable rcon φ.

Nuestra área de elemento, r dr dq, ahora se convierte en el sin no mucho más complicado (φ ) d φ d θ. Así que nuestra densidad conjunta para el espaciado uniforme es sin (φ)/4π. La integración de salida q, encontramos f(φ) = sin(f)/2, por lo tanto F(φ) = (1 - cos(φ))/2. Invirtiendo esto podemos ver que una variable aleatoria uniforme se vería como acos(1 - 2 u), pero muestreamos uniformemente en lugar de aleatoriamente, por lo que en su lugar usamos φk = acos(1 - 2 (k + 0.5)/N). Y el resto del algoritmo está proyectando esto sobre las coordenadas x, y y 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()

De nuevo para n = 100 y n = 1000 los resultados parecen: introduzca la descripción de la imagen aquí introduzca la descripción de la imagen aquí

Notas

  1. Esas "barras" están formadas por aproximaciones racionales a un número, y las mejores aproximaciones racionales a un número provienen de su expresión de fracción continua, z + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...))) donde z es un entero y n_1, n_2, n_3, ... es una secuencia finita o infinita de enteros positivos:

    def continued_fraction(r):
        while r != 0:
            n = floor(r)
            yield n
            r = 1/(r - n)
    

    Dado que la parte de la fracción 1/(...) está siempre entre cero y uno, un entero grande en la fracción continua permite una aproximación racional particularmente buena: "uno dividido por algo entre 100 y 101" es mejor que "uno dividido por algo entre 1 y 2"."El número más irracional es, por lo tanto, el que es 1 + 1/(1 + 1/(1 + ...)) y no tiene un racional particularmente bueno aproximaciones; uno puede solucionar φ = 1 + 1/φ multiplicando por f para obtener la fórmula de la proporción áurea.

    1. Para las personas que no están tan familiarizadas con NumPy all todas las funciones están "vectorizadas", de modo que sqrt(array) es lo mismo que lo que otros lenguajes podrían escribir map(sqrt, array). Así que esta es una aplicación componente por componente sqrt. Lo mismo se aplica también para la división por un escalar o la adición con escalares those esos se aplican a todos los componentes en paralelo.

    2. La prueba es simple una vez que sabes que este es el resultado. Si usted pregunta ¿cuál es la probabilidad de que z Z z + dz, este es el mismo que preguntar ¿cuál es la probabilidad de que z F-1(U) z + dz, aplicar F para todos los tres expresiones destacar que es una función monótonamente creciente, por lo tanto F(z) U F(z + dz), expanda el lado derecho para encontrar F(z) + f(z d) z, y desde U es uniforme, esta probabilidad es sólo f(z d) z como se había prometido.

 30
Author: CR Drost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-06 15:45:42

Esta respuesta se basa en la misma' teoría ' que está bien delineada por esta respuesta

Estoy agregando esta respuesta como:
-- Ninguna de las otras opciones se ajusta a la necesidad de "uniformidad" (o no, obviamente, claramente). (Teniendo en cuenta para obtener el planeta como distribución buscando comportamiento particurally querido en la pregunta original, usted acaba de rechazar de la lista finita de los k puntos creados uniformemente al azar (wrt aleatorio el recuento de índice en el k elementos de nuevo).)
--El otro más cercano impl te obligó a decidir la ' N ' por 'eje angular', vs. solo 'un valor de N' a través de ambos valores de eje angular (que a conteos bajos de N es muy difícil saber qué puede, o no puede importar (por ejemplo, quieres '5' puntos have diviértete))
-- Además, es muy difícil 'grok' cómo diferenciar entre las otras opciones sin ninguna imagen, así que esto es lo que esta opción se ve como (abajo), y la implementación lista para ejecutar que va con ella.

Con N en 20:

introduzca la descripción de la imagen aquí
y luego N en 80: introduzca la descripción de la imagen aquí


Aquí está el código de python3 listo para ejecutarse, donde la emulación es la misma fuente:"http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere " encontrado por otros. (El trazado que he incluido, que se dispara cuando se ejecuta como 'principal', está tomado 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 __name__ == '__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

Probado con recuentos bajos (N en 2, 5, 7, 13, etc.) y parece funcionar 'bien'

 6
Author: Matt S.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:38

Lo que está buscando se llama una cubierta esférica. El problema de la cubierta esférica es muy difícil y las soluciones son desconocidas, excepto por un pequeño número de puntos. Una cosa que se sabe con certeza es que dados n puntos en una esfera, siempre existen dos puntos de distancia d = (4-csc^2(\pi n/6(n-2)))^(1/2) o más cerca.

Si desea un método probabilístico para generar puntos distribuidos uniformemente en una esfera, es fácil: generar puntos en el espacio uniformemente por distribución gaussiana (está integrado en Java, no es difícil encontrar el código para otros idiomas). Así que en el espacio tridimensional, necesitas algo como

Random r = new Random();
double[] p = { r.nextGaussian(), r.nextGaussian(), r.nextGaussian() };

Luego proyecta el punto sobre la esfera normalizando su distancia desde el origen

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 distribución gaussiana en n dimensiones es esféricamente simétrica por lo que la proyección sobre la esfera es uniforme.

Por supuesto, no hay garantía de que la distancia entre dos puntos cualesquiera en un conjunto de puntos generados uniformemente se limitará a continuación, por lo que puede usar rechazo para hacer cumplir las condiciones que pueda tener: probablemente es mejor generar toda la colección y luego rechazar toda la colección si es necesario. (O usa "rechazo temprano" para rechazar toda la colección que has generado hasta ahora; simplemente no guardes algunos puntos y dejes caer otros.) Puede usar la fórmula para d dada anteriormente, menos un poco de holgura, para determinar la distancia mínima entre los puntos por debajo de la cual rechazará un conjunto de puntos. Tendrás que calcular n elegir 2 las distancias, y la probabilidad de rechazo dependerá de la holgura; es difícil decir cómo, así que ejecute una simulación para tener una idea de las estadísticas relevantes.

 5
Author: Edward Doolittle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-16 01:26:50

Intenta:

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 función anterior debe ejecutarse en bucle con N total de bucle y k iteración de corriente de bucle.

Se basa en un patrón de semillas de girasol, excepto que las semillas de girasol se curvan alrededor en una media cúpula, y de nuevo en una esfera.

Aquí hay una imagen, excepto que puse la cámara a mitad de camino dentro de la esfera para que se vea 2d en lugar de 3d porque la cámara está a la misma distancia de todos punto. http://3.bp.blogspot.com/-9lbPHLccQHA/USXf88_bvVI/AAAAAAAAADY/j7qhQsSZsA8/s640/sphere.jpg

 3
Author: com.prehensible,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-04 05:08:20

Con un pequeño número de puntos se podría ejecutar una simulación:

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)]
 1
Author: robert king,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-07 12:20:11

Tome los dos factores más grandes de su N, si N==20 entonces los dos factores más grandes son {5,4}, o, más generalmente {a,b}. Calcular

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

Ponga su primer punto en {90-dlat/2,(dlong/2)-180}, su segundo en {90-dlat/2,(3*dlong/2)-180}, su 3er en {90-dlat/2,(5*dlong/2)-180}, hasta que haya dado la vuelta al mundo una vez, momento en el que tiene que aproximadamente {75,150} cuando vaya al lado de {90-3*dlat/2,(dlong/2)-180}.

Obviamente estoy trabajando esto en grados en la superficie de la tierra esférica, con las convenciones habituales para traducir + / - a N/S o E/W. Y obviamente esto le da una distribución completamente no aleatoria, pero es uniforme y los puntos no están agrupados.

Para añadir un cierto grado de aleatoriedad, puede generar 2 distribuidos normalmente (con media 0 y std dev de {dlat/3, dlong/3} según corresponda) y agregarlos a sus puntos distribuidos uniformemente.

 1
Author: High Performance Mark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-07 12:44:36

Edit: Esto no responde a la pregunta que el OP pretendía hacer, dejándola aquí en caso de que la gente la encuentre útil de alguna manera.

Usamos la regla de multiplicación de probabilidad, combinada con infinitesimales. Esto resulta en 2 líneas de código para lograr el resultado deseado:

longitude: φ = uniform([0,2pi))
azimuth:   θ = -arcsin(1 - 2*uniform([0,1]))

(definido en el siguiente sistema de coordenadas:)

introduzca la descripción de la imagen aquí

Su lenguaje típicamente tiene un número aleatorio uniforme primitivo. Por ejemplo, en python se puede usar random.random() para devolver un número en el rango [0,1). Puede multiplicar este número por k para obtener un número aleatorio en el rango [0,k). Así en python, uniform([0,2pi)) significaría random.random()*2*math.pi.


Prueba

Ahora no podemos asignar θ uniformemente, de lo contrario nos agruparíamos en los polos. Queremos asignar probabilidades proporcionales a la superficie de la cuña esférica (la θ en este diagrama es en realidad φ):

introduzca la descripción de la imagen aquí

Un desplazamiento angular dφ en el ecuador dará lugar a un desplazamiento de dφ * r. ¿Cuál será ese desplazamiento en un acimut arbitrario θ? Bueno, el radio desde el eje z es r*sin(θ), por lo que la longitud arcl de esa "latitud" que cruza la cuña es dφ * r*sin(θ). Así calculamos ladistribución acumulativa del área a muestrear de ella, integrando el área de la rebanada del polo sur al polo norte.

introduzca la descripción de la imagen aquí (donde las cosas=dφ*r)

Ahora intentaremos obtener la inversa de la CDF para muestrearla: http://en.wikipedia.org/wiki/Inverse_transform_sampling

Primero normalizamos dividiendo nuestro casi-CDF por su valor máximo. Esto tiene el efecto secundario de anular los dφ y r.

azimuthalCDF: cumProb = (sin(θ)+1)/2 from -pi/2 to pi/2

inverseCDF: θ = -sin^(-1)(1 - 2*cumProb)

Así:

let x by a random float in range [0,1]
θ = -arcsin(1-2*x)
 1
Author: ninjagecko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-08 00:03:50

O... para colocar 20 puntos, calcule los centros de las caras icosaedronales. Para 12 puntos, encuentre los vértices del icosaedro. Para 30 puntos, el punto medio de los bordes del icosaedro. usted puede hacer lo mismo con el tetraedro, cubo dodecaedro y octaedros: un conjunto de puntos en los vértices, otro en el centro de la cara y otro en el centro de los bordes. Sin embargo, no pueden mezclarse.

 1
Author: user19371,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-22 03:26:41

Healpix resuelve un problema estrechamente relacionado (pixelar la esfera con píxeles de área igual):

Http://healpix.sourceforge.net/

Probablemente es exagerado, pero tal vez después de mirarlo te darás cuenta de que algunas de sus otras propiedades son interesantes para ti. Es mucho más que una función que genera una nube de puntos.

Aterricé aquí tratando de encontrarlo de nuevo; el nombre "healpix" no evoca exactamente esferas...

 1
Author: Andrew Wagner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-16 23:12:47
# 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)])
 0
Author: ksmith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-26 06:56:40

Esto funciona y es mortalmente simple. Tantos puntos como quieras:

    private function moveTweets():void {


        var newScale:Number=Scale(meshes.length,50,500,6,2);
        trace("new scale:"+newScale);


        var l:Number=this.meshes.length;
        var tweetMeshInstance:TweetMesh;
        var destx:Number;
        var desty:Number;
        var destz:Number;
        for (var i:Number=0;i<this.meshes.length;i++){

            tweetMeshInstance=meshes[i];

            var phi:Number = Math.acos( -1 + ( 2 * i ) / l );
            var theta:Number = Math.sqrt( l * Math.PI ) * phi;

            tweetMeshInstance.origX = (sphereRadius+5) * Math.cos( theta ) * Math.sin( phi );
            tweetMeshInstance.origY= (sphereRadius+5) * Math.sin( theta ) * Math.sin( phi );
            tweetMeshInstance.origZ = (sphereRadius+5) * Math.cos( phi );

            destx=sphereRadius * Math.cos( theta ) * Math.sin( phi );
            desty=sphereRadius * Math.sin( theta ) * Math.sin( phi );
            destz=sphereRadius * Math.cos( phi );

            tweetMeshInstance.lookAt(new Vector3D());


            TweenMax.to(tweetMeshInstance, 1, {scaleX:newScale,scaleY:newScale,x:destx,y:desty,z:destz,onUpdate:onLookAtTween, onUpdateParams:[tweetMeshInstance]});

        }

    }
    private function onLookAtTween(theMesh:TweetMesh):void {
        theMesh.lookAt(new Vector3D());
    }
 0
Author: Arthur Flower,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-04 00:48:26