src/vertexmap.cpp

changeset 200
ca23936b455b
parent 151
e628fc2e0c72
child 250
2837b549e616
--- a/src/vertexmap.cpp	Wed May 25 20:36:34 2022 +0300
+++ b/src/vertexmap.cpp	Mon Jun 06 22:01:22 2022 +0300
@@ -1,5 +1,5 @@
 #include "vertexmap.h"
-#include "linetypes/polygonobject.h"
+#include "gl/common.h"
 
 unsigned int hashVertex(const glm::vec3& vec)
 {
@@ -40,14 +40,75 @@
 	const glm::vec3& b;
 };
 
-inline void edges(const ldraw::Object* object, std::function<void(Edge&&)> fn)
+inline void edges(const ModelElement& element, std::function<void(Edge&&)> fn)
+{
+	std::visit<void>(overloaded{
+		[fn](const Colored<LineSegment>& edge) {
+			fn(Edge{edge.p1, edge.p2});
+		},
+		[fn](const Colored<Triangle>& triangle) {
+			fn(Edge{triangle.p1, triangle.p2});
+			fn(Edge{triangle.p2, triangle.p3});
+			fn(Edge{triangle.p3, triangle.p1});
+		},
+		[fn](const Colored<Quadrilateral>& quad) {
+			fn(Edge{quad.p1, quad.p2});
+			fn(Edge{quad.p2, quad.p3});
+			fn(Edge{quad.p3, quad.p4});
+			fn(Edge{quad.p4, quad.p1});
+		},
+		[fn](const Colored<ConditionalEdge>& cedge) {
+			fn(Edge{cedge.p1, cedge.p2});
+		},
+		[](const ModelElement&&){}
+	}, element);
+}
+
+inline void points(
+	const ModelElement& element,
+	std::function<void(const glm::vec3&)> 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});
-	}
+	std::visit<void>(overloaded{
+		[fn](const Colored<LineSegment>& edge) {
+			fn(edge.p1);
+			fn(edge.p2);
+		},
+		[fn](const Colored<Triangle>& triangle) {
+			fn(triangle.p1);
+			fn(triangle.p2);
+			fn(triangle.p3);
+		},
+		[fn](const Colored<Quadrilateral>& quad) {
+			fn(quad.p1);
+			fn(quad.p2);
+			fn(quad.p3);
+			fn(quad.p4);
+		},
+		[fn](const Colored<ConditionalEdge>& cedge) {
+			fn(cedge.p1);
+			fn(cedge.p2);
+			fn(cedge.c1);
+			fn(cedge.c2);
+		},
+		[](const ModelElement&&){}
+	}, element);
+}
+
+template<typename R>
+auto ifplanar(
+	const ModelElement& element,
+	std::function<R(const glm::vec3&, const glm::vec3&, const glm::vec3&)> fn
+)
+{
+	return std::visit(overloaded{
+		[fn](const Triangle& triangle) -> std::optional<R> {
+			return fn(triangle.p1, triangle.p2, triangle.p3);
+		},
+		[fn](const Quadrilateral quad) -> std::optional<R> {
+			return fn(quad.p1, quad.p2, quad.p3);
+		},
+		[](const ModelElement&&) -> std::optional<R> {return {};}
+	}, element);
 }
 
 void VertexMap::build()
@@ -55,30 +116,27 @@
 	this->map.clear();
 	this->vertices.clear();
 	this->vertexHashes.clear();
-	applyToModel<ldraw::Object>(*this->model, [&](const ldraw::Object* object)
+	for (int i = 0; i < this->model->size(); ++i)
 	{
-		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 ModelElement& element = this->model->at(i);
+		std::optional<glm::mat4> matrix = ifplanar<glm::mat4>(
+			element,
+			[](const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& p3)
+			{
+				const glm::vec3 a = glm::normalize(p2 - p1);
+				const glm::vec3 b = glm::normalize(p3 - p1);
+				const glm::vec3 c = glm::normalize(glm::cross(a, b));
+				const glm::vec3 d = glm::normalize(glm::cross(a, c));
+				return glm::mat4{{a, 0}, {-c, 0}, {d, 0}, {}};
+			});
+		points(element, [&](const glm::vec3 point) {
 			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.objects.insert(this->model->idAt(i));
+			if (matrix.has_value() and not info.transformSet)
 			{
-				info.transform = matrix;
+				info.transform = matrix.value();
 				info.transform[3] = {point, 1};
 				info.transformSet = true;
 			}
@@ -87,8 +145,8 @@
 				this->vertexHashes.insert(hash);
 				this->vertices.push_back(point);
 			}
-		}
-	});
+		});
+	}
 	for (auto& pair : this->map)
 	{
 		auto& info = pair.second;
@@ -100,15 +158,18 @@
 			info.transformSet = true;
 		}
 		float scale = 1.0f;
-		for (const ldraw::id_t objectId : info.objects)
+		for (const ModelId objectId : info.objects)
 		{
-			edges(model->get(objectId), [&](Edge&& edge)
-			{
-				if (hashVertex(edge.a) == pair.first or hashVertex(edge.b) == pair.first)
+			const std::optional<int> index = model->find(objectId);
+			if (index.has_value()) {
+				edges(this->model->at(index.value()), [&](Edge&& edge)
 				{
-					scale = std::min(scale, glm::length(edge.b - edge.a) / 3);
-				}
-			});
+					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});
 	}

mercurial