球のn個の点を均等に分散


120

Nポイント(おそらく20未満)の球の周りの位置をぼんやりと広げるアルゴリズムを必要としています。「完璧」の必要はありませんが、私はそれが必要なので、それらが一緒に束ねられることはありません。

  • この質問は良いコードを提供しましたが、これは100%ランダム化されているように見えたため、これを統一する方法を見つけることができませんでした。
  • この推奨ブログ投稿には、球体上の点の数を入力できる2つの方法がありましたが、SaffおよびKuijlaarsアルゴリズムは、転記できる疑似コード内にあり、見つけたコード例には、「node [k]」が含まれていましたが、これはできませんでした説明してその可能性を台無しにしてください。2番目のブログの例はゴールデンセクションスパイラルで、一定の半径を定義する明確な方法がなく、奇妙な束になった結果が得られました。
  • この質問からのこのアルゴリズムはおそらく機能するようですが、そのページの内容を疑似コードなどにまとめることはできません。

私が遭遇した他のいくつかの質問スレッドは、ランダム化された均一分布について話しました。これは、気にしないレベルの複雑さを追加します。これはばかげた質問であることをお詫びしますが、私は本当に一見懸命に見ていて、まだ足りないことを示したいと思いました。

したがって、私が探しているのは、球または直交座標で返される単位球の周りにN個の点を均等に分散する単純な疑似コードです。少しのランダム化で分布さえできればなおさらです(星の周りの惑星は、まあまあ広がっていますが、余裕があります)。


「少しランダム化して」とはどういう意味ですか?ある意味で摂動を意味しますか?
ninjagecko 2012年

32
OPが混乱しています。 彼が探しているのは、球にn点を配置して、2点間の最小距離ができるだけ大きくなるようにすることです。 これにより、ポイントは球全体に「均等に分散」されているように見えます。これは、球に均一なランダム分布を作成することとはまったく関係がありません。これは、これらのリンクの多くがそうであるものであり、以下の多くの答えが話しているものです。
BlueRaja-Danny Pflughoeft 2012年

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

これをプロットすると、極の近くで垂直間隔が広くなり、各点がほぼ同じ合計スペース領域に配置されることがわかります(極の近くでは、「水平方向」にスペースが少なくなり、「垂直方向」により多くのスペースが得られます。 )。

これは、隣接点までの距離がほぼ同じであるすべてのポイントと同じではありませんが(これはリンクが話していることだと思います)、必要なものには十分であり、単純な緯度/経度グリッドを作成することで改善される場合があります。


いいですね、数学的解を見ることは良いことです。らせんと弧長の分離を使用することを考えていました。興味深い問題である最適なソリューションをどのように取得するかはまだわかりません。
ロバートキング2012

上部にnode [k]の説明が含まれるように回答を編集したことをご存知ですか?
それで十分

素晴らしい、説明ありがとう。まだ時間がないので、後で試してみるが、手伝ってくれてありがとう。最終的にどのように機能するかをお知らせします。^^
降りかかる

スパイラル法を使用すると、私のニーズに完全に適合します。ヘルプと明確化に感謝します。:)
降臨

13
リンクが機能していないようです。
Scheintod 2014

139

これにはフィボナッチ球アルゴリズムが最適です。それは高速であり、ひと目で人間の目を簡単にだます結果が得られます。ポイントが追加されると時間の経過とともに結果が表示される、処理行った例を見ることができます。@gmanが作成したもう1つのすばらしいインタラクティブな例を次に示します。そして、これがPythonでの簡単な実装です。

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)*増分。n =サンプルですか?
Andrew Staroscik 2014年

@AndrewStaroscikはい!私が最初にコードを書いたとき、私は変数として "n"を使用し、後で名前を変更しましたが、デューデリジェンスをしませんでした。それをキャッチしてくれてありがとう!
2014年


4
@Xarbroughコードは単位球の周りにポイントを与えるので、半径に必要なスカラーを各ポイントに乗算します。
Fnord 2017年

2
@Fnord:より高い次元でこれを行うことはできますか?
pikachuchameleon

108

ゴールデンスパイラル法

