summaryrefslogtreecommitdiffstats
path: root/examples/sensors/cubehouse/camera.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'examples/sensors/cubehouse/camera.cpp')
-rw-r--r--examples/sensors/cubehouse/camera.cpp1051
1 files changed, 1051 insertions, 0 deletions
diff --git a/examples/sensors/cubehouse/camera.cpp b/examples/sensors/cubehouse/camera.cpp
new file mode 100644
index 00000000..2e7b6af4
--- /dev/null
+++ b/examples/sensors/cubehouse/camera.cpp
@@ -0,0 +1,1051 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "camera.h"
+#include <QtGui/qquaternion.h>
+#include <QtCore/qmath.h>
+
+/*!
+ \class Camera
+ \brief The Camera class defines the projection to apply to simulate a camera's position, orientation, and optics.
+ \since 4.7
+ \ingroup qt3d
+ \ingroup qt3d::viewing
+
+ \section1 Modelview and projection transformations
+
+ A Camera instance is applied to the scene in two phases:
+ modelview transformation and projection transformation.
+
+ During the modelview transformation, the eye(), center(), and
+ upVector() are used to generate a 4x4 transformation matrix that
+ reflects the viewer's current position and orientation.
+
+ During the projection transformation, the projectionType(),
+ nearPlane(), farPlane(), fieldOfView(), and viewSize() are used
+ to define a viewing volume as a 4x4 transformation matrix.
+
+ The modelview transformation matrix is returned by modelViewMatrix().
+ The projection transformation matrix is returned by projectionMatrix().
+
+ \section1 Positioning and orienting the view
+
+ The viewer position and orientation are defined by eye(), center(),
+ and upVector(). The location of the viewer in world co-ordinates is
+ given by eye(), the viewer is looking at the object of interest located
+ at center(), and the upVector() specifies the direction that should
+ be considered "up" with respect to the viewer.
+
+ The vector from the eye() to the center() is called the "view vector",
+ and the cross-product of the view vector and upVector() is called
+ the "side vector". The view vector specifies the direction the
+ viewer is looking, and the side vector points off to the right of
+ the viewer.
+
+ It is recommended that the view vector and upVector() be at right angles
+ to each other, but this is not required as long as the angle between
+ them is close to 90 degrees.
+
+ The most common use of view and up vectors that are not at right angles
+ is to simulate a human eye at a specific height above the ground looking
+ down at a lower object or up at a higher object. In this case, the
+ the view vector will not be true horizontal, but the upVector() indicating
+ the human's upright stance will be true vertical.
+
+ \section1 Zooming the camera image
+
+ There are two ways to zoom the image seen through the camera: either
+ the camera eye() position can be moved closer to the object of interest,
+ or the field of view of the camera lens can be changed to make it appear
+ as though the object is moving closer.
+
+ Changing the eye() position changes the lighting calculation in the
+ scene because the viewer is in a different position, changing the
+ angle of light reflection on the object's surface.
+
+ The setFieldOfView() function can be used to simulate the effect of a
+ camera lens. The smaller the fieldOfView(), the closer the object
+ will appear. The lighting calculation will be the same as for the
+ unzoomed scene.
+
+ If fieldOfView() is zero, then a standard perspective frustum of
+ viewSize() is used to define the viewing volume. The viewSize()
+ can be adjusted with setViewSize() to zoom the view. A smaller
+ viewSize() will make the the object appear closer.
+
+ The fieldOfView() or viewSize() is applied as part of the
+ projectionMatrix().
+
+\section1 Rotating the viewer or object of interest
+
+Rotating a viewer in 3D space is a very delicate process. It is very
+easy to construct the rotation incorrectly and end up in a "gimbal lock"
+state where further rotations are impossible in certain directions.
+
+To help alleviate this problem, Camera uses a quaternion-based
+approach to generate rotations. A quaternion is a compact representation
+of a rotation in 3D space. Rotations can be combined through quaternion
+multiplication. More information on quaternions can be found in the
+documentation for QQuaternion.
+
+Before rotating the view, you should first decide the type
+of rotation you want to perform:
+
+\list
+\i Tilting or panning a fixed eye to reveal the scene in different
+directions and orientations. This is equivalent to mounting a camera
+on a fixed tripod and then adjusting the direction of view and
+orientation with the tripod controls.
+\i Rotating a moving viewer about the object of interest. This is
+equivalent to moving the viewer around the object at a fixed distance,
+ but with the viewer always pointing at the object.
+ \endlist
+
+ In the Camera class, the first type of rotation is performed with
+ rotateEye() and the second with rotateCenter(). Each of these functions
+ take a quaternion argument that defines the type of rotation to perform.
+
+ The tilt(), pan(), and roll() functions return values that can help with
+ constructing the rotation quaternions to pass to rotateEye() and
+ rotateCenter(). Tilt and pan are also known as "pitch" and "yaw" in
+ flight dynamics.
+
+Three axes of rotation are used to compute the quaternions. The tilt()
+quaternion is computed with respect to the side vector, the pan()
+quaterion is computed with respect to the upVector(), and the roll()
+quaternion is computed with respect to the view vector.
+
+The following example tilts the direction the eye() is pointing
+by 5 degrees, and then pans by 45 degrees:
+
+\code
+camera.rotateEye(camera.tilt(5));
+camera.rotateEye(camera.pan(45));
+\endcode
+
+The next example performs the two rotations in a single fluid step
+(note that the rotation to be performed first is multiplied last):
+
+ \code
+ camera.rotateEye(camera.pan(45) * camera.tilt(5));
+ \endcode
+
+ These two examples will not produce the same visual result, even though
+it looks like they might. In the first example, the upVector() is tilted
+before the pan() quaternion is computed. In the second example, the pan()
+quaternion is computed using the original upVector().
+
+This difference in behavior is useful in different situations. Some
+applications may wish to perform all rotations relative to the original
+viewer orientation, and other applications may wish to perform rotations
+relative to the current viewer orientation. These application types
+correspond to the second and first examples above.
+
+\section1 Moving the viewer or object of interest
+
+The simplest way to move the viewer or object of interest is to call
+setEye() or setCenter() respectively and supply a new position in
+world co-ordinates. However, this can lead to non-intuitive movements
+if the viewer orientation is not aligned with the world co-ordinate axes.
+
+For example, subtracting 3 from the eye() x co-ordinate will appear to
+move the eye left 3 units if the viewer orientation is aligned with the
+world co-ordinate axes. But it will not appear to move the eye left 3
+units in any other orientation.
+
+The translation() function can be used to construct a translation
+vector that is aligned with the viewer's current orientation.
+Movement in the x direction will move along the side vector, movement in
+the y direction will move along upVector(), and movement in the z
+direction will move along the view vector.
+
+The translation() function is useful when implementing operations such
+as "step left", "jump up", and so on where the movement should be
+interpreted relative to the viewer's current orientation, not the
+world co-ordinate axes,
+
+ In other words, the following two lines of code are not equivalent
+ unless the view is oriented with the world co-ordinate axes:
+
+ \code
+ camera.translateEye(camera.translation(x, y, z));
+
+ camera.translateEye(QVector3D(x, y, z));
+ \endcode
+
+ The following example translates the eye() position while
+ keeping the object of interest at the original center():
+
+ \code
+ camera.translateEye(camera.translation(x, y, z));
+ \endcode
+
+ The following example translates the object of interest at
+ center() while keeping the eye() position fixed:
+
+ \code
+ camera.translateCenter(camera.translation(x, y, z));
+ \endcode
+
+The following example translates both the eye() and the center()
+by the same amount, which will maintain the original view vector.
+
+\code
+QVector3D vector = camera.translation(x, y, z);
+camera.translateEye(vector);
+camera.translateCenter(vector);
+\endcode
+
+It is important that the translation vector for center() be computed
+before eye() is translated if both eye() and center() must move by the
+same amount. The following code translates center() in the viewer
+orientation after the eye() is translated:
+
+\code
+camera.translateEye(camera.translation(x, y, z));
+camera.translateCenter(camera.translation(x, y, z));
+\endcode
+
+Translating both eye() and center() by the same amount can be used
+to simulate sliding a viewer past a scene while always looking in the
+same direction (for example, filming a scene from a moving vehicle).
+An alternative is to fix the viewer and move the scene itself:
+the negation of the translation() vector can be applied to the
+scene's modelview transformation.
+
+\section1 Motion tracking
+
+Viewing of 3D scenes can be enhanced if there is some way to track
+the motion of the viewer or the orientation of the display device.
+
+Applications can use setMotionAdjustment() to alter the position
+of the camera to account for the viewer's motion. This indicates
+the viewer's position relative to the center of the screen.
+The motionAdjustment() vector is used to determine by how much
+the camera position should be adjusted. The distance of the viewer
+from the screen is ignored.
+
+On handheld devices that use accelerometers to determine the
+orientation of the device, the down vector due to gravity
+can be adjusted to serve as a motion tracking vector.
+
+The output of motion tracking hardware can be very noisy,
+ with minor fluctuations due to viewer twitch movements or
+ environmental factors. The application is responsible for
+ cleaning up the signal and removing these fluctuations before
+ setMotionAdjustment() is called.
+ */
+
+ class CameraPrivate
+{
+public:
+ CameraPrivate();
+
+ Camera::ProjectionType projectionType;
+ qreal fieldOfView;
+ qreal nearPlane;
+ qreal farPlane;
+ QSizeF viewSize;
+ QSizeF minViewSize;
+ int screenRotation;
+ QVector3D eye;
+ QVector3D upVector;
+ QVector3D center;
+ QVector3D viewVector;
+ qreal eyeSeparation;
+ QVector3D motionAdjustment;
+ QQuaternion motionQuaternion;
+ bool adjustForAspectRatio;
+};
+
+CameraPrivate::CameraPrivate()
+: projectionType(Camera::Perspective),
+ fieldOfView(0.0f),
+ nearPlane(5.0f),
+ farPlane(1000.0f),
+ viewSize(2.0f, 2.0f),
+ minViewSize(0.0001f, 0.0001f),
+ screenRotation(0),
+ eye(0.0f, 0.0f, 10.0f),
+ upVector(0.0f, 1.0f, 0.0f),
+ center(0.0f, 0.0f, 0.0f),
+ viewVector(0.0f, 0.0f, -10.0f),
+ eyeSeparation(0.0f),
+ motionAdjustment(0.0f, 0.0f, 1.0f),
+ adjustForAspectRatio(true)
+{
+}
+
+/*!
+ Constructs a Camera with the default properties and
+ attaches it to \a parent.
+*/
+Camera::Camera(QObject *parent)
+: QObject(parent), d_ptr(new CameraPrivate)
+{
+}
+
+/*!
+ Destroys this Camera object.
+*/
+Camera::~Camera()
+{
+ delete d_ptr;
+}
+
+/*!
+ \enum Camera::ProjectionType
+ This enum defines the type of view projection to use for a Camera.
+
+ \value Perspective Use a perspective view.
+ \value Orthographic Use an ortographic view.
+*/
+
+/*!
+ \property Camera::projectionType
+ \brief the projection type for this camera. The default is Perspective.
+*/
+Camera::ProjectionType Camera::projectionType() const
+{
+ Q_D(const Camera);
+ return d->projectionType;
+}
+
+void Camera::setProjectionType(Camera::ProjectionType value)
+{
+ Q_D(Camera);
+ if (d->projectionType != value) {
+ d->projectionType = value;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property Camera::fieldOfView
+ \brief the field of view in degrees for a perspective projection.
+
+ The default value is zero, which indicates a standard perspective
+ frustum view volume of viewSize() in size. If the value is not
+ zero, then viewSize() is ignored.
+
+ This value is ignored if projectionType() is Orthographic.
+
+ \sa viewSize()
+*/
+qreal Camera::fieldOfView() const
+{
+ Q_D(const Camera);
+ return d->fieldOfView;
+}
+
+void Camera::setFieldOfView(qreal angle)
+{
+ Q_D(Camera);
+ if (d->fieldOfView != angle) {
+ d->fieldOfView = angle;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property Camera::nearPlane
+ \brief the distance from the eye to the near clipping plane.
+ The default value is 5.
+
+ \sa farPlane()
+*/
+qreal Camera::nearPlane() const
+{
+ Q_D(const Camera);
+ return d->nearPlane;
+}
+
+void Camera::setNearPlane(qreal value)
+{
+ Q_D(Camera);
+ if (d->nearPlane != value) {
+ d->nearPlane = value;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property Camera::farPlane
+ \brief the distance from the eye to the far clipping plane.
+ The default value is 1000.
+
+ \sa nearPlane()
+*/
+qreal Camera::farPlane() const
+{
+ Q_D(const Camera);
+ return d->farPlane;
+}
+
+void Camera::setFarPlane(qreal value)
+{
+ Q_D(Camera);
+ if (d->farPlane != value) {
+ d->farPlane = value;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property Camera::viewSize
+ \brief the size of the front of the projection viewing volume.
+ The viewing volume is assumed to be centered on the origin.
+
+ The default value is (2, 2), which indicates a viewing volume front
+ from (-1, -1) to (1, 1).
+
+ If the width or height of the viewing volume is negative, then the
+ co-ordinates will be swapped. For example, a size of (2, -2) will
+ flip the vertical axis upside down for a viewing volume from
+ (-1, 1) to (1, -1).
+
+ The view size will be further adjusted by the window's aspect ratio
+ when projectionMatrix() is called. For best results, the width and
+ height of the view size should be the same to define an ideal square
+ viewing volume, which is then extended to the final viewing volume
+ width and height based on the window's aspect ratio.
+
+ \sa projectionMatrix(), minViewSize()
+*/
+QSizeF Camera::viewSize() const
+{
+ Q_D(const Camera);
+ return d->viewSize;
+}
+
+void Camera::setViewSize(const QSizeF& size)
+{
+ Q_D(Camera);
+ QSizeF sz(size);
+ if (sz.width() < d->minViewSize.width())
+ sz.setWidth(d->minViewSize.width());
+ if (sz.height() < d->minViewSize.height())
+ sz.setHeight(d->minViewSize.height());
+ if (d->viewSize != sz) {
+ d->viewSize = sz;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property Camera::minViewSize
+ \brief the minimum size of the front of the projection viewing volume.
+
+ The minimum view size is used to clamp viewSize() when zooming
+ the camera closer to an object to prevent it "passing through"
+ the object and causing the scale factor to become infinite.
+
+ The default value is (0.0001, 0.0001).
+
+ \sa projectionMatrix(), viewSize()
+*/
+QSizeF Camera::minViewSize() const
+{
+ Q_D(const Camera);
+ return d->minViewSize;
+}
+
+void Camera::setMinViewSize(const QSizeF& size)
+{
+ Q_D(Camera);
+ if (d->viewSize != size) {
+ d->viewSize = size;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property Camera::screenRotation
+ \brief the screen rotation angle in degrees. The default
+ value is 0. If this value is 90 or 270, then the view
+ will be flipped width for height. The only supported values
+ are 0, 90, 180, and 270. The screen is rotated around the
+ positive z axis.
+
+ This setting is intended for simple screen rotations on handheld
+ devices that can be held in either portrait or landscape orientations.
+ The entire screen image is rotated so that it can be viewed in a
+ different device orientation.
+
+ Use rotateEye() or rotateCenter() for more complex rotations
+ that are not aligned with 0, 90, 180, or 270 degrees.
+*/
+int Camera::screenRotation() const
+{
+ Q_D(const Camera);
+ return d->screenRotation;
+}
+
+void Camera::setScreenRotation(int angle)
+{
+ Q_D(Camera);
+ if (d->screenRotation != angle) {
+ d->screenRotation = angle;
+ emit projectionChanged();
+ }
+}
+
+/*!
+ \property Camera::xEye
+ \brief the x position of the viewer's eye. The default value is 0.
+
+ \sa eye(), translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+qreal Camera::xEye() const
+{
+ Q_D(Camera);
+ return d->eye.x();
+}
+
+void Camera::setXEye(qreal value)
+{
+ Q_D(Camera);
+ d->eye.setX(value);
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::yEye
+ \brief the y position of the viewer's eye. The default value is 0.
+
+ \sa eye(), translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+qreal Camera::yEye() const
+{
+ Q_D(Camera);
+ return d->eye.y();
+}
+
+void Camera::setYEye(qreal value)
+{
+ Q_D(Camera);
+ d->eye.setY(value);
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::zEye
+ \brief the z position of the viewer's eye. The default value is 10.
+
+ \sa eye(), translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+qreal Camera::zEye() const
+{
+ Q_D(Camera);
+ return d->eye.z();
+}
+
+void Camera::setZEye(qreal value)
+{
+ Q_D(Camera);
+ d->eye.setZ(value);
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::eye
+ \brief the position of the viewer's eye. The default value is (0, 0, 10).
+
+ \sa translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+QVector3D Camera::eye() const
+{
+ Q_D(const Camera);
+ return d->eye;
+}
+
+void Camera::setEye(const QVector3D& vertex)
+{
+ Q_D(Camera);
+ if (d->eye != vertex) {
+ d->eye = vertex;
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+ }
+}
+
+/*!
+ Adjusts the position of the viewer's eye by the components of \a vector.
+ The final position is eye() + \a vector.
+
+ \sa eye(), setEye(), translateCenter()
+*/
+void Camera::translateEye(const QVector3D& vector)
+{
+ Q_D(Camera);
+ d->eye += vector;
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::upVector
+ \brief the up vector for the viewer. The default value is (0, 1, 0).
+
+ \sa eye(), center()
+*/
+QVector3D Camera::upVector() const
+{
+ Q_D(const Camera);
+ return d->upVector;
+}
+
+void Camera::setUpVector(const QVector3D& vector)
+{
+ Q_D(Camera);
+ if (d->upVector != vector) {
+ d->upVector = vector;
+ emit viewChanged();
+ }
+}
+
+/*!
+ \property Camera::xCentre
+ \brief the x position of the center of the view visible from the viewer's
+ position. The default value is 0.
+
+ \sa eye(), translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+qreal Camera::xCentre() const
+{
+ Q_D(Camera);
+ return d->center.x();
+}
+
+void Camera::setXCentre(qreal value)
+{
+ Q_D(Camera);
+ d->center.setX(value);
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::yCentre
+ \brief the y position of the center of the view visible from the
+ viewer's position. The default value is 0.
+
+ \sa eye(), translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+qreal Camera::yCentre() const
+{
+ Q_D(Camera);
+ return d->center.y();
+}
+
+void Camera::setYCentre(qreal value)
+{
+ Q_D(Camera);
+ d->center.setY(value);
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::zCentre
+ \brief the z position of the center of the view visible from the
+ viewer's position. The default value is 0.
+
+ \sa eye(), translateEye(), upVector(), center(), eyeSeparation()
+ \sa motionAdjustment()
+*/
+qreal Camera::zCentre() const
+{
+ Q_D(Camera);
+ return d->center.z();
+}
+
+void Camera::setZCentre(qreal value)
+{
+ Q_D(Camera);
+ d->center.setZ(value);
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::center
+ \brief the center of the view visible from the viewer's position.
+ The default value is (0, 0, 0).
+
+ \sa translateCenter(), eye(), upVector()
+*/
+QVector3D Camera::center() const
+{
+ Q_D(const Camera);
+ return d->center;
+}
+
+void Camera::setCenter(const QVector3D& vertex)
+{
+ Q_D(Camera);
+ if (d->center != vertex) {
+ d->center = vertex;
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+ }
+}
+
+/*!
+ Adjusts the center of the view by the components of \a vector.
+ The final position is center() + \a vector.
+
+ \sa center(), setCenter(), translateEye()
+*/
+void Camera::translateCenter(const QVector3D& vector)
+{
+ Q_D(Camera);
+ d->center += vector;
+ d->viewVector = d->center - d->eye;
+ emit viewChanged();
+}
+
+/*!
+ \property Camera::eyeSeparation
+ \brief the separation between the eyes when stereo viewing is in use,
+ with eye() specifying the mid-point between the eyes. The default
+ value is 0.
+
+ \sa eye()
+*/
+qreal Camera::eyeSeparation() const
+{
+ Q_D(const Camera);
+ return d->eyeSeparation;
+}
+
+void Camera::setEyeSeparation(qreal value)
+{
+ Q_D(Camera);
+ if (d->eyeSeparation != value) {
+ d->eyeSeparation = value;
+ emit viewChanged();
+ }
+}
+
+/*!
+ \property Camera::motionAdjustment
+ \brief the adjustment vector to apply to the eye() for user motion.
+
+ This property is typically used to implement motion tracking.
+ It is interpreted as a vector from the center of the screen to the
+ current position of the viewer. The angle between the motion
+ adjustment vector and the screen center is used to adjust the
+ position of the eye() when apply() is called.
+
+ The default value is (0, 0, 1), which indicates a viewer
+ directly in front of the center of the screen.
+
+ The units for the vector are unspecified. They could be
+ meters, centimeters, or the force due to gravity in various
+ directions from an accelerometer. The angle defined
+ by the vector is used to perform the adjustment, not its
+ magnitude.
+
+ The output of motion tracking hardware can be very noisy,
+ with minor fluctuations due to viewer twitch movements or
+ environmental factors. The application is responsible for
+ cleaning up the signal and removing these fluctuations before
+ altering this property.
+
+ \sa eye(), apply()
+*/
+
+QVector3D Camera::motionAdjustment() const
+{
+ Q_D(const Camera);
+ return d->motionAdjustment;
+}
+
+void Camera::setMotionAdjustment(const QVector3D& vector)
+{
+ Q_D(Camera);
+ if (d->motionAdjustment != vector) {
+ d->motionAdjustment = vector;
+ if (vector.x() == 0.0f && vector.y() == 0.0f) {
+ // If the vector is centered, then don't perform any rotations.
+ d->motionQuaternion = QQuaternion();
+ } else {
+ // Determine the pan and tilt angles from the vector.
+ QVector3D view = -vector.normalized();
+ if (view.z() < 0.0f)
+ view = -view;
+ qreal xangle = asin(view.x()) * 180.0f / M_PI;
+ qreal yangle = asin(-view.y()) * 180.0f / M_PI;
+
+ // Construct the pan and tilt quaternions.
+ if (qFuzzyIsNull(xangle))
+ d->motionQuaternion = tilt(yangle);
+ else if (qFuzzyIsNull(yangle))
+ d->motionQuaternion = pan(xangle);
+ else
+ d->motionQuaternion = tilt(yangle) * pan(xangle);
+ }
+ emit viewChanged();
+ }
+}
+
+/*!
+ \property Camera::adjustForAspectRatio
+ \brief the adjustment state of the aspect ratio in the viewing volume.
+
+ By default, Camera adjusts the viewing volume for the aspect
+ ratio of the window so that pixels appear square without the
+ application needing to adjust viewSize() manually.
+
+ If this property is false, then the aspect ratio adjustment is
+ not performed.
+*/
+
+bool Camera::adjustForAspectRatio() const
+{
+ Q_D(const Camera);
+ return d->adjustForAspectRatio;
+}
+
+void Camera::setAdjustForAspectRatio(bool value)
+{
+ Q_D(Camera);
+ if (d->adjustForAspectRatio != value) {
+ d->adjustForAspectRatio = value;
+ emit viewChanged();
+ }
+}
+
+/*!
+ Returns the quaternion corresponding to tilting the view up or
+ down by \a angle degrees. The returned quaternion can be applied to
+ the eye() position with rotateEye() or to the center() position with
+ rotateCenter().
+
+ \sa pan(), roll(), rotateEye(), rotateCenter()
+*/
+QQuaternion Camera::tilt(qreal angle) const
+{
+ Q_D(const Camera);
+ QVector3D side = QVector3D::crossProduct(d->viewVector, d->upVector);
+ return QQuaternion::fromAxisAndAngle(side, angle);
+}
+
+/*!
+ Returns the quaternion corresponding to panning the view left or
+ right by \a angle degrees. The returned quaternion can be applied to
+ the eye() position with rotateEye() or to the center() position with
+ rotateCenter().
+
+ \sa tilt(), roll(), rotateEye(), rotateCenter()
+*/
+QQuaternion Camera::pan(qreal angle) const
+{
+ Q_D(const Camera);
+ return QQuaternion::fromAxisAndAngle(d->upVector, angle);
+}
+
+/*!
+ Returns the quaternion corresponding to rolling the view left or
+ right by \a angle degrees. The returned quaternion can be applied to
+ the eye() position with rotateEye() or to the center() position with
+ rotateCenter().
+
+ \sa tilt(), pan(), rotateEye(), rotateCenter()
+*/
+QQuaternion Camera::roll(qreal angle) const
+{
+ Q_D(const Camera);
+ return QQuaternion::fromAxisAndAngle(d->viewVector, angle);
+}
+
+/*!
+ Rotates the orientation of the eye() according to the quaternion \a q.
+ The eye() will remain in the same position, but the upVector() and
+ center() may be altered by the rotation.
+
+ \sa rotateCenter(), tilt(), pan(), roll()
+*/
+void Camera::rotateEye(const QQuaternion& q)
+{
+ Q_D(Camera);
+ d->upVector = q.rotatedVector(d->upVector);
+ d->viewVector = q.rotatedVector(d->viewVector);
+ d->center = d->eye + d->viewVector;
+ emit viewChanged();
+}
+
+/*!
+ Rotates the position and orientation of the eye() around center()
+ according to the quaternion \a q. The center() will remain in the
+ same position, but the upVector() and eye() may be altered by
+ the rotation.
+
+ \sa rotateEye(), tilt(), pan(), roll()
+*/
+void Camera::rotateCenter(const QQuaternion& q)
+{
+ Q_D(Camera);
+ d->upVector = q.rotatedVector(d->upVector);
+ d->viewVector = q.rotatedVector(d->viewVector);
+ d->eye = d->center - d->viewVector;
+ emit viewChanged();
+}
+
+/*!
+ Returns a translation vector that can be used to adjust the eye()
+ or center() by \a x units side-ways, \a y units up,
+ and \a z units forwards.
+
+ This function is useful when implementing operations such as
+ "step left", "jump up", and so on where the movement should be
+ interpreted relative to the viewer's current orientation, not the
+ world co-ordinate axes,
+
+ The translation vector can be applied to eye() or center() by
+ calling translateEye() or translateCenter() respectively.
+
+ \sa translateEye(), translateCenter()
+*/
+QVector3D Camera::translation(qreal x, qreal y, qreal z) const
+{
+ Q_D(const Camera);
+ QVector3D vector(0.0f, 0.0f, 0.0f);
+ if (x != 0.0f)
+ vector += QVector3D::normal(d->viewVector, d->upVector) * x;
+ if (y != 0.0f)
+ vector += d->upVector.normalized() * y;
+ if (z != 0.0f)
+ vector += d->viewVector.normalized() * z;
+ return vector;
+}
+
+/*!
+ Returns the transformation matrix to apply to the projection matrix
+ to present the scene as viewed from the camera position.
+
+ The \a aspectRatio specifies the aspect ratio of the window the
+ camera view is being displayed in. An \a aspectRatio of 1 indicates that
+ the window is square. An \a aspectRatio greater than 1 indicates that
+ the window is wider than it is high. An \a aspectRatio less than 1
+ indicates that the window is higher than it is wide.
+
+ \sa apply(), modelViewMatrix()
+*/
+QMatrix4x4 Camera::projectionMatrix(qreal aspectRatio) const
+{
+ Q_D(const Camera);
+ QMatrix4x4 m;
+ if (!d->adjustForAspectRatio)
+ aspectRatio = 1.0f;
+ if (d->screenRotation != 0) {
+ m.rotate((qreal)(d->screenRotation), 0.0f, 0.0f, 1.0f);
+ if (d->screenRotation == 90 || d->screenRotation == 270) {
+ if (aspectRatio != 0.0f)
+ aspectRatio = 1.0f / aspectRatio;
+ }
+ }
+ if (d->projectionType == Perspective && d->fieldOfView != 0.0f) {
+ m.perspective(d->fieldOfView, aspectRatio,
+ d->nearPlane, d->farPlane);
+ } else {
+ qreal halfWidth = d->viewSize.width() / 2.0f;
+ qreal halfHeight = d->viewSize.height() / 2.0f;
+ if (aspectRatio > 1.0f) {
+ halfWidth *= aspectRatio;
+ } else if (aspectRatio > 0.0f && aspectRatio < 1.0f) {
+ halfHeight /= aspectRatio;
+ }
+ if (d->projectionType == Perspective) {
+ m.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight,
+ d->nearPlane, d->farPlane);
+ } else {
+ m.ortho(-halfWidth, halfWidth, -halfHeight, halfHeight,
+ d->nearPlane, d->farPlane);
+ }
+ }
+ return m;
+}
+
+/*!
+ Returns the transformation to apply to the modelview matrix
+ to present the scene as viewed from the eye() position.
+
+ \sa apply(), projectionMatrix()
+*/
+QMatrix4x4 Camera::modelViewMatrix() const
+{
+ Q_D(const Camera);
+ QMatrix4x4 m;
+ if (d->motionQuaternion.isIdentity()) {
+ m.lookAt(d->eye, d->center, d->upVector);
+ } else {
+ QVector3D up = d->motionQuaternion.rotatedVector(d->upVector);
+ QVector3D view = d->motionQuaternion.rotatedVector(d->viewVector);
+ QVector3D eye = d->center - view;
+ m.lookAt(eye, d->center, up);
+ }
+ return m;
+}
+
+/*!
+ \fn void Camera::projectionChanged()
+
+ This signal is emitted when one of projectionType(), fieldOfView(),
+ nearPlane(), farPlane(), viewSize(), or screenRotation() changes,
+ indicating a modification to the optical properties of the camera
+ looking at the scene.
+
+ \sa viewChanged()
+*/
+
+/*!
+ \fn void Camera::viewChanged()
+
+ This signal is emitted when one of eye(), upVector(), or center()
+ changes, indicating a modification to the viewer's position or
+ orientation.
+
+ \sa projectionChanged()
+*/