구에 n 개의 점을 균등하게 분배


121

모호하게 퍼지는 N 개의 점 (아마 20 개 미만)에 대해 구 주위에 위치를 제공 할 수있는 알고리즘이 필요합니다. "완벽 함"은 필요하지 않지만 그냥 필요하기 때문에 함께 묶이지 않습니다.

  • 이 질문 은 좋은 코드를 제공했지만 100 % 무작위로 보였기 때문에이 유니폼을 만드는 방법을 찾을 수 없었습니다.
  • 이 블로그 게시물 은 구의 점 수를 입력 할 수있는 두 가지 방법을 제공했지만 Saff 및 Kuijlaars 알고리즘은 정확히 필자가 필사 할 수있는 의사 코드에 있으며 제가 찾은 코드 예제 에는 "node [k]"가 포함되어있었습니다. 그 가능성을 설명하고 망쳤습니다. 두 번째 블로그 예제는 Golden Section Spiral로, 일정 반경을 정의하는 명확한 방법이없는 이상하고 뭉친 결과를 제공했습니다.
  • 질문 의이 알고리즘 은 작동 할 수있는 것처럼 보이지만 해당 페이지에있는 내용을 의사 코드 또는 다른 것으로 통합 할 수는 없습니다.

내가 만난 몇 가지 다른 질문 스레드는 무작위 균일 분포에 대해 언급했으며, 이는 내가 걱정하지 않는 수준의 복잡성을 추가합니다. 정말 어리석은 질문이라는 점 사과드립니다.하지만 제가 정말 열심히 보였지만 여전히 부족하다는 것을 보여 드리고 싶었습니다.

그래서 제가 찾고있는 것은 구형 또는 데카르트 좌표로 반환되는 단위 구 주위에 N 개의 점을 균등하게 분배하는 간단한 의사 코드입니다. 약간의 무작위 화로도 분포 할 수 있다면 더 좋습니다 (별 주위의 행성을 적절하게 흩어져 있지만 여유 공간이있는 것을 생각해보십시오).


"약간의 무작위 화"란 무엇을 의미합니까? 어떤 의미에서 섭동을 의미합니까?
ninjagecko

32
OP는 혼란 스럽습니다. 그가 찾고있는 것은 구에 n 점을 놓아 두 점 사이의 최소 거리가 가능한 한 커지도록하는 것입니다. 이렇게하면 점이 전체 구에 "균등하게 분포"된 것처럼 보입니다. 이것은 구에 균일 한 무작위 분포를 만드는 것과는 완전히 관련이 없습니다. 이는 많은 링크가 무엇에 관한 것이고 아래의 많은 답변이 말하는 것입니다.
BlueRaja-Danny Pflughoeft

1
20은 무작위로 보이게하지 않으려면 구에 배치 할 점이 많지 않습니다.
John Alexiou 2014

2
여기에 그것을 할 수있는 방법이다 (이 코드 예제를 가지고) : pdfs.semanticscholar.org/97a6/... (좋아 보이는 반발력 계산을 사용)
trusktr

1
물론 {4, 6, 8, 12, 20}의 N 값에 대해 각 점에서 (각각) 가장 가까운 이웃까지의 거리가 모든 점과 모든 가장 가까운 이웃에 대해 상수 인 정확한 솔루션이 있습니다.
dmckee --- 전 중재자 새끼 고양이

답변:


13

에서 이 예제 코드 node[k] 단지 k 번째 노드입니다. 배열 N 점을 생성하고 node[k]있으며 k 번째입니다 (0에서 N-1까지). 그것이 당신을 혼란스럽게하는 전부라면, 지금 그것을 사용할 수 있기를 바랍니다.

(즉, k코드 조각이 시작되기 전에 정의되고 포인트 목록을 포함하는 크기 N의 배열입니다).

또는 여기에 다른 답변을 빌드하고 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