ゴールデンスパイラルメソッドを機能させることができなかったと言っていましたが、それは本当に良いので残念です。これを完全に理解して、これが「束ねられない」ようにする方法を理解できるようにしたいと思います。

これが、ほぼ正しいラティスを作成するための高速でランダムでない方法です。上で説明したように、完全な格子はありませんが、これで十分な場合があります。BendWavy.orgなどの他の方法と比較されますが、見栄えが良く、制限内の均等な間隔が保証されています。

プライマー:ユニットディスク上のヒマワリスパイラル

このアルゴリズムを理解するために、まず2Dヒマワリスパイラルアルゴリズムを紹介します。これは、最も不合理な数が黄金比で(1 + sqrt(5))/2あり、「中心に立って、全回転の黄金比を回し、次にその方向に別の点を放出する」というアプローチでポイントを放出する場合、自然にスパイラルは、ポイントの数が増えるにつれて、ポイントが並ぶ明確な「バー」を持つことを拒否します。(注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 I少し領域たいR ∈(RR + D R)、Θ ∈(θθ + D θ、その面積に比例する点の数を格納する)をこれは、Rの D のR dはθ。私たちはここに確率変数について話していることをふり今ならば、これは言うほど簡単な解釈を持っている(のための結合確率密度R Θ)がcr定数cの場合 = 1 /πを。。ユニットディスクの正規化は、cを強制します。

では、トリックを紹介しましょう。それはそれはとして知られている確率論から来て逆CDFをサンプリングし、あなたがしたいとします発生確率密度を持つ確率変数FZを)、あなたはランダム変数持つUの出てくるだけのように〜制服(0、1)random()ほとんどのプログラミング言語で。これどうやってやるの?

  1. 最初に、密度を累積分布関数またはCDF に変換します。これをFz)と呼びます。CDFは、導関数fz)を使用して0から1に単調に増加します。
  2. 次に、CDFの逆関数F -1z)を計算します。
  3. Z = F -1U)がターゲット密度に従って分布していることがわかります。(注3)。

ここで、黄金比のスパイラルトリックでポイントをθのパターンにうまく均等に配置します。それを統合してみましょう。ユニットディスクの場合、Fr)= r 2になります。したがって、逆関数はF -1u)= 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のθは、今ではあまりない-より-複雑罪(となりφ)D φ D θ。したがって、等間隔の結合密度はsin(φ)/4πです。θを積分すると、fφ)= sin(φ)/ 2となるため、Fφ)=(1 − cos(φ))/ 2となります。我々は一様確率変数がACOSように見えるであろうことを確認でき、これを反転(1 - 2 Uに)、我々は代わりに使用するので、我々は、ランダムに一様にサンプリングする代わりにφ K 2( - = ACOS(1 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の場合、結果は次のようになります。 ここに画像の説明を入力してください ここに画像の説明を入力してください

さらなる研究

マーティンロバーツのブログに一言お願いしたいと思いました。上記では、各インデックスに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 + 1/(1 + 1/(1 + ...))特に適切な有理近似がないものです。黄金比の式を得るためにφを掛けてφ = 1 + 1 / φを解くことができます。

  2. NumPyにあまり詳しくない人のために-すべての関数は「ベクトル化」されているため、sqrt(array)他の言語で記述されるものと同じmap(sqrt, array)です。したがって、これはコンポーネントごとのsqrtアプリケーションです。スカラによる除算またはスカラによる加算についても同様です。これらはすべてのコンポーネントに並列に適用されます。

  3. これが結果であることがわかったら、証明は簡単です。あなたは可能性があること何尋ねればZ < Z < Z + dはZ、これは確率何尋ねると同じであるZ < F -1U)< Z + dはzは、適用Fを、それがあることを指摘し、すべての3つの式には、単調増加する関数、したがってFz)< U < Fz + d z)、右側を展開してFz)+ fz)d z、そしてUは均一なので、この確率は約束どおりfz)d zです。


4
これがなぜこれほどまでにダウンしているのかはわかりませんが、これはこれを行うのに断然最高の高速な方法です。
2017年

2
@snb優しい言葉をありがとう!それは、ここにある他のすべての回答よりもはるかに若いので、部分的にはずっと下にあります。これまでと同じように機能していることに驚いています。
CR Drost

