src/polygoncache.cpp

Fri, 01 Jul 2022 23:51:16 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Fri, 01 Jul 2022 23:51:16 +0300
changeset 314
4642ba1218e8
parent 309
d862721d19a3
child 318
216f02b50b0a
permissions
-rw-r--r--

Added rudimentary cylinder extrusion into circle tool.
I really had to think which way the vectors are in this one

#include "src/circularprimitive.h"
#include "src/documentmanager.h"
#include "src/invert.h"
#include "src/polygoncache.h"

Model* resolve(const QString& name, const ModelId callingModelId, DocumentManager* documents)
{
	return documents->findDependencyByName(callingModelId, name);
}

static PolygonElement transformed(
	PolygonElement element,
	const glm::mat4& transform)
{
	visitPoints([&transform](glm::vec3& p) {
		p = transform * glm::vec4{p, 1};
	}, element);
	return element;
}

PolygonCache* findPolygonCacheForModel(Model* model, DocumentManager* context)
{
	std::optional<ModelId> modelId = context->findIdForModel(model);
	if (modelId.has_value()) {
		return context->getPolygonCacheForModel(modelId.value());
	}
	else {
		return nullptr;
	}
}

template<typename Fn, typename Fn2>
static void collectPolygons(
	const ModelElement& element,
	Winding& winding,
	GetPolygonsContext* context,
	Fn&& add,
	Fn2&& reserve)
{
	std::visit<void>(overloaded{
		[&](const Colored<LineSegment>& edge) {
			add({edge, edge.color});
		},
		[&](const Colored<Triangle>& triangle) {
			add({triangle, triangle.color});
		},
		[&](const Colored<Quadrilateral>& quad) {
			add({quad, quad.color});
		},
		[&](const Colored<ConditionalEdge>& cedge) {
			add({cedge, cedge.color});
		},
		[&add, context, &reserve](const Colored<SubfileReference>& ref) {
			Model* dependency = context->documents->findDependencyByName(context->modelId, ref.name);
			PolygonCache* cache = nullptr;
			if (dependency != nullptr) {
				cache = findPolygonCacheForModel(dependency, context->documents);
			}
			if (cache != nullptr) {
				const bool needInverting = glm::determinant(ref.transformation) < 0;
				recacheIfNeeded(cache, dependency, context->documents);
				reserve(cache->polygons.size());
				for (const PolygonElement& cacheElement : cache->polygons) {
					PolygonElement polygon = transformed(cacheElement, ref.transformation);
					if (needInverting != ref.inverted) {
						gl::invert(polygon);
					}
					if (polygon.color == MAIN_COLOR) {
						polygon.color = ref.color;
					}
					add(polygon);
				}
			}
		},
		[&add](const Colored<CircularPrimitive>& circ) {
			rasterize(circ, [&](const PlainPolygonElement& polygon, ColorIndex color){
				if (color == MAIN_COLOR) {
					color = circ.color;
				}
				add(PolygonElement{polygon, color});
			});
		},
		[&winding](const Comment& comment) {
			if (comment.text == QStringLiteral("BFC CERTIFY CW")) {
				winding = Clockwise;
			} 
			else if (comment.text == QStringLiteral("BFC CERTIFY CCW")) {
				winding = Anticlockwise;
			}
			else if (comment.text == QStringLiteral("BFC NOCERTIFY")) {
				winding = NoWinding;
			}
		},
		[](const ModelElement&) {}
	}, element);
}

static std::vector<WithId<PolygonElement>> inlinePolygons(
	const Model* model,
	GetPolygonsContext* context)
{
	Winding winding = NoWinding;
	std::vector<WithId<PolygonElement>> result;
	for (std::size_t i = 0; i < model->size(); i += 1)
	{
		const ModelElement& element = (*model)[i];
		const ElementId id = model->idAt(i);
		collectPolygons(element, winding, context,
			[&result, winding, id](const PolygonElement& poly){
				result.push_back({poly, id});
				if (winding == Winding::Clockwise) {
					gl::invert(result.back());
				}
			}, [&result](std::size_t incomingsize){
				reserveMore(result, incomingsize);
			});
	}
	return result;
}

void recacheIfNeeded(PolygonCache *cache, Model *model, DocumentManager *documents)
{
	if (cache->needRecache)
	{
		cache->polygons.clear();
		const std::optional<ModelId> modelId = documents->findIdForModel(model);
		if (modelId.has_value())
		{
			GetPolygonsContext context{modelId.value(), documents};
			cache->polygons = inlinePolygons(model, &context);
		}
		cache->needRecache = false;
	}
}

mercurial