이를 플로팅하면 각 점이 거의 동일한 전체 공간 영역 에 위치하도록 극 근처의 수직 간격이 더 커집니다 (극 근처에는 "수평"공간이 적어 "수직"으로 "더 많이 제공됨). ).

이것은 이웃과의 거리가 거의 같은 모든 포인트와 같지는 않지만 (링크가 말하는 것이라고 생각하는 것입니다) 원하는 것에 충분할 수 있으며 단순히 균일 한 위도 / 경도 그리드를 만드는 것으로 향상됩니다 .


좋습니다, 수학적 해결책을 보는 것이 좋습니다. 나선과 호 길이 분리를 사용할 생각이었습니다. 흥미로운 문제인 최적의 솔루션을 얻는 방법은 아직 확실하지 않습니다.
로버트 왕

맨 위에 node [k]에 대한 설명을 포함하도록 내 답변을 편집 한 것을 보셨습니까? 난 그게 당신이 필요한 모든 것 같아요 ...
앤드류 쿡

훌륭합니다. 설명해 주셔서 감사합니다. 지금은 시간이 없어서 나중에 해보겠습니다. 도와 주셔서 감사합니다. 내 목적을 위해 어떻게 작동하는지 알려 드리겠습니다. ^^
Befall

나선형 방법을 사용하면 제 요구에 완벽하게 맞습니다. 도움과 설명에 감사드립니다. :)
Befall

13
링크가 죽은 것 같습니다.
Scheintod

140

피보나치 구 알고리즘은 이에 적합합니다. 빠르고 쉽게 인간의 눈을 속일 수있는 결과를 제공합니다. 포인트가 추가됨에 따라 시간이 지남에 따라 결과를 표시하는 처리로 완료된 예를 볼 수 있습니다 . @gman이 만든 또 다른 훌륭한 대화 형 예제 가 있습니다. 그리고 여기 파이썬으로 간단한 구현이 있습니다.

import math


def fibonacci_sphere(samples=1):

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

    for i in range(samples):
        y = 1 - (i / float(samples - 1)) * 2  # y goes from 1 to -1
        radius = math.sqrt(1 - y * y)  # radius at y

        theta = phi * i  # golden angle increment

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

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

    return points

1000 개의 샘플은 다음을 제공합니다.

여기에 이미지 설명 입력


phi를 정의 할 때 변수 n이 호출됩니다. phi = ((i + rnd) % n) * increment. n = 샘플입니까?
Andrew Staroscik 2014

트윗 담아 가기 코드를 처음 작성할 때 "n"을 변수로 사용하고 나중에 이름을 변경했지만 실사를하지 않았습니다. 잡아 주셔서 감사합니다!
Fnord


4
@Xarbrough 코드는 단위 구 주위에 포인트를 제공하므로 반경에 대해 원하는 스칼라를 각 포인트에 곱하십시오.
Fnord

2
@Fnord : 더 높은 차원에서이 작업을 수행 할 수 있습니까?
pikachuchameleon 2010 년

108

황금 나선 방법

황금 나선 방법을 사용할 수 없다고 하셨는데, 정말 정말 훌륭하기 때문에 안타깝습니다. 나는 당신이 "번치"되는 것을 막는 방법을 이해할 수 있도록 당신에게 그것에 대한 완전한 이해를 드리고 싶습니다.

그래서 여기에 대략적으로 정확한 격자를 만드는 빠르고 랜덤하지 않은 방법이 있습니다. 위에서 논의한 바와 같이 격자는 완벽하지 않지만 이것만으로도 충분할 수 있습니다. 다른 방법과 비교됩니다. BendWavy.org와 되지만 멋지고 예쁘게 보일뿐만 아니라 한계에서 균일 한 간격을 보장합니다.

입문서 : 단위 디스크의 해바라기 나선

이 알고리즘을 이해하기 위해 먼저 2D 해바라기 나선형 알고리즘을 살펴 보도록하겠습니다. 이것은 가장 비합리적인 숫자가 황금 비율이라는 사실에 기반 (1 + sqrt(5))/2하고 있으며, "중앙에 서서 전체 턴의 황금 비율을 돌린 다음 그 방향으로 다른 지점을 방출"하는 접근 방식으로 포인트를 방출하면 자연스럽게 a 나선형은 점의 수를 점점 더 많이 증가 시키면서도 점이 정렬되는 잘 정의 된 '막대'를 갖기를 거부합니다. (참고 1)

디스크의 균등 한 간격에 대한 알고리즘은 다음과 같습니다.

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

다음과 같은 결과를 생성합니다 (n = 100 및 n = 1000).