私に残っている質問の1つは、2つのポイント間の特定の最大距離に対して、いくつのポイントnを分配する必要があるかです。
Felix D.

1
@FelixD。これは、特にユークリッド距離ではなく大圏距離などを使い始めた場合に、非常に複雑になる可能性がある質問のように聞こえます。しかし、おそらく私は簡単な質問に答えることができます。球のポイントをボロノイ図に変換する場合、各ボロノイセルを約4π/ Nの面積として記述でき、これを円のふりをして特徴的な距離に変換できます菱形よりも、πr²=4π/ N。次に、r = 2 /√(N)です。
CR Drost

2
ランダムに均一な入力ではなく、実際に均一な入力でサンプリング定理を使用することは、「まあ、なぜ#$%&はそれについて考えなかったのですか?」。いいね。
dmckee ---元モデレーターの子猫

86

これは球上のパッキングポイントと呼ばれ、一般的で完全な(既知の)解はありません。しかし、不完全な解決策はたくさんあります。最も人気のある3つは次のようです。

  1. シミュレーションを作成します。各点を球に束縛された電子として扱い、特定のステップ数のシミュレーションを実行します。電子の反発力は当然、システムをより安定した状態にします。この場合、ポイントは互いに可能な限り離れます。
  2. ハイパーキューブの拒否。この派手なサウンドの方法は実際には非常に単純です。球を囲む立方体の内側の点nそれらのよりもはるかに多いを均一に選択し、球の外側の点を拒否します。残りの点をベクトルとして扱い、それらを正規化します。これらはあなたの「サンプル」です- nいくつかの方法(ランダム、貪欲など)を使用して選択します。
  3. スパイラル近似。球の周りのらせんをトレースし、らせんの周りの点を均等に分散させます。数学が関係しているため、これらはシミュレーションよりも理解するのがより複雑ですが、はるかに高速です(おそらくコードが少なくなります)。最も人気があるのはサフらによるようです。

多くのこの問題に関する詳細な情報を見つけることができるここに


アンドリュークックが以下に掲載するスパイラル戦略を検討しますが、私が欲しいものと「均一なランダム分布」が何であるかとの違いを明確にしていただけませんか?それらが均一に配置されるように、球上に点を100%ランダムに配置しただけですか?助けてくれてありがとう。:)
2012年

4
@Befall:「均一なランダム分布」とは、確率分布が均一であることを意味します。つまり、球体上のランダムな点を選択すると、すべての点が選択される可能性が等しくなります。ポイントの最終的な空間分布とは関係がないため、質問とは関係ありません。
BlueRaja-Danny Pflughoeft 2012年

ああ、そうか、どうもありがとう。自分の質問を検索すると、両方にたくさんの答えが返ってきて、どちらが無意味なのか本当にわかりませんでした。
2012年

明確にするために、すべてのポイントが選択される確率はゼロです。ポイントが球の表面上の任意の2つの領域に属する確率の比率は、表面の比率と等しくなります。
AturSams 2016年

2
最後のリンクは死んでいます
フェリックス

10

あなたが探しているものは、球状のカバーリングと呼ばれています。球面被覆の問題は非常に難しく、少数の点を除いて解は不明です。確かに知られていることの1つは、球上のnポイントが与えられた場合、常に2つ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次元のガウス分布は球対称であるため、球への投影は均一です。

もちろん、均一に生成されたポイントのコレクション内の任意の2つのポイント間の距離が下にあるという保証はありません。したがって、拒否を使用して、このような条件を強制できます。おそらくコレクション全体を生成してから、必要に応じてコレクション全体を拒否します。(または、「早期拒否」を使用して、これまでに生成したコレクション全体を拒否します。一部のポイントを保持せずに、他のポイントをドロップしないでください。)d上記の式を使用して、スラックを差し引いて、それより下では、一連のポイントを拒否します。nを計算して2つの距離を選択する必要があり、拒否の確率はスラックに依存します。方法を言うのは難しいので、シミュレーションを実行して、関連する統計の感触をつかんでください。


