src/vertexmap.cpp

changeset 200
ca23936b455b
parent 151
e628fc2e0c72
child 250
2837b549e616
equal deleted inserted replaced
199:6988973515d2 200:ca23936b455b
1 #include "vertexmap.h" 1 #include "vertexmap.h"
2 #include "linetypes/polygonobject.h" 2 #include "gl/common.h"
3 3
4 unsigned int hashVertex(const glm::vec3& vec) 4 unsigned int hashVertex(const glm::vec3& vec)
5 { 5 {
6 return qHash(glm::ivec3{ 6 return qHash(glm::ivec3{
7 int(vec.x * 10000), 7 int(vec.x * 10000),
38 { 38 {
39 const glm::vec3& a; 39 const glm::vec3& a;
40 const glm::vec3& b; 40 const glm::vec3& b;
41 }; 41 };
42 42
43 inline void edges(const ldraw::Object* object, std::function<void(Edge&&)> fn) 43 inline void edges(const ModelElement& element, std::function<void(Edge&&)> fn)
44 { 44 {
45 for (int i = 0; i < object->numPoints() - 1; i += 1) 45 std::visit<void>(overloaded{
46 { 46 [fn](const Colored<LineSegment>& edge) {
47 const glm::vec3 p1 = object->getPoint(i); 47 fn(Edge{edge.p1, edge.p2});
48 const glm::vec3 p2 = object->getPoint((i + 1) % object->numPoints()); 48 },
49 fn(Edge{p1, p2}); 49 [fn](const Colored<Triangle>& triangle) {
50 } 50 fn(Edge{triangle.p1, triangle.p2});
51 fn(Edge{triangle.p2, triangle.p3});
52 fn(Edge{triangle.p3, triangle.p1});
53 },
54 [fn](const Colored<Quadrilateral>& quad) {
55 fn(Edge{quad.p1, quad.p2});
56 fn(Edge{quad.p2, quad.p3});
57 fn(Edge{quad.p3, quad.p4});
58 fn(Edge{quad.p4, quad.p1});
59 },
60 [fn](const Colored<ConditionalEdge>& cedge) {
61 fn(Edge{cedge.p1, cedge.p2});
62 },
63 [](const ModelElement&&){}
64 }, element);
65 }
66
67 inline void points(
68 const ModelElement& element,
69 std::function<void(const glm::vec3&)> fn)
70 {
71 std::visit<void>(overloaded{
72 [fn](const Colored<LineSegment>& edge) {
73 fn(edge.p1);
74 fn(edge.p2);
75 },
76 [fn](const Colored<Triangle>& triangle) {
77 fn(triangle.p1);
78 fn(triangle.p2);
79 fn(triangle.p3);
80 },
81 [fn](const Colored<Quadrilateral>& quad) {
82 fn(quad.p1);
83 fn(quad.p2);
84 fn(quad.p3);
85 fn(quad.p4);
86 },
87 [fn](const Colored<ConditionalEdge>& cedge) {
88 fn(cedge.p1);
89 fn(cedge.p2);
90 fn(cedge.c1);
91 fn(cedge.c2);
92 },
93 [](const ModelElement&&){}
94 }, element);
95 }
96
97 template<typename R>
98 auto ifplanar(
99 const ModelElement& element,
100 std::function<R(const glm::vec3&, const glm::vec3&, const glm::vec3&)> fn
101 )
102 {
103 return std::visit(overloaded{
104 [fn](const Triangle& triangle) -> std::optional<R> {
105 return fn(triangle.p1, triangle.p2, triangle.p3);
106 },
107 [fn](const Quadrilateral quad) -> std::optional<R> {
108 return fn(quad.p1, quad.p2, quad.p3);
109 },
110 [](const ModelElement&&) -> std::optional<R> {return {};}
111 }, element);
51 } 112 }
52 113
53 void VertexMap::build() 114 void VertexMap::build()
54 { 115 {
55 this->map.clear(); 116 this->map.clear();
56 this->vertices.clear(); 117 this->vertices.clear();
57 this->vertexHashes.clear(); 118 this->vertexHashes.clear();
58 applyToModel<ldraw::Object>(*this->model, [&](const ldraw::Object* object) 119 for (int i = 0; i < this->model->size(); ++i)
59 { 120 {
60 glm::mat4 matrix; 121 const ModelElement& element = this->model->at(i);
61 if (object->numPoints() > 2) 122 std::optional<glm::mat4> matrix = ifplanar<glm::mat4>(
62 { 123 element,
63 const auto& p0 = object->getPoint(0); 124 [](const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3)
64 const auto& p1 = object->getPoint(1); 125 {
65 const auto& p2 = object->getPoint(2); 126 const glm::vec3 a = glm::normalize(p2 - p1);
66 const glm::vec3 a = glm::normalize(p1 - p0); 127 const glm::vec3 b = glm::normalize(p3 - p1);
67 const glm::vec3 b = glm::normalize(p2 - p0); 128 const glm::vec3 c = glm::normalize(glm::cross(a, b));
68 const glm::vec3 c = glm::normalize(glm::cross(a, b)); 129 const glm::vec3 d = glm::normalize(glm::cross(a, c));
69 const glm::vec3 d = glm::normalize(glm::cross(a, c)); 130 return glm::mat4{{a, 0}, {-c, 0}, {d, 0}, {}};
70 matrix = glm::mat4{{a, 0}, {-c, 0}, {d, 0}, {}}; 131 });
71 } 132 points(element, [&](const glm::vec3 point) {
72 for (int i = 0; i < object->numPoints(); i += 1)
73 {
74 const glm::vec3& point = object->getPoint(i);
75 const unsigned int hash = hashVertex(point); 133 const unsigned int hash = hashVertex(point);
76 VertexInfo& info = this->map[hash]; 134 VertexInfo& info = this->map[hash];
77 info.point = point; 135 info.point = point;
78 info.objects.insert(object->id); 136 info.objects.insert(this->model->idAt(i));
79 if (object->numPoints() > 2 and not info.transformSet) 137 if (matrix.has_value() and not info.transformSet)
80 { 138 {
81 info.transform = matrix; 139 info.transform = matrix.value();
82 info.transform[3] = {point, 1}; 140 info.transform[3] = {point, 1};
83 info.transformSet = true; 141 info.transformSet = true;
84 } 142 }
85 if (not this->vertexHashes.contains(hash)) 143 if (not this->vertexHashes.contains(hash))
86 { 144 {
87 this->vertexHashes.insert(hash); 145 this->vertexHashes.insert(hash);
88 this->vertices.push_back(point); 146 this->vertices.push_back(point);
89 } 147 }
90 } 148 });
91 }); 149 }
92 for (auto& pair : this->map) 150 for (auto& pair : this->map)
93 { 151 {
94 auto& info = pair.second; 152 auto& info = pair.second;
95 // If there's no transformation calculated yet, make up a simple one that at least 153 // If there's no transformation calculated yet, make up a simple one that at least
96 // contains translation. 154 // contains translation.
98 { 156 {
99 info.transform = glm::translate(glm::identity<glm::mat4>(), info.point); 157 info.transform = glm::translate(glm::identity<glm::mat4>(), info.point);
100 info.transformSet = true; 158 info.transformSet = true;
101 } 159 }
102 float scale = 1.0f; 160 float scale = 1.0f;
103 for (const ldraw::id_t objectId : info.objects) 161 for (const ModelId objectId : info.objects)
104 { 162 {
105 edges(model->get(objectId), [&](Edge&& edge) 163 const std::optional<int> index = model->find(objectId);
106 { 164 if (index.has_value()) {
107 if (hashVertex(edge.a) == pair.first or hashVertex(edge.b) == pair.first) 165 edges(this->model->at(index.value()), [&](Edge&& edge)
108 { 166 {
109 scale = std::min(scale, glm::length(edge.b - edge.a) / 3); 167 if (hashVertex(edge.a) == pair.first or hashVertex(edge.b) == pair.first)
110 } 168 {
111 }); 169 scale = std::min(scale, glm::length(edge.b - edge.a) / 3);
170 }
171 });
172 }
112 } 173 }
113 info.transform = glm::scale(info.transform, glm::vec3{scale, scale, scale}); 174 info.transform = glm::scale(info.transform, glm::vec3{scale, scale, scale});
114 } 175 }
115 Q_EMIT this->verticesChanged(); 176 Q_EMIT this->verticesChanged();
116 } 177 }

mercurial