Sat, 08 Apr 2023 22:09:29 +0300
Add settings import and export
#include "src/circularprimitive.h" #include "src/documentmanager.h" #include "src/invert.h" #include "src/polygoncache.h" #include "src/parser.h" QTextDocument* 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(QTextDocument* model, DocumentManager* context) { std::optional<ModelId> modelId = context->findIdForModel(model); if (modelId.has_value()) { return context->getPolygonCacheForModel(modelId.value()); } else { return nullptr; } } constexpr bool n_xor(bool a) { return a; } template<typename... Args> constexpr bool n_xor(bool a, Args&&... rest) { return a xor n_xor(rest...); } namespace { struct GetPolygonsContext { bool invertnext = false; ModelId modelId; class DocumentManager* documents; }; } template<typename Fn, typename Fn2> static void inlineSubfileReference( const PolygonCache::vector_type& polygons, const Colored<SubfileReference>& ref, GetPolygonsContext* context, Fn&& add, Fn2&& reserve) { const bool needInverting = 0 ^ (glm::determinant(ref.transformation) < 0) ^ (context->invertnext); reserve(polygons.size()); for (const PolygonElement& cacheElement : polygons) { PolygonElement polygon = transformed(cacheElement, ref.transformation); if (needInverting) { gl::invert(polygon); } if (polygon.color == MAIN_COLOR) { polygon.color = ref.color; } add(polygon); } } static QTextDocument* findDependency(const SubfileReference& ref, GetPolygonsContext* context) { return context->documents->findDependencyByName(context->modelId, ref.name); } template<typename Fn, typename Fn2> static void collectPolygons( const ParsedLine& element, Winding& winding, GetPolygonsContext* context, Fn&& add, Fn2&& reserve) { bool foundinvertnext = false; std::visit<void>(overloaded{ [&](const LineType0& line0) { const QString text = line0.value.text.simplified(); if (text == QStringLiteral("BFC INVERTNEXT")) { context->invertnext = true; foundinvertnext = true; } else if (text == QStringLiteral("BFC CERTIFY CW")) { winding = Clockwise; } else if (text == QStringLiteral("BFC CERTIFY CCW")) { winding = Anticlockwise; } else if (text == QStringLiteral("BFC NOCERTIFY")) { winding = NoWinding; } }, [&](const LineType2& line2) { add({line2.value, line2.value.color}); }, [&](const LineType3& line3) { add({line3.value, line3.value.color}); }, [&](const LineType4& line4) { add({line4.value, line4.value.color}); }, [&](const LineType5& line5) { add({line5.value, line5.value.color}); }, [&add, context, &reserve](const LineType1& line1) { QTextDocument* const dependency = findDependency(line1.value, context); if (PolygonCache* cache = (dependency != nullptr) ? findPolygonCacheForModel(dependency, context->documents) : nullptr ) { recacheIfNeeded(cache, dependency, context->documents); inlineSubfileReference(cache->polygons, line1.value, context, add, reserve); } }, #if 0 [&add](const Colored<CircularPrimitive>& circ) { rasterize(circ, [&](const PlainPolygonElement& polygon, ColorIndex color){ if (color == MAIN_COLOR) { color = circ.color; } add(PolygonElement{polygon, color}); }); }, #endif }, element); if (not foundinvertnext) { context->invertnext = false; } } static std::vector<WithId<PolygonElement>> inlinePolygons( const QTextDocument* model, GetPolygonsContext* context) { Winding winding = NoWinding; std::vector<WithId<PolygonElement>> result; int i = 0; const auto add = [&result, winding, i](const PolygonElement& poly){ result.push_back({poly, i}); if (winding == Winding::Clockwise) { gl::invert(result.back()); } }; const auto reserve = [&result](std::size_t incomingsize){ reserveMore(result, incomingsize); }; for (const QString& line : model->toPlainText().split("\n")) { const opt<ParsedLine> parsedline = parse(line); if (parsedline.has_value()) { collectPolygons(*parsedline, winding, context, add, reserve); } ++i; } return result; } void recacheIfNeeded(PolygonCache *cache, QTextDocument *model, DocumentManager *documents) { if (cache->needRecache) { cache->polygons.clear(); const std::optional<ModelId> modelId = documents->findIdForModel(model); if (modelId.has_value()) { GetPolygonsContext context{ .invertnext = false, .modelId = *modelId, .documents = documents, }; cache->polygons = inlinePolygons(model, &context); } cache->needRecache = false; } }