# HG changeset patch # User Teemu Piippo # Date 1647366487 -7200 # Node ID a38a0eb007b06d7820fb6e20768199e32fde18f6 # Parent 35bbfad4d0f40e3e97c8b1dd57d643ad93e50b06 Added line path tool diff -r 35bbfad4d0f4 -r a38a0eb007b0 CMakeLists.txt --- a/CMakeLists.txt Tue Mar 15 18:56:02 2022 +0200 +++ b/CMakeLists.txt Tue Mar 15 19:48:07 2022 +0200 @@ -79,6 +79,7 @@ src/tools/basetool.cpp src/tools/selecttool.cpp src/tools/drawtool.cpp + src/tools/pathtool.cpp src/tools/transformtool.cpp ) set (LDFORGE_HEADERS @@ -139,6 +140,7 @@ src/tools/selecttool.h src/tools/basetool.h src/tools/drawtool.h + src/tools/pathtool.h src/tools/transformtool.h ) set (LDFORGE_FORMS diff -r 35bbfad4d0f4 -r a38a0eb007b0 icons/polyline.png Binary file icons/polyline.png has changed diff -r 35bbfad4d0f4 -r a38a0eb007b0 icons_svg/polyline.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/icons_svg/polyline.svg Tue Mar 15 19:48:07 2022 +0200 @@ -0,0 +1,1 @@ +ionicons-v5-a \ No newline at end of file diff -r 35bbfad4d0f4 -r a38a0eb007b0 ldforge.qrc --- a/ldforge.qrc Tue Mar 15 18:56:02 2022 +0200 +++ b/ldforge.qrc Tue Mar 15 19:48:07 2022 +0200 @@ -30,5 +30,6 @@ icons/trash-bin-outline.png icons/axes.png icons/invert.png + icons/polyline.png diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/document.cpp --- a/src/document.cpp Tue Mar 15 18:56:02 2022 +0200 +++ b/src/document.cpp Tue Mar 15 19:48:07 2022 +0200 @@ -24,6 +24,7 @@ #include "modeleditor.h" #include "tools/basetool.h" #include "tools/drawtool.h" +#include "tools/pathtool.h" #include "tools/selecttool.h" #include "tools/transformtool.h" @@ -83,7 +84,7 @@ { if (this->selectedTool != nullptr) { - this->selectedTool->mouseClick(this, canvas, event); + this->selectedTool->mouseClick(canvas, event); } }); connect(this->renderer, &Canvas::mouseMove, this, [this](Canvas* canvas, QMouseEvent* event) @@ -160,6 +161,7 @@ this->tools.reserve(3); this->tools.push_back(new SelectTool{this}); this->tools.push_back(new DrawTool{this}); + this->tools.push_back(new PathTool{this}); this->tools.push_back(new TransformTool{this}); for (BaseTool* const toolInstance : this->tools) { diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/tools/basetool.h --- a/src/tools/basetool.h Tue Mar 15 18:56:02 2022 +0200 +++ b/src/tools/basetool.h Tue Mar 15 19:48:07 2022 +0200 @@ -14,7 +14,7 @@ virtual QString name() const = 0; virtual QString toolTip() const = 0; - virtual bool mouseClick(Document*, Canvas*, QMouseEvent*) { return false; } + virtual bool mouseClick(Canvas*, QMouseEvent*) { return false; } virtual bool mouseDoubleClicked(QMouseEvent*, QMouseEvent*) { return false; } virtual bool mouseMove(Document*, Canvas*, QMouseEvent*) { return false; } virtual bool keyReleased(Document*, Canvas*, QKeyEvent*) { return false; } diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/tools/drawtool.cpp --- a/src/tools/drawtool.cpp Tue Mar 15 18:56:02 2022 +0200 +++ b/src/tools/drawtool.cpp Tue Mar 15 19:48:07 2022 +0200 @@ -13,8 +13,13 @@ static const QBrush greenPolygonBrush = {QColor{64, 255, 128, 192}}; static const QBrush redPolygonBrush = {QColor{255, 96, 96, 192}}; +AbstractDrawTool::AbstractDrawTool(Document *document) : + BaseTool{document} +{ +} + DrawTool::DrawTool(Document* document) : - BaseTool{document} + AbstractDrawTool{document} { } @@ -30,35 +35,16 @@ return result; } -bool DrawTool::mouseClick(Document* document, Canvas* canvas, QMouseEvent* event) +bool AbstractDrawTool::mouseClick(Canvas* canvas, QMouseEvent* event) { if (event->button() == Qt::LeftButton) { - const auto& worldPosition = canvas->getWorldPosition(); - if (worldPosition.has_value()) - { - const glm::vec3& pos = worldPosition.value(); - const auto isCloseToPos = [&](const glm::vec3& x){return geom::isclose(x, pos);}; - if (any(this->polygon, isCloseToPos)) - { - this->closeShape(document); - } - else - { - this->polygon.push_back(pos); - if (this->polygon.size() == 4) - { - this->closeShape(document); - } - } - } - this->previewPolygon = this->polygon; + this->addCurrentPoint(canvas); return true; } - else if (event->button() == Qt::RightButton and this->polygon.size() > 0) + else if (event->button() == Qt::RightButton) { - this->polygon.erase(this->polygon.end() - 1); - this->updatePreviewPolygon(); + this->removeLastPoint(); return true; } else @@ -67,7 +53,7 @@ } } -bool DrawTool::mouseMove(Document* document, Canvas* canvas, QMouseEvent *event) +bool AbstractDrawTool::mouseMove(Document* document, Canvas* canvas, QMouseEvent *event) { static_cast(document); static_cast(event); @@ -75,15 +61,12 @@ if (worldPosition.has_value()) { this->previewPoint = worldPosition.value(); - if (this->polygon.size() < 4) - { - this->updatePreviewPolygon(); - } + this->updatePreviewPolygon(); } return false; } -bool DrawTool::keyReleased(Document*, Canvas* canvas, QKeyEvent* event) +bool AbstractDrawTool::keyReleased(Document*, Canvas* canvas, QKeyEvent* event) { if (event->key() == Qt::Key_Escape) { @@ -98,8 +81,26 @@ } } -void DrawTool::updatePreviewPolygon() +void AbstractDrawTool::addCurrentPoint(Canvas* canvas) { + const auto& worldPosition = canvas->getWorldPosition(); + if (worldPosition.has_value()) + { + const glm::vec3& pos = worldPosition.value(); + if (this->isCloseToExistingPoints(pos)) + { + this->closeShape(); + } + else + { + this->addPoint(pos); + } + } +} + +void AbstractDrawTool::updatePreviewPolygon() +{ + this->previewPolygon = this->polygon; this->previewPolygon.resize(this->polygon.size() + 1); this->previewPolygon.back() = this->previewPoint; if (this->previewPolygon.size() > 2) @@ -108,12 +109,12 @@ } } -void DrawTool::reset() +void AbstractDrawTool::reset() { this->polygon.clear(); } -void DrawTool::overpaint(Canvas* canvas, QPainter* painter) const +void AbstractDrawTool::overpaint(Canvas* canvas, QPainter* painter) const { painter->setPen(this->isconcave ? ::badPolygonPen : ::polygonPen); if (this->previewPolygon.size() > 2 and not this->isconcave) @@ -138,17 +139,53 @@ { canvas->drawWorldPoint(painter, point); } - if (this->polygon.size() < 4) + canvas->drawWorldPoint(painter, this->previewPoint); +} + +void AbstractDrawTool::addPoint(const glm::vec3 &pos) +{ + this->polygon.push_back(pos); + this->updatePreviewPolygon(); +} + +void AbstractDrawTool::removeLastPoint() +{ + if (this->polygon.size() > 0) { - canvas->drawWorldPoint(painter, this->previewPoint); + this->polygon.erase(this->polygon.end() - 1); + this->updatePreviewPolygon(); } } +void AbstractDrawTool::clearPoints() +{ + this->polygon.clear(); + this->updatePreviewPolygon(); +} + +bool AbstractDrawTool::isCloseToExistingPoints(const glm::vec3 &pos) const +{ + const auto isCloseToPos = [&](const glm::vec3& x) + { + return geom::isclose(x, pos); + }; + return any(this->polygon, isCloseToPos); +} + QString DrawTool::iconName() const { return ":/icons/pencil-outline.png"; } +void DrawTool::addPoint(const glm::vec3 &pos) +{ + AbstractDrawTool::addPoint(pos); + if (this->polygon.size() == 4) + { + this->closeShape(); + } +} + template std::array vectorToArray(const std::vector& x) { @@ -160,11 +197,11 @@ return result; } -void DrawTool::closeShape(Document* document) +void DrawTool::closeShape() { if (this->polygon.size() >= 2 and this->polygon.size() <= 4) { - std::unique_ptr modelEditor = document->editModel(); + std::unique_ptr modelEditor = this->document->editModel(); switch (this->polygon.size()) { case 2: @@ -178,5 +215,5 @@ break; } } - this->polygon.clear(); + this->clearPoints(); } diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/tools/drawtool.h --- a/src/tools/drawtool.h Tue Mar 15 18:56:02 2022 +0200 +++ b/src/tools/drawtool.h Tue Mar 15 19:48:07 2022 +0200 @@ -1,7 +1,30 @@ #pragma once #include "basetool.h" -class DrawTool : public BaseTool +class AbstractDrawTool : public BaseTool +{ +public: + AbstractDrawTool(Document* document); + void reset() override; + void overpaint(Canvas*, QPainter*) const override; + bool mouseMove(Document* document, Canvas* canvas, QMouseEvent* event) override; + bool mouseClick(Canvas* canvas, QMouseEvent* event) override; + bool keyReleased(Document*, Canvas* canvas, QKeyEvent* event) override; +protected: + void addCurrentPoint(Canvas *canvas); + virtual void addPoint(const glm::vec3& pos); + virtual void closeShape() = 0; + void removeLastPoint(); + void clearPoints(); + bool isCloseToExistingPoints(const glm::vec3& pos) const; + std::vector polygon; + std::vector previewPolygon; + glm::vec3 previewPoint; + bool isconcave = false; + void updatePreviewPolygon(); +}; + +class DrawTool : public AbstractDrawTool { Q_OBJECT @@ -10,17 +33,8 @@ QString name() const override; QString toolTip() const override; - bool mouseClick(Document* document, Canvas* canvas, QMouseEvent* event) override; - bool mouseMove(Document* document, Canvas* canvas, QMouseEvent* event) override; - bool keyReleased(Document*, Canvas* canvas, QKeyEvent* event) override; - void reset() override; - void overpaint(Canvas*, QPainter*) const override; QString iconName() const override; -private: - void closeShape(Document *document); - std::vector polygon; - std::vector previewPolygon; - glm::vec3 previewPoint; - bool isconcave = false; - void updatePreviewPolygon(); +protected: + virtual void addPoint(const glm::vec3& pos) override; + void closeShape() override; }; diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/tools/pathtool.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/pathtool.cpp Tue Mar 15 19:48:07 2022 +0200 @@ -0,0 +1,48 @@ +#include "pathtool.h" +#include "modeleditor.h" +#include "linetypes/edge.h" +#include "document.h" + +PathTool::PathTool(Document *document) : + AbstractDrawTool{document} +{ +} + +QString PathTool::name() const +{ + return tr("Draw path"); +} + +QString PathTool::toolTip() const +{ + return tr("Draw paths"); +} + +void PathTool::overpaint(Canvas* canvas, QPainter* painter) const +{ + painter->setPen(QPen{Qt::black, 2, Qt::DashLine, Qt::RoundCap, Qt::MiterJoin}); + if (this->previewPolygon.size() >= 2) + { + canvas->drawWorldPolyline(painter, this->previewPolygon); + } + for (const glm::vec3& point : this->polygon) + { + canvas->drawWorldPoint(painter, point); + } + canvas->drawWorldPoint(painter, this->previewPoint); +} + +QString PathTool::iconName() const +{ + return ":/icons/polyline.png"; +} + +void PathTool::closeShape() +{ + std::unique_ptr modelEditor = this->document->editModel(); + for (std::size_t i = 0; i < this->polygon.size() - 1; i += 1) + { + modelEditor->append(std::array{this->polygon[i], this->polygon[i + 1]}, ldraw::EDGE_COLOR); + } + this->clearPoints(); +} diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/tools/pathtool.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/tools/pathtool.h Tue Mar 15 19:48:07 2022 +0200 @@ -0,0 +1,15 @@ +#pragma once +#include "drawtool.h" + +class PathTool : public AbstractDrawTool +{ + Q_OBJECT + +public: + Q_INVOKABLE PathTool(Document* document); + QString name() const override; + QString toolTip() const override; + void overpaint(Canvas*canvas, QPainter*painter) const override; + QString iconName() const override; + void closeShape() override; +}; diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/tools/selecttool.cpp --- a/src/tools/selecttool.cpp Tue Mar 15 18:56:02 2022 +0200 +++ b/src/tools/selecttool.cpp Tue Mar 15 19:48:07 2022 +0200 @@ -18,11 +18,10 @@ return result; } -bool SelectTool::mouseClick(Document* document, Canvas* canvas, QMouseEvent* event) +bool SelectTool::mouseClick(Canvas* canvas, QMouseEvent* event) { if (event->button() == Qt::LeftButton) { - static_cast(document); const ldraw::id_t highlighted = canvas->getHighlightedObject(); canvas->clearSelection(); if (highlighted != ldraw::NULL_ID) diff -r 35bbfad4d0f4 -r a38a0eb007b0 src/tools/selecttool.h --- a/src/tools/selecttool.h Tue Mar 15 18:56:02 2022 +0200 +++ b/src/tools/selecttool.h Tue Mar 15 19:48:07 2022 +0200 @@ -10,7 +10,7 @@ Q_INVOKABLE SelectTool(Document *document); QString name() const override; QString toolTip() const override; - bool mouseClick(Document*, Canvas*, QMouseEvent*) override; + bool mouseClick(Canvas*, QMouseEvent*) override; QWidget* toolWidget() override; void selectionChanged(const QSet &newSelection) override; QString iconName() const override;