src/layers/edittools.cpp

changeset 314
4642ba1218e8
parent 312
2637134bc37c
child 315
23b47902d857
--- 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;
 }

mercurial