Commit 2c023cab authored by Jan Möbius's avatar Jan Möbius

Reimplemented flyTo with Qt Animation framework to get rid of two process events



git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@12219 383ad7c9-94d9-4d36-a494-682f7c89f535
parent f498fb2a
......@@ -523,7 +523,7 @@ void
glViewer::copyToImage( QImage& _image,
unsigned int _l, unsigned int _t,
unsigned int _w, unsigned int _h,
GLenum /* _buffer */ )
GLenum /* _buffer */ )
{
// qApp->processEvents();
......@@ -920,182 +920,6 @@ void glViewer::viewAll()
//-----------------------------------------------------------------------------
void glViewer::flyTo(const QPoint& _pos, bool _move_back)
{
makeCurrent();
unsigned int nodeIdx, targetIdx;
ACG::Vec3d hitPoint;
if (pick( ACG::SceneGraph::PICK_ANYTHING, _pos, nodeIdx, targetIdx, &hitPoint))
{
if (projectionMode_ == PERSPECTIVE_PROJECTION)
{
ACG::Vec3d eye(glstate_->eye());
ACG::Vec3d t = hitPoint - eye;
ACG::Vec3d e = eye + t * (_move_back ? -0.5f : 0.5f);
flyTo(e, hitPoint, 300);
}
else
{
// Project hitpoint to get depth
ACG::Vec3d hitPointProjected = glstate_->project(hitPoint);
// Create projected center point with same depth as hitpoint
ACG::Vec3d centerPointProjected = hitPointProjected;
// Get viewport data
int w = 0, h = 0,left = 0, bottom = 0;
glstate_->get_viewport(left, bottom, w, h);
// Compute the center point. Note that the project function includes the viewport matrix.
// As we have different viewports for the viewer but one global coord system,
// we need to set the real center coordinates and therefore add the lower left corner position
// which is the left and bottom of the viewport
centerPointProjected[0] = left + glstate_->viewport_width() / 2.0 ;
centerPointProjected[1] = bottom + glstate_->viewport_height() / 2.0 ;
// unproject center point
ACG::Vec3d centerPointUnProjected = glstate_->unproject(centerPointProjected);
// translation vector to make hitpoint project to center point (both need same depth)
ACG::Vec3d t = hitPoint - centerPointUnProjected;
// Transform to correct translation vector with modelview.
t = glstate_->modelview().transform_vector(t);
// originalWidth
double orthoWidthOriginal = properties_.orthoWidth();
// Set the double click point as the new trackball center
// Rotations will use this point as the center.
properties_.trackballCenter( hitPoint );
// how many frames in _time ms ?
unsigned int frames = (unsigned int)(300 / frame_time_);
if (frames > 1000) frames=1000;
// animate it
if (frames > 10)
{
for (unsigned int i=1; i<frames; ++i)
{
// zoom back one frame
if ( _move_back ) {
// Move back by factor 2
properties_.orthoWidth( orthoWidthOriginal * (1.0 + 1.0 / (double)frames * i ) );
} else
// Move forward with factor 0.5
properties_.orthoWidth( orthoWidthOriginal * (1.0 - 0.5 / (double)frames * i ) );
// apply translation
translate(t * (- 1.0 / (double)frames ) );
update();
qApp->processEvents();
}
updatePickCache_ = true;
} else {
// direct translation
translate(-t);
// set the zoom factor when no animation is performed
if ( _move_back )
properties_.orthoWidth( properties_.orthoWidth() * 2.0 );
else
properties_.orthoWidth(properties_.orthoWidth() * -0.5);
}
// Update the projection matrix
updateProjectionMatrix();
// Redraw scene
updateGL();
emit viewChanged();
}
}
}
void glViewer::flyTo(const ACG::Vec3d& _position,
const ACG::Vec3d& _center,
double _time)
{
makeCurrent();
// compute rotation
ACG::Vec3d c = glstate_->modelview().transform_point(_center);
ACG::Vec3d p = glstate_->modelview().transform_point(_position);
ACG::Vec3d view =(p-c).normalize();
ACG::Vec3d z(0,0,1);
ACG::Vec3d axis = (z % -view).normalize();
double angle = acos(std::max(-1.0,
std::min(1.0,
(z | view)))) / M_PI * 180.0;
if (angle > 175)
axis = ACG::Vec3d(0,1,0);
// compute translation
ACG::Vec3d target = glstate_->modelview().transform_point(_center);
ACG::Vec3d trans ( -target[0],
-target[1],
-target[2] - (_position-_center).norm() );
// how many frames in _time ms ?
unsigned int frames = (unsigned int)(_time / frame_time_);
if (frames > 1000) frames=1000;
// animate it
if (frames > 10)
{
ACG::Vec3d t = trans / (double)frames;
double a = angle / (double)frames;
for (unsigned int i=0; i<frames; ++i)
{
translate(t);
if (fabs(a) > FLT_MIN)
rotate(axis, a, _center);
update();
qApp->processEvents();
}
updatePickCache_ = true;
}
// no animation
else
{
translate(trans);
if (fabs(angle) > FLT_MIN)
rotate(axis, angle, _center);
updateGL();
}
properties_.trackballCenter( _center );
properties_.trackballRadius( std::max( properties_.sceneRadius(),( _center - _position ).norm() * 0.9f ) );
}
//-----------------------------------------------------------------------------
void glViewer::setView(const ACG::GLMatrixd& _modelview,
const ACG::GLMatrixd& _inverse_modelview)
{
......
......@@ -83,6 +83,7 @@
#include <QTimer>
#include <QGraphicsWidget>
#include <QGraphicsSceneDragDropEvent>
#include <QPropertyAnimation>
#include <vector>
#include <string>
......@@ -320,21 +321,6 @@ public slots:
virtual void home();
/// view the whole scene
virtual void viewAll();
/// Fly to. Get closer if \c _move_back=\c false, get more distant else.
virtual void flyTo(const QPoint& _pos, bool _move_back);
/// Fly to, get closer.
virtual void flyTo(const QPoint& _pos) { flyTo(_pos,false); }
/// Fly to, get more distant.
virtual void flyFrom(const QPoint& _pos) { flyTo(_pos,true); }
/** Fly to point and set new viewing direction (animated).
* @param _position New viewer position ( the new eye point of the viewer )
* @param _center The new scene center ( the point we are looking at )
* @param _time Animation time in ms
*/
virtual void flyTo(const ACG::Vec3d& _position,
const ACG::Vec3d& _center,
double _time = 1000.0);
/// set perspective view (projectionMode(PERSPECTIVE_PROJECTION))
virtual void perspectiveProjection();
......@@ -1038,6 +1024,104 @@ private:
void applyProperties();
/** @} */
//===========================================================================
/** @name Flying animation properties
* @{ */
//===========================================================================
public slots:
/** \brief Animated flight to or away from a given point
*
* Animated flight to or away from a given point.
*
* @param _pos Point defining direction of flight (eye-point)
* @param _moveBack To or away from point?
*/
virtual void flyTo(const QPoint& _pos, bool _moveBack);
/** \brief Animated flight
*
* Animated flight into the direction of the given point.
*
*/
virtual void flyTo(const QPoint& _pos) { flyTo(_pos,false); }
/** \brief Animated flight
*
* Animated flight away from the given point.
*
*/
virtual void flyFrom(const QPoint& _pos) { flyTo(_pos,true); }
/** Fly to point and set new viewing direction (animated).
* @param _position New viewer position ( the new eye point of the viewer )
* @param _center The new scene center ( the point we are looking at )
* @param _time Animation time in ms
*/
virtual void flyTo(const ACG::Vec3d& _position,
const ACG::Vec3d& _center,
int _time = 1000);
private:
/// The animation object for flyTo
QPropertyAnimation* animation_;
/// Full translation between start and ed of animation
ACG::Vec3d flyTranslation_;
/// The rotation axis for fly to animation
ACG::Vec3d flyAxis_;
/// The rotation angle (full angle) for fly to animation
double flyAngle_;
/// The last position of the animation to compute the difference vector
double lastAnimationPos_;
Q_PROPERTY(double currentAnimationPosition READ currentAnimationPos WRITE currentAnimationPos NOTIFY currentAnimationPosChanged)
/// The property that is animated by flyTo
double currentAnimationPos_;
/// Getter for aflyToAnimationPosition
double currentAnimationPos() {return currentAnimationPos_;};
/// Setter for aflyToAnimationPosition
void currentAnimationPos(double _currentAnimationPos) {currentAnimationPos_ = _currentAnimationPos; emit currentAnimationPosChanged(_currentAnimationPos); };
/// The new center after the flyTo animation
ACG::Vec3d flyCenter_;
/// The new position after the flyTo animation
ACG::Vec3d flyPosition_;
/// Original orthogonal width during flyTo in orthogonal mode
double flyOrthoWidthOriginal_;
/// Flag for fly in orthogonal mode if we move back or forward
bool flyMoveBack_;
signals:
/// Emitted when the currentAnimationPosition changed
void currentAnimationPosChanged(double _currentAnimationPos);
private slots:
/// Slot called during flyTo Animation in perspective mode
void flyAnimationPerspective(QVariant _pos);
/// Slot called during flyTo Animation in orthogonal mode
void flyAnimationOrthogonal(QVariant _pos);
/// Slot called when flyTo perspective Animation finished
void flyAnimationPerspectiveFinished();
/// Slot called when flyTo orthogonal Animation finished
void flyAnimationOrthogonalFinished();
/** @} */
};
......
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen *
* www.openflipper.org *
* *
*--------------------------------------------------------------------------- *
* This file is part of OpenFlipper. *
* *
* OpenFlipper is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version with the *
* following exceptions: *
* *
* If other files instantiate templates or use macros *
* or inline functions from this file, or you compile this file and *
* link it with other files to produce an executable, this file does *
* not by itself cause the resulting executable to be covered by the *
* GNU Lesser General Public License. This exception does not however *
* invalidate any other reasons why the executable file might be *
* covered by the GNU Lesser General Public License. *
* *
* OpenFlipper is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU LesserGeneral Public *
* License along with OpenFlipper. If not, *
* see <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision: 10745 $ *
* $LastChangedBy: moebius $ *
* $Date: 2011-01-26 10:23:50 +0100 (Mi, 26 Jan 2011) $ *
* *
\*===========================================================================*/
//=============================================================================
//
// CLASS glViewer - IMPLEMENTATION
//
//=============================================================================
//== INCLUDES =================================================================
#include "QtBaseViewer.hh"
//== NAMESPACES ===============================================================
//== IMPLEMENTATION ==========================================================
void glViewer::flyTo(const QPoint& _pos, bool _moveBack)
{
makeCurrent();
unsigned int nodeIdx, targetIdx;
ACG::Vec3d hitPoint;
if (pick( ACG::SceneGraph::PICK_ANYTHING, _pos, nodeIdx, targetIdx, &hitPoint))
{
if (projectionMode_ == PERSPECTIVE_PROJECTION)
{
ACG::Vec3d eye(glstate_->eye());
ACG::Vec3d t = hitPoint - eye;
ACG::Vec3d e = eye + t * (_moveBack ? -0.5f : 0.5f);
flyTo(e, hitPoint, 300);
}
else
{
// Project hitpoint to get depth
ACG::Vec3d hitPointProjected = glstate_->project(hitPoint);
// Create projected center point with same depth as hitpoint
ACG::Vec3d centerPointProjected = hitPointProjected;
// Get viewport data
int w = 0, h = 0,left = 0, bottom = 0;
glstate_->get_viewport(left, bottom, w, h);
// Compute the center point. Note that the project function includes the viewport matrix.
// As we have different viewports for the viewer but one global coord system,
// we need to set the real center coordinates and therefore add the lower left corner position
// which is the left and bottom of the viewport
centerPointProjected[0] = left + glstate_->viewport_width() / 2.0 ;
centerPointProjected[1] = bottom + glstate_->viewport_height() / 2.0 ;
// unproject center point
ACG::Vec3d centerPointUnProjected = glstate_->unproject(centerPointProjected);
// translation vector to make hit point project to center point (both need same depth)
ACG::Vec3d t = hitPoint - centerPointUnProjected;
// Transform to correct translation vector with modelview.
flyTranslation_ = glstate_->modelview().transform_vector(t);
// remember originalWidth
flyOrthoWidthOriginal_ = properties_.orthoWidth();
// Initialize as we start at 0.0
lastAnimationPos_ = 0.0;
// store the direction for the actual animation
flyMoveBack_ = _moveBack;
// Set the double click point as the new trackball center
// Rotations will use this point as the center.
properties_.trackballCenter( hitPoint );
// Create animation object
animation_ = new QPropertyAnimation(this, "currentAnimationPosition");
animation_->setDuration(300);
// Range is from 0 to one, as we linearly interpolate the animation
animation_->setStartValue(0.0);
animation_->setEndValue(1.0);
// Connect signals for the animation and its end
connect(animation_, SIGNAL(valueChanged(QVariant)), this, SLOT(flyAnimationOrthogonal(QVariant)));
connect(animation_, SIGNAL(finished()), this, SLOT(flyAnimationOrthogonalFinished()));
// Start it
animation_->start();
}
}
}
void glViewer::flyAnimationOrthogonal(QVariant _pos) {
const double pos = _pos.toDouble();
// compute difference
const double diff = pos - lastAnimationPos_;
// zoom back one frame
if ( flyMoveBack_ ) {
// Move back by factor 2
properties_.orthoWidth( flyOrthoWidthOriginal_ * (1.0 + pos ) );
} else
// Move forward with factor 0.5
properties_.orthoWidth( flyOrthoWidthOriginal_ * (1.0 - 0.5 * pos ) );
// apply translation
translate(- flyTranslation_ * diff );
// Store our current position for next loop
lastAnimationPos_ = pos;
// Pick cache is definitely invalid after that
updatePickCache_ = true;
// update rendering
update();
}
void glViewer::flyAnimationPerspective(QVariant _pos) {
const double pos = _pos.toDouble();
// Animate pos from 0 to 1 so we need to calculate the difference and the resulting transformations
ACG::Vec3d t = (pos - lastAnimationPos_) * flyTranslation_ ;
double a = (pos - lastAnimationPos_) * flyAngle_ ;
translate(t);
// Only rotate, if we have realistic values
if (fabs(a) > FLT_MIN)
rotate(flyAxis_, a, flyCenter_);
// Pick cache is definitely invalid after that
updatePickCache_ = true;
// Store our current position for next loop
lastAnimationPos_ = pos;
// update rendering
update();
}
void glViewer::flyAnimationOrthogonalFinished() {
// Update the projection matrix
updateProjectionMatrix();
// Redraw scene
updateGL();
// Inform others that the current view has changed
emit viewChanged();
if ( animation_)
delete animation_;
}
void glViewer::flyAnimationPerspectiveFinished() {
// Update the trackball to the final position
properties_.trackballCenter( flyCenter_ );
properties_.trackballRadius( std::max( properties_.sceneRadius(),( flyCenter_ - flyPosition_ ).norm() * 0.9f ) );
if ( animation_)
delete animation_;
}
void glViewer::flyTo(const ACG::Vec3d& _position,
const ACG::Vec3d& _center,
int _time)
{
makeCurrent();
// compute rotation
ACG::Vec3d c = glstate_->modelview().transform_point(_center);
ACG::Vec3d p = glstate_->modelview().transform_point(_position);
ACG::Vec3d view =(p-c).normalize();
ACG::Vec3d z(0,0,1);
flyAxis_ = (z % -view).normalize();
flyAngle_ = acos(std::max(-1.0, std::min(1.0, (z | view)))) / M_PI * 180.0;
if (flyAngle_ > 175)
flyAxis_ = ACG::Vec3d(0,1,0);
// compute translation
ACG::Vec3d target = glstate_->modelview().transform_point(_center);
flyTranslation_ = ACG::Vec3d( -target[0], -target[1], -target[2] - (_position-_center).norm() );
// Store other values for animation
flyCenter_ = _center;
flyPosition_ = _position;
// Initialize as we start at 0.0
lastAnimationPos_ = 0.0;
// Create animation object
animation_ = new QPropertyAnimation(this, "currentAnimationPosition");
animation_->setDuration(_time);
// Range is from 0 to one, as we linearly interpolate the animation
animation_->setStartValue(0.0);
animation_->setEndValue(1.0);
// Connect signals for the animation and its end
connect(animation_, SIGNAL(valueChanged(QVariant)), this, SLOT(flyAnimationPerspective(QVariant)));
connect(animation_, SIGNAL(finished()), this, SLOT(flyAnimationPerspectiveFinished()));
// Start it
animation_->start();
}
//=============================================================================
//=============================================================================
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment