diff --git a/src/Camera.cpp b/src/Camera.cpp index bde413d..a28ffdc 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -88,8 +88,15 @@ QMatrix4x4 Camera::modelViewMatrix() const { QMatrix4x4 model; model.translate(m_panX, m_panY, m_zoom); + + if (m_isRotating) { + model.translate(m_rotationPivot); + } model.rotate(m_xRot / 16.0f, 1, 0, 0); model.rotate(m_yRot / 16.0f, 0, 1, 0); + if (m_isRotating) { + model.translate(-m_rotationPivot); + } return model; } @@ -217,6 +224,44 @@ void Camera::animateToPlaneView(int plane) animGroup->start(QAbstractAnimation::DeleteWhenStopped); } +void Camera::startRotation(const QVector3D& pivot) +{ + m_rotationPivot = pivot; + + QMatrix4x4 rotation; + rotation.rotate(m_xRot / 16.0f, 1, 0, 0); + rotation.rotate(m_yRot / 16.0f, 0, 1, 0); + + QVector3D p_rotated = rotation.map(m_rotationPivot); + QVector3D p_diff = p_rotated - m_rotationPivot; + + setPanX(m_panX + p_diff.x()); + setPanY(m_panY + p_diff.y()); + setZoom(m_zoom + p_diff.z()); + + m_isRotating = true; +} + +void Camera::stopRotation() +{ + if (!m_isRotating) { + return; + } + + QMatrix4x4 rotation; + rotation.rotate(m_xRot / 16.0f, 1, 0, 0); + rotation.rotate(m_yRot / 16.0f, 0, 1, 0); + + QVector3D p_rotated = rotation.map(m_rotationPivot); + QVector3D p_diff = p_rotated - m_rotationPivot; + + setPanX(m_panX - p_diff.x()); + setPanY(m_panY - p_diff.y()); + setZoom(m_zoom - p_diff.z()); + + m_isRotating = false; +} + void Camera::animateRestoreState() { auto* animGroup = new QParallelAnimationGroup(this); diff --git a/src/Camera.h b/src/Camera.h index 8d06e61..7e6aec7 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -42,6 +42,11 @@ public: void animateToPlaneView(int plane); void animateRestoreState(); + void startRotation(const QVector3D& pivot); + void stopRotation(); + bool isRotating() const { return m_isRotating; } + const QVector3D& rotationPivot() const { return m_rotationPivot; } + float savedXRot() const { return m_savedXRot; } float savedYRot() const { return m_savedYRot; } float savedZoom() const { return m_savedZoom; } @@ -60,6 +65,9 @@ private: float m_panX; float m_panY; + QVector3D m_rotationPivot; + bool m_isRotating = false; + float m_savedXRot = 0; float m_savedYRot = 0; float m_savedZoom = -5.0f; diff --git a/src/ViewportWidget.cpp b/src/ViewportWidget.cpp index e5b80d2..5ec6880 100644 --- a/src/ViewportWidget.cpp +++ b/src/ViewportWidget.cpp @@ -153,6 +153,29 @@ void ViewportWidget::paintGL() m_snapping->paintGL(); + if (m_camera->isRotating()) { + const float radius = 0.004f * -m_camera->zoom(); + const int numSegments = 16; + QMatrix4x4 invModelView = m_camera->modelViewMatrix().inverted(); + QVector3D rightVec = invModelView.column(0).toVector3D(); + QVector3D upVec = invModelView.column(1).toVector3D(); + + QVector circleFillVertices; + QVector3D center = m_camera->rotationPivot(); + + circleFillVertices << center.x() << center.y() << center.z(); // Center vertex for fan + for (int i = 0; i <= numSegments; ++i) { // <= to close the circle + float angle = (2.0f * M_PI * float(i)) / float(numSegments); + QVector3D p = center + radius * (cos(angle) * rightVec + sin(angle) * upVec); + circleFillVertices << p.x() << p.y() << p.z(); + } + + m_shaderProgram->setUniformValue(m_colorLoc, QVector4D(0.0f, 0.0f, 1.0f, 1.0f)); // Blue + m_vbo.bind(); + m_vbo.allocate(circleFillVertices.constData(), circleFillVertices.size() * sizeof(GLfloat)); + glDrawArrays(GL_TRIANGLE_FAN, 0, circleFillVertices.size() / 3); + } + if (m_activeSketchTool) { m_activeSketchTool->paintGL(); } @@ -196,6 +219,11 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event) { m_camera->mousePressEvent(event); + if (event->button() == Qt::MiddleButton && !(QApplication::keyboardModifiers() & Qt::ShiftModifier)) { + m_camera->startRotation(unproject(event->pos(), m_currentPlane)); + update(); + } + if (event->button() == Qt::LeftButton) { if (m_isSelectingPlane) { if (m_highlightedPlane != SketchPlane::NONE) { @@ -270,6 +298,15 @@ void ViewportWidget::keyPressEvent(QKeyEvent *event) QOpenGLWidget::keyPressEvent(event); } +void ViewportWidget::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::MiddleButton) { + m_camera->stopRotation(); + update(); + } + QOpenGLWidget::mouseReleaseEvent(event); +} + void ViewportWidget::addLine(const gp_Pnt& start, const gp_Pnt& end) { emit lineAdded(start, end);