added a method to find out if the view is perpendicular to grid

Mon, 02 Mar 2020 11:08:13 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Mon, 02 Mar 2020 11:08:13 +0200
changeset 66
77c819262b7a
parent 65
87c906545fc3
child 67
612213a168da

added a method to find out if the view is perpendicular to grid

src/gl/partrenderer.cpp file | annotate | diff | comparison | revisions
src/gl/partrenderer.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/gl/partrenderer.cpp	Sat Feb 29 23:51:03 2020 +0200
+++ b/src/gl/partrenderer.cpp	Mon Mar 02 11:08:13 2020 +0200
@@ -281,15 +281,13 @@
  * @param plane Plane to raycast against
  * @return world co-ordinates, or no value if the point is behind the camera.
  */
-std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point, const geom::Plane& plane)
+std::optional<glm::vec3> PartRenderer::screenToModelCoordinates(const QPoint& point, const geom::Plane& plane) const
 {
-	const glm::vec3 p1 = this->unproject({point.x(), point.y(), 0});
-	const glm::vec3 p2 = this->unproject({point.x(), point.y(), 1});
-	const geom::Line line = geom::lineFromPoints(p1, p2);
+	const geom::Line line = this->cameraLine(point);
 	std::optional<glm::vec3> result;
 	result = geom::linePlaneIntersection(line, plane, 0.01f);
 	// If the point lies behind the camera, do not return a result.
-	if (result.has_value() and glm::dot(line.direction, *result - p1) < 0)
+	if (result.has_value() and glm::dot(line.direction, *result - line.anchor) < 0)
 	{
 		result.reset();
 	}
@@ -301,7 +299,7 @@
  * @param point Point to unproject
  * @return screen coordinates
  */
-QPointF PartRenderer::modelToScreenCoordinates(const glm::vec3& point)
+QPointF PartRenderer::modelToScreenCoordinates(const glm::vec3& point) const
 {
 	const glm::vec3 projected = glm::project(
 		point,
@@ -311,12 +309,19 @@
 	return toQPointF(glm::vec2{projected.x, this->height() - projected.y});
 }
 
+geom::Line PartRenderer::cameraLine(const QPoint& point) const
+{
+	const glm::vec3 p1 = this->unproject({point.x(), point.y(), 0});
+	const glm::vec3 p2 = this->unproject({point.x(), point.y(), 1});
+	return geom::lineFromPoints(p1, p2);
+}
+
 /**
  * @brief Unprojects the specified window coordinates to model coordinates
  * @param win Window coordinates to project. Z-coordinate indicates depth
  * @return model coordinates
  */
-glm::vec3 PartRenderer::unproject(const glm::vec3& win)
+glm::vec3 PartRenderer::unproject(const glm::vec3& win) const
 {
 	return glm::unProject(
 		glm::vec3{win.x, this->height() - win.y, win.z},
--- a/src/gl/partrenderer.h	Sat Feb 29 23:51:03 2020 +0200
+++ b/src/gl/partrenderer.h	Mon Mar 02 11:08:13 2020 +0200
@@ -34,9 +34,10 @@
 	const ldraw::ColorTable& colorTable;
 	gl::Compiler* const compiler;
 	ldraw::Id highlighted = ldraw::NULL_ID;
-	std::optional<glm::vec3> screenToModelCoordinates(const QPoint& point, const geom::Plane& plane);
-	QPointF modelToScreenCoordinates(const glm::vec3& point);
-	glm::vec3 unproject(const glm::vec3& win);
+	std::optional<glm::vec3> screenToModelCoordinates(const QPoint& point, const geom::Plane& plane) const;
+	QPointF modelToScreenCoordinates(const glm::vec3& point) const;
+	geom::Line cameraLine(const QPoint& point) const;
+	glm::vec3 unproject(const glm::vec3& win) const;
 	glm::mat4 projectionMatrix;
 	glm::mat4 viewMatrix;
 	glm::mat4 modelMatrix;
--- a/src/ui/canvas.cpp	Sat Feb 29 23:51:03 2020 +0200
+++ b/src/ui/canvas.cpp	Mon Mar 02 11:08:13 2020 +0200
@@ -45,6 +45,7 @@
 		// grid matrix.
 		this->worldPosition = this->gridMatrix * glm::vec4{*this->worldPosition, 1};
 	}
+	/*
 	if (this->worldPosition.has_value())
 	{
 		this->newStatusText("Position: (%1, %2, %3)"_q
@@ -56,6 +57,10 @@
 	{
 		this->newStatusText("Position: <none>"_q);
 	}
+	*/
+	// use a relatively high threshold so that we know when the grid is somewhat perpendicular so we can
+	// automatically change it properly
+	this->newStatusText("Change: %1"_q.arg(isGridPerpendicularToScreen(0.03f) ? "yes" : "no"));
 	PartRenderer::mouseMoveEvent(event);
 }
 
@@ -167,3 +172,23 @@
 	this->gridPlane = geom::planeFromTriangle(triangle);
 	this->gridProgram->setGridMatrix(this->gridMatrix);
 }
+
+/**
+ * @brief Calculates if the screen is perpendicular to the current grid
+ * @return yes no
+ */
+bool Canvas::isGridPerpendicularToScreen(float threshold) const
+{
+	// Find out where the grid is projected on the screen
+	const QPoint gridOrigin2d = pointFToPoint(this->modelToScreenCoordinates(this->gridPlane.anchor));
+	// Find out which direction the camera is looking at the grid origin in 3d
+	const glm::vec3 cameraDirection = glm::normalize(this->cameraLine(gridOrigin2d).direction);
+	// Compute the dot product. The parameters given are:
+	// - the normal of the grid plane, which is the vector from the grid origin perpendicular to the grid
+	// - the direction of the camera looking at the grid, which is the inverse of the vector from the grid
+	//   origin towards the camera
+	// If the dot product between these two vectors is 0, the grid normal is perpendicular to the camera vector
+	// and the grid is perpendicular to the screen.
+	const float dot = glm::dot(glm::normalize(this->gridPlane.normal), glm::normalize(cameraDirection));
+	return std::abs(dot) < threshold;
+}
--- a/src/ui/canvas.h	Sat Feb 29 23:51:03 2020 +0200
+++ b/src/ui/canvas.h	Mon Mar 02 11:08:13 2020 +0200
@@ -24,6 +24,7 @@
 	void selectionChanged(const QSet<ldraw::Id>& newSelection);
 private:
 	void updateGridMatrix();
+	bool isGridPerpendicularToScreen(float threshold) const;
 	std::optional<GridProgram> gridProgram;
 	std::optional<glm::vec3> worldPosition;
 	glm::mat4 gridMatrix;

mercurial