여기에 이미지 설명 입력

방사형으로 점 간격

중요한 이상한 점은 공식입니다 r = sqrt(indices / num_pts). 내가 그 사람에게 어떻게 왔습니까?(노트 2.)

음, 저는 여기에 제곱근을 사용하고 있습니다. 왜냐하면 디스크 주위에 균등 한 영역 간격을 갖기를 원하기 때문입니다. 그것은 큰 N 의 한계에서 나는 작은 영역 R ∈ ( r , r + d r ), Θ ∈ ( θ , θ + d θ )가 그 면적에 비례하는 수의 점을 포함하기를 원한다고 말하는 것과 같습니다 . 이것은 r d r d θ 입니다. 이제 우리가 여기서 임의의 변수에 대해 이야기하고 있다고 가정하면, 이것은 ( R , Θ )에 대한 결합 확률 밀도 가 단지 cr 이라고 말하는 것으로 간단하게 해석됩니다.일부 상수 = 1 / π 합니다.c . 그러면 단위 디스크의 정규화는 c 를 강제 합니다.

이제 트릭을 소개하겠습니다. 그것은 역 CDF 샘플링으로 알려진 확률 이론에서 비롯된 것 입니다. 확률 밀도 f ( z )를 가진 랜덤 변수 를 생성 하고 싶고 랜덤 변수 U ~ Uniform (0, 1)이 있다고 가정합니다. 대부분의 프로그래밍 언어에서. 어떻게하나요?random()

  1. 먼저 밀도를 누적 분포 함수 또는 CDF 로 바꾸십시오 .이를 F ( z )라고합니다. CDF는 미분 f ( z)를 사용 하여 0에서 1까지 단조롭게 증가합니다. )를 사용 합니다.
  2. 그런 다음 CDF의 역함수 F -1 ( z )를 계산합니다 .
  3. 당신은 발견 할 것이다 Z = F -1 ( U가 ) 목표 밀도에 따라 배포됩니다. (노트 3).

이제 황금비 나선 트릭은 θ 에 대해 매우 균일 한 패턴으로 포인트 간격을 지정 하므로이를 통합 해 보겠습니다. 단위 디스크의 경우 F ( r ) = r 2 로 남습니다 . 따라서 역함수는 F -1 ( u ) = u 1/2 이므로 디스크에 임의의 점을 r = sqrt(random()); theta = 2 * pi * random().

이제이 역함수 를 무작위로 샘플링하는 대신 균일하게 샘플링하고, 균일 한 샘플링에 대한 좋은 점은 점이 큰 N 의 한계에서 어떻게 퍼져 있는지에 대한 결과 가 마치 무작위로 샘플링 한 것처럼 동작한다는 것입니다. 이 조합이 트릭입니다. 대신를 random()사용 (arange(0, num_pts, dtype=float) + 0.5)/num_pts하므로 10 개의 포인트를 샘플링하려면 r = 0.05, 0.15, 0.25, ... 0.95. 동일한 면적의 간격을 얻기 위해 r 을 균일하게 샘플링 하고, 출력에서 ​​점의 끔찍한 "막대"를 피하기 위해 해바라기 증분을 사용합니다.

이제 구형에 해바라기를하고

점으로 구에 점을 찍기 위해 필요한 변경 사항은 구면 좌표의 극좌표를 전환하는 것뿐입니다. 물론 방사상 좌표는 우리가 단위 구체에 있기 때문에 여기에 들어 가지 않습니다. 여기서 좀 더 일관성을 유지하기 위해 물리학 자로 훈련을 받았지만 0 ≤ φ ≤ π는 극에서 내려 오는 위도이고 0 ≤ θ ≤ 2π는 경도 인 수학자의 좌표를 사용 합니다. 따라서 위와의 차이점은 기본적으로 변수 rφ로 대체한다는 것 입니다.

r d r d θ 였던 면적 요소는 이제 그다지 복잡하지 않은 sin ( φ ) d φ d θ가 됩니다. 따라서 균일 한 간격을위한 접합 밀도는 sin ( φ ) / 4π입니다. 밖으로 통합 θ를 , 우리는 찾을 수 F ( φ ) = 죄 ( φ ) / 2, 따라서 F ( φ -) = (COS (1 φ / 2)). 이것을 반전하면 균일 한 랜덤 변수가 acos (1-2 u ) 처럼 보일 것임을 알 수 있지만, 우리는 랜덤이 아닌 균일하게 샘플링하므로 대신 φ k = acos (1 − 2 ( k+ 0.5) / N ). 나머지 알고리즘은 이것을 x, 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()

