introduce Mesh class with subgroup context

This commit is contained in:
David Allemang
2020-10-13 22:44:46 -04:00
committed by David Allemang
parent 6ff09dc375
commit 9ce626ee64
5 changed files with 183 additions and 155 deletions

2
vendor/toddcox vendored

View File

@@ -62,11 +62,6 @@ namespace cgl {
put(data.data(), data.size(), usage);
}
template<>
void put<std::vector<T>>(const std::vector<T> &data, GLenum usage = GL_STATIC_DRAW) {
put(data.data, data.size(), usage);
}
void bound(GLenum target, const std::function<void()> &action) const {
glBindBuffer(target, id);
action();

View File

@@ -47,8 +47,9 @@ public:
template<class T>
Slice(const tc::Group &g, T all_sg_gens, const std::vector<std::vector<int>> &exclude) : group(g) {
const auto &data = merge<N>(hull<N>(g, all_sg_gens, exclude));
ibo.put(data);
auto mesh = merge(hull<N>(g, exclude));
ibo.put(mesh);
vao.ipointer(0, ibo, 4, GL_UNSIGNED_INT);
}

View File

@@ -7,6 +7,7 @@
#include <iostream>
#include <geometry.hpp>
#include <utility>
#include "combo_iterator.hpp"
@@ -19,6 +20,7 @@ std::vector<int> generators(const tc::Group &context) {
return g_gens;
}
namespace {
/**
* Determine which of g_gens are the correct names for sg_gens within the current context
*/
@@ -66,157 +68,187 @@ void apply(const tc::Cosets &table, int gen, Prims<N> &mat) {
data[i] = table.get(data[i], gen);
}
}
}
//template<unsigned N, class T>
//auto hull(const tc::Group &group, T all_sg_gens, const std::vector<std::vector<int>> &exclude) {
// std::vector<Prims<N>> parts;
// auto g_gens = generators(group);
// for (const std::vector<int> &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<N>(group, sg_gens);
// const auto &tiles = tile<N>(base, group, g_gens, sg_gens);
// for (const auto &tile : tiles) {
// parts.push_back(tile);
// }
// }
// return parts;
//}
/**
* 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<unsigned N>
[[nodiscard]]
Prims<N> recontext(
Prims<N> prims,
const tc::Group &context,
const std::vector<int> &g_gens,
const std::vector<int> &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;
class Mesh {
public:
const tc::Group *g; // todo this needs to be handled more consistently
std::vector<int> ctx;
Prims<N> prims;
Mesh(const tc::Group &g_, std::vector<int> ctx_, size_t cols);
Mesh(const tc::Group &g_, std::vector<int> ctx_);
Mesh<N> recontext(std::vector<int> ctx_);
std::vector<Mesh<N>> tile(const std::vector<int> &ctx_);
Mesh<N + 1> 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<class M>
M merge(const std::vector<M> &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;
}
template<unsigned N>
Mesh<N> Mesh<N>::recontext(std::vector<int> ctx_) {
Mesh<N> 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<int, int>(0, proper_sg_gens, [table](int coset, int gen) {
return table.get(coset, gen);
});
Prims<N> 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<unsigned N>
Prims<N> merge(const std::vector<Prims<N>> &meshes) {
size_t cols = 0;
for (const auto &mesh : meshes) {
cols += mesh.cols();
}
std::vector<Mesh<N>> Mesh<N>::tile(const std::vector<int> &ctx_) {
auto base = recontext(ctx_);
Prims<N> res(N, cols);
auto table = solve(*g, base.ctx, {});
auto path = solve(*g, base.ctx, ctx).path;
size_t offset = 0;
for (const Prims<N> &mesh : meshes) {
res.middleCols(offset, mesh.cols()) = mesh;
offset += mesh.cols();
}
return res;
}
template<unsigned N>
[[nodiscard]]
std::vector<Prims<N>> tile(
Prims<N> prims,
const tc::Group &context,
const std::vector<int> &g_gens,
const std::vector<int> &sg_gens
) {
Prims<N> base = recontext<N>(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<int> _gens = generators(context);
std::vector<Prims<N>> res = path.walk<Prims<N>, int>(
base, _gens,
[&](Prims<N> from, int gen) {
apply<N>(table, gen, from);
return from;
std::vector<Mesh<N>> res = path.template walk<Mesh<N>, int>(
base, generators(*g),
[&](Mesh<N> mesh, int gen) {
apply<N>(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<unsigned N>
[[nodiscard]]
Prims<N + 1> fan(Prims<N> prims, int root) {
Prims<N + 1> res(N + 1, prims.cols());
Mesh<N + 1> Mesh<N>::fan(unsigned root) {
Mesh<N + 1> 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<unsigned N>
Prims<N> triangulate(
const tc::Group &context,
const std::vector<int> &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<N>::Mesh(const tc::Group &g_, std::vector<int> 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<unsigned N>
Mesh<N>::Mesh(const tc::Group &g_, std::vector<int> 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<Prims<N>> meshes;
const auto &combos = Combos(ctx, ctx.size() - 1);
for (const auto &sg_gens : combos) {
auto base = triangulate<N - 1>(context, sg_gens);
auto parts = tile<N - 1>(base, context, g_gens, sg_gens);
std::vector<Mesh<N>> meshes;
for (const auto &sctx : combos) {
Mesh<N - 1> base(*g, sctx);
auto parts = base.tile(ctx);
parts.erase(parts.begin(), parts.begin() + 1);
auto raised = merge<N - 1>(parts);
auto fanned = fan<N - 1>(raised, 0);
if (parts.empty()) continue;
auto raised = merge(parts);
auto fanned = raised.fan(0);
meshes.push_back(fanned);
}
return merge<N>(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<int> &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<int> 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<unsigned N, class T>
auto hull(const tc::Group &group, T all_sg_gens, const std::vector<std::vector<int>> &exclude) {
std::vector<Prims<N>> parts;
auto g_gens = generators(group);
for (const std::vector<int> &sg_gens : all_sg_gens) {
bool excluded = false;
for (const auto &test : exclude) {
if (sg_gens == test) {
excluded = true;
break;
}
}
template<unsigned N>
auto hull(const tc::Group &g, const std::vector<std::vector<int>> &exclude) {
std::vector<Mesh<N>> 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<N>(group, sg_gens);
const auto &tiles = tile<N>(base, group, g_gens, sg_gens);
for (const auto &tile : tiles) {
parts.push_back(tile);
}
auto sub_parts = Mesh<N>(g, sub_ctx).tile(ctx);
parts.insert(parts.end(), sub_parts.begin(), sub_parts.end());
}
return parts;
}

View File

@@ -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<int> symbol = {3, 4, 3, 2};
std::vector<int> symbol = {5, 3, 2, 2};
root << .80, .02, .02, .02, .02;
auto group = tc::schlafli(symbol);