구에 n 개의 점을 균등하게 분배
모호하게 퍼지는 N 개의 점 (아마 20 개 미만)에 대해 구 주위에 위치를 제공 할 수있는 알고리즘이 필요합니다. "완벽 함"이 필요하지 않습니다.하지만 난 그냥 필요하기 때문에 함께 묶이지 않습니다.
- 이 질문 은 좋은 코드를 제공했지만 100 % 무작위로 보였기 때문에이 유니폼을 만드는 방법을 찾을 수 없었습니다.
- 이 블로그 게시물 은 구의 점 수를 입력 할 수있는 두 가지 방법을 제공했지만 Saff 및 Kuijlaars 알고리즘은 정확히 필자가 필사 할 수있는 의사 코드에 있으며 제가 찾은 코드 예제 에는 "node [k]"가 포함되어있었습니다. 그 가능성을 설명하고 망쳤습니다. 두 번째 블로그 예제는 Golden Section Spiral로, 일정 반경을 정의하는 명확한 방법이없는 이상하고 뭉친 결과를 제공했습니다.
- 이 질문 의이 알고리즘 은 작동 할 수있는 것처럼 보이지만 해당 페이지에있는 내용을 의사 코드 나 다른 것으로 통합 할 수는 없습니다.
내가 만난 몇 가지 다른 질문 스레드는 무작위 균일 분포에 대해 언급했으며, 이는 내가 걱정하지 않는 수준의 복잡성을 추가합니다. 정말 어리석은 질문이라는 점 사과드립니다.하지만 제가 정말 열심히 보였지만 여전히 부족하다는 것을 보여 드리고 싶었습니다.
그래서 제가 찾고있는 것은 구형 또는 데카르트 좌표로 반환되는 단위 구 주위에 N 개의 점을 균등하게 분배하는 간단한 의사 코드입니다. 약간의 무작위 화로도 분포 할 수 있다면 더 좋습니다 (별 주위의 행성을 적절하게 흩어져 있지만 여유 공간이있는 것을 생각해보십시오).
에서 이 예제 코드 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
이를 플로팅하면 각 점이 거의 동일한 전체 공간 영역 에 위치하도록 극 근처의 수직 간격이 더 커집니다 (극 근처에는 "수평"공간이 적어 "수직"으로 "더 많이 제공됨). ).
이것은 이웃과의 거리가 거의 같은 모든 포인트와 같지는 않지만 (링크가 말하는 것이라고 생각하는 것입니다) 원하는 것에 충분할 수 있으며 단순히 균일 한 위도 / 경도 그리드를 만드는 것으로 향상됩니다 .
피보나치 구 알고리즘은 이에 적합합니다. 빠르고 쉽게 사람의 눈을 속일 수있는 결과를 제공합니다. 포인트가 추가됨에 따라 시간이 지남에 따라 결과를 표시하는 처리로 완료된 예제를 볼 수 있습니다 . @gman이 만든 또 다른 훌륭한 대화 형 예제 가 있습니다. 다음은 간단한 무작위 화 옵션이있는 빠른 파이썬 버전입니다.
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 개의 샘플은 다음을 제공합니다.
이것은 구의 패킹 포인트로 알려져 있으며 (알려진) 일반적이고 완벽한 솔루션은 없습니다. 그러나 불완전한 해결책이 많이 있습니다. 가장 인기있는 세 가지는 다음과 같습니다.
- 시뮬레이션을 만듭니다 . 각 점을 구에 구속 된 전자로 취급 한 다음 특정 단계 수에 대한 시뮬레이션을 실행합니다. 전자의 반발은 자연스럽게 시스템을보다 안정된 상태로 만들 것입니다. 여기서 포인트는 가능한 한 서로 멀리 떨어져 있습니다.
- 하이퍼 큐브 거부 . 이 화려한 사운드 방법은 실제로 정말 간단합니다 : 당신은 균일하게 점을 선택 (더 이상
n
그들의) 구를 둘러싼 큐브의 내부에, 다음 영역의 외부에 포인트를 거부합니다. 나머지 점을 벡터로 취급하고 정규화합니다. 이것들은 당신의 "샘플"입니다-n
어떤 방법 (무작위, 욕심 등)을 사용하여 선택하십시오 . - 나선형 근사치 . 구를 중심으로 나선을 추적하고 나선 주위에 점을 고르게 분포시킵니다. 관련된 수학 때문에 시뮬레이션보다 이해하기가 더 복잡하지만 훨씬 빠릅니다 (그리고 아마도 더 적은 코드를 포함). 가장 인기있는 것은 Saff, et al .
많은 이 문제에 대한 자세한 정보를 찾을 수 있습니다 여기에
황금 나선 방법
황금 나선 방법을 사용할 수 없다고 하셨는데, 정말 정말 훌륭하기 때문에 안타깝습니다. 나는 당신이 "번치"되는 것을 막는 방법을 이해할 수 있도록 당신에게 그것에 대한 완전한 이해를 드리고 싶습니다.
그래서 여기에 대략적으로 정확한 격자를 만드는 빠르고 랜덤하지 않은 방법이 있습니다. 위에서 논의한 바와 같이 격자는 완벽하지 않지만 "충분히 충분"할 수 있습니다. 예를 들어 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 이라고 말하는 것으로 간단하게 해석됩니다.일부 상수 c . 그러면 단위 디스크에 대한 정규화는 c = 1 / π 를 강제 합니다.
이제 트릭을 소개하겠습니다. 그것은 역 CDF 샘플링으로 알려진 확률 이론에서 비롯된 것 입니다. 확률 밀도 f ( z )를 가진 랜덤 변수 를 생성 하고 싶고 랜덤 변수 U ~ Uniform (0, 1)이 있다고 가정합니다. 대부분의 프로그래밍 언어에서. 어떻게하나요?random()
- 먼저 밀도를 누적 분포 함수 F ( z ) 로 바꾸십시오.이 함수 는 미분 f ( z )를 사용 하여 0에서 1로 단조 증가 합니다.
- 그런 다음 CDF의 역함수 F -1 ( z )를 계산합니다 .
- 당신은 발견 할 것이다 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에 대한 결과는 다음과 같습니다.
노트
이러한 "바"는 다수 합리적인 근사치에 의해 형성되고, 다수의 가장 합리적인 근사치 지속적인 분획 식 온되는 정수이고, 한정된 양의 정수 또는 무한 시퀀스 중입니다
z + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))
z
n_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 / φ 를 풀 수 있습니다 .NumPy에 익숙하지 않은 사람들을 위해-모든 함수는 "벡터화"되어 있으므로
sqrt(array)
다른 언어가 작성하는 것과 동일map(sqrt, array)
합니다. 따라서 이것은 구성 요소 별sqrt
응용 프로그램입니다. 스칼라로 나누거나 스칼라를 추가하는 경우에도 마찬가지입니다. 모든 구성 요소에 병렬로 적용됩니다.이것이 결과라는 것을 알면 증거는 간단합니다. 당신은 확률 무엇을 요구하는 경우에 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 입니다.
당신이 찾고있는 것을 구면 커버 라고합니다 . 구형 커버링 문제는 매우 어렵고 적은 수의 포인트를 제외하고 솔루션을 알 수 없습니다. 확실히 알려진 한 가지는 구에 n 개의 점이 주어지면 항상 거리 d = (4-csc^2(\pi n/6(n-2)))^(1/2)
또는 그보다 가까운 두 점이 존재한다는 것 입니다.
구에 균일하게 분포 된 점을 생성하는 확률 적 방법을 원한다면 간단합니다. 가우스 분포에 의해 균일하게 공간에 점을 생성합니다 (다른 언어에 대한 코드를 찾기 어렵지 않고 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 개의 거리를 선택해야하며 거부 확률은 여유에 따라 달라집니다. 방법을 말하기는 어렵 기 때문에 시뮬레이션을 실행하여 관련 통계에 대한 느낌을 얻으십시오.
이 답변은에 의해 잘 설명되어 같은 '이론'을 기반으로 이 답변
나는이 대답을 다음과 같이 추가하고
있습니다 .-- '균일 성'에 맞는 다른 옵션은 '스팟 온'이 필요하지 않습니다 (또는 분명하지 않음). () particurally 당신이 무작위 (랜덤 WRT에서 K 균일하게 만든 점의 유한 목록에서 다시 K 항목의 인덱스 수를 거부 물어 원래의 원 분포를 찾고 행동과 같은 행성을 얻을 주목.)
--The 가장 가까운 다른 impl은 '각축'에 의해 'N'을 결정하도록 강요하고 두 각도 축 값에서 'N의 하나의 값'을 결정하도록 강요했습니다 (N의 낮은 계수에서 무엇이 문제가 될 수 있는지 아는 것은 매우 까다 롭습니다 ( 예 : 당신은 '5'점을 원합니다-재미있게 보내십시오))
-또한 이미지없이 다른 옵션을 구별하는 방법을 'grok'하기가 매우 어렵 기 때문에이 옵션의 모양 (아래)과 함께 실행 가능한 즉시 실행 가능한 구현이 있습니다.
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)에서 테스트되었으며 '좋게'작동하는 것 같습니다.
시험:
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
Healpix는 밀접하게 관련된 문제를 해결합니다 (동일한 영역 픽셀로 구를 픽셀 화).
http://healpix.sourceforge.net/
아마도 과잉 일 수도 있지만, 살펴본 후에는 다른 멋진 속성 중 일부가 흥미 롭다는 것을 알게 될 것입니다. 포인트 클라우드를 출력하는 기능 그 이상입니다.
나는 그것을 다시 찾으려고 여기에 착륙했다. "healpix"라는 이름은 정확히 구체를 불러 일으키지는 않습니다.
적은 수의 포인트로 시뮬레이션을 실행할 수 있습니다.
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)]
두 개의 가장 큰 요인이 이거나보다 일반적으로 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}의 표준 개발)를 생성하여 균일하게 분포 된 점에 추가 할 수 있습니다.
편집 : 이것은 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)
또는 ... 20 개의 점을 배치하려면 20 면체면의 중심을 계산합니다. 12 개의 점에 대해 정 이십 면체의 꼭지점을 찾습니다. 30 점의 경우 정 이십 면체 가장자리의 중간 점입니다. 4 면체, 정육면체, 십이 면체 및 팔면체에 대해서도 동일한 작업을 수행 할 수 있습니다. 한 세트는 정점에 있고, 다른 한 세트는면 중앙에 있고, 다른 하나는 가장자리 중앙에 있습니다. 그러나 혼합 할 수는 없습니다.
# 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)])
이것은 작동하며 치명적입니다. 원하는만큼 포인트 :
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());
}
참고 URL : https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere
'Programming' 카테고리의 다른 글
CardView 배경색은 항상 흰색입니다. (0) | 2020.08.08 |
---|---|
새 툴바의 제목 색상은 어떻게 설정합니까? (0) | 2020.08.08 |
자바 싱글 톤 및 동기화 (0) | 2020.08.08 |
Java에서 뮤텍스와 세마포어는 무엇입니까? (0) | 2020.08.08 |
Ruby : 문자열의 첫 번째 문자를 얻는 방법 (0) | 2020.08.08 |