diff --git a/libs/geom/CMakeLists.txt b/libs/geom/CMakeLists.txt index e71c70f6..ec2122ff 100644 --- a/libs/geom/CMakeLists.txt +++ b/libs/geom/CMakeLists.txt @@ -10,7 +10,7 @@ file(GLOB_RECURSE PSEMEK_GEOM_SOURCES "source/*.cpp") psemek_add_library(psemek-geom ${PSEMEK_GEOM_HEADERS} ${PSEMEK_GEOM_SOURCES}) target_include_directories(psemek-geom PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") -target_link_libraries(psemek-geom PUBLIC psemek-util Boost::boost) +target_link_libraries(psemek-geom PUBLIC psemek-util psemek-group Boost::boost) if(PSEMEK_ROBUST_PREDICATES) target_link_libraries(psemek-geom PUBLIC gmp) endif() diff --git a/libs/geom/include/psemek/geom/symmetry.hpp b/libs/geom/include/psemek/geom/symmetry.hpp new file mode 100644 index 00000000..619be3f5 --- /dev/null +++ b/libs/geom/include/psemek/geom/symmetry.hpp @@ -0,0 +1,155 @@ +#pragma once + +#include +#include + +#include +#include + +#include + +namespace psemek::geom +{ + + template + struct symmetry + { + matrix m; + + symmetry(); + symmetry(symmetry const &) = default; + + template + symmetry(group::cyclic const & g); + + template + symmetry(group::cyclic const & g, std::size_t i, std::size_t j); + + template + symmetry(group::dihedral const & g); + + template + symmetry(group::dihedral const & g, std::size_t i, std::size_t j); + + matrix affine_matrix() const; + matrix linear_matrix() const; + vector translation_vector() const; + matrix homogeneous_matrix() const; + + affine_transform transform() const; + + vector operator()(vector const & v) const; + point operator()(point const & p) const; + }; + + template + symmetry::symmetry() + { + m = m.identity(); + } + + template + template + symmetry::symmetry(group::cyclic const & g) + : symmetry(g, 0, 1) + {} + + template + template + symmetry::symmetry(group::cyclic const & g, std::size_t i, std::size_t j) + { + m = m.identity(); + + T angle = (T{2} * geom::pi * static_cast(g.value())) / static_cast(D); + + m[i][i] = std::cos(angle); + m[i][j] = -std::sin(angle); + m[j][i] = std::sin(angle); + m[j][j] = std::cos(angle); + } + + template + template + symmetry::symmetry(group::dihedral const & g) + : symmetry(g, 0, 1) + {} + + template + template + symmetry::symmetry(group::dihedral const & g, std::size_t i, std::size_t j) + { + m = m.identity(); + + T angle = (T{2} * geom::pi * static_cast(g.value())) / static_cast(D); + + // See https://en.wikipedia.org/wiki/Dihedral_group#Matrix_representation + + if (g.is_rotation()) + { + m[i][i] = std::cos(angle); + m[i][j] = -std::sin(angle); + m[j][i] = std::sin(angle); + m[j][j] = std::cos(angle); + } + else + { + m[i][i] = std::cos(angle); + m[i][j] = std::sin(angle); + m[j][i] = std::sin(angle); + m[j][j] = -std::cos(angle); + } + } + + template + matrix symmetry::affine_matrix() const + { + matrix result; + for (std::size_t i = 0; i < N; ++i) + for (std::size_t j = 0; j < N; ++j) + result[i][j] = m[i][j]; + for (std::size_t i = 0; i < N; ++i) + result[i][N] = T{0}; + return result; + } + + template + matrix symmetry::linear_matrix() const + { + return m; + } + + template + vector symmetry::translation_vector() const + { + return vector::zero(); + } + + template + matrix symmetry::homogeneous_matrix() const + { + auto result = matrix::identity(); + for (std::size_t i = 0; i < N; ++i) + for (std::size_t j = 0; j < N; ++j) + result[i][j] = m[i][j]; + return result; + } + + template + affine_transform symmetry::transform() const + { + return {m, geom::vector::zero()}; + } + + template + vector symmetry::operator()(vector const & v) const + { + return m * v; + } + + template + point symmetry::operator()(point const & p) const + { + return p.zero() + m * (p - p.zero()); + } + +}