src/vertexmap.cpp

changeset 120
8c9fff699241
parent 119
24275a4064f4
child 151
e628fc2e0c72
--- a/src/vertexmap.cpp	Wed Jul 28 08:23:09 2021 +0300
+++ b/src/vertexmap.cpp	Wed Jul 28 13:22:51 2021 +0300
@@ -1,6 +1,15 @@
 #include "vertexmap.h"
 #include "linetypes/polygonobject.h"
 
+unsigned int 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}
 {
@@ -25,6 +34,22 @@
 	this->build();
 }
 
+struct Edge
+{
+	const glm::vec3& a;
+	const glm::vec3& b;
+};
+
+inline void edges(const ldraw::Object* object, std::function<void(Edge&&)> fn)
+{
+	for (int i = 0; i < object->numPoints() - 1; i += 1)
+	{
+		const glm::vec3 p1 = object->getPoint(i);
+		const glm::vec3 p2 = object->getPoint((i + 1) % object->numPoints());
+		fn(Edge{p1, p2});
+	}
+}
+
 void VertexMap::build()
 {
 	this->map.clear();
@@ -32,11 +57,31 @@
 	this->vertexHashes.clear();
 	this->model->apply<ldraw::Object>([&](const ldraw::Object* object)
 	{
+		glm::mat4 matrix;
+		if (object->numPoints() > 2)
+		{
+			const auto& p0 = object->getPoint(0);
+			const auto& p1 = object->getPoint(1);
+			const auto& p2 = object->getPoint(2);
+			const glm::vec3 a = glm::normalize(p1 - p0);
+			const glm::vec3 b = glm::normalize(p2 - p0);
+			const glm::vec3 c = glm::normalize(glm::cross(a, b));
+			const glm::vec3 d = glm::normalize(glm::cross(a, c));
+			matrix = glm::mat4{{a, 0}, {-c, 0}, {d, 0}, {}};
+		}
 		for (int i = 0; i < object->numPoints(); i += 1)
 		{
 			const glm::vec3& point = object->getPoint(i);
-			const unsigned int hash = qHash(point);
-			this->map[hash].insert(object->id);
+			const unsigned int hash = hashVertex(point);
+			VertexInfo& info = this->map[hash];
+			info.point = point;
+			info.objects.insert(object->id);
+			if (object->numPoints() > 2 and not info.transformSet)
+			{
+				info.transform = matrix;
+				info.transform[3] = {point, 1};
+				info.transformSet = true;
+			}
 			if (not this->vertexHashes.contains(hash))
 			{
 				this->vertexHashes.insert(hash);
@@ -44,6 +89,29 @@
 			}
 		}
 	});
+	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 ldraw::id_t objectId : info.objects)
+		{
+			edges(model->get(objectId), [&](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();
 }
 
@@ -56,6 +124,6 @@
 	for (unsigned int i = 0; i < this->vertices.size(); i += 1)
 	{
 		const glm::vec3& point = this->vertices[i];
-		fn(point, this->map.at(qHash(point)));
+		fn(point, this->map.at(hashVertex(point)));
 	}
 }

mercurial