src/polygoncache.cpp

Fri, 01 Jul 2022 16:46:43 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Fri, 01 Jul 2022 16:46:43 +0300
changeset 312
2637134bc37c
parent 309
d862721d19a3
child 318
216f02b50b0a
permissions
-rw-r--r--

Fix right click to delete not really working properly
Instead of removing the point that had been added, it would remove
the point that is being drawn, which would cause it to overwrite the
previous point using the new point, causing a bit of a delay

#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