다시 n = 100 및 n = 1000에 대한 결과는 다음과 같습니다. 여기에 이미지 설명 입력 여기에 이미지 설명 입력

추가 연구

Martin Roberts의 블로그에 한마디하고 싶었습니다. 위에서 각 인덱스에 0.5를 추가하여 인덱스 오프셋을 생성했습니다. 이것은 시각적으로 매력적 이었지만 오프셋 선택이 매우 중요 하고 간격 동안 일정하지 않으며 올바르게 선택하면 패킹에서 최대 8 % 더 나은 정확도를 얻을 수 있음이 밝혀졌습니다 . 또한 그의 R 2 시퀀스 가 구를 덮도록 하는 방법이 있어야하며, 이것이 아마도있는 그대로의 좋은 균등 커버링을 생성하는지 확인하는 것이 흥미로울 것입니다. 단위 사각형은 대각선으로 자르고 원을 만들기 위해 늘어납니다.

노트

  1. 이러한 "바"는 다수 합리적인 근사치에 의해 형성되고, 다수의 가장 합리적인 근사치 지속적인 분획 식 온되는 정수이고, 한정된 양의 정수 또는 무한 시퀀스 중입니다z + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))zn_1, n_2, n_3, ...

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

    분수 부분 1/(...)은 항상 0과 1 사이에 있기 때문에 연속 된 분수의 큰 정수는 특히 좋은 합리적인 근사치를 허용합니다. "1을 100과 101 사이의 것으로 나눈 것"이 "1과 2 사이의 것으로 나눈 것"보다 낫습니다. 그러므로 가장 비합리적인 숫자는 1 + 1/(1 + 1/(1 + ...))특히 좋은 합리적 근사치를 갖고 있지 않은 숫자입니다 . 황금 비율에 대한 공식을 얻기 위해 φ 를 곱하여 φ = 1 + 1 / φ 를 풀 수 있습니다 .

  2. NumPy에 익숙하지 않은 사람들을 위해 모든 함수가 "벡터화"되어 있으므로 sqrt(array)다른 언어가 작성하는 것과 동일 map(sqrt, array)합니다. 따라서 이것은 구성 요소 별 sqrt응용 프로그램입니다. 스칼라로 나누거나 스칼라를 추가하는 경우에도 마찬가지입니다. 모든 구성 요소에 병렬로 적용됩니다.

  3. 이것이 결과라는 것을 알면 증거는 간단합니다. 당신은 확률 무엇을 요구하는 경우에 z는 < Z는 < Z + D의 z는 ,이 확률 무엇을 물어와 동일한 Z < F -1 ( U는 ) < Z + D z는 적용 F를 가 있음을 주목할 세 가지 표현으로는 단조 증가하는 함수, 따라서 F ( z ) < U < F ( z + d z ), 오른쪽을 확장하여 F ( z ) + f(z ) d z 이고 U 는 균일하기 때문에이 확률은 약속 한대로 f ( z ) d z 입니다.


4
나는 이것이 왜 그렇게 멀리 떨어지는 지 잘 모르겠습니다. 이것이 이것을 수행하는 가장 빠른 방법입니다.
whn

2
@snb 친절한 말 감사합니다! 여기에있는 나머지 모든 답변보다 훨씬 더 젊기 때문에 부분적으로는 훨씬 아래에 있습니다. 나는 그것이 그랬던 것처럼 잘하고 있다는 것에 놀랐다.
CR Drost dec

나에게 남아있는 한 가지 질문은 다음과 같습니다. 두 포인트 사이의 주어진 최대 거리에 대해 몇 개의 포인트 n을 분배해야합니까?
Felix D.

