Wed, 29 Jun 2022 14:11:58 +0300
Add support for BFC CERTIFY statements
src/circularprimitive.h | file | annotate | diff | comparison | revisions | |
src/gl/compiler.cpp | file | annotate | diff | comparison | revisions | |
src/layers/edittools.cpp | file | annotate | diff | comparison | revisions | |
src/model.h | file | annotate | diff | comparison | revisions | |
src/polygoncache.cpp | file | annotate | diff | comparison | revisions | |
src/polygoncache.h | file | annotate | diff | comparison | revisions |
--- a/src/circularprimitive.h Tue Jun 28 22:18:11 2022 +0300 +++ b/src/circularprimitive.h Wed Jun 29 14:11:58 2022 +0300 @@ -17,23 +17,23 @@ case CircularPrimitive::Circle: ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ - fn(edge(xform(p1, 0), xform(p2, 0))); + fn(LineSegment{xform(p1, 0), xform(p2, 0)}, EDGE_COLOR); }); break; case CircularPrimitive::Disc: ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ - fn(triangle(primitiveOrigin, xform(p1, 0), xform(p2, 0))); + fn(Triangle{primitiveOrigin, xform(p1, 0), xform(p2, 0)}, MAIN_COLOR); }); break; case CircularPrimitive::Cylinder: ldraw::circle(circ.fraction.segments, circ.fraction.divisions, [&] (const glm::vec2&, const glm::vec2& p1, const glm::vec2& p2){ - Colored<Quadrilateral> quad = quadrilateral(xform(p1, 1), xform(p2, 1), xform(p2, 0), xform(p1, 0)); + Quadrilateral quad{xform(p1, 1), xform(p2, 1), xform(p2, 0), xform(p1, 0)}; if (invertedMatrix) { std::swap(quad.p2, quad.p4); } - fn(quad); + fn(quad, MAIN_COLOR); }); break; case CircularPrimitive::CylinderOpen: @@ -77,7 +77,7 @@ {+1, -1}, }; const glm::vec2& corner = corners[i * 4 / circ.fraction.divisions]; - fn(triangle(xform(p2, 0), xform(p1, 0), xform(corner, 0))); + fn(Triangle{xform(p2, 0), xform(p1, 0), xform(corner, 0)}, MAIN_COLOR); ++i; }); } @@ -86,7 +86,7 @@ for (unsigned int i = 1; i < circ.fraction.segments; ++i) { const glm::vec2& p1 = ldraw::rimpoint(circ.fraction.divisions, i); const glm::vec2& p2 = ldraw::rimpoint(circ.fraction.divisions, i + 1); - fn(triangle(xform(p2, 0), xform(p1, 0), xform({1, 0}, 0))); + fn(Triangle{xform(p2, 0), xform(p1, 0), xform({1, 0}, 0)}, MAIN_COLOR); } break; }
--- a/src/gl/compiler.cpp Tue Jun 28 22:18:11 2022 +0300 +++ b/src/gl/compiler.cpp Wed Jun 29 14:11:58 2022 +0300 @@ -224,10 +224,10 @@ template<typename Fn> void iterateModelPolygons(Model* model, DocumentManager* context, Fn&& fn) { - PolygonCache* cache = findPolygonCacheForModel(model, context); + PolygonCache* const cache = findPolygonCacheForModel(model, context); if (cache != nullptr) { - const PolygonCache::vector_type* polygons = getCachedPolygons(cache, model, context); - for (const WithId<PolygonElement>& polygon : *polygons) { + recacheIfNeeded(cache, model, context); + for (const WithId<PolygonElement>& polygon : cache->polygons) { fn(polygon); } }
--- a/src/layers/edittools.cpp Tue Jun 28 22:18:11 2022 +0300 +++ b/src/layers/edittools.cpp Wed Jun 29 14:11:58 2022 +0300 @@ -141,7 +141,19 @@ painter->drawPolygon(QPolygonF{convertWorldPointsToScreenPoints(points, renderer)}); } -static std::vector<std::vector<glm::vec3>> modelActionPoints(const ModelAction& action) +//! \brief Conversion function from PlainPolygonElement to ModelElement +ModelElement elementFromPolygonAndColor(const PlainPolygonElement& poly, ColorIndex color) +{ + // use std::visit with a templated lambda to resolve the type of poly. + return std::visit([color](const auto& resolvedPoly) -> ModelElement { + // unlike with normal templates we need to pry out the type out manually + using PolygonType = std::decay_t<decltype(resolvedPoly)>; + // add color and return as a model element. + return Colored<PolygonType>{resolvedPoly, color}; + }, poly); +} + +static std::vector<std::vector<glm::vec3>> polygonsToBeInserted(const ModelAction& action) { std::vector<std::vector<glm::vec3>> result; if (const AppendToModel* append = std::get_if<AppendToModel>(&action)) { @@ -156,8 +168,10 @@ result.push_back({quad->p1, quad->p2, quad->p3, quad->p4}); } else if (const CircularPrimitive* circ = std::get_if<Colored<CircularPrimitive>>(&newElement)) { - rasterize(*circ, [&](const ModelElement& element){ - const auto& subpoints = modelActionPoints(AppendToModel{element}); + // rasterize the circle down to polygons, and append them to the result. + rasterize(*circ, [&](const PlainPolygonElement& poly, const ColorIndex color){ + AppendToModel append{elementFromPolygonAndColor(poly, color)}; + const auto& subpoints = polygonsToBeInserted(append); std::copy(subpoints.begin(), subpoints.end(), std::back_inserter(result)); }); } @@ -232,7 +246,7 @@ const Pens& pens = *reinterpret_cast<const Pens*>(pensptr); painter->setPen(pens.polygonPen); for (const ModelAction& action : this->modelActions()) { - for (const std::vector<glm::vec3>& points : modelActionPoints(action)) { + for (const std::vector<glm::vec3>& points : polygonsToBeInserted(action)) { if (points.size() == 2) { drawWorldPolyline(painter, points, renderer); }
--- a/src/model.h Tue Jun 28 22:18:11 2022 +0300 +++ b/src/model.h Wed Jun 29 14:11:58 2022 +0300 @@ -108,11 +108,13 @@ Empty, ParseError>; -using PolygonElement = Colored<std::variant< +using PlainPolygonElement = std::variant< LineSegment, Triangle, Quadrilateral, - ConditionalEdge>>; + ConditionalEdge>; + +using PolygonElement = Colored<PlainPolygonElement>; template<typename T> struct remove_color {};
--- a/src/polygoncache.cpp Tue Jun 28 22:18:11 2022 +0300 +++ b/src/polygoncache.cpp Wed Jun 29 14:11:58 2022 +0300 @@ -29,101 +29,106 @@ } } -static std::vector<WithId<PolygonElement>> getPolygonsAt( +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 ModelId id = model->idAt(i); - std::visit<void>(overloaded{ - [&](const Colored<LineSegment>& edge) { - result.push_back({{edge, edge.color}, id}); - }, - [&](const Colored<Triangle>& triangle) { - result.push_back({{triangle, triangle.color}, id}); - }, - [&](const Colored<Quadrilateral>& quad) { - result.push_back({{quad, quad.color}, id}); - }, - [&](const Colored<ConditionalEdge>& cedge) { - result.push_back({{cedge, cedge.color}, id}); - }, - [&result, &id, context](const Colored<SubfileReference>& ref) { - Model* dependency = context->documents->findDependencyByName(context->modelId, ref.name); - PolygonCache* cache = nullptr; - if (dependency != nullptr) { - cache = findPolygonCacheForModel(dependency, context->documents); + collectPolygons(element, winding, context, + [&result, winding, id](const PolygonElement& poly){ + result.push_back({poly, id}); + if (winding == Winding::Clockwise) { + gl::invert(result.back()); } - if (cache != nullptr) { - const bool needInverting = glm::determinant(ref.transformation) < 0; - const PolygonCache::vector_type* modelPolygons = getCachedPolygons( - cache, - dependency, - context->documents); - reserveMore(result, modelPolygons->size()); - for (WithId<PolygonElement> polygon : *modelPolygons) { - polygon = {transformed(polygon, ref.transformation), polygon.id}; - if (needInverting != ref.inverted) { - gl::invert(polygon); - } - if (polygon.color == MAIN_COLOR) { - polygon.color = ref.color; - } - polygon.id = id; - result.push_back(polygon); - } - } - }, - [&result, id](const Colored<CircularPrimitive>& circ) { - rasterize(circ, [&](const ModelElement& element){ - std::visit<void>(overloaded{ - // TODO: :-( - [&](const Colored<LineSegment>& edge) { - result.push_back({{edge, edge.color}, id}); - }, - [&](const Colored<Triangle>& triangle) { - result.push_back({{triangle, triangle.color}, id}); - }, - [&](const Colored<Quadrilateral>& quad) { - result.push_back({{quad, quad.color}, id}); - }, - [&](const Colored<ConditionalEdge>& cedge) { - result.push_back({{cedge, cedge.color}, id}); - }, - [&](const auto&){}, - }, element); - }); - }, - [](const ModelElement&) {} - }, element); + }, [&result](std::size_t incomingsize){ + reserveMore(result, incomingsize); + }); } return result; } -/** - * @brief Gets a list of GL polygons that are used to represent this model. - * @details Will build polygons if polygons are outdated. - * @param documents Documents to use to resolve subfile references - * @return vector of GL polygons - */ -const PolygonCache::vector_type* getCachedPolygons( - PolygonCache *cache, - Model *model, - DocumentManager *documents) +void recacheIfNeeded(PolygonCache *cache, Model *model, DocumentManager *documents) { if (cache->needRecache) { - cache->cachedPolygons.clear(); + cache->polygons.clear(); const std::optional<ModelId> modelId = documents->findIdForModel(model); if (modelId.has_value()) { GetPolygonsContext context{modelId.value(), documents}; - cache->cachedPolygons = getPolygonsAt(model, &context); + cache->polygons = inlinePolygons(model, &context); } cache->needRecache = false; } - return &cache->cachedPolygons; }
--- a/src/polygoncache.h Tue Jun 28 22:18:11 2022 +0300 +++ b/src/polygoncache.h Wed Jun 29 14:11:58 2022 +0300 @@ -18,11 +18,11 @@ struct PolygonCache { using vector_type = std::vector<WithId<PolygonElement>>; - vector_type cachedPolygons; + vector_type polygons; bool needRecache = true; }; -const PolygonCache::vector_type* getCachedPolygons( +void recacheIfNeeded( PolygonCache* cache, Model* model, class DocumentManager* documents);