#pragma once #include #include #include namespace kel { namespace impl { struct ico_surface_helper { /** * On each triangle we assume a ccw order and we start on the top-left part of the * triangle. The orientation of the triangle is determined by the horizontal line * (on the 2D foldout of the icosahedron) which is the down direction. */ static constexpr std::array, 20u> neighbour_map {{ {1,4,5},//0 {2,0,6},//1 {3,1,7},//2 {4,2,8},//3 {0,3,9},//4 {14,10,0},//5 {10,11,1},//6 {11,12,2},//7 {12,13,3},//8 {13,14,4},//9 {6,5,15},//10 {7,6,16},//11 {8,7,17},//12 {9,8,18},//13 {5,9,19},//14 {19,16,10},//15 {15,17,11},//16 {16,18,12},//17 {17,19,13},//18 {18,15,14} //19 }}; }; } template class ico_addr { private: std::array vals_; public: uint8_t& at(uint64_t i){ return vals_[i]; } const uint8_t& at(uint64_t i) const { return vals_[i]; } constexpr uint64_t size() const { return SubD; } bool is_equal(const ico_addr& rhs) const { bool eq = true; for(uint64_t i = 0u; i < size(); ++i){ eq &= (at(i) == rhs.at(i)); } return eq; } bool has_zero() const { uint64_t z_ctr = 0u; for(uint64_t i = 1u; i < size(); ++i){ z_ctr += (at(i) == 0u ? 1u : 0u); } return (z_ctr > 0u); } std::array count_groups() const { std::array grps{0,0,0,0}; for(uint64_t i = 1u; i < size(); ++i){ auto& addr_i = vals_[i]; assert(addr_i < 4); ++grps[addr_i]; } return grps; } uint64_t count_non_zero_groups() const { auto ctr = count_groups(); uint64_t grp_ctr = 0u; for(uint64_t i = 1u; i < ctr.size(); ++i){ grp_ctr += (ctr[i] > 0u ? 1u : 0u); } return grp_ctr; } bool has_all_non_zero_groups() const { auto ctr = count_non_zero_groups(); return (ctr == 3u); } ico_addr go_to(uint8_t dir_i){ ico_addr cpy_addr; cpy_addr.vals_ = vals_; if(at(size() - 1u) == 0u){ cpy_addr.at(size() - 1u) = dir_i + 1u; } if(at(size() - 1u) == (dir_i + 1u)){ cpy_addr.at(size() - 1u) = 0u; } return cpy_addr; } bool borders_root() const { return not (has_all_non_zero_groups() or has_zero()); } }; template class ico_triangle { private: std::array,4u> subdivs_; public: ico_triangle& at(uint8_t i){ return subdivs_[i]; } template ico_triangle at(const ico_addr& addr, uint64_t next_i){ auto& addr_i = addr[next_i]; auto& sub_triangle = subdivs_[addr_i]; if constexpr ( D == 1u){ return sub_triangle; } return sub_triangle.at(addr,next_i+1u); } }; template class ico_triangle final { private: T val_; public: }; namespace impl { } template class icosahedron final { private: std::array,20u> surfaces_; public: template ico_triangle at(const ico_addr& addr){ static_assert(AddrD <= (SubD+1u), "Addr length to large."); static_assert(AddrD > 0u, "Addr length to small."); auto& root_addr = addr[0u]; auto& root_triangle = surfaces_[root_addr]; return root_triangle.at(addr, 1u); } }; }