Added line path tool

Tue, 15 Mar 2022 19:48:07 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Tue, 15 Mar 2022 19:48:07 +0200
changeset 185
a38a0eb007b0
parent 184
35bbfad4d0f4
child 186
922662adb72a

Added line path tool

CMakeLists.txt file | annotate | diff | comparison | revisions
icons/polyline.png file | annotate | diff | comparison | revisions
icons_svg/polyline.svg file | annotate | diff | comparison | revisions
ldforge.qrc file | annotate | diff | comparison | revisions
src/document.cpp file | annotate | diff | comparison | revisions
src/tools/basetool.h file | annotate | diff | comparison | revisions
src/tools/drawtool.cpp file | annotate | diff | comparison | revisions
src/tools/drawtool.h file | annotate | diff | comparison | revisions
src/tools/pathtool.cpp file | annotate | diff | comparison | revisions
src/tools/pathtool.h file | annotate | diff | comparison | revisions
src/tools/selecttool.cpp file | annotate | diff | comparison | revisions
src/tools/selecttool.h file | annotate | diff | comparison | revisions
--- 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
Binary file icons/polyline.png has changed
--- /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 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5-a</title><line x1="344" y1="280" x2="432" y2="192" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="232" y1="216" x2="296" y2="280" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><line x1="80" y1="320" x2="184" y2="216" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><circle cx="456" cy="168" r="24" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><circle cx="320" cy="304" r="24" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><circle cx="208" cy="192" r="24" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/><circle cx="56" cy="344" r="24" style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>
\ No newline at end of file
--- 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 @@
         <file>icons/trash-bin-outline.png</file>
         <file>icons/axes.png</file>
         <file>icons/invert.png</file>
+        <file>icons/polyline.png</file>
     </qresource>
 </RCC>
--- 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)
 	{
--- 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; }
--- 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<void>(document);
 	static_cast<void>(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::size_t N, typename T>
 std::array<T, N> vectorToArray(const std::vector<T>& 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> modelEditor = document->editModel();
+		std::unique_ptr<ModelEditor> modelEditor = this->document->editModel();
 		switch (this->polygon.size())
 		{
 		case 2:
@@ -178,5 +215,5 @@
 			break;
 		}
 	}
-	this->polygon.clear();
+	this->clearPoints();
 }
--- 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<glm::vec3> polygon;
+	std::vector<glm::vec3> 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<glm::vec3> polygon;
-	std::vector<glm::vec3> previewPolygon;
-	glm::vec3 previewPoint;
-	bool isconcave = false;
-	void updatePreviewPolygon();
+protected:
+	virtual void addPoint(const glm::vec3& pos) override;
+	void closeShape() override;
 };
--- /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> modelEditor = this->document->editModel();
+	for (std::size_t i = 0; i < this->polygon.size() - 1; i += 1)
+	{
+		modelEditor->append<ldraw::Edge>(std::array{this->polygon[i], this->polygon[i + 1]}, ldraw::EDGE_COLOR);
+	}
+	this->clearPoints();
+}
--- /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;
+};
--- 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<void>(document);
 		const ldraw::id_t highlighted = canvas->getHighlightedObject();
 		canvas->clearSelection();
 		if (highlighted != ldraw::NULL_ID)
--- 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<ldraw::id_t> &newSelection) override;
 	QString iconName() const override;

mercurial