Added rudimentary cylinder extrusion into circle tool.

Fri, 01 Jul 2022 23:51:16 +0300

author
Teemu Piippo <teemu.s.piippo@gmail.com>
date
Fri, 01 Jul 2022 23:51:16 +0300
changeset 314
4642ba1218e8
parent 313
c24d87f64bed
child 315
23b47902d857

Added rudimentary cylinder extrusion into circle tool.
I really had to think which way the vectors are in this one

src/layers/edittools.cpp file | annotate | diff | comparison | revisions
src/layers/edittools.h file | annotate | diff | comparison | revisions
--- a/src/layers/edittools.cpp	Fri Jul 01 23:48:27 2022 +0300
+++ b/src/layers/edittools.cpp	Fri Jul 01 23:51:16 2022 +0300
@@ -84,6 +84,7 @@
 void EditTools::mouseMoved(const QMouseEvent* event)
 {
 	this->worldPosition = this->renderer->screenToModelCoordinates(event->pos(), this->gridPlane);
+	this->localPosition = event->localPos();
 	if (this->worldPosition.has_value())
 	{
 		// Snap the position to grid. This procedure is basically the "change of basis" and almost follows the
@@ -99,10 +100,7 @@
 		// grid matrix.
 		this->worldPosition = this->gridMatrix * glm::vec4{*this->worldPosition, 1};
 		this->polygon.back() = *this->worldPosition;
-	}
-	this->numpoints = this->polygon.size();
-	if (this->isCloseToExistingPoints()) {
-		this->numpoints -= 1;
+		this->numpoints = this->calcNumPoints();
 	}
 }
 
@@ -253,6 +251,11 @@
 	}
 }
 
+constexpr QPointF vecToQPoint(const glm::vec2& a)
+{
+	return {a.x, a.y};
+}
+
 void EditTools::renderPreview(QPainter* painter, const void* pensptr)
 {
 	const Pens& pens = *reinterpret_cast<const Pens*>(pensptr);
@@ -278,12 +281,43 @@
 	for (const glm::vec3& point : this->polygon) {
 		drawWorldPoint(painter, point, this->renderer);
 	}
+	if (this->mode == CircleMode and this->polygon.size() >= 2) {
+		const glm::vec3 circleOrigin = this->polygon[0];
+		const QPointF originScreen = this->renderer->modelToScreenCoordinates(circleOrigin);
+		const auto extremity = [this, &originScreen](const glm::vec3& p){
+			const QPointF s2 = this->renderer->modelToScreenCoordinates(p);
+			const auto intersection = rayRectangleIntersection(
+				rayFromPoints(toVec2(originScreen), toVec2(s2)),
+				this->renderer->rect());
+			if (intersection.has_value()) {
+				return intersection->position;
+			}
+			else {
+				return glm::vec2{s2.x(), s2.y()};
+			}
+		};
+		const glm::vec3 zvec = this->gridMatrix[2];
+		const glm::vec2 p1 = extremity(this->polygon[0] + zvec);
+		const glm::vec2 p2 = extremity(this->polygon[0] - zvec);
+		const glm::vec2 lateral = glm::normalize(glm::mat2{{0, 1}, {-1, 0}} * (p2 - p1));
+		painter->setPen(QPen{Qt::white, 3});
+		painter->drawLine(vecToQPoint(p1), vecToQPoint(p2));
+		constexpr float notchsize = 40.0f;
+		for (int a = -30; a <= 30; ++a) {
+			const glm::vec3 notch = this->polygon[0] + static_cast<float>(a) * zvec;
+			const QPointF s_notchcenter = this->renderer->modelToScreenCoordinates(notch);
+			const QPointF notch_s1 = s_notchcenter + notchsize * 0.5f * vecToQPoint(lateral);
+			const QPointF notch_s2 = s_notchcenter - notchsize * 0.5f * vecToQPoint(lateral);
+			painter->drawLine(notch_s1, notch_s2);
+		}
+	}
 }
 
 void EditTools::removeLastPoint()
 {
 	if (this->polygon.size() > 1) {
 		this->polygon.erase(this->polygon.end() - 2);
+		this->numpoints = this->calcNumPoints();
 	}
 }
 
@@ -300,6 +334,15 @@
 	}
 }
 
