monman53のぶろぐ

いろいろ載せるよ

正二十面体を扱いたい

f:id:monman53:20181115174156p:plain
こういうのやりたいよねと思った

正二十面体とかGeodesic Gridをプログラムで扱いたいことが時々あるので,頂点の座標とか接続関係とかメモ. きれいな別の方法が見つかったら更新すると思います.

頂点の座標

ここを見よう(他力本願)

正20面体の頂点座標の求め方 - Weblog on mebius.tokaichiba.jp

辺が黄金比の長方形を3枚使うと求まるらしい.黄金数は(1+\sqrt 5)/2

なんか立方体からいい感じに計算を進めていって求められそうな気もする.

頂点のインデックス

いつも正二十面体のギザギザの展開図上の点を,左上から右下にインデクスを振っている.

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