diff options
-rw-r--r-- | .nix/derivation.nix | 8 | ||||
-rw-r--r-- | README.md | 50 | ||||
-rw-r--r-- | SConstruct | 1 | ||||
-rw-r--r-- | c++/ico.hpp | 114 | ||||
-rw-r--r-- | default.nix | 14 | ||||
-rw-r--r-- | node_neighbours.md | 13 | ||||
-rw-r--r-- | tests/SConscript | 31 | ||||
-rw-r--r-- | tests/ico.cpp | 68 |
8 files changed, 291 insertions, 8 deletions
diff --git a/.nix/derivation.nix b/.nix/derivation.nix index a927e8d..fd41fc1 100644 --- a/.nix/derivation.nix +++ b/.nix/derivation.nix @@ -1,5 +1,6 @@ { stdenv , scons +, forstio }: stdenv.mkDerivation { pname = "icosahedrical_destruction"; @@ -9,5 +10,12 @@ stdenv.mkDerivation { nativeBuildInputs = [ scons + forstio.core ]; + + doCheck = true; + checkPhase = '' + scons test + ./bin/tests + ''; } diff --git a/README.md b/README.md new file mode 100644 index 0000000..d531c6d --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# Icosahedrical Destruction + +## Triangle Neighbours + +Starting at zero, the described operations match while the remainder "falls out". +The next level takes over then. And so on .... + +### Level - 0 + +0 x 1 => 1 +0 x 2 => 2 +0 x 3 => 3 +// Mirror +1 x 1 => 0 +2 x 2 => 0 +3 x 3 => 0 + +### Level - 1 + +0-1 x 2 => 2-3 +0-1 x 3 => 3-2 +0-2 x 1 => 1-3 +0-2 x 3 => 3-1 +0-3 x 1 => 1-2 +0-3 x 2 => 2-1 +// Mirror +1-2 x 1 => 0-3 +1-3 x 1 => 0-2 +2-1 x 2 => 0-3 +2-3 x 2 => 0-1 +3-1 x 3 => 0-2 +3-2 x 3 => 0-1 + +### Level - 2 + +0-1-1 x 2 => 2-3-3 +0-1-1 x 3 => 3-2-2 +0-1-2 x 3 => 3-2-1 +0-1-3 x 2 => 2-3-1 +0-2-1 x 3 => 3-1-2 +0-2-2 x 1 => 1-3-3 +0-2-2 x 3 => 3-1-1 +0-2-3 x 1 => 1-3-2 +0-3-1 x 2 => 2-1-3 +0-3-2 x 1 => 1-2-3 +0-3-3 x 1 => 1-2-2 +0-3-3 x 2 => 2-1-1 +... + + @@ -59,6 +59,7 @@ env.targets = []; Export('env') SConscript('c++/SConscript') +SConscript('tests/SConscript') # Aliasing env.Alias('cdb', env.cdb); diff --git a/c++/ico.hpp b/c++/ico.hpp index 0ac1a91..257f12d 100644 --- a/c++/ico.hpp +++ b/c++/ico.hpp @@ -1,6 +1,7 @@ #pragma once #include <array> +#include <cassert> #include <cstdint> namespace kel { @@ -11,7 +12,7 @@ struct ico_surface_helper { * 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 { + static constexpr std::array<std::array<uint8_t,3u>, 20u> neighbour_map {{ {1,4,5},//0 {2,0,6},//1 {3,1,7},//2 @@ -32,26 +33,112 @@ struct ico_surface_helper { {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+1u> vals_; + std::array<uint8_t, SubD> vals_; public: - template<uint64_t Div = 1u> - ico_addr<Div> slice() const { - return {}; + 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>> subdivs_; + 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> @@ -61,10 +148,23 @@ private: 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); + } }; } diff --git a/default.nix b/default.nix index 99e112c..f7c4be7 100644 --- a/default.nix +++ b/default.nix @@ -1,3 +1,15 @@ { pkgs ? import <nixpkgs> {} +, stdenv ? pkgs.llvmPackages_16.stdenv +, clang-tools ? pkgs.clang-tools_16 +, forstio ? (import ((builtins.fetchGit { + url = "git@git.keldu.de:forstio/forstio"; + ref = "dev"; + }).outPath + "/default.nix"){ + inherit stdenv; + inherit clang-tools; + }).forstio }: -pkgs.callPackage ./.nix/derivation.nix {} + +pkgs.callPackage ./.nix/derivation.nix { + inherit forstio; +} diff --git a/node_neighbours.md b/node_neighbours.md new file mode 100644 index 0000000..0f3c660 --- /dev/null +++ b/node_neighbours.md @@ -0,0 +1,13 @@ +0 - 1,2,3,4,5 +1 - 0,5,10,6,2 +2 - 0,1,6,7,3 +3 - 0,2,7,8,4 +4 - 0,3,8,9,5 +5 - 0,4,9,10,1 +6 - 2,1,10,11,7 +7 - 3,2,6,11,8 +8 - 4,3,7,11,9 +9 - 5,4,8,11,10 +10 - 1,5,9,11,6 +11 - 6,10,9,8,7 + diff --git a/tests/SConscript b/tests/SConscript new file mode 100644 index 0000000..8756d5a --- /dev/null +++ b/tests/SConscript @@ -0,0 +1,31 @@ +#!/bin/false + +import os +import os.path +import glob + + +Import('env') + +dir_path = Dir('.').abspath + +# Environment for base library +test_cases_env = env.Clone(); + +test_cases_env.Append(LIBS=['forstio-test']); + +test_cases_env.sources = sorted(glob.glob(dir_path + "/*.cpp")) +test_cases_env.headers = sorted(glob.glob(dir_path + "/*.hpp")) + +env.sources += test_cases_env.sources; +env.headers += test_cases_env.headers; + +objects_static = [] +test_cases_env.add_source_files(objects_static, test_cases_env.sources, shared=False); +test_cases_env.program = test_cases_env.Program('#bin/tests', [objects_static, env.library_shared]); + +# Set Alias +env.Alias('test', test_cases_env.program); +env.Alias('check', test_cases_env.program); + +env.targets += ['test','check']; diff --git a/tests/ico.cpp b/tests/ico.cpp new file mode 100644 index 0000000..021e3c2 --- /dev/null +++ b/tests/ico.cpp @@ -0,0 +1,68 @@ +#include <forstio/test/suite.hpp> +#include "../c++/ico.hpp" + +namespace { +SAW_TEST("Ico Triangle/Border"){ + using namespace kel; + + { + ico_addr<1> addr; + addr.at(0u) = 2u; + + SAW_EXPECT(addr.borders_root(), "Triangle address 0 doesn't borders root while it should."); + } + { + ico_addr<2> addr; + addr.at(0u) = 1u; + addr.at(1u) = 0u; + + SAW_EXPECT(!addr.borders_root(), "Triangle address 1 borders root while it shouldn't."); + } + { + ico_addr<4> addr; + addr.at(0u) = 2u; + addr.at(1u) = 1u; + addr.at(2u) = 2u; + addr.at(3u) = 3u; + + SAW_EXPECT(!addr.borders_root(), "Triangle address 2 borders root while it shouldn't."); + } + { + ico_addr<4> addr; + addr.at(0u) = 2u; + addr.at(1u) = 1u; + addr.at(2u) = 1u; + addr.at(3u) = 3u; + + SAW_EXPECT(addr.borders_root(), "Triangle address 3 doesn't border root while it should."); + } + { + ico_addr<4> addr; + addr.at(0u) = 2u; + addr.at(1u) = 1u; + addr.at(2u) = 1u; + addr.at(3u) = 1u; + + SAW_EXPECT(addr.borders_root(), "Triangle address 4 doesn't border root while it should."); + } + { + ico_addr<4> addr; + addr.at(0u) = 2u; + addr.at(1u) = 2u; + addr.at(2u) = 1u; + addr.at(3u) = 1u; + + SAW_EXPECT(addr.borders_root(), "Triangle address 5 doesn't border root while it should."); + } + { + ico_addr<4> addr; + addr.at(0u) = 2u; + addr.at(1u) = 2u; + addr.at(2u) = 1u; + addr.at(3u) = 2u; + + SAW_EXPECT(addr.borders_root(), "Triangle address 6 doesn't border root while it should."); + } +} + +} |