demos/boxes/trackball.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demos/boxes/trackball.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "trackball.h"
+#include "scene.h"
+
+//============================================================================//
+//                                  TrackBall                                 //
+//============================================================================//
+
+TrackBall::TrackBall(TrackMode mode)
+    : m_angularVelocity(0)
+    , m_paused(false)
+    , m_pressed(false)
+    , m_mode(mode)
+{
+    m_axis = QVector3D(0, 1, 0);
+    m_rotation = QQuaternion();
+    m_lastTime = QTime::currentTime();
+}
+
+TrackBall::TrackBall(float angularVelocity, const QVector3D& axis, TrackMode mode)
+    : m_axis(axis)
+    , m_angularVelocity(angularVelocity)
+    , m_paused(false)
+    , m_pressed(false)
+    , m_mode(mode)
+{
+    m_rotation = QQuaternion();
+    m_lastTime = QTime::currentTime();
+}
+
+void TrackBall::push(const QPointF& p, const QQuaternion &)
+{
+    m_rotation = rotation();
+    m_pressed = true;
+    m_lastTime = QTime::currentTime();
+    m_lastPos = p;
+    m_angularVelocity = 0.0f;
+}
+
+void TrackBall::move(const QPointF& p, const QQuaternion &transformation)
+{
+    if (!m_pressed)
+        return;
+
+    QTime currentTime = QTime::currentTime();
+    int msecs = m_lastTime.msecsTo(currentTime);
+    if (msecs <= 20)
+        return;
+
+    switch (m_mode) {
+    case Plane:
+        {
+            QLineF delta(m_lastPos, p);
+            m_angularVelocity = 180*delta.length() / (PI*msecs);
+            m_axis = QVector3D(-delta.dy(), delta.dx(), 0.0f).normalized();
+            m_axis = transformation.rotateVector(m_axis);
+            m_rotation = QQuaternion::fromAxisAndAngle(m_axis, 180 / PI * delta.length()) * m_rotation;
+        }
+        break;
+    case Sphere:
+        {
+            QVector3D lastPos3D = QVector3D(m_lastPos.x(), m_lastPos.y(), 0.0f);
+            float sqrZ = 1 - QVector3D::dotProduct(lastPos3D, lastPos3D);
+            if (sqrZ > 0)
+                lastPos3D.setZ(sqrt(sqrZ));
+            else
+                lastPos3D.normalize();
+
+            QVector3D currentPos3D = QVector3D(p.x(), p.y(), 0.0f);
+            sqrZ = 1 - QVector3D::dotProduct(currentPos3D, currentPos3D);
+            if (sqrZ > 0)
+                currentPos3D.setZ(sqrt(sqrZ));
+            else
+                currentPos3D.normalize();
+
+            m_axis = QVector3D::crossProduct(lastPos3D, currentPos3D);
+            float angle = 180 / PI * asin(sqrt(QVector3D::dotProduct(m_axis, m_axis)));
+
+            m_angularVelocity = angle / msecs;
+            m_axis.normalize();
+            m_axis = transformation.rotateVector(m_axis);
+            m_rotation = QQuaternion::fromAxisAndAngle(m_axis, angle) * m_rotation;
+        }
+        break;
+    }
+
+
+    m_lastPos = p;
+    m_lastTime = currentTime;
+}
+
+void TrackBall::release(const QPointF& p, const QQuaternion &transformation)
+{
+    // Calling move() caused the rotation to stop if the framerate was too low.
+    move(p, transformation);
+    m_pressed = false;
+}
+
+void TrackBall::start()
+{
+    m_lastTime = QTime::currentTime();
+    m_paused = false;
+}
+
+void TrackBall::stop()
+{
+    m_rotation = rotation();
+    m_paused = true;
+}
+
+QQuaternion TrackBall::rotation() const
+{
+    if (m_paused || m_pressed)
+        return m_rotation;
+
+    QTime currentTime = QTime::currentTime();
+    float angle = m_angularVelocity * m_lastTime.msecsTo(currentTime);
+    return QQuaternion::fromAxisAndAngle(m_axis, angle) * m_rotation;
+}
+