1
@FelixD. 특히 유클리드 거리가 아닌 대원 거리를 사용하기 시작하면 매우 복잡해질 수있는 질문처럼 들립니다. 하지만 간단한 질문에 답할 수 있습니다. 구의 점을 보로 노이 다이어그램으로 변환하면 각 보로 노이 셀이 대략 4π / N의 면적을 갖는 것으로 설명 할 수 있으며, 원인 척하여이를 특성 거리로 변환 할 수 있습니다. 마름모보다 πr² = 4π / N. 그러면 r = 2 / √ (N).
CR Drost

2
무작위로 균일 한 입력 대신 실제로 균일 한 샘플링 정리를 사용하는 것은 "글쎄, 왜 # $ % &가 그렇게 생각하지 않았습니까?" 라고 말하는 것 중 하나입니다. . 좋은.
dmckee --- 전 중재자 새끼 고양이

86

이것은 구의 패킹 포인트로 알려져 있으며 (알려진) 일반적이고 완벽한 솔루션은 없습니다. 그러나 불완전한 해결책이 많이 있습니다. 가장 인기있는 세 가지는 다음과 같습니다.

  1. 시뮬레이션을 만듭니다 . 각 점을 구에 구속 된 전자로 취급 한 다음 특정 단계 수에 대해 시뮬레이션을 실행합니다. 전자의 반발은 자연스럽게 시스템을보다 안정된 상태로 만들 것입니다. 여기서 포인트는 가능한 한 서로 멀리 떨어져 있습니다.
  2. 하이퍼 큐브 거부 . 이 화려한 사운드 방법은 실제로 정말 간단합니다 : 당신은 균일하게 점을 선택 (더 이상 n그들의) 구를 둘러싼 큐브의 내부에, 다음 영역의 외부에 포인트를 거부합니다. 나머지 점을 벡터로 취급하고 정규화합니다. 이것들은 당신의 "샘플"입니다- n어떤 방법 (무작위, 탐욕 등)을 사용하여 그것들을 선택하십시오 .
  3. 나선형 근사치 . 구를 중심으로 나선을 추적하고 나선 주위에 점을 고르게 분포시킵니다. 관련된 수학 때문에 시뮬레이션보다 이해하기가 더 복잡하지만 훨씬 빠릅니다 (그리고 아마도 더 적은 코드를 포함 함). 가장 인기있는 것은 Saff, et al .

많은 이 문제에 대한 자세한 정보를 찾을 수 있습니다 여기에


Andrew Cooke이 아래에 게시 한 나선형 전술을 살펴볼 것입니다. 그러나 내가 원하는 것과 "균일 한 무작위 분포"가 무엇인지의 차이점을 명확히 해주시겠습니까? 균일하게 배치되도록 구에 점을 100 % 무작위로 배치하는 것입니까? 도와 주셔서 감사합니다. :)
Befall

4
@Befall : "균일 무작위 분포"는 확률 분포 가 균일 함을 의미합니다. 즉, 구에서 임의의 점을 선택할 때 모든 점이 선택 될 가능성이 동일합니다. 포인트 의 최종 공간 분포와는 관련이 없으므로 질문과 관련이 없습니다.
BlueRaja-Danny Pflughoeft 2011 년

아, 좋아요, 정말 고마워요. 내 질문을 검색하면 두 가지 모두에 대한 많은 답변을 얻었고 어떤 것이 나에게 무의미한 지 파악할 수 없었습니다.
Befall

명확하게 말하면 모든 포인트는 선택 될 확률이 0입니다. 점이 구 표면의 두 영역에 속할 확률의 비율은 표면의 비율과 같습니다.
AturSams

2
마지막 링크는 이제 죽었습니다
Felix D.

10

당신이 찾고있는 것을 구면 커버 라고합니다 . 구형 커버링 문제는 매우 어렵고 적은 수의 포인트를 제외하고 솔루션을 알 수 없습니다. 확실히 알려진 한 가지는 구에 n 개의 점이 주어지면 항상 거리 d = (4-csc^2(\pi n/6(n-2)))^(1/2)또는 그보다 가까운 두 점이 존재한다는 것 입니다.

구에 균일하게 분포 된 점을 생성하는 확률 적 방법을 원한다면 간단합니다. Gaussian 분포에 의해 균일하게 공간에 점을 생성합니다 (다른 언어에 대한 코드를 찾기 어렵지 않고 Java에 내장 됨). 따라서 3 차원 공간에서는 다음과 같은 것이 필요합니다.

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

