show fundamental lines

This commit is contained in:
David Allemang
2022-09-14 14:17:16 -04:00
parent 181bf0cf19
commit aa88aee643
7 changed files with 122 additions and 43 deletions

View File

@@ -11,4 +11,20 @@
namespace tc { namespace tc {
Cosets solve(const Group &group, const std::vector<Gen> &sub_gens, const Coset &bound = UNBOUNDED); Cosets solve(const Group &group, const std::vector<Gen> &sub_gens, const Coset &bound = UNBOUNDED);
// todo
///**
// * 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<tc::Gen> &g_gens,
// const std::vector<tc::Gen> &sg_gens
// ) {
// // todo this should also be handled with 'global' generators.
// const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens);
//
// return tc::solve(context.subgroup(g_gens), proper_sg_gens);
// }
} }

View File

@@ -67,14 +67,14 @@ namespace tc {
return _orders(i, j); return _orders(i, j);
} }
[[nodiscard]] SubGroup subgroup(const std::vector<int> &gens) const; [[nodiscard]] SubGroup subgroup(const std::vector<tc::Gen> &gens) const;
}; };
struct SubGroup : public Group { struct SubGroup : public Group {
std::vector<int> gen_map; std::vector<tc::Gen> gen_map;
const Group &parent; const Group &parent;
SubGroup(const Group &parent, std::vector<int> gen_map) SubGroup(const Group &parent, std::vector<tc::Gen> gen_map)
: Group(gen_map.size()), parent(parent), gen_map() { : Group(gen_map.size()), parent(parent), gen_map() {
std::sort(gen_map.begin(), gen_map.end()); std::sort(gen_map.begin(), gen_map.end());

View File

@@ -6,7 +6,7 @@
#include <vector> #include <vector>
namespace tc { namespace tc {
SubGroup Group::subgroup(const std::vector<int> &gens) const { SubGroup Group::subgroup(const std::vector<tc::Gen> &gens) const {
return {*this, gens}; return {*this, gens};
} }

View File

@@ -11,12 +11,12 @@
#include "combo.hpp" #include "combo.hpp"
/** /**
* Produce a list of all generators for the group context. The range [0..group.ngens). * Produce a list of all generators for the group context. The range [0..group.rank).
*/ */
std::vector<int> generators(const tc::Group &context) { std::vector<tc::Gen> generators(const tc::Group &context) {
// todo if tc::Group has 'global' generators, then this will be a member of tc::Group. // todo if tc::Group has 'global' generators, then this will be a member of tc::Group.
// std::iota would populate a 'default' list of names, if names are not provided. // std::iota would populate a 'default' list of names, if names are not provided.
std::vector<int> g_gens(context.ngens); std::vector<tc::Gen> g_gens(context.rank);
std::iota(g_gens.begin(), g_gens.end(), 0); std::iota(g_gens.begin(), g_gens.end(), 0);
return g_gens; return g_gens;
} }
@@ -24,20 +24,20 @@ std::vector<int> generators(const tc::Group &context) {
/** /**
* Determine which of g_gens are the correct names for sg_gens within the current context * Determine which of g_gens are the correct names for sg_gens within the current context
*/ */
std::vector<int> recontext_gens( std::vector<tc::Gen> recontext_gens(
const tc::Group &context, const tc::Group &context,
std::vector<int> g_gens, std::vector<tc::Gen> g_gens,
std::vector<int> sg_gens) { std::vector<tc::Gen> sg_gens) {
// todo ideally tc::Group will deal in 'global' generators so this stell will be unecessary. // todo ideally tc::Group will deal in 'global' generators so this stell will be unecessary.
std::sort(g_gens.begin(), g_gens.end()); std::sort(g_gens.begin(), g_gens.end());
int inv_gen_map[context.ngens]; tc::Gen inv_gen_map[context.rank];
for (size_t i = 0; i < g_gens.size(); i++) { for (size_t i = 0; i < g_gens.size(); i++) {
inv_gen_map[g_gens[i]] = i; inv_gen_map[g_gens[i]] = i;
} }
std::vector<int> s_sg_gens; std::vector<tc::Gen> s_sg_gens;
s_sg_gens.reserve(sg_gens.size()); s_sg_gens.reserve(sg_gens.size());
for (const auto gen: sg_gens) { for (const auto gen: sg_gens) {
s_sg_gens.push_back(inv_gen_map[gen]); s_sg_gens.push_back(inv_gen_map[gen]);
@@ -52,21 +52,22 @@ std::vector<int> recontext_gens(
*/ */
tc::Cosets solve( tc::Cosets solve(
const tc::Group &context, const tc::Group &context,
const std::vector<int> &g_gens, const std::vector<tc::Gen> &g_gens,
const std::vector<int> &sg_gens const std::vector<tc::Gen> &sg_gens
) { ) {
// todo this should also be handled with 'global' generators. // todo this should also be handled with 'global' generators.
const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens); const auto proper_sg_gens = recontext_gens(context, g_gens, sg_gens);
return context.subgroup(g_gens).solve(proper_sg_gens);
return tc::solve(context.subgroup(g_gens), proper_sg_gens);
} }
/** /**
* Apply some context transformation to all primitives of this mesh. * Apply some context transformation to all primitives of this mesh.
*/ */
template<unsigned N> template<unsigned N>
void apply(const tc::Cosets &table, int gen, Prims<N> &mat) { void apply(const tc::Cosets &table, tc::Gen gen, Prims<N> &mat) {
auto data = mat.data(); auto data = mat.data();
for (int i = 0; i < mat.size(); ++i) { for (tc::Gen i = 0; i < mat.size(); ++i) {
data[i] = table.get(data[i], gen); data[i] = table.get(data[i], gen);
} }
} }
@@ -79,15 +80,15 @@ template<unsigned N>
Prims<N> recontext( Prims<N> recontext(
Prims<N> prims, Prims<N> prims,
const tc::Group &context, const tc::Group &context,
const std::vector<int> &g_gens, const std::vector<tc::Gen> &g_gens,
const std::vector<int> &sg_gens const std::vector<tc::Gen> &sg_gens
) { ) {
// todo this will be simpler with 'global' gens, but it's still not free... // todo this will be simpler with 'global' gens, but it's still not free...
const auto proper_sg_gens = recontext_gens(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 table = solve(context, g_gens, {});
const auto path = solve(context, sg_gens, {}).path; const auto path = solve(context, sg_gens, {}).path;
auto map = path.template walk<int, int>(0, proper_sg_gens, [table](int coset, int gen) { auto map = path.template walk<tc::Coset, tc::Gen>(0, proper_sg_gens, [table](tc::Coset coset, tc::Gen gen) {
return table.get(coset, gen); return table.get(coset, gen);
}); });
@@ -127,8 +128,8 @@ template<unsigned N>
std::vector<Prims<N>> tile( std::vector<Prims<N>> tile(
Prims<N> prims, Prims<N> prims,
const tc::Group &context, const tc::Group &context,
const std::vector<int> &g_gens, const std::vector<tc::Gen> &g_gens,
const std::vector<int> &sg_gens const std::vector<tc::Gen> &sg_gens
) { ) {
// todo convert to nullaryexpr. // todo convert to nullaryexpr.
// some stuff will be easier with global generators, but not all. // some stuff will be easier with global generators, but not all.
@@ -138,11 +139,11 @@ std::vector<Prims<N>> tile(
const auto table = solve(context, g_gens, {}); const auto table = solve(context, g_gens, {});
const auto path = solve(context, g_gens, sg_gens).path; const auto path = solve(context, g_gens, sg_gens).path;
std::vector<int> _gens = generators(context); std::vector<tc::Gen> _gens = generators(context);
std::vector<Prims<N>> res = path.walk<Prims<N>, int>( std::vector<Prims<N>> res = path.walk<Prims<N>, tc::Gen>(
base, _gens, base, _gens,
[&](Prims<N> from, int gen) { [&](Prims<N> from, tc::Gen gen) {
apply<N>(table, gen, from); apply<N>(table, gen, from);
return from; return from;
} }
@@ -172,7 +173,7 @@ Prims<N + 1> fan(Prims<N> prims, int root) {
template<unsigned N> template<unsigned N>
Prims<N> triangulate( Prims<N> triangulate(
const tc::Group &context, const tc::Group &context,
const std::vector<int> &g_gens const std::vector<tc::Gen> &g_gens
) { ) {
// todo (?) might be possible with nullaryexpr // todo (?) might be possible with nullaryexpr
// not so sure, though. // not so sure, though.
@@ -201,7 +202,7 @@ Prims<N> triangulate(
template<> template<>
Prims<1> triangulate<1>( Prims<1> triangulate<1>(
const tc::Group &context, const tc::Group &context,
const std::vector<int> &g_gens const std::vector<tc::Gen> &g_gens
) { ) {
if (not g_gens.empty()) // todo make static assert if (not g_gens.empty()) // todo make static assert
throw std::logic_error("g_gens must be empty for a trivial Mesh"); throw std::logic_error("g_gens must be empty for a trivial Mesh");
@@ -210,10 +211,10 @@ Prims<1> triangulate<1>(
} }
template<unsigned N, class T> template<unsigned N, class T>
auto hull(const tc::Group &group, T all_sg_gens, const std::vector<std::vector<int>> &exclude) { auto hull(const tc::Group &group, T all_sg_gens, const std::vector<std::vector<tc::Gen>> &exclude) {
std::vector<Prims<N>> parts; std::vector<Prims<N>> parts;
auto g_gens = generators(group); auto g_gens = generators(group);
for (const std::vector<int> &sg_gens: all_sg_gens) { for (const std::vector<tc::Gen> &sg_gens: all_sg_gens) {
bool excluded = false; bool excluded = false;
for (const auto &test: exclude) { for (const auto &test: exclude) {
if (sg_gens == test) { if (sg_gens == test) {

View File

@@ -15,6 +15,7 @@ public:
private: private:
GLuint id = 0; GLuint id = 0;
GLuint count = 0;
template<size_t ...idx> template<size_t ...idx>
inline void formatall( inline void formatall(

View File

@@ -118,23 +118,34 @@ void set_style() {
int run(GLFWwindow *window, ImGuiContext *context) { int run(GLFWwindow *window, ImGuiContext *context) {
State state; State state;
PointCloud pc;
LineCloud lc;
PointRenderer<Eigen::Vector4f> point_render; PointRenderer<Eigen::Vector4f> point_render;
LineRenderer<Eigen::Vector4f> line_render;
{ {
tc::Group group = tc::coxeter("3 4 3"); tc::Group group = tc::coxeter("3 4 3");
Eigen::Vector4f coords{1, 1, 1, 1}; Eigen::Vector4f coords{1, 1, 1, 1};
auto cosets = tc::solve(group, {}, 1000000); auto cosets = tc::solve(group, {}, 1000000);
auto mirrors = mirror<4>(group); auto mirrors = mirror<4>(group);
auto corners = plane_intersections(mirrors); auto corners = plane_intersections(mirrors);
auto start = barycentric(corners, coords); auto start = barycentric(corners, coords);
start.normalize(); start.normalize();
auto points = cosets.path.walk<vec4, vec4>(start, mirrors, reflect<vec4>); auto points = cosets.path.walk<vec4, vec4>(start, mirrors, reflect<vec4>);
point_render.upload(points); std::vector<unsigned> edges = {
0, 1,
0, 2,
0, 3,
0, 4,
};
pc.upload(points);
lc.upload(points, edges);
} }
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@@ -158,7 +169,8 @@ int run(GLFWwindow *window, ImGuiContext *context) {
auto aspect = (float) display_h / (float) display_w; auto aspect = (float) display_h / (float) display_w;
state.proj = Eigen::AlignedScaling3f(aspect, 1.0, -0.6); state.proj = Eigen::AlignedScaling3f(aspect, 1.0, -0.6);
point_render.draw(state); point_render.draw(pc, state);
line_render.draw(lc, state);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(window); glfwSwapBuffers(window);

View File

@@ -18,18 +18,13 @@ struct State {
}; };
template<typename V_=Eigen::Vector4f> template<typename V_=Eigen::Vector4f>
struct PointRenderer { struct PointCloud {
using Vertex = V_; using Vertex = V_;
VertexShader vs{std::ifstream("res/shaders/main.vert.glsl")};
FragmentShader fs{std::ifstream("res/shaders/main.frag.glsl")};
Program pgm{vs, fs};
Buffer<Vertex> vbo; Buffer<Vertex> vbo;
VertexArray<Vertex> vao{vbo}; VertexArray<Vertex> vao{vbo};
GLuint count; GLuint count{};
template<typename T> template<typename T>
void upload(const T &points) { void upload(const T &points) {
@@ -38,15 +33,69 @@ struct PointRenderer {
// Buffer<GLuint> ind_buf; // Buffer<GLuint> ind_buf;
// glVertexArrayElementBuffer(vao, ind_buf); // glVertexArrayElementBuffer(vao, ind_buf);
} }
};
void draw(const State &state) { template<typename V_=Eigen::Vector4f>
struct PointRenderer {
using Vertex = V_;
VertexShader vs{std::ifstream("res/shaders/main.vert.glsl")};
FragmentShader fs{std::ifstream("res/shaders/main.frag.glsl")};
Program pgm{vs, fs};
void draw(const PointCloud<Vertex> &obj, const State &state) {
glUseProgram(pgm); glUseProgram(pgm);
glBindVertexArray(vao); glBindVertexArray(obj.vao);
glUniform4fv(0, 1, state.fg.data()); glUniform4fv(0, 1, state.fg.data());
glUniform1f(1, state.time); glUniform1f(1, state.time);
glUniformMatrix4fv(2, 1, false, state.proj.data()); glUniformMatrix4fv(2, 1, false, state.proj.data());
glUniformMatrix4fv(3, 1, false, state.view.data()); glUniformMatrix4fv(3, 1, false, state.view.data());
glDrawArrays(GL_POINTS, 0, count); glDrawArrays(GL_POINTS, 0, obj.count);
glBindVertexArray(0);
glUseProgram(0);
}
};
template<typename V_=Eigen::Vector4f>
struct LineCloud {
using Vertex = V_;
Buffer<Vertex> vbo{};
Buffer<unsigned> ibo{};
VertexArray<Vertex> vao{vbo};
GLuint count{};
LineCloud() {
glVertexArrayElementBuffer(vao, ibo);
}
template<typename T, typename U>
void upload(const T &points, const U &inds) {
vbo.upload(points);
count = ibo.upload(inds);
}
};
template<typename V_=Eigen::Vector4f>
struct LineRenderer {
using Vertex = V_;
VertexShader vs{std::ifstream("res/shaders/main.vert.glsl")};
FragmentShader fs{std::ifstream("res/shaders/main.frag.glsl")};
Program pgm{vs, fs};
void draw(const LineCloud<Vertex> &obj, const State &state) {
glUseProgram(pgm);
glBindVertexArray(obj.vao);
glUniform4fv(0, 1, state.fg.data());
glUniform1f(1, state.time);
glUniformMatrix4fv(2, 1, false, state.proj.data());
glUniformMatrix4fv(3, 1, false, state.view.data());
glDrawElements(GL_LINES, obj.count, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0); glBindVertexArray(0);
glUseProgram(0); glUseProgram(0);
} }