src/vertexmap.cpp

changeset 120
8c9fff699241
parent 119
24275a4064f4
child 151
e628fc2e0c72
equal deleted inserted replaced
119:24275a4064f4 120:8c9fff699241
1 #include "vertexmap.h" 1 #include "vertexmap.h"
2 #include "linetypes/polygonobject.h" 2 #include "linetypes/polygonobject.h"
3
4 unsigned int hashVertex(const glm::vec3& vec)
5 {
6 return qHash(glm::ivec3{
7 int(vec.x * 10000),
8 int(vec.y * 10000),
9 int(vec.z * 10000),
10 });
11 }
3 12
4 VertexMap::VertexMap(const Model *model) : 13 VertexMap::VertexMap(const Model *model) :
5 model{model} 14 model{model}
6 { 15 {
7 connect( 16 connect(
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.
54 void VertexMap::apply(ApplyFunction fn) const 122 void VertexMap::apply(ApplyFunction fn) const
55 { 123 {
56 for (unsigned int i = 0; i < this->vertices.size(); i += 1) 124 for (unsigned int i = 0; i < this->vertices.size(); i += 1)
57 { 125 {
58 const glm::vec3& point = this->vertices[i]; 126 const glm::vec3& point = this->vertices[i];
59 fn(point, this->map.at(qHash(point))); 127 fn(point, this->map.at(hashVertex(point)));
60 } 128 }
61 } 129 }

mercurial