From 9ce626ee64058e233f41a3d4f4388f04ab8abc7f Mon Sep 17 00:00:00 2001 From: David Allemang Date: Tue, 13 Oct 2020 22:44:46 -0400 Subject: [PATCH] introduce Mesh class with subgroup context --- vendor/toddcox | 2 +- vis/include/cgl/buffer.hpp | 5 - vis/include/rendering.hpp | 5 +- vis/include/solver.hpp | 318 ++++++++++++++++++++----------------- vis/src/main.cpp | 8 +- 5 files changed, 183 insertions(+), 155 deletions(-) diff --git a/vendor/toddcox b/vendor/toddcox index 16c9d7d..265de59 160000 --- a/vendor/toddcox +++ b/vendor/toddcox @@ -1 +1 @@ -Subproject commit 16c9d7d62f728196c5d2c078d268fe46d81a17be +Subproject commit 265de59917bdf94709b40ad8aef5dd9ce5574242 diff --git a/vis/include/cgl/buffer.hpp b/vis/include/cgl/buffer.hpp index ad3226e..aaa40fd 100644 --- a/vis/include/cgl/buffer.hpp +++ b/vis/include/cgl/buffer.hpp @@ -62,11 +62,6 @@ namespace cgl { put(data.data(), data.size(), usage); } - template<> - void put>(const std::vector &data, GLenum usage = GL_STATIC_DRAW) { - put(data.data, data.size(), usage); - } - void bound(GLenum target, const std::function &action) const { glBindBuffer(target, id); action(); diff --git a/vis/include/rendering.hpp b/vis/include/rendering.hpp index 9f40ccf..068db9e 100644 --- a/vis/include/rendering.hpp +++ b/vis/include/rendering.hpp @@ -47,8 +47,9 @@ public: template Slice(const tc::Group &g, T all_sg_gens, const std::vector> &exclude) : group(g) { - const auto &data = merge(hull(g, all_sg_gens, exclude)); - ibo.put(data); + auto mesh = merge(hull(g, exclude)); + ibo.put(mesh); + vao.ipointer(0, ibo, 4, GL_UNSIGNED_INT); } diff --git a/vis/include/solver.hpp b/vis/include/solver.hpp index d8afb92..94265d9 100644 --- a/vis/include/solver.hpp +++ b/vis/include/solver.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "combo_iterator.hpp" @@ -19,204 +20,235 @@ std::vector generators(const tc::Group &context) { return g_gens; } -/** - * Determine which of g_gens are the correct names for sg_gens within the current context - */ -std::vector recontext_gens( - const tc::Group &context, - std::vector g_gens, - std::vector sg_gens) { +namespace { + /** + * Determine which of g_gens are the correct names for sg_gens within the current context + */ + std::vector recontext_gens( + const tc::Group &context, + std::vector g_gens, + std::vector sg_gens) { - std::sort(g_gens.begin(), g_gens.end()); + std::sort(g_gens.begin(), g_gens.end()); - int inv_gen_map[context.ngens]; - for (size_t i = 0; i < g_gens.size(); i++) { - inv_gen_map[g_gens[i]] = i; + int inv_gen_map[context.ngens]; + for (size_t i = 0; i < g_gens.size(); i++) { + inv_gen_map[g_gens[i]] = i; + } + + std::vector s_sg_gens; + s_sg_gens.reserve(sg_gens.size()); + for (const auto gen : sg_gens) { + s_sg_gens.push_back(inv_gen_map[gen]); + } + std::sort(s_sg_gens.begin(), s_sg_gens.end()); + + return s_sg_gens; } - std::vector s_sg_gens; - s_sg_gens.reserve(sg_gens.size()); - for (const auto gen : sg_gens) { - s_sg_gens.push_back(inv_gen_map[gen]); + /** + * Solve the cosets generated by sg_gens within the subgroup generated by g_gens of the group context + */ + tc::Cosets solve( + 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); + return context.subgroup(g_gens).solve(proper_sg_gens); } - std::sort(s_sg_gens.begin(), s_sg_gens.end()); - return s_sg_gens; + /** + * Apply some context transformation to all primitives of this mesh. + */ + template + void apply(const tc::Cosets &table, int gen, Prims &mat) { + auto data = mat.data(); + for (int i = 0; i < mat.size(); ++i) { + data[i] = table.get(data[i], gen); + } + } } -/** - * Solve the cosets generated by sg_gens within the subgroup generated by g_gens of the group context - */ -tc::Cosets solve( - 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); - return context.subgroup(g_gens).solve(proper_sg_gens); -} +//template +//auto hull(const tc::Group &group, T all_sg_gens, const std::vector> &exclude) { +// std::vector> parts; +// auto g_gens = generators(group); +// for (const std::vector &sg_gens : all_sg_gens) { +// bool excluded = false; +// for (const auto &test : exclude) { +// if (sg_gens == test) { +// excluded = true; +// break; +// } +// } +// if (excluded) continue; +// +// const auto &base = triangulate(group, sg_gens); +// const auto &tiles = tile(base, group, g_gens, sg_gens); +// for (const auto &tile : tiles) { +// parts.push_back(tile); +// } +// } +// return parts; +//} -/** - * Apply some context transformation to all primitives of this mesh. - */ template -void apply(const tc::Cosets &table, int gen, Prims &mat) { - auto data = mat.data(); - for (int i = 0; i < mat.size(); ++i) { - data[i] = table.get(data[i], gen); +class Mesh { +public: + const tc::Group *g; // todo this needs to be handled more consistently + std::vector ctx; + Prims prims; + + Mesh(const tc::Group &g_, std::vector ctx_, size_t cols); + + Mesh(const tc::Group &g_, std::vector ctx_); + + Mesh recontext(std::vector ctx_); + + std::vector> tile(const std::vector &ctx_); + + Mesh fan(unsigned root); + + [[nodiscard]] size_t size() const { return prims.size(); } + + [[nodiscard]] size_t rows() const { return prims.rows(); } + + [[nodiscard]] size_t cols() const { return prims.cols(); } + + [[nodiscard]] unsigned *data() { return prims.data(); } + + [[nodiscard]] const unsigned *data() const { return prims.data(); } +}; + +template +M merge(const std::vector &meshes) { + if (meshes.empty()) throw std::logic_error("cannot merge an empty list of meshes"); + + auto g = meshes[0].g; + auto ctx = meshes[0].ctx; + + size_t cols = 0; + for (const auto &mesh : meshes) { + cols += mesh.prims.cols(); } + + M res(*g, ctx, cols); + + size_t offset = 0; + for (const auto &mesh : meshes) { + res.prims.middleCols(offset, mesh.prims.cols()) = mesh.prims; + offset += mesh.prims.cols(); + } + + return 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. - */ template -[[nodiscard]] -Prims recontext( - Prims 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; +Mesh Mesh::recontext(std::vector ctx_) { + Mesh res = *this; + res.ctx = ctx_; + + const auto proper_sg_gens = recontext_gens(*g, res.ctx, ctx); + const auto table = solve(*g, res.ctx, {}); + const auto path = solve(*g, ctx, {}).path; auto map = path.template walk(0, proper_sg_gens, [table](int coset, int gen) { return table.get(coset, gen); }); - Prims res(prims); - auto data = res.data(); - for (int i = 0; i < prims.size(); ++i) { + auto data = res.prims.data(); + for (int i = 0; i < res.prims.size(); ++i) { data[i] = map[data[i]]; } return res; } -/** - * Union several meshes of the same dimension - */ template -Prims merge(const std::vector> &meshes) { - size_t cols = 0; - for (const auto &mesh : meshes) { - cols += mesh.cols(); - } +std::vector> Mesh::tile(const std::vector &ctx_) { + auto base = recontext(ctx_); - Prims res(N, cols); + auto table = solve(*g, base.ctx, {}); + auto path = solve(*g, base.ctx, ctx).path; - size_t offset = 0; - for (const Prims &mesh : meshes) { - res.middleCols(offset, mesh.cols()) = mesh; - offset += mesh.cols(); - } - - return res; -} - -template -[[nodiscard]] -std::vector> tile( - Prims prims, - const tc::Group &context, - const std::vector &g_gens, - const std::vector &sg_gens -) { - Prims 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; - - std::vector _gens = generators(context); - - std::vector> res = path.walk, int>( - base, _gens, - [&](Prims from, int gen) { - apply(table, gen, from); - return from; + std::vector> res = path.template walk, int>( + base, generators(*g), + [&](Mesh mesh, int gen) { + apply(table, gen, mesh.prims); + return mesh; } ); return res; } -/** - * Produce a mesh of higher dimension by fanning a single point to all primitives in this mesh. - */ template -[[nodiscard]] -Prims fan(Prims prims, int root) { - Prims res(N + 1, prims.cols()); +Mesh Mesh::fan(unsigned root) { + Mesh res(*g, ctx, prims.cols()); - res.topRows(1) = Prims<1>::Constant(1, prims.cols(), root); - res.bottomRows(N) = prims; + res.prims.topRows(1) = Prims<1>::Constant(1, prims.cols(), root); + res.prims.bottomRows(N) = prims; 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 -Prims triangulate( - const tc::Group &context, - const std::vector &g_gens -) { - if (g_gens.size() + 1 != N) // todo make static assert - throw std::logic_error("g_gens size must be one less than N"); +Mesh::Mesh(const tc::Group &g_, std::vector ctx_, size_t cols) + : g(&g_), ctx(std::move(ctx_)) { + prims.setZero(N, cols); +} - const auto &combos = Combos(g_gens, g_gens.size() - 1); +template +Mesh::Mesh(const tc::Group &g_, std::vector ctx_) + : g(&g_), ctx(std::move(ctx_)) { + if (ctx.size() + 1 != N) // todo make static assert + throw std::logic_error("ctx size must be one less than N"); - std::vector> meshes; + const auto &combos = Combos(ctx, ctx.size() - 1); - for (const auto &sg_gens : combos) { - auto base = triangulate(context, sg_gens); - auto parts = tile(base, context, g_gens, sg_gens); + std::vector> meshes; + + for (const auto &sctx : combos) { + Mesh base(*g, sctx); + auto parts = base.tile(ctx); parts.erase(parts.begin(), parts.begin() + 1); - auto raised = merge(parts); - auto fanned = fan(raised, 0); + + if (parts.empty()) continue; + auto raised = merge(parts); + + auto fanned = raised.fan(0); meshes.push_back(fanned); } - return merge(meshes); + prims = merge(meshes).prims; } -/** - * Single-index primitives should not be further triangulated. - */ template<> -Prims<1> triangulate<1>( - 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>::Mesh(const tc::Group &g_, std::vector ctx_) : g(&g_), ctx(std::move(ctx_)) { + if (not ctx.empty()) + throw std::logic_error("ctx must be empty for a trivial Mesh."); - return Prims<1>::Zero(1, 1); + prims.setZero(1, 1); } -template -auto hull(const tc::Group &group, T all_sg_gens, const std::vector> &exclude) { - std::vector> parts; - auto g_gens = generators(group); - for (const std::vector &sg_gens : all_sg_gens) { - bool excluded = false; - for (const auto &test : exclude) { - if (sg_gens == test) { - excluded = true; - break; - } - } +template +auto hull(const tc::Group &g, const std::vector> &exclude) { + std::vector> parts; + + auto ctx = generators(g); + auto sub_ctxs = Combos(ctx, N - 1); + + for (const auto &sub_ctx : sub_ctxs) { + bool excluded = std::any_of( + exclude.begin(), exclude.end(), + [&](auto e) { return e == sub_ctx; } + ); if (excluded) continue; - const auto &base = triangulate(group, sg_gens); - const auto &tiles = tile(base, group, g_gens, sg_gens); - for (const auto &tile : tiles) { - parts.push_back(tile); - } + auto sub_parts = Mesh(g, sub_ctx).tile(ctx); + parts.insert(parts.end(), sub_parts.begin(), sub_parts.end()); } + return parts; -} +} \ No newline at end of file diff --git a/vis/src/main.cpp b/vis/src/main.cpp index 5fc46e7..bc0fc4a 100644 --- a/vis/src/main.cpp +++ b/vis/src/main.cpp @@ -18,9 +18,9 @@ mat5 wander(float time) { r *= rot<5>(1, 2, time * .13f); r *= rot<5>(0, 1, time * .20f); - r *= rot<5>(0, 3, time * .17f); - r *= rot<5>(1, 3, time * .25f); - r *= rot<5>(2, 3, time * .12f); +// r *= rot<5>(0, 3, time * .17f); +// r *= rot<5>(1, 3, time * .25f); +// r *= rot<5>(2, 3, time * .12f); // r *= rot<5>(1, 4, time * .27f); @@ -66,7 +66,7 @@ public: std::cout << utilInfo(); - std::vector symbol = {3, 4, 3, 2}; + std::vector symbol = {5, 3, 2, 2}; root << .80, .02, .02, .02, .02; auto group = tc::schlafli(symbol);