Tue, 11 Apr 2023 11:11:28 +0300
More refactor and renaming
Added a test function that makes recolors stuff red
src/documentmanager.cpp | file | annotate | diff | comparison | revisions | |
src/geometry.h | file | annotate | diff | comparison | revisions | |
src/gl/compiler.cpp | file | annotate | diff | comparison | revisions | |
src/invert.cpp | file | annotate | diff | comparison | revisions | |
src/invert.h | file | annotate | diff | comparison | revisions | |
src/layers/edittools.cpp | file | annotate | diff | comparison | revisions | |
src/layers/edittools.h | file | annotate | diff | comparison | revisions | |
src/main.cpp | file | annotate | diff | comparison | revisions | |
src/mainwindow.ui | file | annotate | diff | comparison | revisions | |
src/model.cpp | file | annotate | diff | comparison | revisions | |
src/model.h | file | annotate | diff | comparison | revisions | |
src/polygoncache.cpp | file | annotate | diff | comparison | revisions | |
src/triangulate.cpp | file | annotate | diff | comparison | revisions | |
src/vertexmap.cpp | file | annotate | diff | comparison | revisions |
--- a/src/documentmanager.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/documentmanager.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -364,7 +364,7 @@ for (const QString& line : model->toPlainText().split("\n")) { const opt<ParsedLine> parsed = parse(line); if (parsed.has_value() and std::holds_alternative<LineType1>(*parsed)) { - result.insert(std::get<LineType1>(*parsed).value.name); + result.insert(std::get<LineType1>(*parsed).value.element.name); } } return result;
--- a/src/geometry.h Mon Apr 10 14:46:36 2023 +0300 +++ b/src/geometry.h Tue Apr 11 11:11:28 2023 +0300 @@ -57,18 +57,6 @@ glm::vec2 p1, p2; }; -// get polygon type from amount of points -template<int N> -struct PolygonType {}; -template<> -struct PolygonType<2> { using type = LineSegment; }; -template<> -struct PolygonType<3> { using type = Triangle; }; -template<> -struct PolygonType<4> { using type = Quadrilateral; }; -template<int N> -using Polygon = typename PolygonType<N>::type; - /** * @brief Computes a line from two points * @param point_1 @@ -131,11 +119,6 @@ }; unscaled_matrix unscale_matrix(const glm::mat4& matrix); -struct NPolygon -{ - std::vector<glm::vec3> points; -}; - inline constexpr bool isclose(const glm::vec3& a, const glm::vec3& b) { return qFuzzyCompare(a.x, b.x)
--- a/src/gl/compiler.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/gl/compiler.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -114,33 +114,34 @@ )"; template<typename Fn> -constexpr void pointsToRender(const PolygonElement& element, Fn func) +constexpr void pointsToRender(const PlainPolygonElement& element, Fn func) { - visitPolygon<void>( - [&func](const LineSegment& edge) - { - func(edge.p1, glm::vec3{}); - func(edge.p2, glm::vec3{}); - }, - [&func](const Triangle& tri) - { - func(tri.p1, normalVector({tri.p3, tri.p1, tri.p2})); - func(tri.p2, normalVector({tri.p1, tri.p2, tri.p3})); - func(tri.p3, normalVector({tri.p2, tri.p3, tri.p1})); - }, - [&func](const Quadrilateral& quad) - { - func(quad.p1, normalVector({quad.p4, quad.p1, quad.p2})); - func(quad.p2, normalVector({quad.p1, quad.p2, quad.p3})); - func(quad.p3, normalVector({quad.p2, quad.p3, quad.p4})); - func(quad.p4, normalVector({quad.p3, quad.p4, quad.p1})); - }, - [&func](const ConditionalEdge& cedge) - { - func(cedge.p1, glm::vec3{}); - func(cedge.p2, glm::vec3{}); - }, - element); + if (const LineSegment* edge = std::get_if<LineSegment>(&element)) + { + func(edge->p1, glm::vec3{}); + func(edge->p2, glm::vec3{}); + } + else if (std::holds_alternative<Triangle>(element)) + { + const Triangle& tri = std::get<Triangle>(element); + func(tri.p1, normalVector({tri.p3, tri.p1, tri.p2})); + func(tri.p2, normalVector(tri)); + func(tri.p3, normalVector({tri.p2, tri.p3, tri.p1})); + } + else if (std::holds_alternative<Quadrilateral>(element)) + { + const Quadrilateral& quad = std::get<Quadrilateral>(element); + func(quad.p1, normalVector({quad.p4, quad.p1, quad.p2})); + func(quad.p2, normalVector({quad.p1, quad.p2, quad.p3})); + func(quad.p3, normalVector({quad.p2, quad.p3, quad.p4})); + func(quad.p4, normalVector({quad.p3, quad.p4, quad.p1})); + } + else + { + const ConditionalEdge& conditional_edge = std::get<ConditionalEdge>(element); + func(conditional_edge.p1, glm::vec3{}); + func(conditional_edge.p2, glm::vec3{}); + } } void gl::buildShaders( @@ -211,7 +212,7 @@ } } -static constexpr gl::ArrayClass classifyPolygon(const PolygonElement& element) +static constexpr gl::ArrayClass classifyPolygon(const PlainPolygonElement& element) { return visitPolygon<gl::ArrayClass>( [](const LineSegment&) { return gl::ArrayClass::Lines; }, @@ -267,7 +268,7 @@ { visitPoints([&result](const glm::vec3& p) { addPointToBox(result, p); - }, polygon); + }, polygon.element); }); return result; } @@ -287,10 +288,10 @@ } iterateModelPolygons(model, context, [&](const WithId<PolygonElement>& polygon) { - const int index = static_cast<int>(classifyPolygon(polygon)); + const int index = static_cast<int>(classifyPolygon(polygon.element)); std::vector<gl::ModelShaders::Vertex>& vertexBuffer = shaders->shaderObjects[index].cachedData; const QColor color = getColorForPolygon(polygon, preferences, colorTable); - pointsToRender(polygon, [&](const glm::vec3& point, const glm::vec3& normal){ + pointsToRender(polygon.element, [&](const glm::vec3& point, const glm::vec3& normal){ gl::ModelShaders::Vertex& vertex = vertexBuffer.emplace_back(); vertex.position = point; vertex.normal = normal;
--- a/src/invert.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/invert.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -36,7 +36,7 @@ /* * Inverts the winding of a polygon. */ -void gl::invert(PolygonElement& polygon) +void gl::invert(PlainPolygonElement& polygon) { visitPolygon<void>( [](LineSegment&) {},
--- a/src/invert.h Mon Apr 10 14:46:36 2023 +0300 +++ b/src/invert.h Tue Apr 11 11:11:28 2023 +0300 @@ -51,7 +51,7 @@ namespace gl { - void invert(PolygonElement &polygon); + void invert(PlainPolygonElement& polygon); } using gl::invert;
--- a/src/layers/edittools.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/layers/edittools.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -35,15 +35,15 @@ { } -void EditTools::setEditMode(EditingMode newMode) +void EditTools::setEditMode(editing_mode_e newMode) { this->mode = newMode; switch (this->mode) { - case SelectMode: + case editing_mode_e::select: Q_EMIT this->suggestCursor(Qt::ArrowCursor); break; - case DrawMode: - case CircleMode: + case editing_mode_e::draw: + case editing_mode_e::circle: Q_EMIT this->suggestCursor(Qt::CrossCursor); break; } @@ -108,18 +108,18 @@ std::vector<std::vector<glm::vec3>> result; if (const AppendToModel* append = std::get_if<AppendToModel>(&action)) { const ModelElement& newElement = append->newElement; - if (const LineSegment* seg = std::get_if<Colored<LineSegment>>(&newElement)) { - result.push_back({seg->p1, seg->p2}); + if (const Colored<LineSegment>* seg = std::get_if<Colored<LineSegment>>(&newElement)) { + result.push_back({seg->element.p1, seg->element.p2}); } - else if (const Triangle* tri = std::get_if<Colored<Triangle>>(&newElement)) { - result.push_back({tri->p1, tri->p2, tri->p3}); + else if (const Colored<Triangle>* tri = std::get_if<Colored<Triangle>>(&newElement)) { + result.push_back({tri->element.p1, tri->element.p2, tri->element.p3}); } - else if (const Quadrilateral* quad = std::get_if<Colored<Quadrilateral>>(&newElement)) { - result.push_back({quad->p1, quad->p2, quad->p3, quad->p4}); + else if (const Colored<Quadrilateral>* quad = std::get_if<Colored<Quadrilateral>>(&newElement)) { + result.push_back({quad->element.p1, quad->element.p2, quad->element.p3, quad->element.p4}); } - else if (const CircularPrimitive* circ = std::get_if<Colored<CircularPrimitive>>(&newElement)) { + else if (const Colored<CircularPrimitive>* circ = std::get_if<Colored<CircularPrimitive>>(&newElement)) { // rasterize the circle down to polygons, and append them to the result. - rasterize(*circ, [&](const PlainPolygonElement& poly, const ColorIndex color){ + rasterize(circ->element, [&](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)); @@ -183,12 +183,12 @@ const std::vector<ModelAction> EditTools::modelActions() const { switch(this->mode) { - case SelectMode: + case editing_mode_e::select: return {}; - case DrawMode: - return drawModeActions(); - case CircleMode: - return circleModeActions(); + case editing_mode_e::draw: + return this->drawModeActions(); + case editing_mode_e::circle: + return this->circleModeActions(); } } @@ -217,7 +217,7 @@ for (const glm::vec3& point : this->inputPolygon) { drawWorldPoint(painter, point, this->renderer); } - if (this->mode == CircleMode and this->inputPolygon.polygonSize() >= 2) { + if (this->mode == editing_mode_e::circle and this->inputPolygon.polygonSize() >= 2) { const glm::vec3 circleOrigin = this->inputPolygon[0]; const QPointF originScreen = this->renderer->modelToScreenCoordinates(circleOrigin); const auto extremity = [this, &originScreen](const glm::vec3& p){ @@ -282,7 +282,7 @@ } } -EditingMode EditTools::currentEditingMode() const +editing_mode_e EditTools::currentEditingMode() const { return this->mode; } @@ -290,13 +290,13 @@ void EditTools::mouseClick(const QMouseEvent* event) { switch(this->mode) { - case SelectMode: + case editing_mode_e::select: if (event->button() == Qt::LeftButton) { const std::int32_t highlighted = this->renderer->pick(event->pos()); Q_EMIT this->select({highlighted}, false); } break; - case DrawMode: + case editing_mode_e::draw: if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) { if (this->inputPolygon.currentPointOnExistingPoint()) { this->closeShape(); @@ -306,7 +306,7 @@ } } break; - case CircleMode: + case editing_mode_e::circle: if (event->button() == Qt::LeftButton) { if (this->inputPolygon.bufferSize() == 3) { this->closeShape(); @@ -370,10 +370,10 @@ bool EditTools::usePolygon() const { switch (this->mode) { - case SelectMode: + case editing_mode_e::select: return false; - case DrawMode: - case CircleMode: + case editing_mode_e::draw: + case editing_mode_e::circle: return true; } return {};
--- a/src/layers/edittools.h Mon Apr 10 14:46:36 2023 +0300 +++ b/src/layers/edittools.h Tue Apr 11 11:11:28 2023 +0300 @@ -25,14 +25,14 @@ #include "src/gl/common.h" #include "src/inputvertices.h" -enum EditingMode +enum class editing_mode_e { - SelectMode, - DrawMode, - CircleMode + select, + draw, + circle }; -Q_DECLARE_METATYPE(EditingMode) +Q_DECLARE_METATYPE(editing_mode_e) Q_DECLARE_METATYPE(ModelAction) @@ -40,7 +40,7 @@ { Q_OBJECT InputVertices inputPolygon; - EditingMode mode = SelectMode; + editing_mode_e mode = editing_mode_e::select; glm::mat4 mvpMatrix; glm::mat4 gridMatrix{1}; Plane gridPlane; @@ -55,8 +55,8 @@ ~EditTools() override; void applyToVertices(VertexMap::ApplyFunction fn) const; [[nodiscard]] const QSet<ModelId> selectedObjects() const; - [[nodiscard]] EditingMode currentEditingMode() const; - Q_SLOT void setEditMode(EditingMode mode); + [[nodiscard]] editing_mode_e currentEditingMode() const; + Q_SLOT void setEditMode(editing_mode_e mode); Q_SLOT void setGridMatrix(const glm::mat4& gridMatrix); Q_SLOT void setCircleToolOptions(const CircleToolOptions& options); Q_SIGNALS:
--- a/src/main.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/main.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -238,7 +238,7 @@ QAction* action = new QAction{editingModeInfo.name, parent}; action->setCheckable(true); action->setEnabled(false); - action->setData(static_cast<EditingMode>(i)); + action->setData(QVariant::fromValue(static_cast<editing_mode_e>(i))); action->setToolTip(editingModeInfo.tooltip); action->setIcon(QPixmap{editingModeInfo.icon}); ui->editingModesToolBar->addAction(action); @@ -371,7 +371,7 @@ &EditTools::suggestCursor, data->canvas.get(), &QWidget::setCursor); - data->tools->setEditMode(SelectMode); + data->tools->setEditMode(editing_mode_e::select); const QFileInfo fileInfo{*state->documents.modelPath(modelId)}; auto* const subWindow = createSubWindow<ModelSubWindow>(state->mainWindow.mdiArea, modelId); subWindow->setMinimumSize({96, 96}); @@ -468,13 +468,13 @@ } } -static void checkEditingModeAction(MainState* state, const EditingMode mode) +static void checkEditingModeAction(MainState* state, const editing_mode_e mode) { const bool hasDocument = currentModelData(&state->mainWindow, &state->documents) != nullptr; for (QAction* action : state->mainWindow.editingModesToolBar->actions()) { action->setEnabled(hasDocument); - action->setChecked(hasDocument and action->data().value<EditingMode>() == mode); + action->setChecked(hasDocument and action->data().value<editing_mode_e>() == mode); } } @@ -502,6 +502,18 @@ update_model_grid_matrix(state); } +static void replace_color_in_selected_code(QTextCursor* cursor, const ColorIndex color) +{ + const auto pattern = R"(^(\s*(?:1|2|3|4|5)\s+)\d+)"; + static const QRegularExpression regular_expression{pattern, QRegularExpression::MultilineOption}; + QString text = cursor->selectedText(); + // Qt has decided to be "smart" and uses strange unicode characters instead of newlines + text.replace("\u2029", "\n"); + text.replace(regular_expression, QStringLiteral(R"(\1%1)").arg(color.index)); + cursor->removeSelectedText(); + cursor->insertText(text); +} + int main(int argc, char *argv[]) { doQtRegistrations(); @@ -609,7 +621,7 @@ { if (ModelData* data = currentModelData(&state.mainWindow, &state.documents)) { - const EditingMode mode = action->data().value<EditingMode>(); + const editing_mode_e mode = action->data().value<editing_mode_e>(); data->tools->setEditMode(mode); checkEditingModeAction(&state, mode); } @@ -631,7 +643,7 @@ } else { - checkEditingModeAction(&state, EditingMode::SelectMode); + checkEditingModeAction(&state, editing_mode_e::select); } state.mainWindow.modelEdit->setEnabled(modelSubWindow != nullptr); }); @@ -713,6 +725,14 @@ set_grid_scale(&state, 0.1f); } ); + QObject::connect( + state.mainWindow.action_make_stuff_red, + &QAction::triggered, + [&state]{ + QTextCursor cursor = state.mainWindow.modelEdit->textCursor(); + replace_color_in_selected_code(&cursor, ColorIndex{4}); + } + ); restoreSettings(&state); updateRenderPreferences(&state.mainWindow, &state.renderPreferences, &state.documents); const int result = app.exec();
--- a/src/mainwindow.ui Mon Apr 10 14:46:36 2023 +0300 +++ b/src/mainwindow.ui Tue Apr 11 11:11:28 2023 +0300 @@ -334,6 +334,7 @@ <addaction name="actionCopy"/> <addaction name="actionPaste"/> <addaction name="actionSelectAll"/> + <addaction name="action_make_stuff_red"/> </widget> <action name="actionQuit"> <property name="icon"> @@ -624,6 +625,11 @@ <string>Ctrl+Y</string> </property> </action> + <action name="action_make_stuff_red"> + <property name="text"> + <string>Make stuff red</string> + </property> + </action> </widget> <customwidgets> <customwidget>
--- a/src/model.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/model.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -115,44 +115,44 @@ QString result; result += QStringLiteral("1 %1 %2 %3") .arg(ref.color.index) - .arg(transformToString(ref.transformation)) - .arg(ref.name); + .arg(transformToString(ref.element.transformation)) + .arg(ref.element.name); return result; }, [](const Colored<LineSegment>& seg) { return QStringLiteral("2 %1 %2 %3") .arg(seg.color.index) - .arg(vertexToString(seg.p1)) - .arg(vertexToString(seg.p2)); + .arg(vertexToString(seg.element.p1)) + .arg(vertexToString(seg.element.p2)); }, [](const Colored<Triangle>& triangle) { return QStringLiteral("3 %1 %2 %3 %4") .arg(triangle.color.index) - .arg(vertexToString(triangle.p1)) - .arg(vertexToString(triangle.p2)) - .arg(vertexToString(triangle.p3)); + .arg(vertexToString(triangle.element.p1)) + .arg(vertexToString(triangle.element.p2)) + .arg(vertexToString(triangle.element.p3)); }, [](const Colored<Quadrilateral>& quad) { return QStringLiteral("4 %1 %2 %3 %4 %5") .arg(quad.color.index) - .arg(vertexToString(quad.p1)) - .arg(vertexToString(quad.p2)) - .arg(vertexToString(quad.p3)) - .arg(vertexToString(quad.p4)); + .arg(vertexToString(quad.element.p1)) + .arg(vertexToString(quad.element.p2)) + .arg(vertexToString(quad.element.p3)) + .arg(vertexToString(quad.element.p4)); }, [](const Colored<ConditionalEdge>& cedge) { return QStringLiteral("5 %1 %2 %3 %4 %5") .arg(cedge.color.index) - .arg(vertexToString(cedge.p1)) - .arg(vertexToString(cedge.p2)) - .arg(vertexToString(cedge.c1)) - .arg(vertexToString(cedge.c2)); + .arg(vertexToString(cedge.element.p1)) + .arg(vertexToString(cedge.element.p2)) + .arg(vertexToString(cedge.element.c1)) + .arg(vertexToString(cedge.element.c2)); }, [](const Colored<CircularPrimitive>& circ) { return QStringLiteral("1 %1 %2 %3") .arg(circ.color.index) - .arg(transformToString(circ.transformation)) - .arg(circularPrimitiveFilePath(circ)); + .arg(transformToString(circ.element.transformation)) + .arg(circularPrimitiveFilePath(circ.element)); }, [](const Comment& comment) { return "0 " + comment.text;
--- a/src/model.h Mon Apr 10 14:46:36 2023 +0300 +++ b/src/model.h Tue Apr 11 11:11:28 2023 +0300 @@ -30,8 +30,9 @@ }; template<typename T> -struct Colored : T +struct Colored { + T element; ldraw::Color color; };
--- a/src/polygoncache.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/polygoncache.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -10,13 +10,13 @@ } static PolygonElement transformed( - PolygonElement element, + PolygonElement coloredElement, const glm::mat4& transform) { visitPoints([&transform](glm::vec3& p) { p = transform * glm::vec4{p, 1}; - }, element); - return element; + }, coloredElement.element); + return coloredElement; } PolygonCache* findPolygonCacheForModel(QTextDocument* model, DocumentManager* context) @@ -59,13 +59,13 @@ Fn2&& reserve) { const bool needInverting = 0 - ^ (glm::determinant(ref.transformation) < 0) + ^ (glm::determinant(ref.element.transformation) < 0) ^ (context->invertnext); reserve(polygons.size()); for (const PolygonElement& cacheElement : polygons) { - PolygonElement polygon = transformed(cacheElement, ref.transformation); + PolygonElement polygon = transformed(cacheElement, ref.element.transformation); if (needInverting) { - gl::invert(polygon); + gl::invert(polygon.element); } if (polygon.color == MAIN_COLOR) { polygon.color = ref.color; @@ -106,19 +106,19 @@ } }, [&](const LineType2& line2) { - add(2, {line2.value, line2.value.color}); + add(2, {line2.value.element, line2.value.color}); }, [&](const LineType3& line3) { - add(3, {line3.value, line3.value.color}); + add(3, {line3.value.element, line3.value.color}); }, [&](const LineType4& line4) { - add(4, {line4.value, line4.value.color}); + add(4, {line4.value.element, line4.value.color}); }, [&](const LineType5& line5) { - add(5, {line5.value, line5.value.color}); + add(5, {line5.value.element, line5.value.color}); }, [&add, context, &reserve](const LineType1& line1) { - QTextDocument* const dependency = findDependency(line1.value, context); + QTextDocument* const dependency = findDependency(line1.value.element, context); if (PolygonCache* cache = (dependency != nullptr) ? findPolygonCacheForModel(dependency, context->documents) : nullptr @@ -153,7 +153,7 @@ const auto add = [&result, &winding, &i](int lineno, const PolygonElement& poly){ result.push_back({poly, i}); if (lineno != 1 and winding == winding_e::clockwise) { - gl::invert(result.back()); + gl::invert(result.back().element); } }; const auto reserve = [&result](std::size_t incomingsize){
--- a/src/triangulate.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/triangulate.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -151,10 +151,11 @@ } for (std::size_t i = 0; i < indices.size(); i += 3) { if (not mergedTriangles.cutTriangles.contains({i})) { - Triangle tri = triangle( - *(begin + indices[i]), - *(begin + indices[i + 1]), - *(begin + indices[i + 2])); + Triangle tri = Triangle{ + .p1 = *(begin + indices[i]), + .p2 = *(begin + indices[i + 1]), + .p3 = *(begin + indices[i + 2]), + }; result.push_back(tri); } }
--- a/src/vertexmap.cpp Mon Apr 10 14:46:36 2023 +0300 +++ b/src/vertexmap.cpp Tue Apr 11 11:11:28 2023 +0300 @@ -22,51 +22,50 @@ const glm::vec3& b; }; -inline void edges(const ModelElement& element, std::function<void(Edge&&)> fn) +static void edges(const PlainPolygonElement& element, std::function<void(Edge&&)> fn) { std::visit<void>(overloaded{ - [fn](const Colored<LineSegment>& edge) { + [fn](const LineSegment& edge) { fn(Edge{edge.p1, edge.p2}); }, - [fn](const Colored<Triangle>& triangle) { + [fn](const 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](const 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](const ConditionalEdge& cedge) { fn(Edge{cedge.p1, cedge.p2}); }, - [](const ModelElement&&){} }, element); } inline void points( - const ModelElement& element, + const PlainPolygonElement& element, std::function<void(const glm::vec3&)> fn) { std::visit<void>(overloaded{ - [fn](const Colored<LineSegment>& edge) { + [fn](const LineSegment& edge) { fn(edge.p1); fn(edge.p2); }, - [fn](const Colored<Triangle>& triangle) { + [fn](const Triangle& triangle) { fn(triangle.p1); fn(triangle.p2); fn(triangle.p3); }, - [fn](const Colored<Quadrilateral>& quad) { + [fn](const Quadrilateral& quad) { fn(quad.p1); fn(quad.p2); fn(quad.p3); fn(quad.p4); }, - [fn](const Colored<ConditionalEdge>& cedge) { + [fn](const ConditionalEdge& cedge) { fn(cedge.p1); fn(cedge.p2); fn(cedge.c1);