+std::size_t EditTools::calcNumPoints() const
+{
+	std::size_t result = this->polygon.size();
+	if (this->isCloseToExistingPoints()) {
+		result -= 1;
+	}
+	return result;
+}
+
 EditingMode EditTools::currentEditingMode() const
 {
 	return this->mode;
@@ -326,7 +369,7 @@
 		break;
 	case CircleMode:
 		if (event->button() == Qt::LeftButton and this->worldPosition.has_value()) {
-			if (this->polygon.size() == 2) {
+			if (this->polygon.size() == 3) {
 				this->closeShape();
 			}
 			else {
@@ -406,23 +449,39 @@
 const std::vector<ModelAction> EditTools::circleModeActions() const
 {
 	std::vector<ModelAction> result;
-	if (this->numpoints == 2) {
+	if (this->numpoints == 3) {
 		const glm::vec3 x = polygon[1] - polygon[0];
-		glm::mat4 transform{
-			glm::vec4{x, 0},
-			this->gridMatrix[2],
-			glm::vec4{glm::cross(glm::vec3{-this->gridMatrix[2]}, x), 0},
-			glm::vec4{this->polygon[0], 1},
-		};
-		Colored<CircularPrimitive> circ{
-			CircularPrimitive{
-				.type = this->circleToolOptions.type,
-				.fraction = this->circleToolOptions.fraction,
-				.transformation = transform,
-			},
-			MAIN_COLOR
-		};
-		result.push_back(AppendToModel{.newElement = circ});
+		const opt<float> cyliheight = [&]() -> opt<float> {
+			const Plane plane{
+				.normal = glm::normalize(this->renderer->cameraVector(this->localPosition)),
+				.anchor = this->polygon[0],
+			};
+			const opt<glm::vec3> p = this->renderer->screenToModelCoordinates(this->localPosition, plane);
+			if (p.has_value()) {
+				const glm::vec3 heightvec = glm::normalize(glm::vec3{gridMatrix[2]});
+				return std::round(glm::dot(*p - polygon[0], heightvec));
+			}
+			else {
+				return {};
+			}
+		}();
+		if (cyliheight.has_value()) {
+			glm::mat4 transform{
+				glm::vec4{x, 0},
+				*cyliheight * this->gridMatrix[2],
+				glm::vec4{glm::cross(glm::vec3{-this->gridMatrix[2]}, x), 0},
+				glm::vec4{this->polygon[0], 1},
+			};
+			Colored<CircularPrimitive> circ{
+				CircularPrimitive{
+					.type = this->circleToolOptions.type,
+					.fraction = this->circleToolOptions.fraction,
+					.transformation = transform,
+				},
+				MAIN_COLOR
+			};
+			result.push_back(AppendToModel{.newElement = circ});
+		}
 	}
 	return result;
 }
--- a/src/layers/edittools.h	Fri Jul 01 23:48:27 2022 +0300
+++ b/src/layers/edittools.h	Fri Jul 01 23:51:16 2022 +0300
@@ -44,6 +44,7 @@
 	glm::mat4 mvpMatrix;
 	glm::mat4 gridMatrix{1};
 	Plane gridPlane;
+	QPointF localPosition;
 	opt<glm::vec3> worldPosition;
 	CircleToolOptions circleToolOptions = {
 		.fraction = {16, 16},
@@ -53,8 +54,8 @@
 	explicit EditTools(QObject *parent = nullptr);
 	~EditTools() override;
 	void applyToVertices(VertexMap::ApplyFunction fn) const;
-	const QSet<ModelId> selectedObjects() const;
-	EditingMode currentEditingMode() const;
+	[[nodiscard]] const QSet<ModelId> selectedObjects() const;
+	[[nodiscard]] EditingMode currentEditingMode() const;
 	Q_SLOT void setEditMode(EditingMode mode);
 	Q_SLOT void setGridMatrix(const glm::mat4& gridMatrix);
 	Q_SLOT void setCircleToolOptions(const CircleToolOptions& options);
@@ -69,12 +70,13 @@
 	void mouseClick(const QMouseEvent* event) override;
 	void overpaint(QPainter* painter) override;
 private:
-	const std::vector<ModelAction> modelActions() const;
-	const std::vector<ModelAction> circleModeActions() const;
-	const std::vector<ModelAction> drawModeActions() const;
+	[[nodiscard]] const std::vector<ModelAction> modelActions() const;
+	[[nodiscard]] const std::vector<ModelAction> circleModeActions() const;
+	[[nodiscard]] const std::vector<ModelAction> drawModeActions() const;
 	bool usePolygon() const;
 	void closeShape();
 	void renderPreview(QPainter* painter, const void* pensptr);
 	void removeLastPoint();
-	bool isCloseToExistingPoints() const;
+	[[nodiscard]] bool isCloseToExistingPoints() const;
+	[[nodiscard]] std::size_t calcNumPoints() const;
 };

mercurial