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 } |