diff --git a/vis/include/geometry.hpp b/vis/include/geometry.hpp index c03031a..7526440 100644 --- a/vis/include/geometry.hpp +++ b/vis/include/geometry.hpp @@ -108,127 +108,121 @@ tc::Cosets solve( return context.subgroup(g_gens).solve(proper_sg_gens); } +/** + * Apply some context transformation to all primitives of this mesh. + */ template -struct Mesh { - std::vector> prims; - - Mesh() : prims() {} - - Mesh(const Mesh &) = default; - - explicit Mesh(std::vector> &prims) : prims(prims) {} - - [[nodiscard]] size_t size() const { - return prims.size(); +std::vector> apply(std::vector> prims, const tc::Cosets &table, int gen) { + for (auto &prim : prims) { + prim.apply(table, gen); } + return prims; +} - /** - * Apply some context transformation to all primitives of this mesh. - */ - void apply(const tc::Cosets &table, int gen) { - for (auto &prim : prims) { - prim.apply(table, gen); +/** + * Reverse the orientation of all primitives in this mesh. + */ +template +void flip(std::vector> prims) { + for (auto &prim : prims) { + prim.flip(); + } +} + +/** + * Convert the indexes of this mesh to those of a different context, using g_gens to build the parent context and sg_gens to build this context. + */ +template +[[nodiscard]] +std::vector> recontext( + std::vector> prims, + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + const auto table = solve(context, g_gens, {}); + const auto path = solve(context, sg_gens, {}).path; + + auto map = path.template walk(0, proper_sg_gens, [table](int coset, int gen) { + return table.get(coset, gen); + }); + + std::vector> res(prims); + for (Primitive &prim : res) { + for (auto &ind : prim.inds) { + ind = map[ind]; } } - /** - * Reverse the orientation of all primitives in this mesh. - */ - void flip() { - for (auto &prim : prims) { - prim.flip(); - } - } + if (get_parity(context, g_gens, sg_gens) == 1) + flip(res); - /** - * Convert the indexes of this mesh to those of a different context, using g_gens to build the parent context and sg_gens to build this context. - */ - [[nodiscard]] - Mesh recontext( - const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens - ) const { - const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); - const auto table = solve(context, g_gens, {}); - const auto path = solve(context, sg_gens, {}).path; - - auto map = path.template walk(0, proper_sg_gens, [table](int coset, int gen) { - return table.get(coset, gen); - }); - - Mesh res = *this; - for (Primitive &prim : res.prims) { - for (auto &ind : prim.inds) { - ind = map[ind]; - } - } - - if (get_parity(context, g_gens, sg_gens) == 1) - res.flip(); - - return res; - } - - [[nodiscard]] - Mesh tile( - const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens - ) const { - Mesh base = recontext(context, g_gens, sg_gens); - const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); - - const auto table = solve(context, g_gens, {}); - const auto path = solve(context, g_gens, sg_gens).path; - - const auto all = path.template walk, int>(base, gens(context), [table](Mesh from, int gen) { - from.apply(table, gen); - return from; - }); - - return merge(all); - } - - /** - * Produce a mesh of higher dimension by fanning a single point to all primitives in this mesh. - */ - [[nodiscard]] - Mesh fan(int root) const { - std::vector> res(prims.size()); - std::transform(prims.begin(), prims.end(), res.begin(), - [root](const Primitive &prim) { - return Primitive(prim, root); - } - ); - return Mesh(res); - } -}; + return res; +} /** * Union several meshes of the same dimension */ template -Mesh merge(const std::vector> &meshes) { +std::vector> merge(const std::vector>> &meshes) { size_t size = 0; for (const auto &mesh : meshes) { size += mesh.size(); } - std::vector> prims; - prims.reserve(size); + std::vector> res; + res.reserve(size); for (const auto &mesh : meshes) { - prims.insert(prims.end(), mesh.prims.begin(), mesh.prims.end()); + res.insert(res.end(), mesh.begin(), mesh.end()); } - return Mesh(prims); + return res; +} + +template +[[nodiscard]] +std::vector> tile( + std::vector> prims, + const tc::Group &context, + const std::vector &g_gens, + const std::vector &sg_gens +) { + std::vector> base = recontext(prims, context, g_gens, sg_gens); + const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); + + const auto table = solve(context, g_gens, {}); + const auto path = solve(context, g_gens, sg_gens).path; + + auto _gens = gens(context); + + auto res = path.walk>, int>(base, gens(context), [&](auto from, auto gen) { + return apply(from, table, gen); + }); + + return merge(res); +} + +/** + * Produce a mesh of higher dimension by fanning a single point to all primitives in this mesh. + */ +template +[[nodiscard]] +std::vector> fan(std::vector> prims, int root) { + std::vector> res(prims.size()); + std::transform(prims.begin(), prims.end(), res.begin(), + [root](const Primitive &prim) { + return Primitive(prim, root); + } + ); + return res; } /** * Produce a mesh of primitives that fill out the volume of the subgroup generated by generators g_gens within the group context */ template -Mesh triangulate( +std::vector> triangulate( const tc::Group &context, const std::vector &g_gens ) { @@ -237,13 +231,13 @@ Mesh triangulate( const auto &combos = Combos(g_gens, g_gens.size() - 1); - std::vector> meshes; + std::vector>> meshes; + for (const auto &sg_gens : combos) { - Mesh base = triangulate(context, sg_gens); - Mesh raised = base.tile(context, g_gens, sg_gens); - raised.prims.erase(raised.prims.begin(), raised.prims.begin() + base.size()); - Mesh fan = raised.fan(0); - meshes.push_back(fan); + auto base = triangulate(context, sg_gens); + auto raised = tile(base, context, g_gens, sg_gens); + raised.erase(raised.begin(), raised.begin() + base.size()); + meshes.push_back(fan(raised, 0)); } return merge(meshes); @@ -253,14 +247,14 @@ Mesh triangulate( * Single-index primitives should not be further triangulated. */ template<> -Mesh<1> triangulate<1>( +std::vector> triangulate( const tc::Group &context, const std::vector &g_gens ) { if (not g_gens.empty()) // todo make static assert throw std::logic_error("g_gens must be empty for a trivial Mesh"); - Mesh<1> res; - res.prims.emplace_back(); + std::vector> res; + res.emplace_back(); return res; } diff --git a/vis/src/main.cpp b/vis/src/main.cpp index 232e3d1..81099fe 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -85,12 +85,12 @@ Matrices build(GLFWwindow *window, float st) { } template -std::vector> poly_parts(const tc::Group &group) { - std::vector> parts; +std::vector>> poly_parts(const tc::Group &group) { + std::vector>> parts; auto g_gens = gens(group); for (const auto &sg_gens : Combos(g_gens, N - 1)) { parts.push_back( - triangulate(group, sg_gens).tile(group, g_gens, sg_gens) + tile(triangulate(group, sg_gens), group, g_gens, sg_gens) ); } return parts; @@ -171,10 +171,10 @@ void run(GLFWwindow *window) { } Drawable<2, float> wires(GL_LINES); - wires.ibo.put(wire_data.prims); + wires.ibo.put(wire_data); Drawable<4, glm::vec3> slices(GL_POINTS); - slices.ibo.put(slice_data.prims); + slices.ibo.put(slice_data); slices.vbo.put(slice_colors); slices.vao.ipointer(0, slices.ibo, 4, GL_UNSIGNED_INT); slices.vao.pointer(1, slices.vbo, 3, GL_FLOAT);