그런 다음 원점으로부터의 거리를 정규화하여 점을 구에 투영합니다.

double norm = Math.sqrt( (p[0])^2 + (p[1])^2 + (p[2])^2 ); 
double[] sphereRandomPoint = { p[0]/norm, p[1]/norm, p[2]/norm };

n 차원의 가우스 분포는 구형 대칭이므로 구에 대한 투영이 균일합니다.

물론, 균일하게 생성 된 포인트 모음에서 두 포인트 사이의 거리가 아래에 제한된다는 보장은 없으므로 거부를 사용하여 이러한 조건을 적용 할 수 있습니다. 전체 모음을 생성 한 다음 필요한 경우 전체 컬렉션을 거부합니다. (또는 지금까지 생성 한 전체 컬렉션을 거부하려면 "조기 거부"를 사용하십시오. 일부 포인트를 유지하고 다른 포인트를 삭제하지 마십시오.) d위 의 공식을 사용하여 약간의 여유를 뺀 다음 사이의 최소 거리를 결정할 수 있습니다. 그 이하의 포인트는 포인트 세트를 거부합니다. n을 계산하여 2 개의 거리를 선택해야하며 거부 확률은 여유에 따라 달라집니다. 방법을 말하기는 어렵 기 때문에 시뮬레이션을 실행하여 관련 통계에 대한 느낌을 얻으십시오.


최소 최대 거리 표현에 찬성했습니다. 사용하려는 포인트 수를 제한하는 데 유용합니다. 하지만 이에 대한 권위있는 출처에 대한 참조는 좋을 것입니다.
dmckee --- 전 중재자 새끼 고양이

6

이 답변은에 의해 잘 설명되어 같은 '이론'을 기반으로 이 답변

나는이 대답을 다음과 같이 추가하고
있습니다 .-- '균일 성'에 맞는 다른 옵션은 '스팟 온'이 필요하지 않습니다 (또는 분명하지 않음). (원래 질문에서 특정 적으로 원하는 분포처럼 보이는 행동을 얻기 위해, k 개의 균일하게 생성 된 점의 유한 목록에서 무작위로 거부합니다 (k 항목의 인덱스 수를 무작위로 계산).)- 게다가, 이미지없이 다른 옵션을 구별하는 방법을 'grok'하는 것은 매우 어렵습니다. 따라서 다음은이 옵션의 모양 (아래)과 함께 실행할 준비가 된 구현입니다.
--The 가장 가까운 다른 impl은 '각축'에 의해 'N'을 결정하도록 강요하고 두 각도 축 값에서 'N의 하나의 값'을 결정하도록 강요했습니다 (N의 낮은 계수에서 무엇이 문제가 될 수 있는지 아는 것은 매우 까다 롭습니다 ( 예 : 당신은 '5'점을 원합니다-재미있게 보내십시오))

N이 20 인 경우 :

여기에 이미지 설명 입력
80에서 N : 여기에 이미지 설명 입력


여기 에뮬레이션이 동일한 소스 인 즉시 실행 가능한 python3 코드가 있습니다. " http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere " . (내가 포함시킨 플로팅은 'main'으로 실행될 때 발생하며 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

낮은 카운트 (2, 5, 7, 13 등의 N)에서 테스트되었으며 '좋게'작동하는 것 같습니다.


5

시험:

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); 
};

위의 함수는 총 N 개의 루프와 k 개의 루프 전류 반복으로 루프에서 실행되어야합니다.

해바라기 씨 패턴을 기반으로합니다. 단, 해바라기 씨는 반 돔으로 휘어진 다음 다시 구형으로 휘어져 있습니다.

여기 사진이 있습니다. 카메라가 모든 지점에서 같은 거리에 있기 때문에 3d 대신 2d로 보이도록 카메라를 구 안쪽에 반쯤 배치 한 것을 제외하고는 다음과 같습니다. http://3.bp.blogspot.com/-9lbPHLccQHA/USXf88_bvVI/AAAAAAAAADY/j7qhQsSZsA8/s640/sphere.jpg


2

Healpix는 밀접하게 관련된 문제를 해결합니다 (동일한 영역 픽셀로 구를 픽셀 화).

http://healpix.sourceforge.net/

