grid snapping now also works with transformed grids

Sat, 29 Feb 2020 23:43:38 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Sat, 29 Feb 2020 23:43:38 +0200
changeset 64
f99d52b1646b
parent 63
f7dd937667a5
child 65
87c906545fc3

grid snapping now also works with transformed grids

src/geometry.cpp file | annotate | diff | comparison | revisions
src/geometry.h file | annotate | diff | comparison | revisions
src/gl/gridprogram.cpp file | annotate | diff | comparison | revisions
src/gl/gridprogram.h file | annotate | diff | comparison | revisions
src/main.h file | annotate | diff | comparison | revisions
src/ui/canvas.cpp file | annotate | diff | comparison | revisions
src/ui/canvas.h file | annotate | diff | comparison | revisions
--- a/src/geometry.cpp	Fri Feb 28 19:24:33 2020 +0200
+++ b/src/geometry.cpp	Sat Feb 29 23:43:38 2020 +0200
@@ -1,3 +1,4 @@
+#include <glm/gtc/matrix_transform.hpp>
 #include "geometry.h"
 
 /**
@@ -38,7 +39,7 @@
  */
 geom::Plane geom::planeFromTriangle(const geom::Triangle& triangle)
 {
-	return geom::Plane{triangle.points[0], normalVector(triangle)};
+	return geom::Plane{normalVector(triangle), triangle.points[0]};
 }
 
 /**
@@ -53,3 +54,31 @@
 			triangle.points[1] - triangle.points[0],
 			triangle.points[2] - triangle.points[0]));
 }
+
+/**
+ * @brief Extracts the scaling component of the specified matrix into a vector and returns both the scaling
+ * components as well as the unscaled matrix.
+ * @param matrix Matrix to compute
+ * @return scaling vector and unscaled matrix
+ */
+geom::ScalingExtract geom::extractScaling(const glm::mat4& matrix)
+{
+	geom::ScalingExtract result;
+	result.scaling = geom::scalingVector(matrix);
+	result.unscaled = glm::scale(matrix, 1.0f / result.scaling);
+	return result;
+}
+
+/**
+ * @brief Computes the scaling vector, which contains the scaling of the specified matrix
+ * @param matrix
+ * @return scaling vector
+ */
+glm::vec3 geom::scalingVector(const glm::mat4 matrix)
+{
+	auto component = [](const glm::mat4& matrix, const int i) -> float
+	{
+		return std::hypot(std::hypot(matrix[i][0], matrix[i][1]), matrix[i][2]);
+	};
+	return glm::vec3{component(matrix, 0), component(matrix, 1), component(matrix, 2)};
+}
--- a/src/geometry.h	Fri Feb 28 19:24:33 2020 +0200
+++ b/src/geometry.h	Sat Feb 29 23:43:38 2020 +0200
@@ -30,5 +30,12 @@
 	Line lineFromPoints(const glm::vec3& point_1, const glm::vec3 point_2);
 	Plane planeFromTriangle(const Triangle& triangle);
 	glm::vec3 normalVector(const Triangle& triangle);
-	std::optional<glm::vec3> linePlaneIntersection(const Line& line, const Plane& plane, const float epsilon = 1e-6);
+	std::optional<glm::vec3> linePlaneIntersection(const Line& line, const Plane& plane, const float epsilon = 1e-6f);
+	glm::vec3 scalingVector(const glm::mat4 matrix);
+	struct ScalingExtract
+	{
+		glm::vec3 scaling;
+		glm::mat4 unscaled;
+	};
+	ScalingExtract extractScaling(const glm::mat4& matrix);
 }
--- a/src/gl/gridprogram.cpp	Fri Feb 28 19:24:33 2020 +0200
+++ b/src/gl/gridprogram.cpp	Sat Feb 29 23:43:38 2020 +0200
@@ -28,11 +28,11 @@
 uniform mat4 model;
 smooth out vec2 ex_uv;
 const mat4 stretch = mat4(vec4(10000, 0, 0, 0), vec4(0, 10000, 0, 0), vec4(0, 0, 10000, 0), vec4(0, 0, 0, 1));
