summaryrefslogtreecommitdiff
path: root/app/c++/ico.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'app/c++/ico.hpp')
-rw-r--r--app/c++/ico.hpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/app/c++/ico.hpp b/app/c++/ico.hpp
new file mode 100644
index 0000000..5dc00a0
--- /dev/null
+++ b/app/c++/ico.hpp
@@ -0,0 +1,170 @@
+#pragma once
+
+#include <array>
+#include <cassert>
+#include <cstdint>
+
+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<std::array<uint8_t,3u>, 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<uint64_t SubD>
+class ico_addr {
+private:
+ std::array<uint8_t, SubD> 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<SubD>& 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<uint64_t,4u> count_groups() const {
+ std::array<uint64_t,4u> 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<SubD> go_to(uint8_t dir_i){
+ ico_addr<SubD> 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<typename T, uint64_t D>
+class ico_triangle {
+private:
+ std::array<ico_triangle<T,D-1u>,4u> subdivs_;
+public:
+
+ ico_triangle<T,D-1u>& at(uint8_t i){
+ return subdivs_[i];
+ }
+
+ template<uint64_t AddrOrigLen>
+ ico_triangle<T,0u> at(const ico_addr<AddrOrigLen>& 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<typename T>
+class ico_triangle<T,0u> final {
+private:
+ T val_;
+public:
+};
+
+namespace impl {
+}
+
+template<typename T, uint64_t SubD>
+class icosahedron final {
+private:
+ std::array<ico_triangle<T,SubD>,20u> surfaces_;
+public:
+
+ template<uint64_t AddrD>
+ ico_triangle<T,SubD+1u-AddrD> at(const ico_addr<AddrD>& 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);
+ }
+};
+}
+}