--- a/src/vertexmap.cpp Wed May 25 20:36:34 2022 +0300 +++ b/src/vertexmap.cpp Mon Jun 06 22:01:22 2022 +0300 @@ -1,5 +1,5 @@ #include "vertexmap.h" -#include "linetypes/polygonobject.h" +#include "gl/common.h" unsigned int hashVertex(const glm::vec3& vec) { @@ -40,14 +40,75 @@ const glm::vec3& b; }; -inline void edges(const ldraw::Object* object, std::function<void(Edge&&)> fn) +inline void edges(const ModelElement& element, std::function<void(Edge&&)> fn) +{ + std::visit<void>(overloaded{ + [fn](const Colored<LineSegment>& edge) { + fn(Edge{edge.p1, edge.p2}); + }, + [fn](const Colored<Triangle>& triangle) { + fn(Edge{triangle.p1, triangle.p2}); + fn(Edge{triangle.p2, triangle.p3}); + fn(Edge{triangle.p3, triangle.p1}); + }, + [fn](const Colored<Quadrilateral>& quad) { + fn(Edge{quad.p1, quad.p2}); + fn(Edge{quad.p2, quad.p3}); + fn(Edge{quad.p3, quad.p4}); + fn(Edge{quad.p4, quad.p1}); + }, + [fn](const Colored<ConditionalEdge>& cedge) { + fn(Edge{cedge.p1, cedge.p2}); + }, + [](const ModelElement&&){} + }, element); +} + +inline void points( + const ModelElement& element, + std::function<void(const glm::vec3&)> fn) { - for (int i = 0; i < object->numPoints() - 1; i += 1) - { - const glm::vec3 p1 = object->getPoint(i); - const glm::vec3 p2 = object->getPoint((i + 1) % object->numPoints()); - fn(Edge{p1, p2}); - } + std::visit<void>(overloaded{ + [fn](const Colored<LineSegment>& edge) { + fn(edge.p1); + fn(edge.p2); + }, + [fn](const Colored<Triangle>& triangle) { + fn(triangle.p1); + fn(triangle.p2); + fn(triangle.p3); + }, + [fn](const Colored<Quadrilateral>& quad) { + fn(quad.p1); + fn(quad.p2); + fn(quad.p3); + fn(quad.p4); + }, + [fn](const Colored<ConditionalEdge>& cedge) { + fn(cedge.p1); + fn(cedge.p2); + fn(cedge.c1); + fn(cedge.c2); + }, + [](const ModelElement&&){} + }, element); +} + +template<typename R> +auto ifplanar( + const ModelElement& element, + std::function<R(const glm::vec3&, const glm::vec3&, const glm::vec3&)> fn +) +{ + return std::visit(overloaded{ + [fn](const Triangle& triangle) -> std::optional<R> { + return fn(triangle.p1, triangle.p2, triangle.p3); + }, + [fn](const Quadrilateral quad) -> std::optional<R> { + return fn(quad.p1, quad.p2, quad.p3); + }, + [](const ModelElement&&) -> std::optional<R> {return {};} + }, element); } void VertexMap::build() @@ -55,30 +116,27 @@ this->map.clear(); this->vertices.clear(); this->vertexHashes.clear(); - applyToModel<ldraw::Object>(*this->model, [&](const ldraw::Object* object) + for (int i = 0; i < this->model->size(); ++i) { - glm::mat4 matrix; - if (object->numPoints() > 2) - { - const auto& p0 = object->getPoint(0); - const auto& p1 = object->getPoint(1); - const auto& p2 = object->getPoint(2); - const glm::vec3 a = glm::normalize(p1 - p0); - const glm::vec3 b = glm::normalize(p2 - p0); - const glm::vec3 c = glm::normalize(glm::cross(a, b)); - const glm::vec3 d = glm::normalize(glm::cross(a, c)); - matrix = glm::mat4{{a, 0}, {-c, 0}, {d, 0}, {}}; - } - for (int i = 0; i < object->numPoints(); i += 1) - { - const glm::vec3& point = object->getPoint(i); + const ModelElement& element = this->model->at(i); + std::optional<glm::mat4> matrix = ifplanar<glm::mat4>( + element, + [](const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3) + { + const glm::vec3 a = glm::normalize(p2 - p1); + const glm::vec3 b = glm::normalize(p3 - p1); + const glm::vec3 c = glm::normalize(glm::cross(a, b)); + const glm::vec3 d = glm::normalize(glm::cross(a, c)); + return glm::mat4{{a, 0}, {-c, 0}, {d, 0}, {}}; + }); + points(element, [&](const glm::vec3 point) { const unsigned int hash = hashVertex(point); VertexInfo& info = this->map[hash]; info.point = point; - info.objects.insert(object->id); - if (object->numPoints() > 2 and not info.transformSet) + info.objects.insert(this->model->idAt(i)); + if (matrix.has_value() and not info.transformSet) { - info.transform = matrix; + info.transform = matrix.value(); info.transform[3] = {point, 1}; info.transformSet = true; } @@ -87,8 +145,8 @@ this->vertexHashes.insert(hash); this->vertices.push_back(point); } - } - }); + }); + } for (auto& pair : this->map) { auto& info = pair.second; @@ -100,15 +158,18 @@ info.transformSet = true; } float scale = 1.0f; - for (const ldraw::id_t objectId : info.objects) + for (const ModelId objectId : info.objects) { - edges(model->get(objectId), [&](Edge&& edge) - { - if (hashVertex(edge.a) == pair.first or hashVertex(edge.b) == pair.first) + const std::optional<int> index = model->find(objectId); + if (index.has_value()) { + edges(this->model->at(index.value()), [&](Edge&& edge) { - scale = std::min(scale, glm::length(edge.b - edge.a) / 3); - } - }); + if (hashVertex(edge.a) == pair.first or hashVertex(edge.b) == pair.first) + { + scale = std::min(scale, glm::length(edge.b - edge.a) / 3); + } + }); + } } info.transform = glm::scale(info.transform, glm::vec3{scale, scale, scale}); }