-const mat4 gridmatrix = mat4(vec4(1, 0, 0, 0), vec4(0, 1, 0, 0), vec4(0, 0, 1, 0), vec4(0, 0, 0, 1));
+uniform mat4 grid;
 
 void main()
 {
-	gl_Position = projection * view * model * gridmatrix * stretch * vec4(in_position, 0.0, 1.0);
+	gl_Position = projection * view * model * grid * stretch * vec4(in_position, 0.0, 1.0);
 	ex_uv = in_position;
 }
 )";
@@ -99,27 +99,29 @@
 
 void GridProgram::setViewMatrix(const glm::mat4& newViewMatrix)
 {
-	Q_ASSERT(this->isInitialized);
-	this->program->bind();
-	this->program->setUniformMatrix("view", newViewMatrix);
-	this->program->release();
-	this->checkForGLErrors();
+	this->setMatrix("view", newViewMatrix);
 }
 
 void GridProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix)
 {
-	Q_ASSERT(this->isInitialized);
-	this->program->bind();
-	this->program->setUniformMatrix("projection", newProjectionMatrix);
-	this->program->release();
-	this->checkForGLErrors();
+	this->setMatrix("projection", newProjectionMatrix);
 }
 
 void GridProgram::setModelMatrix(const glm::mat4& newModelMatrix)
 {
+	this->setMatrix("model", newModelMatrix);
+}
+
+void GridProgram::setGridMatrix(const glm::mat4& newGridMatrix)
+{
+	this->setMatrix("grid", newGridMatrix);
+}
+
+void GridProgram::setMatrix(const char* name, const glm::mat4& matrix)
+{
 	Q_ASSERT(this->isInitialized);
 	this->program->bind();
-	this->program->setUniformMatrix("model", newModelMatrix);
+	this->program->setUniformMatrix(name, matrix);
 	this->program->release();
 	this->checkForGLErrors();
 }
--- a/src/gl/gridprogram.h	Fri Feb 28 19:24:33 2020 +0200
+++ b/src/gl/gridprogram.h	Sat Feb 29 23:43:38 2020 +0200
@@ -31,11 +31,13 @@
 	void setViewMatrix(const glm::mat4& newViewMatrix);
 	void setProjectionMatrix(const glm::mat4& newProjectionMatrix);
 	void setModelMatrix(const glm::mat4& newModelMatrix);
+	void setGridMatrix(const glm::mat4& newGridMatrix);
 	void setGridColor(const QColor& newGridColor);
 	void operator=(GridProgram) = delete;
 	void draw();
 	void teardown();
 private:
+	void setMatrix(const char* name, const glm::mat4& matrix);
 	void checkForGLErrors();
 	bool isInitialized = false;
 	QOpenGLBuffer buffer;
--- a/src/main.h	Fri Feb 28 19:24:33 2020 +0200
+++ b/src/main.h	Sat Feb 29 23:43:38 2020 +0200
@@ -87,3 +87,27 @@
 {
 	vector.reserve(vector.size() + amount);
 }
+
+inline QString vectorToString(const glm::vec2& vec)
+{
+	return "(%1, %2)"_q
+		.arg(toDouble(vec.x))
+		.arg(toDouble(vec.y));
+}
+
+inline QString vectorToString(const glm::vec3& vec)
+{
+	return "(%1, %2, %3)"_q
+		.arg(toDouble(vec.x))
+		.arg(toDouble(vec.y))
+		.arg(toDouble(vec.z));
+}
+
+inline QString vectorToString(const glm::vec4& vec)
+{
+	return "(%1, %2, %3, %4)"_q
+		.arg(toDouble(vec.x))
+		.arg(toDouble(vec.y))
+		.arg(toDouble(vec.z))
+		.arg(toDouble(vec.w));
+}
--- a/src/ui/canvas.cpp	Fri Feb 28 19:24:33 2020 +0200
+++ b/src/ui/canvas.cpp	Sat Feb 29 23:43:38 2020 +0200
@@ -22,23 +22,17 @@
 	this->update();
 }
 