아마도 과잉 일 수도 있지만, 살펴본 후에는 다른 멋진 속성 중 일부가 흥미 롭다는 것을 알게 될 것입니다. 포인트 클라우드를 출력하는 기능 그 이상입니다.

나는 그것을 다시 찾으려고 여기에 착륙했다. "healpix"라는 이름은 정확히 구체를 불러 일으키지는 않습니다.


1

적은 수의 포인트로 시뮬레이션을 실행할 수 있습니다.

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

내 대답을 개선하기 위해 당신은 내가 closest_index = randchoice (I, J)에 = closest_index을 변경해야합니다
로버트 왕

1

두 개의 가장 큰 요인이 이거나보다 일반적으로 N이면에서 가장 큰 두 요인을 취하십시오 . 계산하다N==20{5,4}{a,b}

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

에서 첫 번째 지점 넣어 {90-dlat/2,(dlong/2)-180},에서 두 번째 {90-dlat/2,(3*dlong/2)-180}에서 3 번째를 {90-dlat/2,(5*dlong/2)-180}당신이 당신에 대해에있어이 기간에 의해 한 번 세계, 라운드 트립 할 때까지, {75,150}당신이 다음에 갈 때 {90-3*dlat/2,(dlong/2)-180}.

분명히 나는 ​​+/-를 N / S 또는 E / W로 변환하는 일반적인 규칙을 사용하여 구형 지구 표면에서 각도 단위로 작업하고 있습니다. 그리고 분명히 이것은 당신에게 완전히 무작위가 아닌 분포를 제공하지만 균일하고 포인트가 함께 묶이지 않습니다.

어느 정도의 임의성을 추가하려면 2 개의 정규 분포 (평균 0 및 {dlat / 3, dlong / 3}의 표준 개발)를 생성하고 균일하게 분포 된 점에 추가 할 수 있습니다.


5
위도가 아닌 sin (lat)에서 작업하면 훨씬 더 좋아 보일 것입니다. 그대로, 당신은 극 근처에서 많은 뭉치를 얻을 것입니다.
andrew cooke 2012 년

1

편집 : 이것은 OP가 묻는 질문에 대한 답변이 아니며 사람들이 어떻게 든 유용하다고 생각하는 경우 여기에 남겨 둡니다.

무한대와 결합 된 확률의 곱셈 규칙을 사용합니다. 그러면 원하는 결과를 얻을 수있는 두 줄의 코드가 생성됩니다.

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

(다음 좌표계에 정의 됨 :)

여기에 이미지 설명 입력

귀하의 언어는 일반적으로 균일 난수 프리미티브를 가지고 있습니다. 예를 들어 파이썬 random.random()에서는 범위의 숫자를 반환하는 데 사용할 수 있습니다 [0,1). 이 숫자에 k를 곱하여 범위에있는 임의의 숫자를 얻을 수 있습니다 [0,k). 따라서 파이썬에서, uniform([0,2pi))의미 할 것입니다 random.random()*2*math.pi.


증명

이제 우리는 θ를 균일하게 할당 할 수 없습니다. 그렇지 않으면 극점에서 뭉쳐지게됩니다. 구형 쐐기의 표면적에 비례하는 확률을 할당하려고합니다 (이 다이어그램의 θ는 실제로 φ입니다).

여기에 이미지 설명 입력

적도에서의 각도 변위 dφ는 dφ * r의 변위를 초래합니다. 임의의 방위각 θ에서 변위는 얼마입니까? 음, z 축으로부터의 반경은 r*sin(θ)이므로 쐐기를 교차하는 "위도"의 호 길이는 dφ * r*sin(θ)입니다. 따라서 우리는 누적 분포를 계산합니다 남극에서 북극까지 슬라이스 영역을 통합하여 샘플링 할 영역 를 .

여기에 이미지 설명 입력(물건 = dφ*r)

이제 CDF의 역을 가져 와서 샘플링하려고합니다. http://en.wikipedia.org/wiki/Inverse_transform_sampling

먼저 거의 CDF를 최대 값으로 나누어 정규화합니다. 이것은 dφ와 r을 취소하는 부작용이 있습니다.

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

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

그러므로:

let x by a random float in range [0,1]
θ = -arcsin(1-2*x)

