23 &VertexMap::build |
32 &VertexMap::build |
24 ); |
33 ); |
25 this->build(); |
34 this->build(); |
26 } |
35 } |
27 |
36 |
|
37 struct Edge |
|
38 { |
|
39 const glm::vec3& a; |
|
40 const glm::vec3& b; |
|
41 }; |
|
42 |
|
43 inline void edges(const ldraw::Object* object, std::function<void(Edge&&)> fn) |
|
44 { |
|
45 for (int i = 0; i < object->numPoints() - 1; i += 1) |
|
46 { |
|
47 const glm::vec3 p1 = object->getPoint(i); |
|
48 const glm::vec3 p2 = object->getPoint((i + 1) % object->numPoints()); |
|
49 fn(Edge{p1, p2}); |
|
50 } |
|
51 } |
|
52 |
28 void VertexMap::build() |
53 void VertexMap::build() |
29 { |
54 { |
30 this->map.clear(); |
55 this->map.clear(); |
31 this->vertices.clear(); |
56 this->vertices.clear(); |
32 this->vertexHashes.clear(); |
57 this->vertexHashes.clear(); |
33 this->model->apply<ldraw::Object>([&](const ldraw::Object* object) |
58 this->model->apply<ldraw::Object>([&](const ldraw::Object* object) |
34 { |
59 { |
|
60 glm::mat4 matrix; |
|
61 if (object->numPoints() > 2) |
|
62 { |
|
63 const auto& p0 = object->getPoint(0); |
|
64 const auto& p1 = object->getPoint(1); |
|
65 const auto& p2 = object->getPoint(2); |
|
66 const glm::vec3 a = glm::normalize(p1 - p0); |
|
67 const glm::vec3 b = glm::normalize(p2 - p0); |
|
68 const glm::vec3 c = glm::normalize(glm::cross(a, b)); |
|
69 const glm::vec3 d = glm::normalize(glm::cross(a, c)); |
|
70 matrix = glm::mat4{{a, 0}, {-c, 0}, {d, 0}, {}}; |
|
71 } |
35 for (int i = 0; i < object->numPoints(); i += 1) |
72 for (int i = 0; i < object->numPoints(); i += 1) |
36 { |
73 { |
37 const glm::vec3& point = object->getPoint(i); |
74 const glm::vec3& point = object->getPoint(i); |
38 const unsigned int hash = qHash(point); |
75 const unsigned int hash = hashVertex(point); |
39 this->map[hash].insert(object->id); |
76 VertexInfo& info = this->map[hash]; |
|
77 info.point = point; |
|
78 info.objects.insert(object->id); |
|
79 if (object->numPoints() > 2 and not info.transformSet) |
|
80 { |
|
81 info.transform = matrix; |
|
82 info.transform[3] = {point, 1}; |
|
83 info.transformSet = true; |
|
84 } |
40 if (not this->vertexHashes.contains(hash)) |
85 if (not this->vertexHashes.contains(hash)) |
41 { |
86 { |
42 this->vertexHashes.insert(hash); |
87 this->vertexHashes.insert(hash); |
43 this->vertices.push_back(point); |
88 this->vertices.push_back(point); |
44 } |
89 } |
45 } |
90 } |
46 }); |
91 }); |
|
92 for (auto& pair : this->map) |
|
93 { |
|
94 auto& info = pair.second; |
|
95 // If there's no transformation calculated yet, make up a simple one that at least |
|
96 // contains translation. |
|
97 if (not info.transformSet) |
|
98 { |
|
99 info.transform = glm::translate(glm::identity<glm::mat4>(), info.point); |
|
100 info.transformSet = true; |
|
101 } |
|
102 float scale = 1.0f; |
|
103 for (const ldraw::id_t objectId : info.objects) |
|
104 { |
|
105 edges(model->get(objectId), [&](Edge&& edge) |
|
106 { |
|
107 if (hashVertex(edge.a) == pair.first or hashVertex(edge.b) == pair.first) |
|
108 { |
|
109 scale = std::min(scale, glm::length(edge.b - edge.a) / 3); |
|
110 } |
|
111 }); |
|
112 } |
|
113 info.transform = glm::scale(info.transform, glm::vec3{scale, scale, scale}); |
|
114 } |
47 Q_EMIT this->verticesChanged(); |
115 Q_EMIT this->verticesChanged(); |
48 } |
116 } |
49 |
117 |
50 /** |
118 /** |
51 * @brief Apply \c fn for all vertices in the map. |
119 * @brief Apply \c fn for all vertices in the map. |