mirror of
https://github.com/allemangD/toddcox-visualize.git
synced 2025-11-10 03:52:48 -05:00
show fundamental lines
This commit is contained in:
@@ -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);
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user