이것은 그가 "100 % 무작위 화"된 것으로 버리는 옵션과 동일하지 않습니까? 내 이해는 그가 균일 한 무작위 분포보다 더 균등 한 간격을 원한다는 것입니다.
앤드류 쿡 2012 년

@ BlueRaja-DannyPflughoeft : 흠, 공평합니다. 나는 내가해야 할만큼 신중하게 질문을 읽지 않았던 것 같다. 어쨌든 다른 사람들이 유용하다고 생각할 수 있도록 여기에 남겨 둡니다. 지적 해 주셔서 감사합니다.
ninjagecko

1

또는 ... 20 개의 점을 배치하려면 20 면체면의 중심을 계산합니다. 12 개의 점에 대해 정 이십 면체의 꼭지점을 찾습니다. 30 점의 경우 정 이십 면체 가장자리의 중간 점입니다. 4 면체, 정육면체, 십이 면체 및 팔면체에 대해서도 동일한 작업을 수행 할 수 있습니다. 한 세트는 정점에 있고, 다른 한 세트는면 중앙에 있고, 다른 하나는 가장자리 중앙에 있습니다. 그러나 혼합 할 수는 없습니다.


좋은 생각이지만 4, 6, 8, 12, 20, 24 또는 30 점에 대해서만 작동합니다.
모자입니다 가진 사람

속임수를 쓰려면면과 정점의 중심을 사용할 수 있습니다. 그들은 것입니다 하지 동등 간격하지만 괜찮은 근사합니다. 이것은 결정적이기 때문에 좋습니다.
chessofnerd

0
# 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)])

4
이것이 의미하는 바를 설명하는 텍스트를 작성하면 도움이 될 것이므로 OP는 그것이 작동한다는 믿음을 가질 필요가 없습니다.
hcarver

0

@robert king 정말 좋은 솔루션이지만 약간의 엉성한 버그가 있습니다. 나는 그것이 나를 많이 도왔다는 것을 알고 있으므로 엉성한 것에 신경 쓰지 마십시오. :) 여기에 정리 된 버전이 있습니다 ....

from math import pi, asin, sin, degrees
halfpi, twopi = .5 * pi, 2 * pi
sphere_area = lambda R=1.0: 4 * pi * R ** 2

lat_dist = lambda lat, R=1.0: R*(1-sin(lat))

#A = 2*pi*R^2(1-sin(lat))
def sphere_latarea(lat, R=1.0):
    if -halfpi > lat or lat > halfpi:
        raise ValueError("lat must be between -halfpi and halfpi")
    return 2 * pi * R ** 2 * (1-sin(lat))

sphere_lonarea = lambda lon, R=1.0: \
        4 * pi * R ** 2 * lon / twopi

#A = 2*pi*R^2 |sin(lat1)-sin(lat2)| |lon1-lon2|/360
#    = (pi/180)R^2 |sin(lat1)-sin(lat2)| |lon1-lon2|
sphere_rectarea = lambda lat0, lat1, lon0, lon1, R=1.0: \
        (sphere_latarea(lat0, R)-sphere_latarea(lat1, R)) * (lon1-lon0) / twopi


def test_sphere(n_lats=10, n_lons=19, radius=540.0):
    total_area = 0.0
    for i_lons in range(n_lons):
        lon0 = twopi * float(i_lons) / n_lons
        lon1 = twopi * float(i_lons+1) / n_lons
        for i_lats in range(n_lats):
            lat0 = asin(2 * float(i_lats) / n_lats - 1)
            lat1 = asin(2 * float(i_lats+1)/n_lats - 1)
            area = sphere_rectarea(lat0, lat1, lon0, lon1, radius)
            print("{:} {:}: {:9.4f} to  {:9.4f}, {:9.4f} to  {:9.4f} => area {:10.4f}"
                    .format(i_lats, i_lons
                    , degrees(lat0), degrees(lat1)
                    , degrees(lon0), degrees(lon1)
                    , area))
            total_area += area
    print("total_area = {:10.4f} (difference of {:10.4f})"
            .format(total_area, abs(total_area) - sphere_area(radius)))

test_sphere()

-1

이것은 작동하며 치명적입니다. 원하는만큼 포인트 :

    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());
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.