【Python】球面上に点を一様分布させるプログラム④

やったこと

球面上に複数の点を一様かつ対称的にプロットするプログラムをPythonで書きました。

なぜ?

研究にて3D物理シミュレーションをしています。
その中で、球面上に点を一様分布させる必要がありました。

単に3次元極座標にある偏角のとり方では、極と赤道付近とで格子点の密度が変わってしまいます。
そこで数学的なアプローチにより、密度の偏りを解決しました。

しかし、その方法では対称性が保たれず、目的と合致しませんでした。そこで「ジオデシックドーム」という構造を参考に、点をプロットしていきました。

ただし、通常利用されているジオデシックドーム構造は球体へ近づけることが目的なので、正20面体を分割していきます。

すると頂点数は離散的な値をとります。

そこでその頂点数のレパートリーを増やすために、正8面体スタートのジオデシックドーム構造をもとに、球面上に点をプロットしていきました。

ここまでが前回の話。


分割してできた多面体の頂点に点をプロットしていくと、ある離散的な点数しかとれません。

  頂点数 面数
0回分割 6 8
1回分割 18 32
2回分割 66 128
3回分割 258 512
4回分割 1026 2048

研究の目的上「2の累乗個の点」が欲しかったのですが、
多面体の頂点ではなく面の重心をプロットすることでその目標を達成できることに気づきました。

 

方法

基本的には、前回の操作である

  1. 単位球に内接する正8面体の頂点座標を取得
  2. その頂点座標のうち、x軸,y軸,z軸のいずれからも最も遠い点の座標を取得(それらの点というのは最も密度が小さい点たち)
  3. その得られた座標間の距離(隣り合いつつ最も離れている点同士の距離)を基準にして、多面体の頂点から2点選びその中点を計算
  4. 基準よりも近くにある中点座標を保存
  5. 保存した中点座標を単位球に内接するように押し出す
  6. 得られた座標すべてを多面体の頂点とし、2番に戻る

という流れの後、各面の重心を計算しました。

面を指定する際に、張られる三角形の面積として認められる範囲を制限することで余分な三角形を生成しないようにしています
(57行目のseparate関数←かなり乱暴な計算法です)。

もうちょっと数学的に解決できそうな部分は沢山ありますが…、現状困らなかったのでこれでいきました。

 

結果

結果的にこんな感じになりました。

似たような計算が何度も出てくるので関数にしろよって感じですが、分割回数n=1から順に作っていったのでコピペしてたらそうなっちゃいました。

あとfor回してるので動作は遅めです。

 

こちらがインプットするのは、分割回数nです(プログラムを実行すると入力を求められます)。
n=0~4の範囲で動作します。

n=4の場合、結果は以下の通り。

対称性は保たれていますが、密度のばらつきが強調されたような気もします。

欠点は冒頭にもあった通り、頂点数が任意の数でないこと。
分割の関係で、離散的な値しかとれません。

頂点数が大事な場合は検討が必要です。