diff --git a/cosets/src/main.cpp b/cosets/src/main.cpp index 5a46978..15b8336 100644 --- a/cosets/src/main.cpp +++ b/cosets/src/main.cpp @@ -13,11 +13,14 @@ using namespace std; class CosetsWindow : public Window { GLint program; - GLuint tri; + GLuint points_vao, edges_vao; - GLuint verts; + GLuint verts_buf; std::vector verts_data; + GLuint edges_buf; + std::vector edge_data; + public: void init() override { auto vs = build_shader_file( @@ -32,21 +35,34 @@ public: program = build_program("main", vs, fs); - verts_data = vertices<3>( - schlafli<3>({5, 3}), - {10, 1, 1}); + const Mults &mults = schlafli<4>({3, 4, 3}); + verts_data = vertices<4>(mults, {10, 1, 1, 1}); + edge_data = edges<4>(mults); - glGenBuffers(1, &verts); - glBindBuffer(GL_ARRAY_BUFFER, verts); + glGenBuffers(1, &verts_buf); + glBindBuffer(GL_ARRAY_BUFFER, verts_buf); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * verts_data.size(), &verts_data[0], GL_STATIC_DRAW); + glGenBuffers(1, &edges_buf); + glBindBuffer(GL_ARRAY_BUFFER, edges_buf); + glBufferData(GL_ARRAY_BUFFER, sizeof(int) * edge_data.size(), &edge_data[0], GL_STATIC_DRAW); - glGenVertexArrays(1, &tri); - glBindVertexArray(tri); - glBindBuffer(GL_ARRAY_BUFFER, verts); + glGenVertexArrays(1, &points_vao); + glBindVertexArray(points_vao); + glBindBuffer(GL_ARRAY_BUFFER, verts_buf); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr); glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenVertexArrays(1, &edges_vao); + glBindVertexArray(edges_vao); + glBindBuffer(GL_ARRAY_BUFFER, verts_buf); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, edges_buf); + + glBindVertexArray(0); } void render() override { @@ -66,26 +82,30 @@ public: const glm::mat4 proj = glm::ortho(-ar * sc, ar * sc, -sc, sc, -10.f, 10.f); const glm::mat4 view = glm::rotate(id, angle, ax_1) * glm::rotate(id, angle, ax_2); - const glm::mat4 mat = proj * view; glUseProgram(program); - glUniformMatrix4fv(1, 1, false, glm::value_ptr(mat)); + glUniformMatrix4fv(1, 1, false, glm::value_ptr(proj)); + glUniformMatrix4fv(2, 1, false, glm::value_ptr(view)); glEnable(GL_DEPTH_TEST); glEnable(GL_POINT_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPointSize(10.f); - glBindVertexArray(tri); + glBindVertexArray(points_vao); glUniform4f(0, 1, 1, 1, 1); glDrawArrays(GL_POINTS, 0, verts_data.size()); + glBindVertexArray(edges_vao); + glUniform4f(0, 1, 1, 0, 1); + glDrawElements(GL_LINES, edge_data.size(), GL_UNSIGNED_INT, 0); + swapbuffers(); } void deinit() override { glDeleteProgram(program); - glDeleteVertexArrays(1, &tri); + glDeleteVertexArrays(1, &points_vao); } }; diff --git a/cosets/src/mesh.cpp b/cosets/src/mesh.cpp index 4eb26ab..2ef34ed 100644 --- a/cosets/src/mesh.cpp +++ b/cosets/src/mesh.cpp @@ -1,20 +1,14 @@ #include "util/mesh.hpp" int main(int argc, char *argv[]) { - const auto &mults = schlafli<4>({4, 3, 3}); - const std::vector &vs = vertices<4>(mults, {10, 1, 1, 1}); + const int N = 3; + const Mults &mults = schlafli({4, 3}); + const std::vector &vs = vertices(mults, {10, 1, 1}); - for (const auto &v:vs) { - std::cout << glm::to_string(v) << std::endl; - } + std::cout << "# verts: " << vs.size() << std::endl; -// Table *table = solve({}, mults); -// std::cout << table->size() << std::endl; -// -// for (const auto &rel : mults.relations()) { -// for (const auto &e : rel) { -// std::cout << e << " "; -// } -// std::cout << std::endl; -// } -} \ No newline at end of file + const auto es = edges(mults); + + + return 0; +} diff --git a/cosets/src/shaders/main.vs.glsl b/cosets/src/shaders/main.vs.glsl index a9f2ad3..a9269cc 100644 --- a/cosets/src/shaders/main.vs.glsl +++ b/cosets/src/shaders/main.vs.glsl @@ -1,6 +1,7 @@ #version 440 core uniform mat4 proj; +uniform mat4 view; in vec4 pos; out vec4 v; @@ -9,7 +10,10 @@ out vec4 screen; void main(){ v = pos; + vec4 vert = view * pos; + /* stereographic projection */ - vec4 vert = vec4(pos.xyz / (1 - pos.w), 1); + vert = vec4(vert.xyw / (1 - vert.z), 1); + screen = gl_Position = proj * vert; } diff --git a/cosets/src/util/coxeter.hpp b/cosets/src/util/coxeter.hpp index 54d39d6..f385992 100644 --- a/cosets/src/util/coxeter.hpp +++ b/cosets/src/util/coxeter.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -8,7 +9,6 @@ #include #include -template struct Mults { std::map, int> mults{}; @@ -40,11 +40,11 @@ struct Mults { return res; } - [[nodiscard]] std::vector> relations() const { + [[nodiscard]] std::vector> relations(std::vector gens) const { std::vector> res{}; - for (int a = 0; a < N; ++a) { - for (int b = a; b < N; ++b) { - res.push_back(relation(a, b)); + for (int a = 0; a < gens.size(); ++a) { + for (int b = a; b < gens.size(); ++b) { + res.push_back(relation(gens[a], gens[b])); } } return res; @@ -52,8 +52,8 @@ struct Mults { }; template -Mults schlafli(const int (&symbol)[N - 1]) { - Mults mults{}; +Mults schlafli(const int (&symbol)[N - 1]) { + Mults mults{}; for (int i = 0; i < N; ++i) { mults.set(i, i + 1, symbol[i]); } @@ -61,23 +61,31 @@ Mults schlafli(const int (&symbol)[N - 1]) { } struct Table { - int N; + const std::vector gens; std::vector> fwd{}; std::vector> rev{}; - explicit Table(int N) { - this->N = N; + explicit Table(const std::vector gens) : gens(gens) { add_row(); } + [[nodiscard]] int gen_index(int gen) const { + for (unsigned i = 0; i < gens.size(); ++i) + if (gens[i] == gen) + return i; + + throw std::logic_error("Referencing nonexistant generator"); + } + void add_row() { + int N = gens.size(); fwd.emplace_back(N, -1); rev.emplace_back(N, -1); } int add_coset() { for (int from = 0; from < (int) size(); ++from) { - for (int gen = 0; gen < N; ++gen) { + for (int gen : gens) { if (get(from, gen) < 0) { int to = (int) size(); add_row(); @@ -94,16 +102,19 @@ struct Table { } void set(int from, int gen, int to) { - fwd[from][gen] = to; - rev[to][gen] = from; + int i = gen_index(gen); + fwd[from][i] = to; + rev[to][i] = from; } [[nodiscard]] int get(int from, int gen) const { - return fwd[from][gen]; + int i = gen_index(gen); + return fwd[from][i]; } [[nodiscard]] int rget(int gen, int to) const { - return rev[to][gen]; + int i = gen_index(gen); + return rev[to][i]; } std::vector> words() { @@ -117,7 +128,7 @@ struct Table { continue; } - for (int gen = 0; gen < (int) N; ++gen) { + for (int gen : gens) { int to = get(from, gen); if (vecs[to] != nullptr) { continue; @@ -137,6 +148,31 @@ struct Table { return res; } + + [[nodiscard]] int apply(int e, const std::vector &word) const { + for (const auto &gen : word) { + e = get(e, gen); + } + return e; + } + + [[nodiscard]] int apply(const std::vector &word) const { + return apply(0, word); + } + + [[nodiscard]] std::vector apply_each(int e, const std::vector> &words) const { + std::vector res{}; + + for (const auto &word:words) { + res.push_back(apply(e, word)); + } + + return res; + } + + [[nodiscard]] std::vector apply_each(const std::vector> &words) const { + return apply_each(0, words); + } }; struct Row { @@ -192,10 +228,8 @@ std::ostream &operator<<(std::ostream &out, const Row &row) { return out; } -template -Table *solve(const std::vector &subgens, const Mults &mults) { - const auto rels = mults.relations(); - int gens = N; +Table *solve(const std::vector &gens, const std::vector &subgens, const Mults &mults) { + const auto rels = mults.relations(gens); auto *table = new Table(gens); for (int gen : subgens) @@ -231,6 +265,15 @@ Table *solve(const std::vector &subgens, const Mults &mults) { return table; } +template +Table *solve(const std::vector &subgens, const Mults &mults) { + std::vector gens{}; + for (int i = 0; i < N; ++i) { + gens.push_back(i); + } + return solve(gens, subgens, mults); +} + std::ostream &operator<<(std::ostream &out, const Table &table) { int k = ceil(log10(table.size())); @@ -238,10 +281,10 @@ std::ostream &operator<<(std::ostream &out, const Table &table) { for (unsigned j = 0; j < table.size(); ++j) { auto arr = table.fwd[j]; out << " " << std::setw(k) << j << " ["; - for (int i = 0; i < table.N; ++i) { + for (int i = 0; i < (int) table.gens.size(); ++i) { out << arr[i]; - if (i < table.N - 1) + if (i < table.gens.size() - 1) out << " "; } diff --git a/cosets/src/util/mesh.hpp b/cosets/src/util/mesh.hpp index 23197d4..01a666b 100644 --- a/cosets/src/util/mesh.hpp +++ b/cosets/src/util/mesh.hpp @@ -23,8 +23,8 @@ glm::vec4 identity(const std::vector &normals, const float(&coords)[N template std::vector -vertices(const Mults &mults, const float (&coords)[N]) { - Table *table = solve({}, mults); +vertices(const Mults &mults, const float (&coords)[N]) { + Table *table = solve({}, mults); const std::vector normals = mirror(mults); glm::vec4 ident = identity(normals, coords); @@ -42,9 +42,25 @@ vertices(const Mults &mults, const float (&coords)[N]) { } template -std::vector lines(const Mults &mults) { -// Table *table = solve(N, {}, coxeter_rels(mults)); +std::vector edges(const Mults &mults) { + std::vector res{}; - return {}; + Table *verts = solve({}, mults); + + int K = 1; + for (const auto &subgens : combinations(N, K)) { + Table *edge = solve(subgens, {}, mults); + + std::vector primitive = verts->apply_each(edge->words()); + + Table *cosets = solve(subgens, mults); + + for (const auto &coset : cosets->words()) { + for (const auto &e : primitive) { + res.push_back(verts->apply(e, coset)); + } + } + } + + return res; } - diff --git a/cosets/src/util/mirrors.hpp b/cosets/src/util/mirrors.hpp index ce107bd..9551a26 100644 --- a/cosets/src/util/mirrors.hpp +++ b/cosets/src/util/mirrors.hpp @@ -11,7 +11,7 @@ #include "coxeter.hpp" template -std::vector mirror(const Mults &mults) { +std::vector mirror(const Mults &mults) { static_assert(1 <= N and N <= 4, "Vector size is unsupported"); std::vector mirrors{}; diff --git a/cosets/src/util/numeric.hpp b/cosets/src/util/numeric.hpp index 663be4a..064892c 100644 --- a/cosets/src/util/numeric.hpp +++ b/cosets/src/util/numeric.hpp @@ -57,3 +57,23 @@ std::vector plane_intersections(std::vector normals) { return results; } + + +std::vector> combinations(int N, int K) { + std::string bitmask(K, 1); // K leading 1's + bitmask.resize(N, 0); // N-K trailing 0's + std::vector> combos{}; + + do { + std::vector combo{}; + for (int i = 0; i < N; ++i) // [0..N-1] integers + { + if (bitmask[i]) { + combo.push_back(i); + } + } + combos.push_back(combo); + } while (std::prev_permutation(bitmask.begin(), bitmask.end())); + + return combos; +}