optimize vertex generation; break edge/face generation
This commit is contained in:
@@ -9,10 +9,7 @@ add_custom_command(
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
src/main.cpp
|
||||
src/util/coxeter.cpp
|
||||
src/util/files.cpp
|
||||
src/util/mesh.cpp
|
||||
src/util/mirrors.cpp
|
||||
src/util/numeric.cpp
|
||||
src/util/shader.cpp
|
||||
src/util/window.cpp)
|
||||
|
||||
@@ -4,90 +4,233 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
template<int NGENS>
|
||||
struct Mults;
|
||||
template<int NGENS>
|
||||
struct Table;
|
||||
struct IRow;
|
||||
|
||||
template<int NGENS>
|
||||
struct Mults {
|
||||
int num_gens;
|
||||
std::map<std::tuple<int, int>, int> mults;
|
||||
const int dim = NGENS;
|
||||
std::map<std::tuple<int, int>, int> mults;
|
||||
|
||||
Mults();
|
||||
Mults() {
|
||||
mults = std::map<std::tuple<int, int>, int>();
|
||||
}
|
||||
|
||||
void set(int a, int b, int mult);
|
||||
void set(int a, int b, int mult) {
|
||||
if (a > b) std::swap(a, b);
|
||||
mults[std::make_tuple(a, b)] = mult;
|
||||
}
|
||||
|
||||
[[nodiscard]] int get(int a, int b) const;
|
||||
[[nodiscard]] int get(int a, int b) const {
|
||||
if (a == b) return 1;
|
||||
if (a > b) std::swap(a, b);
|
||||
|
||||
[[nodiscard]] std::vector<int> relation(int a, int b) const;
|
||||
const auto &tup = std::make_tuple(a, b);
|
||||
const auto &res = mults.find(tup);
|
||||
|
||||
[[nodiscard]] std::vector<std::vector<int>> relations(const std::vector<int> &gens) const;
|
||||
if (res == mults.end()) return 2;
|
||||
return res->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::vector<int>> irelations(const Table *table, const std::vector<int> &gens) const;
|
||||
[[nodiscard]] std::vector<int> irelation(int a, int b) const {
|
||||
std::vector<int> res{};
|
||||
int mult = get(a, b);
|
||||
|
||||
[[nodiscard]] Table *solve(const std::vector<int> &subgens) const;
|
||||
[[nodiscard]] Table *solve(const std::vector<int> &gens, const std::vector<int> &subgens) const;
|
||||
for (int i = 0; i < mult; ++i) {
|
||||
res.push_back(a);
|
||||
res.push_back(b);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
[[nodiscard]] Table<NGENS> *isolve(const std::vector<int> &isubgens) const;
|
||||
|
||||
template<int IGENS>
|
||||
[[nodiscard]] Table<IGENS> *isolve(const int (&igens)[IGENS], const std::vector<int> &isubgens) const;
|
||||
};
|
||||
|
||||
template<int NGENS>
|
||||
struct Table {
|
||||
const std::vector<int> gens;
|
||||
const Mults mults;
|
||||
std::vector<int> gen_inds;
|
||||
std::vector<std::vector<int>> fwd;
|
||||
std::vector<std::vector<int>> rev;
|
||||
const Mults<NGENS> mults;
|
||||
std::vector<std::vector<int>> fwd;
|
||||
|
||||
explicit Table(const std::vector<int> &gens, Mults mults);
|
||||
explicit Table(Mults<NGENS> mults) : mults(mults) {
|
||||
add_row();
|
||||
}
|
||||
|
||||
[[nodiscard]] int gen_index(int gen) const;
|
||||
void add_row() {
|
||||
fwd.emplace_back(NGENS, -1);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<int> gen_index_each(std::vector<int> rel) const;
|
||||
int add_coset() {
|
||||
for (int from = 0; from < (int) size(); ++from) {
|
||||
for (int igen = 0; igen < (int) NGENS; igen++) {
|
||||
if (iget(from, igen) < 0) {
|
||||
int to = (int) size();
|
||||
add_row();
|
||||
iset(from, igen, to);
|
||||
return to;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void add_row();
|
||||
[[nodiscard]] unsigned size() const {
|
||||
return fwd.size();
|
||||
}
|
||||
|
||||
int add_coset();
|
||||
void iset(int from, int igen, int to) {
|
||||
fwd[from][igen] = to;
|
||||
fwd[to][igen] = from;
|
||||
}
|
||||
|
||||
[[nodiscard]] unsigned size() const;
|
||||
[[nodiscard]] int iget(int from, int igen) const {
|
||||
return fwd[from][igen];
|
||||
}
|
||||
|
||||
void set(int from, int gen, int to);
|
||||
[[nodiscard]] int irget(int igen, int to) const {
|
||||
return fwd[to][igen];
|
||||
}
|
||||
|
||||
[[nodiscard]] int get(int from, int gen) const;
|
||||
|
||||
[[nodiscard]] int rget(int gen, int to) const;
|
||||
|
||||
void iset(int from, int igen, int to);
|
||||
|
||||
[[nodiscard]] int iget(int from, int igen) const;
|
||||
|
||||
[[nodiscard]] int irget(int igen, int to) const;
|
||||
|
||||
[[nodiscard]] std::vector<std::vector<int>> words() const;
|
||||
|
||||
[[nodiscard]] int apply(int e, const std::vector<int> &word) const;
|
||||
|
||||
[[nodiscard]] int apply(const std::vector<int> &word) const;
|
||||
|
||||
[[nodiscard]] std::vector<int> apply_each(int e, const std::vector<std::vector<int>> &words) const;
|
||||
|
||||
[[nodiscard]] std::vector<int> apply_each(const std::vector<std::vector<int>> &words) const;
|
||||
};
|
||||
|
||||
struct IRow {
|
||||
std::vector<int>::const_iterator l;
|
||||
std::vector<int>::const_iterator r;
|
||||
std::vector<int>::const_iterator l;
|
||||
std::vector<int>::const_iterator r;
|
||||
|
||||
int from;
|
||||
int to;
|
||||
int from;
|
||||
int to;
|
||||
|
||||
IRow(const std::vector<int> &rel, int cos);
|
||||
IRow(const std::vector<int> &rel, int cos)
|
||||
: l(rel.begin()), r(rel.end() - 1), from(cos), to(cos) {
|
||||
}
|
||||
|
||||
[[nodiscard]] bool learn(Table *table);
|
||||
template<int NGENS>
|
||||
[[nodiscard]] bool learn(Table<NGENS> *table) {
|
||||
if (r - l == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (r - l > 0) {
|
||||
int next = table->iget(from, *l);
|
||||
if (next < 0) break;
|
||||
l++;
|
||||
from = next;
|
||||
}
|
||||
|
||||
while (r - l > 0) {
|
||||
int next = table->irget(*r, to);
|
||||
if (next < 0) break;
|
||||
r--;
|
||||
to = next;
|
||||
}
|
||||
|
||||
if (r - l == 0) {
|
||||
table->iset(from, *l, to);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//Table *solve(const std::vector<int> &gens, const std::vector<int> &subgens, const Mults &mults);
|
||||
//
|
||||
//Table *solve(const std::vector<int> &subgens, const Mults &mults);
|
||||
//
|
||||
//Table *solve_elems(const Mults &mults);
|
||||
template<int NGENS>
|
||||
Mults<NGENS> schlafli(const int(&symbol)[NGENS - 1]) {
|
||||
Mults<NGENS> mults{};
|
||||
for (int i = 0; i < NGENS; ++i) {
|
||||
mults.set(i, i + 1, symbol[i]);
|
||||
}
|
||||
return mults;
|
||||
}
|
||||
|
||||
Mults schlafli(const std::vector<int> &symbol);
|
||||
template<int NGENS>
|
||||
Table<NGENS> *Mults<NGENS>::isolve(const std::vector<int> &isubgens) const {
|
||||
auto *table = new Table<NGENS>(*this);
|
||||
for (int igen : isubgens)
|
||||
table->iset(0, igen, 0);
|
||||
|
||||
std::vector<int> all_gens(int N);
|
||||
std::vector<std::vector<int>> irels{};
|
||||
for (unsigned a = 0; a < NGENS; ++a) {
|
||||
for (unsigned b = a + 1; b < NGENS; ++b) {
|
||||
irels.push_back(irelation(a, b));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<IRow> irows;
|
||||
irows.reserve(irels.size());
|
||||
for (const auto &irel : irels)
|
||||
irows.emplace_back(irel, 0);
|
||||
|
||||
while (!irows.empty()) {
|
||||
while (true) {
|
||||
bool learned = false;
|
||||
for (int i = (int) irows.size() - 1; i >= 0; i--) {
|
||||
if (irows[i].learn(table)) {
|
||||
learned = true;
|
||||
irows.erase(irows.begin() + i);
|
||||
}
|
||||
}
|
||||
if (!learned)
|
||||
break;
|
||||
}
|
||||
|
||||
int i = (int) table->size();
|
||||
if (table->add_coset() > 0) {
|
||||
for (const auto &irel : irels)
|
||||
irows.emplace_back(irel, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
template<int NGENS>
|
||||
template<int IGENS>
|
||||
Table<IGENS> *Mults<NGENS>::isolve(const int (&igens)[IGENS], const std::vector<int> &isubgens) const {
|
||||
auto *table = new Table<IGENS>(*this);
|
||||
for (int igen : isubgens)
|
||||
table->iset(0, igen, 0);
|
||||
|
||||
std::vector<std::vector<int>> irels{};
|
||||
for (unsigned a = 0; a < igens.size(); ++a) {
|
||||
for (unsigned b = a + 1; b < igens.size(); ++b) {
|
||||
irels.push_back(irelation(igens[a], igens[b]));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<IRow> irows;
|
||||
irows.reserve(irels.size());
|
||||
for (const auto &irel : irels)
|
||||
irows.emplace_back(irel, 0);
|
||||
|
||||
while (!irows.empty()) {
|
||||
while (true) {
|
||||
bool learned = false;
|
||||
for (int i = (int) irows.size() - 1; i >= 0; i--) {
|
||||
if (irows[i].learn(table)) {
|
||||
learned = true;
|
||||
irows.erase(irows.begin() + i);
|
||||
}
|
||||
}
|
||||
if (!learned)
|
||||
break;
|
||||
}
|
||||
|
||||
int i = (int) table->size();
|
||||
if (table->add_coset() > 0) {
|
||||
for (const auto &irel : irels)
|
||||
irows.emplace_back(irel, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
#include "coxeter.hpp"
|
||||
#include "mirrors.hpp"
|
||||
#include "numeric.hpp"
|
||||
|
||||
glm::vec4 identity(const std::vector<glm::vec4> &normals, const std::vector<float> &coords);
|
||||
glm::vec4 identity(const std::vector<glm::vec4> &normals, const std::vector<float> &coords) {
|
||||
const std::vector<glm::vec4> corners = plane_intersections(normals);
|
||||
const glm::vec4 identity = barycentric(corners, coords);
|
||||
return glm::normalize(identity);
|
||||
}
|
||||
|
||||
glm::vec4 identity(const Mults &mults, const std::vector<float> &coords);
|
||||
|
||||
glm::vec4 center(const Mults &mults);
|
||||
template<int NGENS>
|
||||
glm::vec4 identity(const Mults<NGENS> &mults, const std::vector<float> &coords) {
|
||||
const std::vector<glm::vec4> normals = mirror(mults);
|
||||
return identity(normals, coords);
|
||||
}
|
||||
|
||||
std::vector<glm::vec4> vertices(const Table *t_vert, const glm::vec4 ident);
|
||||
|
||||
std::vector<int> edges(const Table *t_vert);
|
||||
|
||||
std::vector<int> faces(const Table *t_vert);
|
||||
template<int NGENS>
|
||||
glm::vec4 center(const Mults<NGENS> &mults) {
|
||||
const std::vector<glm::vec4> normals = mirror(mults);
|
||||
const std::vector<glm::vec4> corners = plane_intersections(normals);
|
||||
std::vector<float> coords{};
|
||||
for (int i = 0; i < corners.size(); ++i) {
|
||||
const auto u = (i + 2) % corners.size();
|
||||
const auto v = (i + 1) % corners.size();
|
||||
const auto &d = corners[u] - corners[v];
|
||||
coords.push_back(glm::length(d));
|
||||
}
|
||||
const glm::vec4 identity = barycentric(corners, coords);
|
||||
return glm::normalize(identity);
|
||||
}
|
||||
|
||||
|
||||
struct Buffer {
|
||||
const GLuint name;
|
||||
const unsigned size;
|
||||
const float gen_time;
|
||||
GLuint name = 0;
|
||||
unsigned size = 0;
|
||||
};
|
||||
|
||||
template<int NGENS>
|
||||
struct Mesh {
|
||||
const Mults mults;
|
||||
const Table *t_vert;
|
||||
const Mults<NGENS> mults;
|
||||
const Table<NGENS> *t_vert;
|
||||
|
||||
Buffer vert;
|
||||
Buffer edge;
|
||||
Buffer face;
|
||||
const std::vector<glm::vec4> normals;
|
||||
glm::vec4 *vert_data;
|
||||
|
||||
Mesh(Mults mults, const Table *t_vert, Buffer vert, Buffer edge, Buffer face);
|
||||
Buffer vert;
|
||||
Buffer edge;
|
||||
Buffer face;
|
||||
|
||||
~Mesh();
|
||||
explicit Mesh(Mults<NGENS> mults) : mults(mults), normals(mirror(mults)) {
|
||||
auto a = std::chrono::high_resolution_clock::now();
|
||||
t_vert = mults.isolve({});
|
||||
auto b = std::chrono::high_resolution_clock::now();
|
||||
std::cout << "time to solve: " << ((std::chrono::duration<double>) (b - a)).count() << std::endl;
|
||||
|
||||
vert.size = t_vert->size();
|
||||
vert_data = new glm::vec4[vert.size];
|
||||
|
||||
glGenBuffers(1, &vert.name);
|
||||
glGenBuffers(1, &edge.name);
|
||||
glGenBuffers(1, &face.name);
|
||||
|
||||
gen_indices();
|
||||
}
|
||||
|
||||
explicit Mesh(Mults<NGENS> mults, const glm::vec4 root) {
|
||||
this(mults);
|
||||
gen_vertices(root);
|
||||
}
|
||||
|
||||
void gen_vertices(const glm::vec4 root) {
|
||||
vert_data[0] = root;
|
||||
for (unsigned from = 0; from < vert.size; ++from) {
|
||||
for (unsigned gen = 0; gen < NGENS; ++gen) {
|
||||
int to = t_vert->iget((int) from, (int) gen);
|
||||
vert_data[to] = reflect(vert_data[from], normals[gen]);
|
||||
}
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vert.name);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * vert.size, vert_data, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void gen_indices() {
|
||||
std::vector<int> edges;
|
||||
std::vector<int> faces;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, edge.name);
|
||||
// glBufferData(GL_ARRAY_BUFFER, sizeof(int) * edge.size, edge_data, GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
~Mesh() {
|
||||
delete t_vert;
|
||||
delete[] vert_data;
|
||||
|
||||
glDeleteBuffers(1, &vert.name);
|
||||
glDeleteBuffers(1, &edge.name);
|
||||
glDeleteBuffers(1, &face.name);
|
||||
}
|
||||
};
|
||||
|
||||
Mesh *mesh(const Mults &mults, glm::vec4 ident);
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, Buffer b);
|
||||
|
||||
@@ -2,6 +2,31 @@
|
||||
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
#include "coxeter.hpp"
|
||||
#include <cmath>
|
||||
|
||||
std::vector<glm::vec4> mirror(const Mults &mults);
|
||||
#include "coxeter.hpp"
|
||||
#include "numeric.hpp"
|
||||
|
||||
template<int NGENS>
|
||||
std::vector<glm::vec4> mirror(const Mults<NGENS> &mults) {
|
||||
std::vector<glm::vec4> mirrors{};
|
||||
for (int p = 0; p < NGENS; ++p) {
|
||||
glm::vec4 vp{};
|
||||
for (int m = 0; m < p; ++m) {
|
||||
glm::vec4 vq = mirrors[m];
|
||||
vp[m] = (cos(M_PI / mults.get(p, m)) - dot(m, vp, vq)) / vq[m];
|
||||
}
|
||||
vp[p] = std::sqrt(1 - glm::dot(vp, vp));
|
||||
|
||||
for (const auto &v : mirrors) {
|
||||
if (glm::dot(vp, v) > 0) {
|
||||
vp *= -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mirrors.push_back(round(vp, 15));
|
||||
}
|
||||
|
||||
return mirrors;
|
||||
}
|
||||
|
||||
@@ -13,149 +13,152 @@
|
||||
using namespace std;
|
||||
|
||||
class CosetsWindow : public Window {
|
||||
GLint program;
|
||||
GLuint vert_vao, edge_vao, face_vao;
|
||||
GLint program;
|
||||
GLuint vert_vao, edge_vao, face_vao;
|
||||
|
||||
Mesh *figure;
|
||||
Mesh<4> *figure;
|
||||
|
||||
GLint u_proj, u_view, u_color;
|
||||
GLint u_proj, u_view, u_color;
|
||||
|
||||
public:
|
||||
void init() override {
|
||||
std::cout
|
||||
<< "Graphics Information:" << std::endl
|
||||
<< "Vendor: " << glGetString(GL_VENDOR) << std::endl
|
||||
<< "Renderer: " << glGetString(GL_RENDERER) << std::endl
|
||||
<< "Version: " << glGetString(GL_VERSION) << std::endl
|
||||
<< "Shading version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
|
||||
void init() override {
|
||||
std::cout
|
||||
<< "Graphics Information:" << std::endl
|
||||
<< "Vendor: " << glGetString(GL_VENDOR) << std::endl
|
||||
<< "Renderer: " << glGetString(GL_RENDERER) << std::endl
|
||||
<< "Version: " << glGetString(GL_VERSION) << std::endl
|
||||
<< "Shading version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
|
||||
|
||||
auto vs = build_shader_file(
|
||||
GL_VERTEX_SHADER,
|
||||
"vertex",
|
||||
"shaders/main.vs.glsl");
|
||||
auto vs = build_shader_file(
|
||||
GL_VERTEX_SHADER,
|
||||
"vertex",
|
||||
"shaders/main.vs.glsl");
|
||||
|
||||
auto fs = build_shader_file(
|
||||
GL_FRAGMENT_SHADER,
|
||||
"fragment",
|
||||
"shaders/main.fs.glsl");
|
||||
auto fs = build_shader_file(
|
||||
GL_FRAGMENT_SHADER,
|
||||
"fragment",
|
||||
"shaders/main.fs.glsl");
|
||||
|
||||
program = build_program("main", vs, fs);
|
||||
program = build_program("main", vs, fs);
|
||||
|
||||
u_proj = glGetUniformLocation(program, "proj");
|
||||
u_view = glGetUniformLocation(program, "view");
|
||||
u_color = glGetUniformLocation(program, "color");
|
||||
u_proj = glGetUniformLocation(program, "proj");
|
||||
u_view = glGetUniformLocation(program, "view");
|
||||
u_color = glGetUniformLocation(program, "color");
|
||||
|
||||
const Mults &mults = schlafli({5, 3, 2});
|
||||
// const glm::vec4 ident = center(mults);
|
||||
const glm::vec4 ident = identity(mults, {2, .1, .1, 3});
|
||||
std::cout << "Dimension: " << mults.num_gens << std::endl;
|
||||
figure = new Mesh(schlafli<4>({5, 3, 3}));
|
||||
|
||||
figure = mesh(mults, ident);
|
||||
glGenVertexArrays(1, &vert_vao);
|
||||
glBindVertexArray(vert_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, figure->vert.name);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glGenVertexArrays(1, &vert_vao);
|
||||
glBindVertexArray(vert_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, figure->vert.name);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glGenVertexArrays(1, &edge_vao);
|
||||
glBindVertexArray(edge_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, figure->vert.name);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, figure->edge.name);
|
||||
|
||||
glGenVertexArrays(1, &edge_vao);
|
||||
glBindVertexArray(edge_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, figure->vert.name);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, figure->edge.name);
|
||||
glGenVertexArrays(1, &face_vao);
|
||||
glBindVertexArray(face_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, figure->vert.name);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, figure->face.name);
|
||||
|
||||
glGenVertexArrays(1, &face_vao);
|
||||
glBindVertexArray(face_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, figure->vert.name);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, nullptr);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, figure->face.name);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
void render() override {
|
||||
int w, h;
|
||||
getBounds(w, h);
|
||||
glViewport(0, 0, w, h);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
void render() override {
|
||||
int w, h;
|
||||
getBounds(w, h);
|
||||
glViewport(0, 0, w, h);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
const auto id = glm::mat4(1);
|
||||
const auto ax_1 = glm::vec3(0, 0, 1);
|
||||
const auto ax_2 = glm::vec3(.5, 1, 0.2);
|
||||
const auto t = glfwGetTime();
|
||||
const auto angle = (float) t / 3;
|
||||
|
||||
const auto id = glm::mat4(1);
|
||||
const auto ax_1 = glm::vec3(0, 0, 1);
|
||||
const auto ax_2 = glm::vec3(.5, 1, 0.2);
|
||||
const auto t = glfwGetTime();
|
||||
const auto angle = (float) t / 5;
|
||||
const float sc = 1.5f;
|
||||
const float ar = (float) w / (float) h;
|
||||
|
||||
const float sc = 1.5f;
|
||||
const float ar = (float) w / (float) h;
|
||||
const float c1 = std::cos(angle * 3.0);
|
||||
const float s1 = std::sin(angle * 3.0);
|
||||
const float c2 = std::cos(angle * 0.2);
|
||||
const float s2 = std::sin(angle * 0.2);
|
||||
|
||||
const float c1 = std::cos(angle * .7);
|
||||
const float s1 = std::sin(angle * .7);
|
||||
const float c2 = std::cos(angle * .5);
|
||||
const float s2 = std::sin(angle * .5);
|
||||
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)
|
||||
* glm::mat4(
|
||||
c1, 0.0, s1, 0.0,
|
||||
0.0, c2, 0.0, s2,
|
||||
-s1, 0.0, c1, 0.0,
|
||||
0.0, -s2, 0.0, c2
|
||||
);
|
||||
|
||||
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)
|
||||
* glm::mat4(
|
||||
c1, 0.0, s1, 0.0,
|
||||
0.0, c2, 0.0, s2,
|
||||
-s1, 0.0, c1, 0.0,
|
||||
0.0, -s2, 0.0, c2
|
||||
);
|
||||
const float root_x = std::cos((t + 0) * M_PI / 2) / 2 + 0.5;
|
||||
const float root_y = std::cos((t + 1) * M_PI / 2) / 2 + 0.5;
|
||||
const float root_z = std::cos((t + 2) * M_PI / 2) / 2 + 0.5;
|
||||
const float root_w = std::cos((t + 3) * M_PI / 2) / 2 + 0.5;
|
||||
|
||||
glUseProgram(program);
|
||||
glUniformMatrix4fv(u_proj, 1, false, glm::value_ptr(proj));
|
||||
glUniformMatrix4fv(u_view, 1, false, glm::value_ptr(view));
|
||||
const glm::vec4 root = identity<4>(figure->mults, {root_x, root_y, root_z, root_w});
|
||||
figure->gen_vertices(root);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glUseProgram(program);
|
||||
glUniformMatrix4fv(u_proj, 1, false, glm::value_ptr(proj));
|
||||
glUniformMatrix4fv(u_view, 1, false, glm::value_ptr(view));
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glPointSize(10.0f);
|
||||
glLineWidth(5.0f);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glBindVertexArray(vert_vao);
|
||||
glUniform4f(u_color, 1, 0, 0, 1);
|
||||
glDrawArrays(GL_POINTS, 0, figure->vert.size);
|
||||
glPointSize(10.0f);
|
||||
glLineWidth(5.0f);
|
||||
|
||||
glBindVertexArray(edge_vao);
|
||||
glUniform4f(u_color, 1, 0, 0, 1);
|
||||
glDrawElements(GL_LINES, figure->edge.size, GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(vert_vao);
|
||||
glUniform4f(u_color, 1, 0, 0, 1);
|
||||
glDrawArrays(GL_POINTS, 0, figure->vert.size);
|
||||
|
||||
glBindVertexArray(face_vao);
|
||||
glCullFace(GL_NONE);
|
||||
glUniform4f(u_color, 1, 1, 1, 1);
|
||||
glBindVertexArray(edge_vao);
|
||||
glUniform4f(u_color, 1, 0, 0, 1);
|
||||
glDrawElements(GL_LINES, figure->edge.size, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// glBindVertexArray(face_vao);
|
||||
// glCullFace(GL_NONE);
|
||||
// glUniform4f(u_color, 1, 1, 1, 1);
|
||||
// glDrawElements(GL_TRIANGLES, figure->face.size, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// glCullFace(GL_FRONT);
|
||||
// glUniform4f(u_color, .3, .3, 1, 1);
|
||||
// glDrawElements(GL_TRIANGLES, figure->face.size, GL_UNSIGNED_INT, 0);
|
||||
|
||||
swapbuffers();
|
||||
}
|
||||
swapbuffers();
|
||||
}
|
||||
|
||||
void deinit() override {
|
||||
glDeleteProgram(program);
|
||||
glDeleteVertexArrays(1, &vert_vao);
|
||||
}
|
||||
void deinit() override {
|
||||
glDeleteProgram(program);
|
||||
glDeleteVertexArrays(1, &vert_vao);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!glfwInit()) {
|
||||
fprintf(stderr, "Failed to initialize GLFW\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!glfwInit()) {
|
||||
fprintf(stderr, "Failed to initialize GLFW\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Window *window = new CosetsWindow();
|
||||
window->run();
|
||||
Window *window = new CosetsWindow();
|
||||
window->run();
|
||||
|
||||
glfwTerminate();
|
||||
return EXIT_SUCCESS;
|
||||
glfwTerminate();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
#include "coxeter.hpp"
|
||||
|
||||
Mults::Mults() {
|
||||
num_gens = 0;
|
||||
mults = std::map<std::tuple<int, int>, int>();
|
||||
}
|
||||
|
||||
void Mults::set(int a, int b, int mult) {
|
||||
if (a > b) std::swap(a, b);
|
||||
if (b + 1 > num_gens) num_gens = b + 1;
|
||||
mults[std::make_tuple(a, b)] = mult;
|
||||
}
|
||||
|
||||
int Mults::get(int a, int b) const {
|
||||
if (a == b) return 1;
|
||||
if (a > b) std::swap(a, b);
|
||||
|
||||
const auto &tup = std::make_tuple(a, b);
|
||||
const auto &res = mults.find(tup);
|
||||
|
||||
if (res == mults.end()) return 2;
|
||||
return res->second;
|
||||
}
|
||||
|
||||
std::vector<int> Mults::relation(int a, int b) const {
|
||||
std::vector<int> res{};
|
||||
int mult = get(a, b);
|
||||
|
||||
for (int i = 0; i < mult; ++i) {
|
||||
res.push_back(a);
|
||||
res.push_back(b);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::vector<int>> Mults::relations(const std::vector<int> &gens) const {
|
||||
std::vector<std::vector<int>> res{};
|
||||
for (int a = 0; a < (int) gens.size(); ++a) {
|
||||
for (int b = a; b < (int) gens.size(); ++b) {
|
||||
res.push_back(relation(gens[a], gens[b]));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<std::vector<int>> Mults::irelations(const Table *table, const std::vector<int> &gens) const {
|
||||
std::vector<std::vector<int>> rels = relations(gens);
|
||||
std::vector<std::vector<int>> irels(rels.size());
|
||||
for (int i = 0; i < (int) rels.size(); ++i) {
|
||||
irels[i] = table->gen_index_each(rels[i]);
|
||||
}
|
||||
return irels;
|
||||
}
|
||||
|
||||
Table::Table(const std::vector<int> &gens, const Mults mults) : gens(gens), mults(mults) {
|
||||
add_row();
|
||||
|
||||
gen_inds = std::vector<int>(gens[gens.size() - 1] + 1, -1);
|
||||
for (int i = 0; i < (int) gens.size(); i++) {
|
||||
gen_inds[gens[i]] = i;
|
||||
}
|
||||
}
|
||||
|
||||
int Table::gen_index(int gen) const {
|
||||
if (gen >= gen_inds.size())
|
||||
throw std::logic_error("Referencing nonexistant generator (too large)");
|
||||
int i = gen_inds[gen];
|
||||
if (i < 0)
|
||||
throw std::logic_error("Referencing nonexistant generator (not present)");
|
||||
return i;
|
||||
}
|
||||
|
||||
std::vector<int> Table::gen_index_each(std::vector<int> rel) const {
|
||||
std::vector<int> res(rel.size(), 0);
|
||||
for (int i = 0; i < (int) rel.size(); ++i) {
|
||||
res[i] = gen_index(rel[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void Table::add_row() {
|
||||
int N = gens.size();
|
||||
fwd.emplace_back(N, -1);
|
||||
rev.emplace_back(N, -1);
|
||||
}
|
||||
|
||||
int Table::add_coset() {
|
||||
for (int from = 0; from < (int) size(); ++from) {
|
||||
for (int igen = 0; igen < (int) gens.size(); igen++) {
|
||||
if (iget(from, igen) < 0) {
|
||||
int to = (int) size();
|
||||
add_row();
|
||||
iset(from, igen, to);
|
||||
return to;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned Table::size() const {
|
||||
return fwd.size();
|
||||
}
|
||||
|
||||
void Table::set(int from, int gen, int to) {
|
||||
int i = gen_index(gen);
|
||||
fwd[from][i] = to;
|
||||
rev[to][i] = from;
|
||||
}
|
||||
|
||||
int Table::get(int from, int gen) const {
|
||||
int i = gen_index(gen);
|
||||
return fwd[from][i];
|
||||
}
|
||||
|
||||
int Table::rget(int gen, int to) const {
|
||||
int i = gen_index(gen);
|
||||
return rev[to][i];
|
||||
}
|
||||
|
||||
void Table::iset(int from, int igen, int to) {
|
||||
fwd[from][igen] = to;
|
||||
rev[to][igen] = from;
|
||||
}
|
||||
|
||||
int Table::iget(int from, int igen) const {
|
||||
return fwd[from][igen];
|
||||
}
|
||||
|
||||
int Table::irget(int igen, int to) const {
|
||||
return rev[to][igen];
|
||||
}
|
||||
|
||||
std::vector<std::vector<int>> Table::words() const {
|
||||
std::vector<std::vector<int> *> vecs(size());
|
||||
vecs[0] = new std::vector<int>();
|
||||
|
||||
while (std::find(vecs.begin(), vecs.end(), nullptr) != vecs.end()) {
|
||||
for (int from = 0; from < (int) vecs.size(); ++from) {
|
||||
std::vector<int> *word = vecs[from];
|
||||
if (word == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int igen = 0; igen < gens.size(); igen++) {
|
||||
int to = iget(from, igen);
|
||||
if (vecs[to] != nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
vecs[to] = new std::vector<int>(*word);
|
||||
vecs[to]->push_back(gens[igen]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<int>> res(size());
|
||||
for (int i = 0; i < (int) size(); ++i) {
|
||||
res[i] = *vecs[i];
|
||||
delete vecs[i];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int Table::apply(int e, const std::vector<int> &word) const {
|
||||
for (const auto &gen : word) {
|
||||
e = get(e, gen);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
int Table::apply(const std::vector<int> &word) const {
|
||||
return apply(0, word);
|
||||
}
|
||||
|
||||
std::vector<int> Table::apply_each(int e, const std::vector<std::vector<int>> &words) const {
|
||||
std::vector<int> res{};
|
||||
|
||||
for (const auto &word:words) {
|
||||
res.push_back(apply(e, word));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<int> Table::apply_each(const std::vector<std::vector<int>> &words) const {
|
||||
return apply_each(0, words);
|
||||
}
|
||||
|
||||
IRow::IRow(const std::vector<int> &rel, int cos) {
|
||||
this->l = rel.begin();
|
||||
this->r = rel.end() - 1;
|
||||
this->from = cos;
|
||||
this->to = cos;
|
||||
}
|
||||
|
||||
bool IRow::learn(Table *table) {
|
||||
if (r - l == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (r - l > 0) {
|
||||
int next = table->iget(from, *l);
|
||||
if (next < 0) break;
|
||||
l++;
|
||||
from = next;
|
||||
}
|
||||
|
||||
while (r - l > 0) {
|
||||
int next = table->irget(*r, to);
|
||||
if (next < 0) break;
|
||||
r--;
|
||||
to = next;
|
||||
}
|
||||
|
||||
if (r - l == 0) {
|
||||
table->iset(from, *l, to);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Table *Mults::solve(const std::vector<int> &gens, const std::vector<int> &subgens) const {
|
||||
auto *table = new Table(gens, *this);
|
||||
const auto irels = irelations(table, gens);
|
||||
|
||||
for (int gen : subgens)
|
||||
table->set(0, gen, 0);
|
||||
|
||||
std::vector<IRow> irows;
|
||||
irows.reserve(irels.size());
|
||||
for (const auto &irel : irels)
|
||||
irows.emplace_back(irel, 0);
|
||||
|
||||
while (!irows.empty()) {
|
||||
while (true) {
|
||||
bool learned = false;
|
||||
for (int i = (int) irows.size() - 1; i >= 0; i--) {
|
||||
if (irows[i].learn(table)) {
|
||||
learned = true;
|
||||
irows.erase(irows.begin() + i);
|
||||
}
|
||||
}
|
||||
if (!learned)
|
||||
break;
|
||||
}
|
||||
|
||||
int i = (int) table->size();
|
||||
if (table->add_coset() > 0) {
|
||||
for (const auto &irel : irels)
|
||||
irows.emplace_back(irel, i);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
Table *Mults::solve(const std::vector<int> &subgens) const {
|
||||
return this->solve(all_gens(num_gens), subgens);
|
||||
}
|
||||
|
||||
Mults schlafli(const std::vector<int> &symbol) {
|
||||
Mults mults{};
|
||||
for (int i = 0; i < symbol.size(); ++i) {
|
||||
mults.set(i, i + 1, symbol[i]);
|
||||
}
|
||||
return mults;
|
||||
}
|
||||
|
||||
std::vector<int> all_gens(int N) {
|
||||
std::vector<int> gens(N);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
gens[i] = i;
|
||||
}
|
||||
return gens;
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <utility>
|
||||
#include <chrono>
|
||||
#include "mesh.hpp"
|
||||
|
||||
glm::vec4 identity(const std::vector<glm::vec4> &normals, const std::vector<float> &coords) {
|
||||
const std::vector<glm::vec4> corners = plane_intersections(normals);
|
||||
const glm::vec4 identity = barycentric(corners, coords);
|
||||
return glm::normalize(identity);
|
||||
}
|
||||
|
||||
glm::vec4 identity(const Mults &mults, const std::vector<float> &coords) {
|
||||
const std::vector<glm::vec4> normals = mirror(mults);
|
||||
return identity(normals, coords);
|
||||
}
|
||||
|
||||
glm::vec4 center(const Mults &mults) {
|
||||
const std::vector<glm::vec4> normals = mirror(mults);
|
||||
const std::vector<glm::vec4> corners = plane_intersections(normals);
|
||||
std::vector<float> coords{};
|
||||
for (int i = 0; i < corners.size(); ++i) {
|
||||
const auto u = (i + 2) % corners.size();
|
||||
const auto v = (i + 1) % corners.size();
|
||||
const auto &d = corners[u] - corners[v];
|
||||
coords.push_back(glm::length(d));
|
||||
}
|
||||
const glm::vec4 identity = barycentric(corners, coords);
|
||||
return glm::normalize(identity);
|
||||
}
|
||||
|
||||
Mesh::Mesh(Mults mults, const Table *t_vert, Buffer vert, Buffer edge, Buffer face)
|
||||
: mults(std::move(mults)), t_vert(t_vert), vert(vert), edge(edge), face(face) {
|
||||
}
|
||||
|
||||
Mesh::~Mesh() {
|
||||
delete t_vert;
|
||||
|
||||
glDeleteBuffers(1, &vert.name);
|
||||
glDeleteBuffers(1, &edge.name);
|
||||
glDeleteBuffers(1, &face.name);
|
||||
}
|
||||
|
||||
Mesh *mesh(const Mults &mults, glm::vec4 ident) {
|
||||
GLuint buffers[3];
|
||||
glGenBuffers(3, buffers);
|
||||
|
||||
Table *t_vert = mults.solve({});
|
||||
|
||||
auto vert_data = vertices(t_vert, ident);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec4) * vert_data.size(), &vert_data[0], GL_STATIC_DRAW);
|
||||
Buffer vert{buffers[0], vert_data.size()};
|
||||
|
||||
auto edge_data = edges(t_vert);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(int) * edge_data.size(), &edge_data[0], GL_STATIC_DRAW);
|
||||
Buffer edge{buffers[1], edge_data.size()};
|
||||
|
||||
auto face_data = faces(t_vert);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(int) * face_data.size(), &face_data[0], GL_STATIC_DRAW);
|
||||
Buffer face{buffers[2], face_data.size()};
|
||||
|
||||
return new Mesh(mults, t_vert, vert, edge, face);
|
||||
}
|
||||
|
||||
std::vector<glm::vec4>
|
||||
vertices(const Table *t_vert, const glm::vec4 ident) {
|
||||
const std::vector<glm::vec4> normals = mirror(t_vert->mults);
|
||||
|
||||
std::vector<glm::vec4> verts{};
|
||||
for (const auto &word : t_vert->words()) {
|
||||
glm::vec4 vert = ident;
|
||||
for (const auto &gen : word) {
|
||||
vert = reflect(vert, normals[gen]);
|
||||
}
|
||||
verts.push_back(vert);
|
||||
}
|
||||
|
||||
return verts;
|
||||
}
|
||||
|
||||
std::vector<int> edges(const Table *t_vert) {
|
||||
std::vector<int> res{};
|
||||
|
||||
Mults mults = t_vert->mults;
|
||||
int N = mults.num_gens;
|
||||
const std::vector<int> &gens = t_vert->gens;
|
||||
|
||||
for (const auto &subgens : combinations(N, 1)) {
|
||||
Table *t_edge = mults.solve(subgens, {});;
|
||||
|
||||
std::vector<int> edge = t_vert->apply_each(t_edge->words());
|
||||
|
||||
Table *c_edge = mults.solve(gens, subgens);
|
||||
|
||||
for (const auto &coset : c_edge->words()) {
|
||||
for (const auto &e : edge) {
|
||||
res.push_back(t_vert->apply(e, coset));
|
||||
}
|
||||
}
|
||||
|
||||
delete t_edge;
|
||||
delete c_edge;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<int> faces(const Table *t_vert) {
|
||||
std::vector<int> res{};
|
||||
const Mults &mults = t_vert->mults;
|
||||
int N = mults.num_gens;
|
||||
const std::vector<int> &gens = t_vert->gens;
|
||||
|
||||
// for each *kind* of face
|
||||
for (const auto &sg_face : combinations(N, 2)) {
|
||||
Table *cs_face = mults.solve(gens, sg_face);
|
||||
|
||||
// for each *kind* of edge
|
||||
for (const auto &sg_edge : combinations(sg_face, 1)) {
|
||||
Table *cs_edge = mults.solve(sg_face, sg_edge);
|
||||
|
||||
// find the vertices of that edge
|
||||
Table *t_edge = mults.solve(sg_edge, {});
|
||||
std::vector<int> edge = t_vert->apply_each(t_edge->words());
|
||||
|
||||
// for each face
|
||||
for (const auto &c_face : cs_face->words()) {
|
||||
// for each edge
|
||||
for (const auto &c_edge : cs_edge->words()) {
|
||||
if (c_edge.empty()) { continue; }
|
||||
|
||||
for (auto e : edge) {
|
||||
e = t_vert->apply(e, c_edge);
|
||||
e = t_vert->apply(e, c_face);
|
||||
res.push_back(e);
|
||||
}
|
||||
res.push_back(t_vert->apply(0, c_face));
|
||||
|
||||
if (c_edge.size() & 1u)
|
||||
std::swap(res[res.size() - 1], res[res.size() - 2]);
|
||||
|
||||
unsigned ro_si1 = (sg_face[0] + sg_face[1]);
|
||||
unsigned flag = sg_edge[0] == sg_face[0];
|
||||
unsigned n_mirrors = c_face.size();
|
||||
|
||||
if ((n_mirrors + flag + ro_si1) & 1u) {
|
||||
std::swap(res[res.size() - 1], res[res.size() - 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete t_edge;
|
||||
delete cs_edge;
|
||||
}
|
||||
|
||||
delete cs_face;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "mirrors.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include "numeric.hpp"
|
||||
#include "coxeter.hpp"
|
||||
|
||||
std::vector<glm::vec4> mirror(const Mults &mults) {
|
||||
int N = mults.num_gens;
|
||||
|
||||
std::vector<glm::vec4> mirrors{};
|
||||
for (int p = 0; p < N; ++p) {
|
||||
glm::vec4 vp{};
|
||||
for (int m = 0; m < p; ++m) {
|
||||
glm::vec4 vq = mirrors[m];
|
||||
vp[m] = (cos(M_PI / mults.get(p, m)) - dot(m, vp, vq)) / vq[m];
|
||||
}
|
||||
vp[p] = std::sqrt(1 - glm::dot(vp, vp));
|
||||
|
||||
for (const auto &v : mirrors) {
|
||||
if (glm::dot(vp, v) > 0) {
|
||||
vp *= -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mirrors.push_back(round(vp, 15));
|
||||
}
|
||||
|
||||
return mirrors;
|
||||
}
|
||||
Reference in New Issue
Block a user