-QString vectorToString(const glm::vec3& vec)
-{
-	return "(%1, %2, %3)"_q
-		.arg(toDouble(vec.x))
-		.arg(toDouble(vec.y))
-		.arg(toDouble(vec.z));
-}
-
 void Canvas::mouseMoveEvent(QMouseEvent* event)
 {
 	const ldraw::Id id = this->pick(event->pos());
 	this->highlighted = id;
 	this->totalMouseMove += (event->pos() - this->lastMousePosition).manhattanLength();
-	this->worldPosition = this->screenToModelCoordinates(event->pos(), geom::XY);
+	this->worldPosition = this->screenToModelCoordinates(event->pos(), this->gridPlane);
 	if (this->worldPosition.has_value())
 	{
+		this->worldPosition = glm::inverse(this->gridMatrix) * glm::vec4{*this->worldPosition, 1};
 		this->worldPosition = glm::round(*this->worldPosition);
+		this->worldPosition = this->gridMatrix * glm::vec4{*this->worldPosition, 1};
 	}
 	if (this->worldPosition.has_value())
 	{
@@ -107,6 +101,13 @@
 		}
 	});
 	PartRenderer::initializeGL();
+	this->gridMatrix = glm::mat4{
+		{-4, 0, 0, 0},
+		{0, 6.9266, -3.6955, 0},
+		{0, -16.7222, -1.5307, 0},
+		{0, -13.273, -9.255, 1},
+	};
+	this->updateGridMatrix();
 }
 
 void Canvas::paintGL()
@@ -127,4 +128,31 @@
 		painter.setPen(Qt::white);
 		painter.drawText(pos + QPointF{5, 5}, vectorToString(*this->worldPosition));
 	}
+	{
+		QPainter axisPainter{this};
+		axisPainter.setRenderHint(QPainter::Antialiasing);
+		axisPainter.setPen(Qt::red);
+		axisPainter.drawLine(
+			this->modelToScreenCoordinates({10, 0, 0}),
+			this->modelToScreenCoordinates({-10, 0, 0}));
+		axisPainter.setPen(Qt::green);
+		axisPainter.drawLine(
+			this->modelToScreenCoordinates({0, 10, 0}),
+			this->modelToScreenCoordinates({0, -10, 0}));
+		axisPainter.setPen(Qt::blue);
+		axisPainter.drawLine(
+			this->modelToScreenCoordinates({0, 0, 10}),
+			this->modelToScreenCoordinates({0, 0, -10}));
+	}
 }
+
+void Canvas::updateGridMatrix()
+{
+	const geom::Triangle triangle {
+		this->gridMatrix * glm::vec4{0, 0, 0, 1},
+		this->gridMatrix * glm::vec4{1, 0, 0, 1},
+		this->gridMatrix * glm::vec4{0, 1, 0, 1},
+	};
+	this->gridPlane = geom::planeFromTriangle(triangle);
+	this->gridProgram->setGridMatrix(this->gridMatrix);
+}
--- a/src/ui/canvas.h	Fri Feb 28 19:24:33 2020 +0200
+++ b/src/ui/canvas.h	Sat Feb 29 23:43:38 2020 +0200
@@ -23,8 +23,11 @@
 	void newStatusText(const QString& newStatusText);
 	void selectionChanged(const QSet<ldraw::Id>& newSelection);
 private:
+	void updateGridMatrix();
 	std::optional<GridProgram> gridProgram;
 	std::optional<glm::vec3> worldPosition;
+	glm::mat4 gridMatrix;
+	geom::Plane gridPlane;
 	int totalMouseMove = 0;
 	QSet<ldraw::Id> selection;
 };

mercurial