Mon, 27 Jun 2022 01:29:03 +0300
rename ldforge.qrc -> resources.qrc
#include "src/vertexmap.h" #include "src/gl/common.h" hash_t hashVertex(const glm::vec3& vec) { return qHash(glm::ivec3{ int(vec.x * 10000), int(vec.y * 10000), int(vec.z * 10000), }); } VertexMap::VertexMap(const Model *model) : model{model} { connect( model, &Model::dataChanged, this, &VertexMap::build ); connect( model, &Model::rowsInserted, this, &VertexMap::build ); connect( model, &Model::rowsRemoved, this, &VertexMap::build ); this->build(); } struct Edge { const glm::vec3& a; const glm::vec3& b; }; 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) { 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() { this->map.clear(); this->vertices.clear(); this->vertexHashes.clear(); for (std::size_t i = 0; i < this->model->size(); ++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 hash_t hash = hashVertex(point); VertexInfo& info = this->map[hash]; info.point = point; info.objects.insert(this->model->idAt(i)); if (matrix.has_value() and not info.transformSet) { info.transform = matrix.value(); info.transform[3] = {point, 1}; info.transformSet = true; } if (not this->vertexHashes.contains(hash)) { this->vertexHashes.insert(hash); this->vertices.push_back(point); } }); } for (auto& pair : this->map) { auto& info = pair.second; // If there's no transformation calculated yet, make up a simple one that at least // contains translation. if (not info.transformSet) { info.transform = glm::translate(glm::identity<glm::mat4>(), info.point); info.transformSet = true; } float scale = 1.0f; for (const ModelId objectId : info.objects) { const std::optional<int> index = model->find(objectId); if (index.has_value()) { edges(this->model->at(unsigned_cast(index.value())), [&](Edge&& edge) { 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}); } Q_EMIT this->verticesChanged(); } /** * @brief Apply \c fn for all vertices in the map. * @param fn */ void VertexMap::apply(ApplyFunction fn) const { for (unsigned int i = 0; i < this->vertices.size(); i += 1) { const glm::vec3& point = this->vertices[i]; fn(point, this->map.at(hashVertex(point))); } }