最小最大距離式に賛成。使用したいポイントの数を制限するのに役立ちます。しかし、そのための信頼できる情報源への参照は良いでしょう。
dmckee ---元モデレーターの子猫

6

この回答は、この回答で概説されているのと同じ「理論」に基づいています

私はこの答えを次のように追加し
ます。-他のオプションはどれも「スポットオン」の「均一性」のニーズに適合しません(または明らかに明確ではありません)。(元の質問で特に求められている惑星のような分布のような見た目の動作を取得することに注意して、ランダムにk個の均一に作成されたポイントの有限リストから拒否するだけです(k個のアイテムのインデックスカウントをランダムに戻します)。)
-最も近い他の実装では、「N」を「角度軸」で決定することを余儀なくされました。両方の角度軸値で「Nの1つの値」だけを決定する必要があります(Nの数が少ないと、何が問題であるか、または問題ではないかを知るのが非常に困難です(たとえば、「5」ポイントが欲しい-楽しんでください))
-さらに、画像なしで他のオプションを区別する方法を「理解」するのは非常に難しいので、このオプションの外観(下)と、すぐに実行できる実装を以下に示します。

Nが20の場合:

ここに画像の説明を入力してください
そして80でN: ここに画像の説明を入力してください


すぐに実行できるpython3コードを次に示します。エミュレーションは同じソースです: " http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere "他の人が見つけました。(「メイン」として実行すると起動する、私が含めたプロットは、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 = iをnearest_index = randchoice(i、j)に変更する必要があります
robert king

1

あなたの二大要因を取るN場合は、N==202つの最大の要因である{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}、第三に、あなたが{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}のstd devを適切に)、それらを均一に分布したポイントに追加します。


5
latよりもsin(lat)で作業した方がずっと見栄えが良くなります。そのままでは、極の近くにたくさんの束ができます。
アンドリュークック2012年

1

編集:これは、OPが尋ねる質問に答えるものではなく、人々が何らかの形でそれを役立てた場合に備えて、ここに残します。

確率の乗法則を無限小と組み合わせて使用​​します。これにより、2行のコードで目的の結果が得られます。

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

(次の座標系で定義:)

ここに画像の説明を入力してください

あなたの言語は通常、一様な乱数プリミティブを持っています。たとえば、Python random.random()では、範囲内の数値を返すために使用できます[0,1)。この数値にkを掛けて、範囲内の乱数を取得できます[0,k)。したがって、Pythonでは、uniform([0,2pi))を意味しrandom.random()*2*math.piます。


証明

ここで、θを均一に割り当てることはできません。球形ウェッジの表面積に比例する確率を割り当てたいと思います(この図のθは実際にはφです):

ここに画像の説明を入力してください

赤道での角変位dφは、dφ* rの変位になります。その変位は、任意の方位角θでどのようになりますか?まあ、z軸からの半径r*sin(θ)はなので、くさびと交差する「緯度」の弧の長さはdφ * r*sin(θ)です。したがって、南極から北極までのスライスの面積を積分することにより、そこからサンプリングする面積の累積分布を計算します。

ここに画像の説明を入力してください(ここでstuff = 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%ランダム化」されているとして彼が破棄したオプションと同等ではありませんか?私の理解では、彼は均一なランダム分布よりも等間隔に配置したいと考えています。
アンドリュークック

@ BlueRaja-DannyPflughoeft:うーん、まあまあ。質問をよく読んでいないと思います。他の人が便利だと思ったときのために、これはとにかくここに置いておきます。これを指摘してくれてありがとう。
ninjagecko 2012年

1

または... 20点を配置するには、20面体の面の中心を計算します。12点については、正二十面体の頂点を見つけます。30点の場合、正二十面体のエッジの中点。四面体、立方体、十二面体、八面体でも同じことができます。あるセットの点は頂点にあり、別のセットは面の中心にあり、別のセットはエッジの中心にあります。ただし、混在させることはできません。


良いアイデアですが、4、6、8、12、20、24、または30ポイントでのみ機能します。
帽子をかぶった男

チートしたい場合は、面と頂点の中心を使用できます。彼らはなりません等間隔が、まともな近似であること。確定的であるため、これは素晴らしいことです。
chessofnerd 2016

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 2012

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.