feat: Implement middle-mouse rotation around grid intersection with visual pivot
Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
@@ -88,8 +88,15 @@ QMatrix4x4 Camera::modelViewMatrix() const
|
|||||||
{
|
{
|
||||||
QMatrix4x4 model;
|
QMatrix4x4 model;
|
||||||
model.translate(m_panX, m_panY, m_zoom);
|
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_xRot / 16.0f, 1, 0, 0);
|
||||||
model.rotate(m_yRot / 16.0f, 0, 1, 0);
|
model.rotate(m_yRot / 16.0f, 0, 1, 0);
|
||||||
|
if (m_isRotating) {
|
||||||
|
model.translate(-m_rotationPivot);
|
||||||
|
}
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,6 +224,44 @@ void Camera::animateToPlaneView(int plane)
|
|||||||
animGroup->start(QAbstractAnimation::DeleteWhenStopped);
|
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()
|
void Camera::animateRestoreState()
|
||||||
{
|
{
|
||||||
auto* animGroup = new QParallelAnimationGroup(this);
|
auto* animGroup = new QParallelAnimationGroup(this);
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ public:
|
|||||||
void animateToPlaneView(int plane);
|
void animateToPlaneView(int plane);
|
||||||
void animateRestoreState();
|
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 savedXRot() const { return m_savedXRot; }
|
||||||
float savedYRot() const { return m_savedYRot; }
|
float savedYRot() const { return m_savedYRot; }
|
||||||
float savedZoom() const { return m_savedZoom; }
|
float savedZoom() const { return m_savedZoom; }
|
||||||
@@ -60,6 +65,9 @@ private:
|
|||||||
float m_panX;
|
float m_panX;
|
||||||
float m_panY;
|
float m_panY;
|
||||||
|
|
||||||
|
QVector3D m_rotationPivot;
|
||||||
|
bool m_isRotating = false;
|
||||||
|
|
||||||
float m_savedXRot = 0;
|
float m_savedXRot = 0;
|
||||||
float m_savedYRot = 0;
|
float m_savedYRot = 0;
|
||||||
float m_savedZoom = -5.0f;
|
float m_savedZoom = -5.0f;
|
||||||
|
|||||||
@@ -153,6 +153,29 @@ void ViewportWidget::paintGL()
|
|||||||
|
|
||||||
m_snapping->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<GLfloat> 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) {
|
if (m_activeSketchTool) {
|
||||||
m_activeSketchTool->paintGL();
|
m_activeSketchTool->paintGL();
|
||||||
}
|
}
|
||||||
@@ -196,6 +219,11 @@ void ViewportWidget::mousePressEvent(QMouseEvent *event)
|
|||||||
{
|
{
|
||||||
m_camera->mousePressEvent(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 (event->button() == Qt::LeftButton) {
|
||||||
if (m_isSelectingPlane) {
|
if (m_isSelectingPlane) {
|
||||||
if (m_highlightedPlane != SketchPlane::NONE) {
|
if (m_highlightedPlane != SketchPlane::NONE) {
|
||||||
@@ -270,6 +298,15 @@ void ViewportWidget::keyPressEvent(QKeyEvent *event)
|
|||||||
QOpenGLWidget::keyPressEvent(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)
|
void ViewportWidget::addLine(const gp_Pnt& start, const gp_Pnt& end)
|
||||||
{
|
{
|
||||||
emit lineAdded(start, end);
|
emit lineAdded(start, end);
|
||||||
|
|||||||
Reference in New Issue
Block a user