正二十面体を扱いたい
正二十面体とかGeodesic Gridをプログラムで扱いたいことが時々あるので,頂点の座標とか接続関係とかメモ. きれいな別の方法が見つかったら更新すると思います.
頂点の座標
ここを見よう(他力本願)
正20面体の頂点座標の求め方 - Weblog on mebius.tokaichiba.jp
辺が黄金比の長方形を3枚使うと求まるらしい.黄金数は
なんか立方体からいい感じに計算を進めていって求められそうな気もする.
頂点のインデックス
いつも正二十面体のギザギザの展開図上の点を,左上から右下にインデクスを振っている.
https://commons.wikimedia.org/wiki/File:Icosahedron_flat.svg
座標との対応はじっと見つめるしかない.
接続関係
正二十面体の展開図をじっと見つめると良い.
コード(Geodesic gridを求める関数付き)
C++わからん
#include <vector> #include "Eigen/Core" namespace icosahedron { constexpr double G = (1.0+sqrt(5.0))/2.0; // Golden number const std::vector<Eigen::Vector3d> kVertices = { Eigen::Vector3d(1, 0, G), // 0 Eigen::Vector3d(-1, 0, G), // 1 Eigen::Vector3d(0, -G, 1), // 2 Eigen::Vector3d(G, -1, 0), // 3 Eigen::Vector3d(G, 1, 0), // 4 Eigen::Vector3d(0, G, 1), // 5 Eigen::Vector3d(-G, -1, 0), // 6 Eigen::Vector3d(0, -G, -1), // 7 Eigen::Vector3d(1, 0, -G), // 8 Eigen::Vector3d(0, G, -1), // 9 Eigen::Vector3d(-G, 1, 0), // 10 Eigen::Vector3d(-1, 0, -G), // 11 }; const std::vector<std::vector<int>> kTriangles = { {0, 1, 2}, // 0 {0, 2, 3}, // 1 {0, 3, 4}, // 2 {0, 4, 5}, // 3 {0, 5, 1}, // 4 {1, 6, 2}, // 5 {2, 7, 3}, // 6 {3, 8, 4}, // 7 {4, 9, 5}, // 8 {5, 10, 1}, // 9 {2, 6, 7}, // 10 {3, 7, 8}, // 11 {4, 8, 9}, // 12 {5, 9, 10}, // 13 {1, 10, 6}, // 14 {6, 11, 7}, // 15 {7, 11, 8}, // 16 {8, 11, 9}, // 17 {9, 11, 10}, // 18 {10, 11, 6}, // 19 }; std::pair<std::vector<Eigen::Vector3d>, std::vector<std::vector<int>>> GetGeodesicGrid(double radius, int frequency) { // devide triangles std::vector<Eigen::Vector3d> _vertices; const double triangle_length = ((kVertices[0]-kVertices[1])/frequency).norm(); for(const auto &triangle : kTriangles){ auto a = (kVertices[triangle[1]] - kVertices[triangle[0]])/frequency; auto b = (kVertices[triangle[2]] - kVertices[triangle[1]])/frequency; for(int i=0;i<frequency+1;i++){ for(int j=0;j<i+1;j++){ _vertices.push_back(kVertices[triangle[0]] + a*i + b*j); } } } // remove duplication std::vector<bool> _unique(_vertices.size(), true); for(size_t i=0;i<_vertices.size();i++){ if(!_unique[i]) continue; for(size_t j=i+1;j<_vertices.size();j++){ if((_vertices[i]-_vertices[j]).norm() < triangle_length/2){ _unique[j] = false; } } } std::vector<Eigen::Vector3d> vertices; for(size_t i=0;i<_vertices.size();i++){ if(_unique[i]) vertices.push_back(_vertices[i]); } // construct graph std::vector<std::vector<int>> graph(vertices.size()); for(size_t i=0;i<vertices.size();i++){ for(size_t j=0;j<vertices.size();j++){ if(i == j) continue; if((vertices[i]-vertices[j]).norm() < triangle_length*1.5){ graph[i].push_back(j); } } } // project vertices to spherical surface for(auto &v : vertices){ v = v.normalized()*radius; } return {vertices, graph}; } }