Wed, 08 Feb 2017 16:25:06 +0200
Switched from euler angle rotation to matrix rotation. Gimbal lock is now broken.
src/format.h | file | annotate | diff | comparison | revisions | |
src/glRenderer.cpp | file | annotate | diff | comparison | revisions | |
src/glRenderer.h | file | annotate | diff | comparison | revisions |
--- a/src/format.h Sat Feb 04 14:44:39 2017 +0200 +++ b/src/format.h Wed Feb 08 16:25:06 2017 +0200 @@ -18,10 +18,10 @@ #pragma once #include <QIODevice> +#include <QGenericMatrix> #include "basics.h" #include "colors.h" - // Converts a given value into a string that can be retrieved with text(). // Used as the argument type to the formatting functions, hence its name. class StringFormatArg @@ -62,6 +62,29 @@ m_text += "}"; } + template<int Columns, int Rows, typename Type> + StringFormatArg(const QGenericMatrix<Columns, Rows, Type>& matrix) + { + m_text = "{"; + for (int row = 0; row < Rows; ++row) + { + if (row > 0) + m_text += ", "; + + m_text += "{"; + + for (int column = 0; column < Rows; ++column) + { + if (column > 0) + m_text += ", "; + + m_text += StringFormatArg{matrix(row, column)}.text(); + } + + m_text += "}"; + } + } + inline QString text() const { return m_text;
--- a/src/glRenderer.cpp Sat Feb 04 14:44:39 2017 +0200 +++ b/src/glRenderer.cpp Wed Feb 08 16:25:06 2017 +0200 @@ -210,9 +210,15 @@ // void GLRenderer::resetAngles() { - rotation (X) = 30.0f; - rotation (Y) = 325.f; - panning (X) = panning (Y) = rotation (Z) = 0.0f; + // Why did I even bother trying to compute this by pen and paper? Let GL figure it out... + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glRotated(30, 1, 0, 0); + glRotated(330, 0, 1, 0); + glGetDoublev(GL_MODELVIEW_MATRIX, currentDocumentData().rotationMatrix); + glPopMatrix(); + panning(X) = panning(Y) = 0.0f; needZoomToFit(); } @@ -400,9 +406,7 @@ glLoadIdentity(); glTranslatef(0.0f, 0.0f, -2.0f); glTranslatef(panning (X), panning (Y), -zoom()); - glRotatef(rotation(X), 1.0f, 0.0f, 0.0f); - glRotatef(rotation(Y), 0.0f, 1.0f, 0.0f); - glRotatef(rotation(Z), 0.0f, 0.0f, 1.0f); + glMultMatrixd(currentDocumentData().rotationMatrix); } glEnableClientState (GL_VERTEX_ARRAY); @@ -607,8 +611,8 @@ #ifndef RELEASE { - QString text = format("Rotation: (%1°, %2°, %3°)\nPanning: (%4, %5), Zoom: %6", - rotation(X), rotation(Y), rotation(Z), panning(X), panning(Y), zoom()); + QString text = format("Rotation: %1\nPanning: (%2, %3), Zoom: %4", + QGenericMatrix<4, 4, GLdouble>(currentDocumentData().rotationMatrix), panning(X), panning(Y), zoom()); QRect textSize = metrics.boundingRect(0, 0, m_width, m_height, Qt::AlignCenter, text); painter.setPen(textPen()); painter.drawText((width() - textSize.width()) / 2, height() - textSize.height(), textSize.width(), @@ -807,12 +811,17 @@ m_panning = true; m_isCameraMoving = true; } - else if (left and camera() == FreeCamera) + else if (left and camera() == FreeCamera and (xMove != 0 or yMove != 0)) { - rotation(X) = rotation(X) + yMove; - rotation(Y) = rotation(Y) + xMove; - clampAngle(rotation (X)); - clampAngle(rotation (Y)); + // Apply current rotation input to the rotation matrix + // ref: https://forums.ldraw.org/thread-22006-post-24426.html#pid24426 + glPushMatrix(); + glLoadIdentity(); + // 0.6 is an arbitrary rotation sensitivity scalar + glRotated(0.6 * hypot(xMove, yMove), yMove, xMove, 0); + glMultMatrixd(currentDocumentData().rotationMatrix); + glGetDoublev(GL_MODELVIEW_MATRIX, currentDocumentData().rotationMatrix); + glPopMatrix(); m_isCameraMoving = true; } } @@ -1623,14 +1632,6 @@ return *document()->glData(); } -double& GLRenderer::rotation (Axis ax) -{ - return - (ax == X) ? currentDocumentData().rotationX : - (ax == Y) ? currentDocumentData().rotationY : - currentDocumentData().rotationZ; -} - double& GLRenderer::panning (Axis ax) { return (ax == X) ? currentDocumentData().panX[camera()] :
--- a/src/glRenderer.h Sat Feb 04 14:44:39 2017 +0200 +++ b/src/glRenderer.h Wed Feb 08 16:25:06 2017 +0200 @@ -69,9 +69,7 @@ // struct LDGLData { - double rotationX; - double rotationY; - double rotationZ; + GLdouble rotationMatrix[16]; double panX[7]; double panY[7]; double zoom[7]; @@ -81,9 +79,7 @@ bool needZoomToFit; LDGLData() : - rotationX (0.0), - rotationY (0.0), - rotationZ (0.0), + rotationMatrix {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, init (false), needZoomToFit (true) { @@ -249,7 +245,6 @@ LDOverlay* findOverlayObject (Camera cam); double& panning (Axis ax); double panning (Axis ax) const; - double& rotation (Axis ax); double& zoom(); void zoomToFit(); void zoomAllToFit();