WIP Header_only

This commit is contained in:
Maxime Gimeno 2018-03-28 15:49:20 +02:00
parent cbc0ce1130
commit 0c74a68952
44 changed files with 11105 additions and 11273 deletions

View File

@ -49,7 +49,9 @@ if(CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND)
"${CMAKE_CURRENT_BINARY_DIR}/Viewer_moc.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/Scene_moc.cpp" )
add_executable ( AABB_demo AABB_demo.cpp ${UI_FILES} ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES})
add_executable ( AABB_demo AABB_demo.cpp ${UI_FILES} ${CGAL_Qt5_RESOURCE_FILES}
#${CGAL_Qt5_MOC_FILES}
)
# Link with Qt libraries
target_link_libraries( AABB_demo PRIVATE
Qt5::OpenGL Qt5::Gui Qt5::Xml

View File

@ -411,11 +411,7 @@ void MainWindow::on_actionRefine_loop_triggered()
void MainWindow::on_actionSave_snapshot_triggered()
{
// save snapshot to file
QApplication::setOverrideCursor(Qt::WaitCursor);
QString filename = QFileDialog::getSaveFileName(this,tr("Save snapshot to file..."),"snapshot00.png","*.png");
m_pViewer->saveSnapshot(filename);
QApplication::restoreOverrideCursor();
return;
}
void MainWindow::on_actionCopy_snapshot_triggered()
{

View File

@ -68,7 +68,7 @@ class Refiner
typedef typename Polyhedron::Edge_iterator Edge_iterator;
typedef std::priority_queue<Edge,
std::vector<Edge>,
less<Edge> > PQueue;
::less<Edge> > PQueue;
// data
PQueue m_queue;
Polyhedron* m_pMesh;

View File

@ -1,360 +1 @@
// Copyright (c) 2008 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Andreas Fabri <Andreas.Fabri@geometryfactory.com>
// Laurent Rineau <Laurent.Rineau@geometryfactory.com>
#ifndef CGAL_QT_ALPHA_SHAPE_GRAPHICS_ITEM_H
#define CGAL_QT_ALPHA_SHAPE_GRAPHICS_ITEM_H
#include <CGAL/license/GraphicsView.h>
#include <CGAL/Bbox_2.h>
#include <CGAL/apply_to_range.h>
#include <CGAL/Qt/PainterOstream.h>
#include <CGAL/Qt/GraphicsItem.h>
#include <CGAL/Qt/Converter.h>
#include <QGraphicsScene>
#include <QPainter>
#include <QStyleOption>
namespace CGAL {
namespace Qt {
template <typename T>
class AlphaShapeGraphicsItem : public GraphicsItem
{
typedef typename T::Geom_traits Geom_traits;
public:
AlphaShapeGraphicsItem(T* t_);
void modelChanged();
public:
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
virtual void operator()(typename T::Face_handle fh);
const QPen& verticesPen() const
{
return vertices_pen;
}
const QPen& edgesPen() const
{
return edges_pen;
}
const QPen& regularEdgesPen() const
{
return regular_edges_pen;
}
const QPen& singularEdgesPen() const
{
return singular_edges_pen;
}
const QBrush& regularFacesBrush() const
{
return regular_faces_brush;
}
void setVerticesPen(const QPen& pen)
{
vertices_pen = pen;
}
void setEdgesPen(const QPen& pen)
{
edges_pen = pen;
}
void setRegularEdgesPen(const QPen& pen)
{
regular_edges_pen = pen;
}
void setSingularEdgesPen(const QPen& pen)
{
singular_edges_pen = pen;
}
void setRegularFacesBrush(const QBrush& b)
{
regular_faces_brush = b;
}
bool visibleVertices() const
{
return visible_vertices;
}
void setVisibleVertices(const bool b)
{
visible_vertices = b;
update();
}
bool visibleEdges() const
{
return visible_edges;
}
void setVisibleEdges(const bool b)
{
visible_edges = b;
update();
}
protected:
virtual void drawAll(QPainter *painter);
void paintVertices(QPainter *painter);
void paintOneVertex(const typename T::Point& point);
virtual void paintVertex(typename T::Vertex_handle vh);
void updateBoundingBox();
T * t;
QPainter* m_painter;
PainterOstream<Geom_traits> painterostream;
typename T::Vertex_handle vh;
typename T::Point p;
CGAL::Bbox_2 bb;
bool bb_initialized;
QRectF bounding_rect;
QPen vertices_pen;
QPen edges_pen;
QPen regular_edges_pen;
QPen singular_edges_pen;
QBrush regular_faces_brush;
bool visible_edges;
bool visible_vertices;
};
template <typename T>
AlphaShapeGraphicsItem<T>::AlphaShapeGraphicsItem(T * t_)
: t(t_), painterostream(0),
bb(0,0,0,0), bb_initialized(false),
visible_edges(true), visible_vertices(true)
{
setVerticesPen(QPen(::Qt::red, 3.));
if(t->number_of_vertices() == 0){
this->hide();
}
updateBoundingBox();
setZValue(3);
}
template <typename T>
QRectF
AlphaShapeGraphicsItem<T>::boundingRect() const
{
return bounding_rect;
}
template <typename T>
void
AlphaShapeGraphicsItem<T>::operator()(typename T::Face_handle fh)
{
if(visible_edges) {
for (int i=0; i<3; i++) {
if (fh < fh->neighbor(i) || t->is_infinite(fh->neighbor(i))){
m_painter->setPen(this->edgesPen());
painterostream << t->segment(fh,i);
}
}
}
if(visible_vertices) {
for (int i=0; i<3; i++) {
paintVertex(fh->vertex(i));
}
}
}
template <typename T>
void
AlphaShapeGraphicsItem<T>::drawAll(QPainter *painter)
{
painterostream = PainterOstream<Geom_traits>(painter);
painter->setBrush(regularFacesBrush());
typedef typename T::Gt::Triangle_2 Triangle_2;
for(typename T::Finite_faces_iterator fit = t->finite_faces_begin();
fit != t->finite_faces_end();
++fit){
if(t->classify(fit) == T::INTERIOR){
Triangle_2 triangle = t->triangle(fit);
painterostream << triangle;
}
}
if(visibleEdges()) {
for(typename T::Finite_edges_iterator eit = t->finite_edges_begin();
eit != t->finite_edges_end();
++eit){
switch (t->classify(*eit)) {
case T::REGULAR :
painter->setPen(regularEdgesPen());
break;
case T::SINGULAR :
painter->setPen(singularEdgesPen());
break;
default:
painter->setPen(edgesPen());
}
painterostream << t->segment(*eit);
}
}
paintVertices(painter);
}
template <typename T>
void
AlphaShapeGraphicsItem<T>::paintVertices(QPainter *painter)
{
if(visibleVertices()) {
Converter<Geom_traits> convert;
painter->setPen(verticesPen());
QMatrix matrix = painter->matrix();
painter->resetMatrix();
for(typename T::Finite_vertices_iterator it = t->finite_vertices_begin();
it != t->finite_vertices_end();
it++){
QPointF point = matrix.map(convert(it->point()));
painter->drawPoint(point);
}
}
}
template <typename T>
void
AlphaShapeGraphicsItem<T>::paintOneVertex(const typename T::Point& point)
{
Converter<Geom_traits> convert;
m_painter->setPen(this->verticesPen());
QMatrix matrix = m_painter->matrix();
m_painter->resetMatrix();
m_painter->drawPoint(matrix.map(convert(point)));
m_painter->setMatrix(matrix);
}
template <typename T>
void
AlphaShapeGraphicsItem<T>::paintVertex(typename T::Vertex_handle vh)
{
Converter<Geom_traits> convert;
m_painter->setPen(this->verticesPen());
QMatrix matrix = m_painter->matrix();
m_painter->resetMatrix();
m_painter->drawPoint(matrix.map(convert(vh->point())));
m_painter->setMatrix(matrix);
}
template <typename T>
void
AlphaShapeGraphicsItem<T>::paint(QPainter *painter,
const QStyleOptionGraphicsItem * /*option*/,
QWidget * /*widget*/)
{
painter->setPen(this->edgesPen());
// painter->drawRect(boundingRect());
// if ( t->dimension()<2 || option->exposedRect.contains(boundingRect()) ) {
drawAll(painter);
/*
} else {
m_painter = painter;
painterostream = PainterOstream<Geom_traits>(painter);
CGAL::apply_to_range (*t,
typename T::Point(option->exposedRect.left(),
option->exposedRect.bottom()),
typename T::Point(option->exposedRect.right(),
option->exposedRect.top()),
*this);
}
*/
}
// We let the bounding box only grow, so that when vertices get removed
// the maximal bbox gets refreshed in the GraphicsView
template <typename T>
void
AlphaShapeGraphicsItem<T>::updateBoundingBox()
{
prepareGeometryChange();
if(t->number_of_vertices() == 0){
bb = Bbox_2(0,0,0,0);
bb_initialized = false;
return;
} else if(! bb_initialized){
bb = t->finite_vertices_begin()->point().bbox();
bb_initialized = true;
}
if(t->dimension() <2){
for(typename T::Finite_vertices_iterator it = t->finite_vertices_begin();
it != t->finite_vertices_end();
++it){
bb = bb + it->point().bbox();
}
} else {
typename T::Vertex_handle inf = t->infinite_vertex();
typename T::Vertex_circulator vc = t->incident_vertices(inf), done(vc);
do {
bb = bb + vc->point().bbox();
++vc;
} while(vc != done);
}
bounding_rect = QRectF(bb.xmin(),
bb.ymin(),
bb.xmax()-bb.xmin(),
bb.ymax()-bb.ymin());
}
template <typename T>
void
AlphaShapeGraphicsItem<T>::modelChanged()
{
if((t->number_of_vertices() == 0) ){
this->hide();
} else if((t->number_of_vertices() > 0) && (! this->isVisible())){
this->show();
}
updateBoundingBox();
update();
}
} // namespace Qt
} // namespace CGAL
#endif // CGAL_QT_ALPHA_SHAPE_GRAPHICS_ITEM_H

View File

@ -22,15 +22,21 @@
#ifndef QGLVIEWER_CAMERA_H
#define QGLVIEWER_CAMERA_H
#include <QMap>
#include <CGAL/Qt/keyFrameInterpolator.h>
#include <QDomElement>
#include <CGAL/Qt/vec.h>
#include <CGAL/Qt/quaternion.h>
#include <CGAL/Qt/config.h>
#include <QOpenGLFunctions_2_1>
class QGLViewer;
namespace qglviewer {
class KeyFrameInterpolator;
class Frame;
class ManipulatedCameraFrame;
/*! \brief A perspective or orthographic camera.
\class Camera camera.h QGLViewer/camera.h
@ -98,7 +104,7 @@ class QGLVIEWER_EXPORT Camera : public QObject {
Q_OBJECT
public:
Camera();
Camera(QObject *parent);
virtual ~Camera();
Camera(const Camera &camera);
@ -182,9 +188,7 @@ public:
Value is set using setHorizontalFieldOfView() or setFieldOfView(). These
values are always linked by: \code horizontalFieldOfView() = 2.0 * atan (
tan(fieldOfView()/2.0) * aspectRatio() ). \endcode */
qreal horizontalFieldOfView() const {
return 2.0 * atan(tan(fieldOfView() / 2.0) * aspectRatio());
}
qreal horizontalFieldOfView() const;
/*! Returns the Camera aspect ratio defined by screenWidth() / screenHeight().
@ -265,9 +269,7 @@ public Q_SLOTS:
This method actually calls setFieldOfView(( 2.0 * atan (tan(hfov / 2.0) /
aspectRatio()) )) so that a call to horizontalFieldOfView() returns the
expected value. */
void setHorizontalFieldOfView(qreal hfov) {
setFieldOfView(2.0 * atan(tan(hfov / 2.0) / aspectRatio()));
}
void setHorizontalFieldOfView(qreal hfov);
void setFOVToFitScene();
@ -384,7 +386,6 @@ public Q_SLOTS:
virtual void playPath(unsigned int i);
virtual void deletePath(unsigned int i);
virtual void resetPath(unsigned int i);
virtual void drawAllPaths();
//@}
/*! @name OpenGL matrices */
@ -408,15 +409,6 @@ public:
void getModelViewProjectionMatrix(GLdouble m[16]) const;
//@}
/*! @name Drawing */
//@{
#ifndef DOXYGEN
static void drawCamera(qreal scale = 1.0, qreal aspectRatio = 1.33,
qreal fieldOfView = qreal(M_PI) / 4.0);
#endif
virtual void draw(bool drawFarPlane = true, qreal scale = 1.0) const;
//@}
/*! @name World to Camera coordinate systems conversions */
//@{
public:
@ -466,9 +458,7 @@ public:
This is a helper function. It simply returns physicalScreenWidth() / 2.0 /
tan(horizontalFieldOfView() / 2.0); */
qreal physicalDistanceToScreen() const {
return physicalScreenWidth() / 2.0 / tan(horizontalFieldOfView() / 2.0);
}
qreal physicalDistanceToScreen() const;
/*! Returns the physical screen width, in meters. Default value is 0.5m
(average monitor width).
@ -525,6 +515,7 @@ private Q_SLOTS:
void onFrameModified();
private:
QOpenGLFunctions_2_1* gl() const{ return dynamic_cast<QOpenGLFunctions_2_1*>(parent()); }
// F r a m e
ManipulatedCameraFrame *frame_;
@ -553,5 +544,4 @@ private:
};
} // namespace qglviewer
#endif // QGLVIEWER_CAMERA_H

File diff suppressed because it is too large Load Diff

View File

@ -48,7 +48,8 @@ Error : libQGLViewer requires a minimum Qt version of 4.0
#define M_PI 3.14159265358979323846
#endif
#ifndef QGLVIEWER_STATIC
#ifdef CREATE_QGLVIEWER_DLL
#if ( defined(CGAL_BUILD_SHARED_LIBS) && ( ! defined(CGAL_HEADER_ONLY) ) ) \
|| defined(CGAL_USE_Qt5_RESOURCES)
#if QT_VERSION >= 0x040500
#define QGLVIEWER_EXPORT Q_DECL_EXPORT
#else
@ -78,13 +79,6 @@ Error : libQGLViewer requires a minimum Qt version of 4.0
// OpenGL headers.
#include <QOpenGLWidget>
// GLU was removed from Qt in version 4.8
#ifdef Q_OS_MAC
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
// Container classes interfaces changed a lot in Qt.
// Compatibility patches are all grouped here.
#include <QList>

View File

@ -26,10 +26,10 @@
#include <CGAL/Qt/quaternion.h>
#include <CGAL/Qt/vec.h>
namespace qglviewer {
class Frame;
class Camera;
/*! \brief An interface class for Frame constraints.
\class Constraint constraint.h QGLViewer/constraint.h
@ -349,14 +349,14 @@ class QGLVIEWER_EXPORT CameraConstraint : public AxisPlaneConstraint {
public:
explicit CameraConstraint(const Camera *const camera);
/*! Virtual destructor. Empty. */
virtual ~CameraConstraint(){};
virtual ~CameraConstraint(){}
virtual void constrainTranslation(Vec &translation, Frame *const frame);
virtual void constrainRotation(Quaternion &rotation, Frame *const frame);
/*! Returns the associated Camera. Set using the CameraConstraint constructor.
*/
const Camera *camera() const { return camera_; };
const Camera *camera() const { return camera_; }
private:
const Camera *const camera_;
@ -364,4 +364,7 @@ private:
} // namespace qglviewer
#ifdef CGAL_HEADER_ONLY
//#include <CGAL/Qt/qglviewer_impl_list.h>
#endif // CGAL_HEADER_ONLY
#endif // QGLVIEWER_CONSTRAINT_H

View File

@ -0,0 +1,301 @@
/****************************************************************************
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
This file is part of the QGLViewer library version 2.7.0.
http://www.libqglviewer.com - contact@libqglviewer.com
This file may be used under the terms of the GNU General Public License
versions 2.0 or 3.0 as published by the Free Software Foundation and
appearing in the LICENSE file included in the packaging of this file.
In addition, as a special exception, Gilles Debunne gives you certain
additional rights, described in the file GPL_EXCEPTION in this package.
libQGLViewer uses dual licensing. Commercial/proprietary software must
purchase a libQGLViewer Commercial License.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#include <CGAL/license/GraphicsView.h>
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/Qt/constraint.h>
#include <CGAL/Qt/manipulatedCameraFrame.h>
#include <CGAL/Qt/camera.h>
using namespace qglviewer;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Constraint //
////////////////////////////////////////////////////////////////////////////////
/*! Default constructor.
translationConstraintType() and rotationConstraintType() are set to
AxisPlaneConstraint::FREE. translationConstraintDirection() and
rotationConstraintDirection() are set to (0,0,0). */
CGAL_INLINE_FUNCTION
AxisPlaneConstraint::AxisPlaneConstraint()
: translationConstraintType_(FREE), rotationConstraintType_(FREE) {
// Do not use set since setRotationConstraintType needs a read.
}
/*! Simply calls setTranslationConstraintType() and
* setTranslationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void AxisPlaneConstraint::setTranslationConstraint(Type type,
const Vec &direction) {
setTranslationConstraintType(type);
setTranslationConstraintDirection(direction);
}
/*! Defines the translationConstraintDirection(). The coordinate system where \p
* direction is expressed depends on your class implementation. */
CGAL_INLINE_FUNCTION
void AxisPlaneConstraint::setTranslationConstraintDirection(
const Vec &direction) {
if ((translationConstraintType() != AxisPlaneConstraint::FREE) &&
(translationConstraintType() != AxisPlaneConstraint::FORBIDDEN)) {
const qreal norm = direction.norm();
if (norm < 1E-8) {
qWarning("AxisPlaneConstraint::setTranslationConstraintDir: null vector "
"for translation constraint");
translationConstraintType_ = AxisPlaneConstraint::FREE;
} else
translationConstraintDir_ = direction / norm;
}
}
/*! Simply calls setRotationConstraintType() and
* setRotationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void AxisPlaneConstraint::setRotationConstraint(Type type,
const Vec &direction) {
setRotationConstraintType(type);
setRotationConstraintDirection(direction);
}
/*! Defines the rotationConstraintDirection(). The coordinate system where \p
* direction is expressed depends on your class implementation. */
CGAL_INLINE_FUNCTION
void AxisPlaneConstraint::setRotationConstraintDirection(const Vec &direction) {
if ((rotationConstraintType() != AxisPlaneConstraint::FREE) &&
(rotationConstraintType() != AxisPlaneConstraint::FORBIDDEN)) {
const qreal norm = direction.norm();
if (norm < 1E-8) {
qWarning("AxisPlaneConstraint::setRotationConstraintDir: null vector for "
"rotation constraint");
rotationConstraintType_ = AxisPlaneConstraint::FREE;
} else
rotationConstraintDir_ = direction / norm;
}
}
/*! Set the Type() of the rotationConstraintType(). Default is
AxisPlaneConstraint::FREE.
Depending on this value, the Frame will freely rotate
(AxisPlaneConstraint::FREE), will only be able to rotate around an axis
(AxisPlaneConstraint::AXIS), or will not able to rotate at all
(AxisPlaneConstraint::FORBIDDEN).
Use Frame::setOrientation() to define the orientation of the constrained Frame
before it gets constrained.
\attention An AxisPlaneConstraint::PLANE Type() is not meaningful for
rotational constraints and will be ignored. */
CGAL_INLINE_FUNCTION
void AxisPlaneConstraint::setRotationConstraintType(Type type) {
if (rotationConstraintType() == AxisPlaneConstraint::PLANE) {
qWarning("AxisPlaneConstraint::setRotationConstraintType: the PLANE type "
"cannot be used for a rotation constraints");
return;
}
rotationConstraintType_ = type;
}
////////////////////////////////////////////////////////////////////////////////
// LocalConstraint //
////////////////////////////////////////////////////////////////////////////////
/*! Depending on translationConstraintType(), constrain \p translation to be
along an axis or limited to a plane defined in the Frame local coordinate
system by translationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void LocalConstraint::constrainTranslation(Vec &translation,
Frame *const frame) {
Vec proj;
switch (translationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
proj = frame->rotation().rotate(translationConstraintDirection());
translation.projectOnPlane(proj);
break;
case AxisPlaneConstraint::AXIS:
proj = frame->rotation().rotate(translationConstraintDirection());
translation.projectOnAxis(proj);
break;
case AxisPlaneConstraint::FORBIDDEN:
translation = Vec(0.0, 0.0, 0.0);
break;
}
}
/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p
rotation to be a rotation around an axis whose direction is defined in the
Frame local coordinate system by rotationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void LocalConstraint::constrainRotation(Quaternion &rotation, Frame *const) {
switch (rotationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
break;
case AxisPlaneConstraint::AXIS: {
Vec axis = rotationConstraintDirection();
Vec quat = Vec(rotation[0], rotation[1], rotation[2]);
quat.projectOnAxis(axis);
rotation = Quaternion(quat, 2.0 * acos(rotation[3]));
} break;
case AxisPlaneConstraint::FORBIDDEN:
rotation = Quaternion(); // identity
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// WorldConstraint //
////////////////////////////////////////////////////////////////////////////////
/*! Depending on translationConstraintType(), constrain \p translation to be
along an axis or limited to a plane defined in the world coordinate system by
translationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void WorldConstraint::constrainTranslation(Vec &translation,
Frame *const frame) {
Vec proj;
switch (translationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
if (frame->referenceFrame()) {
proj = frame->referenceFrame()->transformOf(
translationConstraintDirection());
translation.projectOnPlane(proj);
} else
translation.projectOnPlane(translationConstraintDirection());
break;
case AxisPlaneConstraint::AXIS:
if (frame->referenceFrame()) {
proj = frame->referenceFrame()->transformOf(
translationConstraintDirection());
translation.projectOnAxis(proj);
} else
translation.projectOnAxis(translationConstraintDirection());
break;
case AxisPlaneConstraint::FORBIDDEN:
translation = Vec(0.0, 0.0, 0.0);
break;
}
}
/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p
rotation to be a rotation around an axis whose direction is defined in the
world coordinate system by rotationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void WorldConstraint::constrainRotation(Quaternion &rotation,
Frame *const frame) {
switch (rotationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
break;
case AxisPlaneConstraint::AXIS: {
Vec quat(rotation[0], rotation[1], rotation[2]);
Vec axis = frame->transformOf(rotationConstraintDirection());
quat.projectOnAxis(axis);
rotation = Quaternion(quat, 2.0 * acos(rotation[3]));
break;
}
case AxisPlaneConstraint::FORBIDDEN:
rotation = Quaternion(); // identity
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// CameraConstraint //
////////////////////////////////////////////////////////////////////////////////
/*! Creates a CameraConstraint, whose constrained directions are defined in the
\p camera coordinate system. */
CGAL_INLINE_FUNCTION
CameraConstraint::CameraConstraint(const Camera *const camera)
: AxisPlaneConstraint(), camera_(camera) {}
/*! Depending on translationConstraintType(), constrain \p translation to be
along an axis or limited to a plane defined in the camera() coordinate system
by translationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void CameraConstraint::constrainTranslation(Vec &translation,
Frame *const frame) {
Vec proj;
switch (translationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
proj =
camera()->frame()->inverseTransformOf(translationConstraintDirection());
if (frame->referenceFrame())
proj = frame->referenceFrame()->transformOf(proj);
translation.projectOnPlane(proj);
break;
case AxisPlaneConstraint::AXIS:
proj =
camera()->frame()->inverseTransformOf(translationConstraintDirection());
if (frame->referenceFrame())
proj = frame->referenceFrame()->transformOf(proj);
translation.projectOnAxis(proj);
break;
case AxisPlaneConstraint::FORBIDDEN:
translation = Vec(0.0, 0.0, 0.0);
break;
}
}
/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p
rotation to be a rotation around an axis whose direction is defined in the
camera() coordinate system by rotationConstraintDirection(). */
CGAL_INLINE_FUNCTION
void CameraConstraint::constrainRotation(Quaternion &rotation,
Frame *const frame) {
switch (rotationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
break;
case AxisPlaneConstraint::AXIS: {
Vec axis = frame->transformOf(
camera()->frame()->inverseTransformOf(rotationConstraintDirection()));
Vec quat = Vec(rotation[0], rotation[1], rotation[2]);
quat.projectOnAxis(axis);
rotation = Quaternion(quat, 2.0 * acos(rotation[3]));
} break;
case AxisPlaneConstraint::FORBIDDEN:
rotation = Quaternion(); // identity
break;
}
}

View File

@ -25,11 +25,13 @@
#include <QObject>
#include <QString>
#include <CGAL/Qt/constraint.h>
// #include "GL/gl.h" is now included in config.h for ease of configuration
#include <CGAL/Qt/config.h>
#include <CGAL/Qt/vec.h>
#include <CGAL/Qt/quaternion.h>
namespace qglviewer {
class Constraint;
/*! \brief The Frame class represents a coordinate system, defined by a position
and an orientation. \class Frame frame.h QGLViewer/frame.h
@ -456,4 +458,8 @@ private:
} // namespace qglviewer
#ifdef CGAL_HEADER_ONLY
//#include <CGAL/Qt/qglviewer_impl_list.h>
#endif // CGAL_HEADER_ONLY
#endif // QGLVIEWER_FRAME_H

File diff suppressed because it is too large Load Diff

View File

@ -28,14 +28,13 @@
#include <CGAL/Qt/quaternion.h>
// Not actually needed, but some bad compilers (Microsoft VS6) complain.
#include <CGAL/Qt/frame.h>
//#include <CGAL/Qt/frame.h>
// If you compiler complains about incomplete type, uncomment the next line
// #include "frame.h"
// and comment "class Frame;" 3 lines below
namespace qglviewer {
class Camera;
class Frame;
/*! \brief A keyFrame Catmull-Rom Frame interpolator.
\class KeyFrameInterpolator keyFrameInterpolator.h
@ -292,12 +291,6 @@ public Q_SLOTS:
virtual void interpolateAtTime(qreal time);
//@}
/*! @name Path drawing */
//@{
public:
virtual void drawPath(int mask = 1, int nbFrames = 6, qreal scale = 1.0);
//@}
/*! @name XML representation */
//@{
public:

View File

@ -0,0 +1,587 @@
/****************************************************************************
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
This file is part of the QGLViewer library version 2.7.0.
http://www.libqglviewer.com - contact@libqglviewer.com
This file may be used under the terms of the GNU General Public License
versions 2.0 or 3.0 as published by the Free Software Foundation and
appearing in the LICENSE file included in the packaging of this file.
In addition, as a special exception, Gilles Debunne gives you certain
additional rights, described in the file GPL_EXCEPTION in this package.
libQGLViewer uses dual licensing. Commercial/proprietary software must
purchase a libQGLViewer Commercial License.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#include <CGAL/license/GraphicsView.h>
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/Qt/keyFrameInterpolator.h>
#include <CGAL/Qt/domUtils.h>
using namespace qglviewer;
using namespace std;
/*! Creates a KeyFrameInterpolator, with \p frame as associated frame().
The frame() can be set or changed using setFrame().
interpolationTime(), interpolationSpeed() and interpolationPeriod() are set to
their default values. */
CGAL_INLINE_FUNCTION
KeyFrameInterpolator::KeyFrameInterpolator(Frame *frame)
: frame_(NULL), period_(40), interpolationTime_(0.0),
interpolationSpeed_(1.0), interpolationStarted_(false),
closedPath_(false), loopInterpolation_(false), pathIsValid_(false),
valuesAreValid_(true), currentFrameValid_(false)
// #CONNECTION# Values cut pasted initFromDOMElement()
{
setFrame(frame);
for (int i = 0; i < 4; ++i)
currentFrame_[i] = new QMutableListIterator<KeyFrame *>(keyFrame_);
connect(&timer_, SIGNAL(timeout()), SLOT(update()));
}
/*! Virtual destructor. Clears the keyFrame path. */
CGAL_INLINE_FUNCTION
KeyFrameInterpolator::~KeyFrameInterpolator() {
deletePath();
for (int i = 0; i < 4; ++i)
delete currentFrame_[i];
}
/*! Sets the frame() associated to the KeyFrameInterpolator. */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::setFrame(Frame *const frame) {
if (this->frame())
disconnect(this, SIGNAL(interpolated()), this->frame(),
SIGNAL(interpolated()));
frame_ = frame;
if (this->frame())
connect(this, SIGNAL(interpolated()), this->frame(),
SIGNAL(interpolated()));
}
/*! Updates frame() state according to current interpolationTime(). Then adds
interpolationPeriod()*interpolationSpeed() to interpolationTime().
This internal method is called by a timer when interpolationIsStarted(). It
can be used for debugging purpose. stopInterpolation() is called when
interpolationTime() reaches firstTime() or lastTime(), unless
loopInterpolation() is \c true. */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::update() {
interpolateAtTime(interpolationTime());
interpolationTime_ += interpolationSpeed() * interpolationPeriod() / 1000.0;
if (interpolationTime() > keyFrame_.last()->time()) {
if (loopInterpolation())
setInterpolationTime(keyFrame_.first()->time() + interpolationTime_ -
keyFrame_.last()->time());
else {
// Make sure last KeyFrame is reached and displayed
interpolateAtTime(keyFrame_.last()->time());
stopInterpolation();
}
Q_EMIT endReached();
} else if (interpolationTime() < keyFrame_.first()->time()) {
if (loopInterpolation())
setInterpolationTime(keyFrame_.last()->time() -
keyFrame_.first()->time() + interpolationTime_);
else {
// Make sure first KeyFrame is reached and displayed
interpolateAtTime(keyFrame_.first()->time());
stopInterpolation();
}
Q_EMIT endReached();
}
}
/*! Starts the interpolation process.
A timer is started with an interpolationPeriod() period that updates the
frame()'s position and orientation. interpolationIsStarted() will return \c
true until stopInterpolation() or toggleInterpolation() is called.
If \p period is positive, it is set as the new interpolationPeriod(). The
previous interpolationPeriod() is used otherwise (default).
If interpolationTime() is larger than lastTime(), interpolationTime() is reset
to firstTime() before interpolation starts (and inversely for negative
interpolationSpeed()).
Use setInterpolationTime() before calling this method to change the starting
interpolationTime().
See the <a href="../examples/keyFrames.html">keyFrames example</a> for an
illustration.
You may also be interested in QGLViewer::animate() and
QGLViewer::startAnimation().
\attention The keyFrames must be defined (see addKeyFrame()) \e before you
startInterpolation(), or else the interpolation will naturally immediately
stop. */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::startInterpolation(int period) {
if (period >= 0)
setInterpolationPeriod(period);
if (!keyFrame_.isEmpty()) {
if ((interpolationSpeed() > 0.0) &&
(interpolationTime() >= keyFrame_.last()->time()))
setInterpolationTime(keyFrame_.first()->time());
if ((interpolationSpeed() < 0.0) &&
(interpolationTime() <= keyFrame_.first()->time()))
setInterpolationTime(keyFrame_.last()->time());
timer_.start(interpolationPeriod());
interpolationStarted_ = true;
update();
}
}
/*! Stops an interpolation started with startInterpolation(). See
* interpolationIsStarted() and toggleInterpolation(). */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::stopInterpolation() {
timer_.stop();
interpolationStarted_ = false;
}
/*! Stops the interpolation and resets interpolationTime() to the firstTime().
If desired, call interpolateAtTime() after this method to actually move the
frame() to firstTime(). */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::resetInterpolation() {
stopInterpolation();
setInterpolationTime(firstTime());
}
/*! Appends a new keyFrame to the path, with its associated \p time (in
seconds).
The keyFrame is given as a pointer to a Frame, which will be connected to the
KeyFrameInterpolator: when \p frame is modified, the KeyFrameInterpolator path
is updated accordingly. This allows for dynamic paths, where keyFrame can be
edited, even during the interpolation. See the <a
href="../examples/keyFrames.html">keyFrames example</a> for an illustration.
\c NULL \p frame pointers are silently ignored. The keyFrameTime() has to be
monotonously increasing over keyFrames.
Use addKeyFrame(const Frame&, qreal) to add keyFrame by values. */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::addKeyFrame(const Frame *const frame, qreal time) {
if (!frame)
return;
if (keyFrame_.isEmpty())
interpolationTime_ = time;
if ((!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time))
qWarning(
"Error in KeyFrameInterpolator::addKeyFrame: time is not monotone");
else
keyFrame_.append(new KeyFrame(frame, time));
connect(frame, SIGNAL(modified()), SLOT(invalidateValues()));
valuesAreValid_ = false;
pathIsValid_ = false;
currentFrameValid_ = false;
resetInterpolation();
}
/*! Appends a new keyFrame to the path, with its associated \p time (in
seconds).
The path will use the current \p frame state. If you want the path to change
when \p frame is modified, you need to pass a \e pointer to the Frame instead
(see addKeyFrame(const Frame*, qreal)).
The keyFrameTime() have to be monotonously increasing over keyFrames. */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::addKeyFrame(const Frame &frame, qreal time) {
if (keyFrame_.isEmpty())
interpolationTime_ = time;
if ((!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time))
qWarning(
"Error in KeyFrameInterpolator::addKeyFrame: time is not monotone");
else
keyFrame_.append(new KeyFrame(frame, time));
valuesAreValid_ = false;
pathIsValid_ = false;
currentFrameValid_ = false;
resetInterpolation();
}
/*! Appends a new keyFrame to the path.
Same as addKeyFrame(const Frame* frame, qreal), except that the keyFrameTime()
is set to the previous keyFrameTime() plus one second (or 0.0 if there is no
previous keyFrame). */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::addKeyFrame(const Frame *const frame) {
qreal time;
if (keyFrame_.isEmpty())
time = 0.0;
else
time = lastTime() + 1.0;
addKeyFrame(frame, time);
}
/*! Appends a new keyFrame to the path.
Same as addKeyFrame(const Frame& frame, qreal), except that the keyFrameTime()
is automatically set to previous keyFrameTime() plus one second (or 0.0 if
there is no previous keyFrame). */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::addKeyFrame(const Frame &frame) {
qreal time;
if (keyFrame_.isEmpty())
time = 0.0;
else
time = keyFrame_.last()->time() + 1.0;
addKeyFrame(frame, time);
}
/*! Removes all keyFrames from the path. The numberOfKeyFrames() is set to 0. */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::deletePath() {
stopInterpolation();
qDeleteAll(keyFrame_);
keyFrame_.clear();
pathIsValid_ = false;
valuesAreValid_ = false;
currentFrameValid_ = false;
}
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::updateModifiedFrameValues() {
Quaternion prevQ = keyFrame_.first()->orientation();
KeyFrame *kf;
for (int i = 0; i < keyFrame_.size(); ++i) {
kf = keyFrame_.at(i);
if (kf->frame())
kf->updateValuesFromPointer();
kf->flipOrientationIfNeeded(prevQ);
prevQ = kf->orientation();
}
KeyFrame *prev = keyFrame_.first();
kf = keyFrame_.first();
int index = 1;
while (kf) {
KeyFrame *next = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
index++;
if (next)
kf->computeTangent(prev, next);
else
kf->computeTangent(prev, kf);
prev = kf;
kf = next;
}
valuesAreValid_ = true;
}
/*! Returns the Frame associated with the keyFrame at index \p index.
See also keyFrameTime(). \p index has to be in the range
0..numberOfKeyFrames()-1.
\note If this keyFrame was defined using a pointer to a Frame (see
addKeyFrame(const Frame* const)), the \e current pointed Frame state is
returned. */
CGAL_INLINE_FUNCTION
Frame KeyFrameInterpolator::keyFrame(int index) const {
const KeyFrame *const kf = keyFrame_.at(index);
return Frame(kf->position(), kf->orientation());
}
/*! Returns the time corresponding to the \p index keyFrame.
See also keyFrame(). \p index has to be in the range 0..numberOfKeyFrames()-1.
*/
CGAL_INLINE_FUNCTION
qreal KeyFrameInterpolator::keyFrameTime(int index) const {
return keyFrame_.at(index)->time();
}
/*! Returns the duration of the KeyFrameInterpolator path, expressed in seconds.
Simply corresponds to lastTime() - firstTime(). Returns 0.0 if the path has
less than 2 keyFrames. See also keyFrameTime(). */
CGAL_INLINE_FUNCTION
qreal KeyFrameInterpolator::duration() const {
return lastTime() - firstTime();
}
/*! Returns the time corresponding to the first keyFrame, expressed in seconds.
Returns 0.0 if the path is empty. See also lastTime(), duration() and
keyFrameTime(). */
CGAL_INLINE_FUNCTION
qreal KeyFrameInterpolator::firstTime() const {
if (keyFrame_.isEmpty())
return 0.0;
else
return keyFrame_.first()->time();
}
/*! Returns the time corresponding to the last keyFrame, expressed in seconds.
Returns 0.0 if the path is empty. See also firstTime(), duration() and
keyFrameTime(). */
CGAL_INLINE_FUNCTION
qreal KeyFrameInterpolator::lastTime() const {
if (keyFrame_.isEmpty())
return 0.0;
else
return keyFrame_.last()->time();
}
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::updateCurrentKeyFrameForTime(qreal time) {
// Assertion: times are sorted in monotone order.
// Assertion: keyFrame_ is not empty
// TODO: Special case for loops when closed path is implemented !!
if (!currentFrameValid_)
// Recompute everything from scrach
currentFrame_[1]->toFront();
while (currentFrame_[1]->peekNext()->time() > time) {
currentFrameValid_ = false;
if (!currentFrame_[1]->hasPrevious())
break;
currentFrame_[1]->previous();
}
if (!currentFrameValid_)
*currentFrame_[2] = *currentFrame_[1];
while (currentFrame_[2]->peekNext()->time() < time) {
currentFrameValid_ = false;
if (!currentFrame_[2]->hasNext())
break;
currentFrame_[2]->next();
}
if (!currentFrameValid_) {
*currentFrame_[1] = *currentFrame_[2];
if ((currentFrame_[1]->hasPrevious()) &&
(time < currentFrame_[2]->peekNext()->time()))
currentFrame_[1]->previous();
*currentFrame_[0] = *currentFrame_[1];
if (currentFrame_[0]->hasPrevious())
currentFrame_[0]->previous();
*currentFrame_[3] = *currentFrame_[2];
if (currentFrame_[3]->hasNext())
currentFrame_[3]->next();
currentFrameValid_ = true;
splineCacheIsValid_ = false;
}
// cout << "Time = " << time << " : " << currentFrame_[0]->peekNext()->time()
// << " , " << currentFrame_[1]->peekNext()->time() << " , " <<
// currentFrame_[2]->peekNext()->time() << " , " <<
// currentFrame_[3]->peekNext()->time() << endl;
}
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::updateSplineCache() {
Vec delta = currentFrame_[2]->peekNext()->position() -
currentFrame_[1]->peekNext()->position();
v1 = 3.0 * delta - 2.0 * currentFrame_[1]->peekNext()->tgP() -
currentFrame_[2]->peekNext()->tgP();
v2 = -2.0 * delta + currentFrame_[1]->peekNext()->tgP() +
currentFrame_[2]->peekNext()->tgP();
splineCacheIsValid_ = true;
}
/*! Interpolate frame() at time \p time (expressed in seconds).
interpolationTime() is set to \p time and frame() is set accordingly.
If you simply want to change interpolationTime() but not the frame() state,
use setInterpolationTime() instead.
Emits the interpolated() signal and makes the frame() emit the
Frame::interpolated() signal. */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::interpolateAtTime(qreal time) {
setInterpolationTime(time);
if ((keyFrame_.isEmpty()) || (!frame()))
return;
if (!valuesAreValid_)
updateModifiedFrameValues();
updateCurrentKeyFrameForTime(time);
if (!splineCacheIsValid_)
updateSplineCache();
qreal alpha;
qreal dt = currentFrame_[2]->peekNext()->time() -
currentFrame_[1]->peekNext()->time();
if (dt == 0.0)
alpha = 0.0;
else
alpha = (time - currentFrame_[1]->peekNext()->time()) / dt;
// Linear interpolation - debug
// Vec pos = alpha*(currentFrame_[2]->peekNext()->position()) +
// (1.0-alpha)*(currentFrame_[1]->peekNext()->position());
Vec pos =
currentFrame_[1]->peekNext()->position() +
alpha * (currentFrame_[1]->peekNext()->tgP() + alpha * (v1 + alpha * v2));
Quaternion q = Quaternion::squad(
currentFrame_[1]->peekNext()->orientation(),
currentFrame_[1]->peekNext()->tgQ(), currentFrame_[2]->peekNext()->tgQ(),
currentFrame_[2]->peekNext()->orientation(), alpha);
frame()->setPositionAndOrientationWithConstraint(pos, q);
Q_EMIT interpolated();
}
/*! Returns an XML \c QDomElement that represents the KeyFrameInterpolator.
The resulting QDomElement holds the KeyFrameInterpolator parameters as well as
the path keyFrames (if the keyFrame is defined by a pointer to a Frame, use its
current value).
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
Use initFromDOMElement() to restore the ManipulatedFrame state from the
resulting QDomElement.
See Vec::domElement() for a complete example. See also
Quaternion::domElement(), Camera::domElement()...
Note that the Camera::keyFrameInterpolator() are automatically saved by
QGLViewer::saveStateToFile() when a QGLViewer is closed. */
CGAL_INLINE_FUNCTION
QDomElement KeyFrameInterpolator::domElement(const QString &name,
QDomDocument &document) const {
QDomElement de = document.createElement(name);
int count = 0;
Q_FOREACH (KeyFrame *kf, keyFrame_) {
Frame fr(kf->position(), kf->orientation());
QDomElement kfNode = fr.domElement("KeyFrame", document);
kfNode.setAttribute("index", QString::number(count));
kfNode.setAttribute("time", QString::number(kf->time()));
de.appendChild(kfNode);
++count;
}
de.setAttribute("nbKF", QString::number(keyFrame_.count()));
de.setAttribute("time", QString::number(interpolationTime()));
de.setAttribute("speed", QString::number(interpolationSpeed()));
de.setAttribute("period", QString::number(interpolationPeriod()));
DomUtils::setBoolAttribute(de, "closedPath", closedPath());
DomUtils::setBoolAttribute(de, "loop", loopInterpolation());
return de;
}
/*! Restores the KeyFrameInterpolator state from a \c QDomElement created by
domElement().
Note that the frame() pointer is not included in the domElement(): you need to
setFrame() after this method to attach a Frame to the KeyFrameInterpolator.
See Vec::initFromDOMElement() for a complete code example.
See also Camera::initFromDOMElement() and Frame::initFromDOMElement(). */
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::initFromDOMElement(const QDomElement &element) {
qDeleteAll(keyFrame_);
keyFrame_.clear();
QDomElement child = element.firstChild().toElement();
while (!child.isNull()) {
if (child.tagName() == "KeyFrame") {
Frame fr;
fr.initFromDOMElement(child);
qreal time = DomUtils::qrealFromDom(child, "time", 0.0);
addKeyFrame(fr, time);
}
child = child.nextSibling().toElement();
}
// #CONNECTION# Values cut pasted from constructor
setInterpolationTime(DomUtils::qrealFromDom(element, "time", 0.0));
setInterpolationSpeed(DomUtils::qrealFromDom(element, "speed", 1.0));
setInterpolationPeriod(DomUtils::intFromDom(element, "period", 40));
setClosedPath(DomUtils::boolFromDom(element, "closedPath", false));
setLoopInterpolation(DomUtils::boolFromDom(element, "loop", false));
// setFrame(NULL);
pathIsValid_ = false;
valuesAreValid_ = false;
currentFrameValid_ = false;
stopInterpolation();
}
#ifndef DOXYGEN
//////////// KeyFrame private class implementation /////////
CGAL_INLINE_FUNCTION
KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame &fr, qreal t)
: time_(t), frame_(NULL) {
p_ = fr.position();
q_ = fr.orientation();
}
CGAL_INLINE_FUNCTION
KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame *fr, qreal t)
: time_(t), frame_(fr) {
updateValuesFromPointer();
}
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::KeyFrame::updateValuesFromPointer() {
p_ = frame()->position();
q_ = frame()->orientation();
}
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::KeyFrame::computeTangent(
const KeyFrame *const prev, const KeyFrame *const next) {
tgP_ = 0.5 * (next->position() - prev->position());
tgQ_ = Quaternion::squadTangent(prev->orientation(), q_, next->orientation());
}
CGAL_INLINE_FUNCTION
void KeyFrameInterpolator::KeyFrame::flipOrientationIfNeeded(
const Quaternion &prev) {
if (Quaternion::dot(prev, q_) < 0.0)
q_.negate();
}
#endif // DOXYGEN

View File

@ -22,8 +22,11 @@
#ifndef QGLVIEWER_MANIPULATED_CAMERA_FRAME_H
#define QGLVIEWER_MANIPULATED_CAMERA_FRAME_H
#include <QTimer>
#include <CGAL/Qt/config.h>
#include <CGAL/Qt/manipulatedFrame.h>
#include <CGAL/Qt/camera.h>
namespace qglviewer {
/*! \brief The ManipulatedCameraFrame class represents a ManipulatedFrame with
@ -41,8 +44,8 @@ namespace qglviewer {
A ManipulatedCameraFrame can also "fly" in the scene. It basically moves
forward, and turns according to the mouse motion. See flySpeed(),
sceneUpVector() and the QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD
QGLViewer::MouseAction.
sceneUpVector() and the MOVE_FORWARD and MOVE_BACKWARD
MouseAction.
See the <a href="../mouse.html">mouse page</a> for a description of the
possible actions that can be performed using the mouse and their bindings.
@ -74,7 +77,7 @@ public:
When the ManipulatedCameraFrame is associated to a Camera,
Camera::pivotPoint() also returns this value. This point can interactively be
changed using the mouse (see Camera::setPivotPointFromPixel() and
QGLViewer::RAP_FROM_PIXEL and QGLViewer::RAP_IS_CENTER in the <a
RAP_FROM_PIXEL and RAP_IS_CENTER in the <a
href="../mouse.html">mouse page</a>). */
Vec pivotPoint() const { return pivotPoint_; }
/*! Sets the pivotPoint(), defined in the world coordinate system. */
@ -125,7 +128,7 @@ public:
rotatesAroundUpVector_ = constrained;
}
/*! Returns whether or not the QGLViewer::ZOOM action zooms on the pivot
/*! Returns whether or not the ZOOM action zooms on the pivot
point.
When set to \c false (default), a zoom action will move the camera along its
@ -169,8 +172,8 @@ public:
/*! Returns the fly speed, expressed in OpenGL units.
It corresponds to the incremental displacement that is periodically applied to
the ManipulatedCameraFrame position when a QGLViewer::MOVE_FORWARD or
QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction is proceeded.
the ManipulatedCameraFrame position when a MOVE_FORWARD or
MOVE_BACKWARD MouseAction is proceeded.
\attention When the ManipulatedCameraFrame is set as the Camera::frame(), this
value is set according to the QGLViewer::sceneRadius() by
@ -180,8 +183,8 @@ public:
/*! Returns the up vector of the scene, expressed in the world coordinate
system.
In 'fly mode' (corresponding to the QGLViewer::MOVE_FORWARD and
QGLViewer::MOVE_BACKWARD QGLViewer::MouseAction bindings), horizontal
In 'fly mode' (corresponding to the MOVE_FORWARD and
MOVE_BACKWARD MouseAction bindings), horizontal
displacements of the mouse rotate the ManipulatedCameraFrame around this
vector. Vertical displacements rotate always around the Camera \c X axis.
@ -229,7 +232,7 @@ public Q_SLOTS:
protected:
virtual void startAction(
int ma,
bool withConstraint = true); // int is really a QGLViewer::MouseAction
bool withConstraint = true); // int is really a MouseAction
#endif
private Q_SLOTS:
@ -260,4 +263,7 @@ private:
} // namespace qglviewer
#ifdef CGAL_HEADER_ONLY
//#include <CGAL/Qt/qglviewer_impl_list.h>
#endif // CGAL_HEADER_ONLY
#endif // QGLVIEWER_MANIPULATED_CAMERA_FRAME_H

View File

@ -0,0 +1,500 @@
/****************************************************************************
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
This file is part of the QGLViewer library version 2.7.0.
http://www.libqglviewer.com - contact@libqglviewer.com
This file may be used under the terms of the GNU General Public License
versions 2.0 or 3.0 as published by the Free Software Foundation and
appearing in the LICENSE file included in the packaging of this file.
In addition, as a special exception, Gilles Debunne gives you certain
additional rights, described in the file GPL_EXCEPTION in this package.
libQGLViewer uses dual licensing. Commercial/proprietary software must
purchase a libQGLViewer Commercial License.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#include <CGAL/license/GraphicsView.h>
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/Qt/manipulatedCameraFrame.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/Qt/domUtils.h>
#include <CGAL/Qt/qglviewer.h>
#include <QMouseEvent>
using namespace qglviewer;
using namespace std;
/*! Default constructor.
flySpeed() is set to 0.0 and sceneUpVector() is (0,1,0). The pivotPoint() is
set to (0,0,0).
\attention Created object is removeFromMouseGrabberPool(). */
CGAL_INLINE_FUNCTION
ManipulatedCameraFrame::ManipulatedCameraFrame()
: driveSpeed_(0.0), sceneUpVector_(0.0, 1.0, 0.0),
rotatesAroundUpVector_(false), zoomsOnPivotPoint_(false) {
setFlySpeed(0.0);
removeFromMouseGrabberPool();
connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate()));
}
/*! Equal operator. Calls ManipulatedFrame::operator=() and then copy
* attributes. */
CGAL_INLINE_FUNCTION
ManipulatedCameraFrame &ManipulatedCameraFrame::
operator=(const ManipulatedCameraFrame &mcf) {
ManipulatedFrame::operator=(mcf);
setFlySpeed(mcf.flySpeed());
setSceneUpVector(mcf.sceneUpVector());
setRotatesAroundUpVector(mcf.rotatesAroundUpVector_);
setZoomsOnPivotPoint(mcf.zoomsOnPivotPoint_);
return *this;
}
/*! Copy constructor. Performs a deep copy of all members using operator=(). */
CGAL_INLINE_FUNCTION
ManipulatedCameraFrame::ManipulatedCameraFrame(
const ManipulatedCameraFrame &mcf)
: ManipulatedFrame(mcf) {
removeFromMouseGrabberPool();
connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate()));
(*this) = (mcf);
}
////////////////////////////////////////////////////////////////////////////////
/*! Overloading of ManipulatedFrame::spin().
Rotates the ManipulatedCameraFrame around its pivotPoint() instead of its
origin. */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::spin() {
rotateAroundPoint(spinningQuaternion(), pivotPoint());
}
#ifndef DOXYGEN
/*! Called for continuous frame motion in fly mode (see
MOVE_FORWARD). Emits manipulated(). */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::flyUpdate() {
static Vec flyDisp(0.0, 0.0, 0.0);
switch (action_) {
case MOVE_FORWARD:
flyDisp.z = -flySpeed();
translate(localInverseTransformOf(flyDisp));
break;
case MOVE_BACKWARD:
flyDisp.z = flySpeed();
translate(localInverseTransformOf(flyDisp));
break;
case DRIVE:
flyDisp.z = flySpeed() * driveSpeed_;
translate(localInverseTransformOf(flyDisp));
break;
default:
break;
}
// Needs to be out of the switch since ZOOM/fastDraw()/wheelEvent use this
// callback to trigger a final draw(). #CONNECTION# wheelEvent.
Q_EMIT manipulated();
}
CGAL_INLINE_FUNCTION
Vec ManipulatedCameraFrame::flyUpVector() const {
qWarning("flyUpVector() is deprecated. Use sceneUpVector() instead.");
return sceneUpVector();
}
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::setFlyUpVector(const Vec &up) {
qWarning("setFlyUpVector() is deprecated. Use setSceneUpVector() instead.");
setSceneUpVector(up);
}
#endif
/*! This method will be called by the Camera when its orientation is changed, so
that the sceneUpVector (private) is changed accordingly. You should not need to
call this method. */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::updateSceneUpVector() {
sceneUpVector_ = inverseTransformOf(Vec(0.0, 1.0, 0.0));
}
////////////////////////////////////////////////////////////////////////////////
// S t a t e s a v i n g a n d r e s t o r i n g //
////////////////////////////////////////////////////////////////////////////////
/*! Returns an XML \c QDomElement that represents the ManipulatedCameraFrame.
Adds to the ManipulatedFrame::domElement() the ManipulatedCameraFrame specific
informations in a \c ManipulatedCameraParameters child QDomElement.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
Use initFromDOMElement() to restore the ManipulatedCameraFrame state from the
resulting \c QDomElement.
See Vec::domElement() for a complete example. See also
Quaternion::domElement(), Frame::domElement(), Camera::domElement()... */
CGAL_INLINE_FUNCTION
QDomElement ManipulatedCameraFrame::domElement(const QString &name,
QDomDocument &document) const {
QDomElement e = ManipulatedFrame::domElement(name, document);
QDomElement mcp = document.createElement("ManipulatedCameraParameters");
mcp.setAttribute("flySpeed", QString::number(flySpeed()));
DomUtils::setBoolAttribute(mcp, "rotatesAroundUpVector",
rotatesAroundUpVector());
DomUtils::setBoolAttribute(mcp, "zoomsOnPivotPoint", zoomsOnPivotPoint());
mcp.appendChild(sceneUpVector().domElement("sceneUpVector", document));
e.appendChild(mcp);
return e;
}
/*! Restores the ManipulatedCameraFrame state from a \c QDomElement created by
domElement().
First calls ManipulatedFrame::initFromDOMElement() and then initializes
ManipulatedCameraFrame specific parameters. */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::initFromDOMElement(const QDomElement &element) {
// No need to initialize, since default sceneUpVector and flySpeed are not
// meaningful. It's better to keep current ones. And it would destroy
// constraint() and referenceFrame(). *this = ManipulatedCameraFrame();
ManipulatedFrame::initFromDOMElement(element);
QDomElement child = element.firstChild().toElement();
while (!child.isNull()) {
if (child.tagName() == "ManipulatedCameraParameters") {
setFlySpeed(DomUtils::qrealFromDom(child, "flySpeed", flySpeed()));
setRotatesAroundUpVector(
DomUtils::boolFromDom(child, "rotatesAroundUpVector", false));
setZoomsOnPivotPoint(
DomUtils::boolFromDom(child, "zoomsOnPivotPoint", false));
QDomElement schild = child.firstChild().toElement();
while (!schild.isNull()) {
if (schild.tagName() == "sceneUpVector")
setSceneUpVector(Vec(schild));
schild = schild.nextSibling().toElement();
}
}
child = child.nextSibling().toElement();
}
}
////////////////////////////////////////////////////////////////////////////////
// M o u s e h a n d l i n g //
////////////////////////////////////////////////////////////////////////////////
#ifndef DOXYGEN
/*! Protected internal method used to handle mouse events. */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::startAction(int ma, bool withConstraint) {
ManipulatedFrame::startAction(ma, withConstraint);
switch (action_) {
case MOVE_FORWARD:
case MOVE_BACKWARD:
case DRIVE:
flyTimer_.setSingleShot(false);
flyTimer_.start(10);
break;
case ROTATE:
constrainedRotationIsReversed_ = transformOf(sceneUpVector_).y < 0.0;
break;
default:
break;
}
}
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::zoom(qreal delta, const Camera *const camera) {
const qreal sceneRadius = camera->sceneRadius();
if (zoomsOnPivotPoint_) {
Vec direction = position() - camera->pivotPoint();
if (direction.norm() > 0.02 * sceneRadius || delta > 0.0)
translate(delta * direction);
} else {
const qreal coef =
qMax(fabs((camera->frame()->coordinatesOf(camera->pivotPoint())).z),
qreal(0.2) * sceneRadius);
Vec trans(0.0, 0.0, -coef * delta);
translate(inverseTransformOf(trans));
}
}
#endif
/*! Overloading of ManipulatedFrame::mouseMoveEvent().
Motion depends on mouse binding (see <a href="../mouse.html">mouse page</a> for
details). The resulting displacements are basically inverted from those of a
ManipulatedFrame. */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::mouseMoveEvent(QMouseEvent *const event,
Camera *const camera) {
// #CONNECTION# mouseMoveEvent does the update().
switch (action_) {
case TRANSLATE: {
const QPoint delta = prevPos_ - event->pos();
Vec trans(delta.x(), -delta.y(), 0.0);
// Scale to fit the screen mouse displacement
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(pivotPoint())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
translate(inverseTransformOf(translationSensitivity() * trans));
break;
}
case MOVE_FORWARD: {
Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
rotate(rot);
//#CONNECTION# wheelEvent MOVE_FORWARD case
// actual translation is made in flyUpdate().
// translate(inverseTransformOf(Vec(0.0, 0.0, -flySpeed())));
break;
}
case MOVE_BACKWARD: {
Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
rotate(rot);
// actual translation is made in flyUpdate().
// translate(inverseTransformOf(Vec(0.0, 0.0, flySpeed())));
break;
}
case DRIVE: {
Quaternion rot = turnQuaternion(event->x(), camera);
rotate(rot);
// actual translation is made in flyUpdate().
driveSpeed_ = 0.01 * (event->y() - pressPos_.y());
break;
}
case ZOOM: {
zoom(deltaWithPrevPos(event, camera), camera);
break;
}
case LOOK_AROUND: {
Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
rotate(rot);
break;
}
case ROTATE: {
Quaternion rot;
if (rotatesAroundUpVector_) {
// Multiply by 2.0 to get on average about the same speed as with the
// deformed ball
qreal dx = 2.0 * rotationSensitivity() * (prevPos_.x() - event->x()) /
camera->screenWidth();
qreal dy = 2.0 * rotationSensitivity() * (prevPos_.y() - event->y()) /
camera->screenHeight();
if (constrainedRotationIsReversed_)
dx = -dx;
Vec verticalAxis = transformOf(sceneUpVector_);
rot = Quaternion(verticalAxis, dx) * Quaternion(Vec(1.0, 0.0, 0.0), dy);
} else {
Vec trans = camera->projectedCoordinatesOf(pivotPoint());
rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1],
camera);
}
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
break;
}
case SCREEN_ROTATE: {
Vec trans = camera->projectedCoordinatesOf(pivotPoint());
const qreal angle = atan2(event->y() - trans[1], event->x() - trans[0]) -
atan2(prevPos_.y() - trans[1], prevPos_.x() - trans[0]);
Quaternion rot(Vec(0.0, 0.0, 1.0), angle);
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
updateSceneUpVector();
break;
}
case ROLL: {
const qreal angle =
M_PI * (event->x() - prevPos_.x()) / camera->screenWidth();
Quaternion rot(Vec(0.0, 0.0, 1.0), angle);
rotate(rot);
setSpinningQuaternion(rot);
updateSceneUpVector();
break;
}
case SCREEN_TRANSLATE: {
Vec trans;
int dir = mouseOriginalDirection(event);
if (dir == 1)
trans.setValue(prevPos_.x() - event->x(), 0.0, 0.0);
else if (dir == -1)
trans.setValue(0.0, event->y() - prevPos_.y(), 0.0);
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(pivotPoint())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
translate(inverseTransformOf(translationSensitivity() * trans));
break;
}
case ZOOM_ON_REGION:
case NO_MOUSE_ACTION:
break;
}
if (action_ != NO_MOUSE_ACTION) {
prevPos_ = event->pos();
if (action_ != ZOOM_ON_REGION)
// ZOOM_ON_REGION should not emit manipulated().
// prevPos_ is used to draw rectangle feedback.
Q_EMIT manipulated();
}
}
/*! This is an overload of ManipulatedFrame::mouseReleaseEvent(). The
MouseAction is terminated. */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::mouseReleaseEvent(QMouseEvent *const event,
Camera *const camera) {
if ((action_ == MOVE_FORWARD) ||
(action_ == MOVE_BACKWARD) || (action_ == DRIVE))
flyTimer_.stop();
if (action_ == ZOOM_ON_REGION)
camera->fitScreenRegion(QRect(pressPos_, event->pos()));
ManipulatedFrame::mouseReleaseEvent(event, camera);
}
/*! This is an overload of ManipulatedFrame::wheelEvent().
The wheel behavior depends on the wheel binded action. Current possible actions
are ZOOM, MOVE_FORWARD, MOVE_BACKWARD.
ZOOM speed depends on wheelSensitivity() while
MOVE_FORWARD and MOVE_BACKWARD depend on flySpeed(). See
QGLViewer::setWheelBinding() to customize the binding. */
CGAL_INLINE_FUNCTION
void ManipulatedCameraFrame::wheelEvent(QWheelEvent *const event,
Camera *const camera) {
//#CONNECTION# QGLViewer::setWheelBinding, ManipulatedFrame::wheelEvent.
switch (action_) {
case ZOOM: {
zoom(wheelDelta(event), camera);
Q_EMIT manipulated();
break;
}
case MOVE_FORWARD:
case MOVE_BACKWARD:
//#CONNECTION# mouseMoveEvent() MOVE_FORWARD case
translate(
inverseTransformOf(Vec(0.0, 0.0, 0.2 * flySpeed() * event->delta())));
Q_EMIT manipulated();
break;
default:
break;
}
// #CONNECTION# startAction should always be called before
if (previousConstraint_)
setConstraint(previousConstraint_);
// The wheel triggers a fastDraw. A final update() is needed after the last
// wheel event to polish the rendering using draw(). Since the last wheel
// event does not say its name, we use the flyTimer_ to trigger flyUpdate(),
// which emits manipulated. Two wheel events separated by more than this delay
// milliseconds will trigger a draw().
const int finalDrawAfterWheelEventDelay = 400;
// Starts (or prolungates) the timer.
flyTimer_.setSingleShot(true);
flyTimer_.start(finalDrawAfterWheelEventDelay);
// This could also be done *before* manipulated is emitted, so that
// isManipulated() returns false. But then fastDraw would not be used with
// wheel. Detecting the last wheel event and forcing a final draw() is done
// using the timer_.
action_ = NO_MOUSE_ACTION;
}
////////////////////////////////////////////////////////////////////////////////
/*! Returns a Quaternion that is a rotation around current camera Y,
* proportionnal to the horizontal mouse position. */
CGAL_INLINE_FUNCTION
Quaternion ManipulatedCameraFrame::turnQuaternion(int x,
const Camera *const camera) {
return Quaternion(Vec(0.0, 1.0, 0.0), rotationSensitivity() *
(prevPos_.x() - x) /
camera->screenWidth());
}
/*! Returns a Quaternion that is the composition of two rotations, inferred from
the mouse pitch (X axis) and yaw (sceneUpVector() axis). */
Quaternion
CGAL_INLINE_FUNCTION
ManipulatedCameraFrame::pitchYawQuaternion(int x, int y,
const Camera *const camera) {
const Quaternion rotX(Vec(1.0, 0.0, 0.0), rotationSensitivity() *
(prevPos_.y() - y) /
camera->screenHeight());
const Quaternion rotY(transformOf(sceneUpVector()),
rotationSensitivity() * (prevPos_.x() - x) /
camera->screenWidth());
return rotY * rotX;
}

View File

@ -22,16 +22,18 @@
#ifndef QGLVIEWER_MANIPULATED_FRAME_H
#define QGLVIEWER_MANIPULATED_FRAME_H
#include <CGAL/Qt/config.h>
#include <CGAL/Qt/frame.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/Qt/mouseGrabber.h>
#include <CGAL/Qt/qglviewer.h>
#include <CGAL/Qt/viewer_actions.h>
#include <QDateTime>
#include <QString>
#include <QTimer>
namespace qglviewer {
/*! \brief A ManipulatedFrame is a Frame that can be rotated and translated
using the mouse. \class ManipulatedFrame manipulatedFrame.h
QGLViewer/manipulatedFrame.h
@ -299,7 +301,7 @@ public:
modifiers, Qt::MouseButton buttons, MouseHandler handler, MouseAction action,
bool withConstraint).
*/
QGLViewer::MouseAction currentMouseAction() const { return action_; }
MouseAction currentMouseAction() const { return action_; }
//@}
/*! @name MouseGrabber implementation */
@ -322,12 +324,12 @@ protected:
Quaternion deformedBallQuaternion(int x, int y, qreal cx, qreal cy,
const Camera *const camera);
QGLViewer::MouseAction action_;
MouseAction action_;
Constraint *previousConstraint_; // When manipulation is without Contraint.
virtual void startAction(
int ma,
bool withConstraint = true); // int is really a QGLViewer::MouseAction
bool withConstraint = true); // int is really a MouseAction
void computeMouseSpeed(const QMouseEvent *const e);
int mouseOriginalDirection(const QMouseEvent *const e);
@ -372,4 +374,7 @@ private:
} // namespace qglviewer
#ifdef CGAL_HEADER_ONLY
//#include <CGAL/Qt/qglviewer_impl_list.h>
#endif // CGAL_HEADER_ONLY
#endif // QGLVIEWER_MANIPULATED_FRAME_H

View File

@ -0,0 +1,592 @@
/****************************************************************************
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
This file is part of the QGLViewer library version 2.7.0.
http://www.libqglviewer.com - contact@libqglviewer.com
This file may be used under the terms of the GNU General Public License
versions 2.0 or 3.0 as published by the Free Software Foundation and
appearing in the LICENSE file included in the packaging of this file.
In addition, as a special exception, Gilles Debunne gives you certain
additional rights, described in the file GPL_EXCEPTION in this package.
libQGLViewer uses dual licensing. Commercial/proprietary software must
purchase a libQGLViewer Commercial License.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#include <CGAL/license/GraphicsView.h>
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/Qt/manipulatedFrame.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/Qt/domUtils.h>
#include <CGAL/Qt/qglviewer.h>
#include <cstdlib>
#include <QMouseEvent>
using namespace qglviewer;
using namespace std;
/*! Default constructor.
The translation is set to (0,0,0), with an identity rotation (0,0,0,1) (see
Frame constructor for details).
The different sensitivities are set to their default values (see
rotationSensitivity(), translationSensitivity(), spinningSensitivity() and
wheelSensitivity()). */
CGAL_INLINE_FUNCTION
ManipulatedFrame::ManipulatedFrame()
: action_(NO_MOUSE_ACTION), keepsGrabbingMouse_(false) {
// #CONNECTION# initFromDOMElement and accessor docs
setRotationSensitivity(1.0);
setTranslationSensitivity(1.0);
setSpinningSensitivity(0.3);
setWheelSensitivity(1.0);
setZoomSensitivity(1.0);
isSpinning_ = false;
previousConstraint_ = NULL;
connect(&spinningTimer_, SIGNAL(timeout()), SLOT(spinUpdate()));
}
/*! Equal operator. Calls Frame::operator=() and then copy attributes. */
CGAL_INLINE_FUNCTION
ManipulatedFrame &ManipulatedFrame::operator=(const ManipulatedFrame &mf) {
Frame::operator=(mf);
setRotationSensitivity(mf.rotationSensitivity());
setTranslationSensitivity(mf.translationSensitivity());
setSpinningSensitivity(mf.spinningSensitivity());
setWheelSensitivity(mf.wheelSensitivity());
setZoomSensitivity(mf.zoomSensitivity());
mouseSpeed_ = 0.0;
dirIsFixed_ = false;
keepsGrabbingMouse_ = false;
action_ = NO_MOUSE_ACTION;
return *this;
}
/*! Copy constructor. Performs a deep copy of all attributes using operator=().
*/
CGAL_INLINE_FUNCTION
ManipulatedFrame::ManipulatedFrame(const ManipulatedFrame &mf)
: Frame(mf), MouseGrabber() {
(*this) = mf;
}
////////////////////////////////////////////////////////////////////////////////
/*! Implementation of the MouseGrabber main method.
The ManipulatedFrame grabsMouse() when the mouse is within a 10 pixels region
around its Camera::projectedCoordinatesOf() position().
See the <a href="../examples/mouseGrabber.html">mouseGrabber example</a> for an
illustration. */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::checkIfGrabsMouse(int x, int y,
const Camera *const camera) {
const int thresold = 10;
const Vec proj = camera->projectedCoordinatesOf(position());
setGrabsMouse(keepsGrabbingMouse_ || ((fabs(x - proj.x) < thresold) &&
(fabs(y - proj.y) < thresold)));
}
////////////////////////////////////////////////////////////////////////////////
// S t a t e s a v i n g a n d r e s t o r i n g //
////////////////////////////////////////////////////////////////////////////////
/*! Returns an XML \c QDomElement that represents the ManipulatedFrame.
Adds to the Frame::domElement() the ManipulatedFrame specific informations in a
\c ManipulatedParameters child QDomElement.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
Use initFromDOMElement() to restore the ManipulatedFrame state from the
resulting \c QDomElement.
See Vec::domElement() for a complete example. See also
Quaternion::domElement(), Camera::domElement()... */
CGAL_INLINE_FUNCTION
QDomElement ManipulatedFrame::domElement(const QString &name,
QDomDocument &document) const {
QDomElement e = Frame::domElement(name, document);
QDomElement mp = document.createElement("ManipulatedParameters");
mp.setAttribute("rotSens", QString::number(rotationSensitivity()));
mp.setAttribute("transSens", QString::number(translationSensitivity()));
mp.setAttribute("spinSens", QString::number(spinningSensitivity()));
mp.setAttribute("wheelSens", QString::number(wheelSensitivity()));
mp.setAttribute("zoomSens", QString::number(zoomSensitivity()));
e.appendChild(mp);
return e;
}
/*! Restores the ManipulatedFrame state from a \c QDomElement created by
domElement().
Fields that are not described in \p element are set to their default values (see
ManipulatedFrame()).
First calls Frame::initFromDOMElement() and then initializes ManipulatedFrame
specific parameters. Note that constraint() and referenceFrame() are not
restored and are left unchanged.
See Vec::initFromDOMElement() for a complete code example. */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::initFromDOMElement(const QDomElement &element) {
// Not called since it would set constraint() and referenceFrame() to NULL.
// *this = ManipulatedFrame();
Frame::initFromDOMElement(element);
stopSpinning();
QDomElement child = element.firstChild().toElement();
while (!child.isNull()) {
if (child.tagName() == "ManipulatedParameters") {
// #CONNECTION# constructor default values and accessor docs
setRotationSensitivity(DomUtils::qrealFromDom(child, "rotSens", 1.0));
setTranslationSensitivity(
DomUtils::qrealFromDom(child, "transSens", 1.0));
setSpinningSensitivity(DomUtils::qrealFromDom(child, "spinSens", 0.3));
setWheelSensitivity(DomUtils::qrealFromDom(child, "wheelSens", 1.0));
setZoomSensitivity(DomUtils::qrealFromDom(child, "zoomSens", 1.0));
}
child = child.nextSibling().toElement();
}
}
////////////////////////////////////////////////////////////////////////////////
// M o u s e h a n d l i n g //
////////////////////////////////////////////////////////////////////////////////
/*! Returns \c true when the ManipulatedFrame is being manipulated with the
mouse.
Can be used to change the display of the manipulated object during
manipulation.
When Camera::frame() of the QGLViewer::camera() isManipulated(),
QGLViewer::fastDraw() is used in place of QGLViewer::draw() for scene
rendering. A simplified drawing will then allow for interactive camera
displacements. */
CGAL_INLINE_FUNCTION
bool ManipulatedFrame::isManipulated() const {
return action_ != NO_MOUSE_ACTION;
}
/*! Starts the spinning of the ManipulatedFrame.
This method starts a timer that will call spin() every \p updateInterval
milliseconds. The ManipulatedFrame isSpinning() until you call stopSpinning().
*/
CGAL_INLINE_FUNCTION
void ManipulatedFrame::startSpinning(int updateInterval) {
isSpinning_ = true;
spinningTimer_.start(updateInterval);
}
/*! Rotates the ManipulatedFrame by its spinningQuaternion(). Called by a timer
when the ManipulatedFrame isSpinning(). */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::spin() { rotate(spinningQuaternion()); }
/* spin() and spinUpdate() differ since spin can be used by itself (for instance
by QGLViewer::SCREEN_ROTATE) without a spun emission. Much nicer to use the
spinningQuaternion() and hence spin() for these incremental updates. Nothing
special to be done for continuous spinning with this design. */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::spinUpdate() {
spin();
Q_EMIT spun();
}
#ifndef DOXYGEN
/*! Protected internal method used to handle mouse events. */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::startAction(int ma, bool withConstraint) {
action_ = (MouseAction)(ma);
// #CONNECTION# manipulatedFrame::wheelEvent,
// manipulatedCameraFrame::wheelEvent and mouseReleaseEvent() restore previous
// constraint
if (withConstraint)
previousConstraint_ = NULL;
else {
previousConstraint_ = constraint();
setConstraint(NULL);
}
switch (action_) {
case ROTATE:
case SCREEN_ROTATE:
mouseSpeed_ = 0.0;
stopSpinning();
break;
case SCREEN_TRANSLATE:
dirIsFixed_ = false;
break;
default:
break;
}
}
/*! Updates mouse speed, measured in pixels/milliseconds. Should be called by
any method which wants to use mouse speed. Currently used to trigger spinning in
mouseReleaseEvent(). */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::computeMouseSpeed(const QMouseEvent *const e) {
const QPoint delta = (e->pos() - prevPos_);
const qreal dist = sqrt(qreal(delta.x() * delta.x() + delta.y() * delta.y()));
delay_ = last_move_time.restart();
if (delay_ == 0)
// Less than a millisecond: assume delay = 1ms
mouseSpeed_ = dist;
else
mouseSpeed_ = dist / delay_;
}
/*! Return 1 if mouse motion was started horizontally and -1 if it was more
vertical. Returns 0 if this could not be determined yet (perfect diagonal
motion, rare). */
CGAL_INLINE_FUNCTION
int ManipulatedFrame::mouseOriginalDirection(const QMouseEvent *const e) {
static bool horiz =
true; // Two simultaneous manipulatedFrame require two mice !
if (!dirIsFixed_) {
const QPoint delta = e->pos() - pressPos_;
dirIsFixed_ = abs(delta.x()) != abs(delta.y());
horiz = abs(delta.x()) > abs(delta.y());
}
if (dirIsFixed_)
if (horiz)
return 1;
else
return -1;
else
return 0;
}
CGAL_INLINE_FUNCTION
qreal ManipulatedFrame::deltaWithPrevPos(QMouseEvent *const event,
Camera *const camera) const {
qreal dx = qreal(event->x() - prevPos_.x()) / camera->screenWidth();
qreal dy = qreal(event->y() - prevPos_.y()) / camera->screenHeight();
qreal value = fabs(dx) > fabs(dy) ? dx : dy;
return value * zoomSensitivity();
}
CGAL_INLINE_FUNCTION
qreal ManipulatedFrame::wheelDelta(const QWheelEvent *event) const {
static const qreal WHEEL_SENSITIVITY_COEF = 8E-4;
return event->delta() * wheelSensitivity() * WHEEL_SENSITIVITY_COEF;
}
CGAL_INLINE_FUNCTION
void ManipulatedFrame::zoom(qreal delta, const Camera *const camera) {
Vec trans(0.0, 0.0, (camera->position() - position()).norm() * delta);
trans = camera->frame()->orientation().rotate(trans);
if (referenceFrame())
trans = referenceFrame()->transformOf(trans);
translate(trans);
}
#endif // DOXYGEN
/*! Initiates the ManipulatedFrame mouse manipulation.
Overloading of MouseGrabber::mousePressEvent(). See also mouseMoveEvent() and
mouseReleaseEvent().
The mouse behavior depends on which button is pressed. See the <a
href="../mouse.html">QGLViewer mouse page</a> for details. */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::mousePressEvent(QMouseEvent *const event,
Camera *const camera) {
Q_UNUSED(camera);
if (grabsMouse())
keepsGrabbingMouse_ = true;
// #CONNECTION setMouseBinding
// action_ should no longer possibly be NO_MOUSE_ACTION since this value is
// not inserted in mouseBinding_
// if (action_ == NO_MOUSE_ACTION)
// event->ignore();
prevPos_ = pressPos_ = event->pos();
}
/*! Modifies the ManipulatedFrame according to the mouse motion.
Actual behavior depends on mouse bindings. See the MouseAction enum
and the <a href="../mouse.html">QGLViewer mouse page</a> for details.
The \p camera is used to fit the mouse motion with the display parameters (see
Camera::screenWidth(), Camera::screenHeight(), Camera::fieldOfView()).
Emits the manipulated() signal. */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::mouseMoveEvent(QMouseEvent *const event,
Camera *const camera) {
switch (action_) {
case TRANSLATE: {
const QPoint delta = event->pos() - prevPos_;
Vec trans(delta.x(), -delta.y(), 0.0);
// Scale to fit the screen mouse displacement
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(position())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
// Transform to world coordinate system.
trans =
camera->frame()->orientation().rotate(translationSensitivity() * trans);
// And then down to frame
if (referenceFrame())
trans = referenceFrame()->transformOf(trans);
translate(trans);
break;
}
case ZOOM: {
zoom(deltaWithPrevPos(event, camera), camera);
break;
}
case SCREEN_ROTATE: {
Vec trans = camera->projectedCoordinatesOf(position());
const qreal prev_angle =
atan2(prevPos_.y() - trans[1], prevPos_.x() - trans[0]);
const qreal angle = atan2(event->y() - trans[1], event->x() - trans[0]);
const Vec axis =
transformOf(camera->frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)));
Quaternion rot(axis, angle - prev_angle);
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
break;
}
case SCREEN_TRANSLATE: {
Vec trans;
int dir = mouseOriginalDirection(event);
if (dir == 1)
trans.setValue(event->x() - prevPos_.x(), 0.0, 0.0);
else if (dir == -1)
trans.setValue(0.0, prevPos_.y() - event->y(), 0.0);
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(position())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
// Transform to world coordinate system.
trans =
camera->frame()->orientation().rotate(translationSensitivity() * trans);
// And then down to frame
if (referenceFrame())
trans = referenceFrame()->transformOf(trans);
translate(trans);
break;
}
case ROTATE: {
Vec trans = camera->projectedCoordinatesOf(position());
Quaternion rot = deformedBallQuaternion(event->x(), event->y(), trans[0],
trans[1], camera);
trans = Vec(-rot[0], -rot[1], -rot[2]);
trans = camera->frame()->orientation().rotate(trans);
trans = transformOf(trans);
rot[0] = trans[0];
rot[1] = trans[1];
rot[2] = trans[2];
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
break;
}
case MOVE_FORWARD:
case MOVE_BACKWARD:
case LOOK_AROUND:
case ROLL:
case DRIVE:
case ZOOM_ON_REGION:
// These MouseAction values make no sense for a manipulatedFrame
break;
case NO_MOUSE_ACTION:
// Possible when the ManipulatedFrame is a MouseGrabber. This method is then
// called without startAction because of mouseTracking.
break;
}
if (action_ != NO_MOUSE_ACTION) {
prevPos_ = event->pos();
Q_EMIT manipulated();
}
}
/*! Stops the ManipulatedFrame mouse manipulation.
Overloading of MouseGrabber::mouseReleaseEvent().
If the action was a ROTATE MouseAction, a continuous
spinning is possible if the speed of the mouse cursor is larger than
spinningSensitivity() when the button is released. Press the rotate button again
to stop spinning. See startSpinning() and isSpinning(). */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::mouseReleaseEvent(QMouseEvent *const event,
Camera *const camera) {
Q_UNUSED(event);
Q_UNUSED(camera);
keepsGrabbingMouse_ = false;
if (previousConstraint_)
setConstraint(previousConstraint_);
if (((action_ == ROTATE) ||
(action_ == SCREEN_ROTATE)) &&
(mouseSpeed_ >= spinningSensitivity()))
startSpinning(delay_);
action_ = NO_MOUSE_ACTION;
}
/*! Overloading of MouseGrabber::mouseDoubleClickEvent().
Left button double click aligns the ManipulatedFrame with the \p camera axis
(see alignWithFrame() and ALIGN_FRAME). Right button projects the
ManipulatedFrame on the \p camera view direction. */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::mouseDoubleClickEvent(QMouseEvent *const event,
Camera *const camera) {
if (event->modifiers() == Qt::NoModifier)
switch (event->button()) {
case Qt::LeftButton:
alignWithFrame(camera->frame());
break;
case Qt::RightButton:
projectOnLine(camera->position(), camera->viewDirection());
break;
default:
break;
}
}
/*! Overloading of MouseGrabber::wheelEvent().
Using the wheel is equivalent to a ZOOM MouseAction. See
QGLViewer::setWheelBinding(), setWheelSensitivity(). */
CGAL_INLINE_FUNCTION
void ManipulatedFrame::wheelEvent(QWheelEvent *const event,
Camera *const camera) {
//#CONNECTION# QGLViewer::setWheelBinding
if (action_ == ZOOM) {
zoom(wheelDelta(event), camera);
Q_EMIT manipulated();
}
// #CONNECTION# startAction should always be called before
if (previousConstraint_)
setConstraint(previousConstraint_);
action_ = NO_MOUSE_ACTION;
}
////////////////////////////////////////////////////////////////////////////////
/*! Returns "pseudo-distance" from (x,y) to ball of radius size.
\arg for a point inside the ball, it is proportional to the euclidean distance
to the ball \arg for a point outside the ball, it is proportional to the inverse
of this distance (tends to zero) on the ball, the function is continuous. */
static qreal projectOnBall(qreal x, qreal y) {
// If you change the size value, change angle computation in
// deformedBallQuaternion().
const qreal size = 1.0;
const qreal size2 = size * size;
const qreal size_limit = size2 * 0.5;
const qreal d = x * x + y * y;
return d < size_limit ? sqrt(size2 - d) : size_limit / sqrt(d);
}
#ifndef DOXYGEN
/*! Returns a quaternion computed according to the mouse motion. Mouse positions
are projected on a deformed ball, centered on (\p cx,\p cy). */
Quaternion
CGAL_INLINE_FUNCTION
ManipulatedFrame::deformedBallQuaternion(int x, int y, qreal cx, qreal cy,
const Camera *const camera) {
// Points on the deformed ball
qreal px =
rotationSensitivity() * (prevPos_.x() - cx) / camera->screenWidth();
qreal py =
rotationSensitivity() * (cy - prevPos_.y()) / camera->screenHeight();
qreal dx = rotationSensitivity() * (x - cx) / camera->screenWidth();
qreal dy = rotationSensitivity() * (cy - y) / camera->screenHeight();
const Vec p1(px, py, projectOnBall(px, py));
const Vec p2(dx, dy, projectOnBall(dx, dy));
// Approximation of rotation angle
// Should be divided by the projectOnBall size, but it is 1.0
const Vec axis = cross(p2, p1);
const qreal angle =
5.0 *
asin(sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm()));
return Quaternion(axis, angle);
}
#endif // DOXYGEN

View File

@ -140,7 +140,7 @@ public:
MouseGrabber();
/*! Virtual destructor. Removes the MouseGrabber from the MouseGrabberPool().
*/
virtual ~MouseGrabber() { MouseGrabber::MouseGrabberPool_.removeAll(this); }
virtual ~MouseGrabber() { MouseGrabber::MouseGrabberPool().removeAll(this); }
/*! @name Mouse grabbing detection */
//@{
@ -198,12 +198,8 @@ public:
You should not have to directly use this list. Use
removeFromMouseGrabberPool() and addInMouseGrabberPool() to modify this list.
\attention This method returns a \c QPtrList<MouseGrabber> with Qt 3 and a \c
QList<MouseGrabber> with Qt 2. */
static const QList<MouseGrabber *> &MouseGrabberPool() {
return MouseGrabber::MouseGrabberPool_;
}
*/
static QList<MouseGrabber *> &MouseGrabberPool();
/*! Returns \c true if the MouseGrabber is currently in the MouseGrabberPool()
list.
@ -212,7 +208,7 @@ public:
removeFromMouseGrabberPool(), the QGLViewers no longer checkIfGrabsMouse() on
this MouseGrabber. Use addInMouseGrabberPool() to insert it back. */
bool isInMouseGrabberPool() const {
return MouseGrabber::MouseGrabberPool_.contains(
return MouseGrabber::MouseGrabberPool().contains(
const_cast<MouseGrabber *>(this));
}
void addInMouseGrabberPool();
@ -289,10 +285,11 @@ private:
bool grabsMouse_;
// Q G L V i e w e r p o o l
static QList<MouseGrabber *> MouseGrabberPool_;
};
} // namespace qglviewer
#ifdef CGAL_HEADER_ONLY
//#include <CGAL/Qt/qglviewer_impl_list.h>
#endif // CGAL_HEADER_ONLY
#endif // QGLVIEWER_MOUSE_GRABBER_H

View File

@ -0,0 +1,90 @@
/****************************************************************************
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
This file is part of the QGLViewer library version 2.7.0.
http://www.libqglviewer.com - contact@libqglviewer.com
This file may be used under the terms of the GNU General Public License
versions 2.0 or 3.0 as published by the Free Software Foundation and
appearing in the LICENSE file included in the packaging of this file.
In addition, as a special exception, Gilles Debunne gives you certain
additional rights, described in the file GPL_EXCEPTION in this package.
libQGLViewer uses dual licensing. Commercial/proprietary software must
purchase a libQGLViewer Commercial License.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#include <CGAL/license/GraphicsView.h>
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/Qt/mouseGrabber.h>
using namespace qglviewer;
// Static private variable
CGAL_INLINE_FUNCTION
QList<MouseGrabber *> &MouseGrabber::MouseGrabberPool() {
static QList<MouseGrabber*> MouseGrabberPool_;
return MouseGrabberPool_;
}
/*! Default constructor.
Adds the created MouseGrabber in the MouseGrabberPool(). grabsMouse() is set to
\c false. */
CGAL_INLINE_FUNCTION
MouseGrabber::MouseGrabber() : grabsMouse_(false) { addInMouseGrabberPool(); }
/*! Adds the MouseGrabber in the MouseGrabberPool().
All created MouseGrabber are automatically added in the MouseGrabberPool() by
the constructor. Trying to add a MouseGrabber that already
isInMouseGrabberPool() has no effect.
Use removeFromMouseGrabberPool() to remove the MouseGrabber from the list, so
that it is no longer tested with checkIfGrabsMouse() by the QGLViewer, and hence
can no longer grab mouse focus. Use isInMouseGrabberPool() to know the current
state of the MouseGrabber. */
CGAL_INLINE_FUNCTION
void MouseGrabber::addInMouseGrabberPool() {
if (!isInMouseGrabberPool())
MouseGrabber::MouseGrabberPool().append(this);
}
/*! Removes the MouseGrabber from the MouseGrabberPool().
See addInMouseGrabberPool() for details. Removing a MouseGrabber that is not in
MouseGrabberPool() has no effect. */
CGAL_INLINE_FUNCTION
void MouseGrabber::removeFromMouseGrabberPool() {
if (isInMouseGrabberPool())
MouseGrabber::MouseGrabberPool().removeAll(const_cast<MouseGrabber *>(this));
}
/*! Clears the MouseGrabberPool().
Use this method only if it is faster to clear the MouseGrabberPool() and then
to add back a few MouseGrabbers than to remove each one independently. Use
QGLViewer::setMouseTracking(false) instead if you want to disable mouse
grabbing.
When \p autoDelete is \c true, the MouseGrabbers of the MouseGrabberPool() are
actually deleted (use this only if you're sure of what you do). */
CGAL_INLINE_FUNCTION
void MouseGrabber::clearMouseGrabberPool(bool autoDelete) {
if (autoDelete)
qDeleteAll(MouseGrabber::MouseGrabberPool());
MouseGrabber::MouseGrabberPool().clear();
}

View File

@ -22,8 +22,13 @@
#ifndef QGLVIEWER_QGLVIEWER_H
#define QGLVIEWER_QGLVIEWER_H
#include <CGAL/Qt/config.h>
#include <CGAL/Qt/viewer_actions.h>
#include <CGAL/Qt/vec.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/Qt/keyFrameInterpolator.h>
#include <CGAL/Qt/manipulatedFrame.h>
#include <CGAL/Qt/manipulatedCameraFrame.h>
#include <QClipboard>
#include <QOpenGLFunctions_2_1>
@ -33,16 +38,13 @@
#include <QMap>
#include <QVector>
#include <QTime>
#include <QTimer>
#include <QGLContext>
class QTabWidget;
namespace qglviewer {
class MouseGrabber;
class ManipulatedFrame;
class ManipulatedCameraFrame;
} // namespace qglviewer
/*! \brief A versatile 3D OpenGL viewer based on QOpenGLWidget.
\class QGLViewer qglviewer.h QGLViewer/qglviewer.h
@ -248,7 +250,7 @@ public:
Default value is 1.0. This method is equivalent to camera()->sceneRadius().
See setSceneRadius(). */
qreal sceneRadius() const { return camera()->sceneRadius(); }
qreal sceneRadius() const;
/*! Returns the scene center, defined in world coordinates.
See sceneRadius() for details.
@ -258,24 +260,20 @@ public:
Do not mismatch this value (that only depends on the scene) with the
qglviewer::Camera::pivotPoint(). */
qglviewer::Vec sceneCenter() const { return camera()->sceneCenter(); }
qglviewer::Vec sceneCenter() const;
public Q_SLOTS:
/*! Sets the sceneRadius().
The camera() qglviewer::Camera::flySpeed() is set to 1% of this value by
this method. Simple wrapper around camera()->setSceneRadius(). */
virtual void setSceneRadius(qreal radius) {
camera()->setSceneRadius(radius);
}
virtual void setSceneRadius(qreal radius);
/*! Sets the sceneCenter(), defined in world coordinates.
\attention The qglviewer::Camera::pivotPoint() is set to the sceneCenter()
value by this method. */
virtual void setSceneCenter(const qglviewer::Vec &center) {
camera()->setSceneCenter(center);
}
virtual void setSceneCenter(const qglviewer::Vec &center);
/*! Convenient way to call setSceneCenter() and setSceneRadius() from a (world
axis aligned) bounding box of the scene. Takes the offset into account.
@ -286,17 +284,12 @@ public Q_SLOTS:
setSceneRadius((max-min).norm() / 2.0);
\endcode */
void setSceneBoundingBox(const qglviewer::Vec &min,
const qglviewer::Vec &max) {
camera()->setSceneBoundingBox(min + offset(), max + offset());
}
const qglviewer::Vec &max);
/*! Moves the camera so that the entire scene is visible.
Simple wrapper around qglviewer::Camera::showEntireScene(). */
void showEntireScene() {
camera()->showEntireScene();
update();
}
void showEntireScene() ;
//@}
/*! @name Associated objects */
@ -861,34 +854,10 @@ compatible with raster mode): use \c glRasterPos3fv() instead. */
/*! @name Keyboard customization */
//@{
public:
/*! Defines the different actions that can be associated with a keyboard
shortcut using setShortcut().
See the <a href="../keyboard.html">keyboard page</a> for details. */
enum KeyboardAction {
DRAW_AXIS,
DRAW_GRID,
DISPLAY_FPS,
ENABLE_TEXT,
EXIT_VIEWER,
CAMERA_MODE,
FULL_SCREEN,
STEREO,
ANIMATION,
HELP,
EDIT_CAMERA,
MOVE_CAMERA_LEFT,
MOVE_CAMERA_RIGHT,
MOVE_CAMERA_UP,
MOVE_CAMERA_DOWN,
INCREASE_FLYSPEED,
DECREASE_FLYSPEED
};
unsigned int shortcut(KeyboardAction action) const;
unsigned int shortcut(qglviewer::KeyboardAction action) const;
#ifndef DOXYGEN
// QGLViewer 1.x
unsigned int keyboardAccelerator(KeyboardAction action) const;
unsigned int keyboardAccelerator(qglviewer::KeyboardAction action) const;
Qt::Key keyFrameKey(unsigned int index) const;
Qt::KeyboardModifiers playKeyFramePathStateKey() const;
// QGLViewer 2.0 without Qt4 support
@ -900,9 +869,9 @@ public:
Qt::KeyboardModifiers playPathKeyboardModifiers() const;
public Q_SLOTS:
void setShortcut(KeyboardAction action, unsigned int key);
void setShortcut(qglviewer::KeyboardAction action, unsigned int key);
#ifndef DOXYGEN
void setKeyboardAccelerator(KeyboardAction action, unsigned int key);
void setKeyboardAccelerator(qglviewer::KeyboardAction action, unsigned int key);
#endif
void setKeyDescription(unsigned int key, QString description);
void clearShortcuts();
@ -924,97 +893,53 @@ public Q_SLOTS:
public:
/*! @name Mouse customization */
//@{
/*! Defines the different mouse handlers: camera() or manipulatedFrame().
Used by setMouseBinding(), setMouseBinding(Qt::KeyboardModifiers modifiers,
Qt::MouseButtons, ClickAction, bool, int) and setWheelBinding() to define
which handler receives the mouse events. */
enum MouseHandler { CAMERA, FRAME };
/*! Defines the possible actions that can be binded to a mouse click using
setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, ClickAction, bool,
int).
See the <a href="../mouse.html">mouse page</a> for details. */
enum ClickAction {
NO_CLICK_ACTION,
ZOOM_ON_PIXEL,
ZOOM_TO_FIT,
SELECT,
RAP_FROM_PIXEL,
RAP_IS_CENTER,
CENTER_FRAME,
CENTER_SCENE,
SHOW_ENTIRE_SCENE,
ALIGN_FRAME,
ALIGN_CAMERA
};
/*! Defines the possible actions that can be binded to a mouse action (a
click, followed by a mouse displacement).
These actions may be binded to the camera() or to the manipulatedFrame() (see
QGLViewer::MouseHandler) using setMouseBinding(). */
enum MouseAction {
NO_MOUSE_ACTION,
ROTATE,
ZOOM,
TRANSLATE,
MOVE_FORWARD,
LOOK_AROUND,
MOVE_BACKWARD,
SCREEN_ROTATE,
ROLL,
DRIVE,
SCREEN_TRANSLATE,
ZOOM_ON_REGION
};
#ifndef DOXYGEN
MouseAction mouseAction(unsigned int state) const;
qglviewer::MouseAction mouseAction(unsigned int state) const;
int mouseHandler(unsigned int state) const;
int mouseButtonState(MouseHandler handler, MouseAction action,
int mouseButtonState(qglviewer::MouseHandler handler, qglviewer::MouseAction action,
bool withConstraint = true) const;
ClickAction clickAction(unsigned int state, bool doubleClick,
qglviewer::ClickAction clickAction(unsigned int state, bool doubleClick,
Qt::MouseButtons buttonsBefore) const;
void getClickButtonState(ClickAction action, unsigned int &state,
void getClickButtonState(qglviewer::ClickAction action, unsigned int &state,
bool &doubleClick,
Qt::MouseButtons &buttonsBefore) const;
unsigned int wheelButtonState(MouseHandler handler, MouseAction action,
unsigned int wheelButtonState(qglviewer::MouseHandler handler, qglviewer::MouseAction action,
bool withConstraint = true) const;
#endif
MouseAction mouseAction(Qt::Key key, Qt::KeyboardModifiers modifiers,
qglviewer::MouseAction mouseAction(Qt::Key key, Qt::KeyboardModifiers modifiers,
Qt::MouseButton button) const;
int mouseHandler(Qt::Key key, Qt::KeyboardModifiers modifiers,
Qt::MouseButton button) const;
void getMouseActionBinding(MouseHandler handler, MouseAction action,
void getMouseActionBinding(qglviewer::MouseHandler handler, qglviewer::MouseAction action,
bool withConstraint, Qt::Key &key,
Qt::KeyboardModifiers &modifiers,
Qt::MouseButton &button) const;
ClickAction clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers,
qglviewer::ClickAction clickAction(Qt::Key key, Qt::KeyboardModifiers modifiers,
Qt::MouseButton button, bool doubleClick = false,
Qt::MouseButtons buttonsBefore = Qt::NoButton) const;
void getClickActionBinding(ClickAction action, Qt::Key &key,
void getClickActionBinding(qglviewer::ClickAction action, Qt::Key &key,
Qt::KeyboardModifiers &modifiers,
Qt::MouseButton &button, bool &doubleClick,
Qt::MouseButtons &buttonsBefore) const;
MouseAction wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const;
qglviewer::MouseAction wheelAction(Qt::Key key, Qt::KeyboardModifiers modifiers) const;
int wheelHandler(Qt::Key key, Qt::KeyboardModifiers modifiers) const;
void getWheelActionBinding(MouseHandler handler, MouseAction action,
void getWheelActionBinding(qglviewer::MouseHandler handler, qglviewer::MouseAction action,
bool withConstraint, Qt::Key &key,
Qt::KeyboardModifiers &modifiers) const;
public Q_SLOTS:
#ifndef DOXYGEN
void setMouseBinding(unsigned int state, MouseHandler handler,
MouseAction action, bool withConstraint = true);
void setMouseBinding(unsigned int state, ClickAction action,
void setMouseBinding(unsigned int state, qglviewer::MouseHandler handler,
qglviewer::MouseAction action, bool withConstraint = true);
void setMouseBinding(unsigned int state, qglviewer::ClickAction action,
bool doubleClick = false,
Qt::MouseButtons buttonsBefore = Qt::NoButton);
void
@ -1024,13 +949,13 @@ public Q_SLOTS:
#endif
void setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton buttons,
MouseHandler handler, MouseAction action,
qglviewer::MouseHandler handler, qglviewer::MouseAction action,
bool withConstraint = true);
void setMouseBinding(Qt::KeyboardModifiers modifiers, Qt::MouseButton button,
ClickAction action, bool doubleClick = false,
qglviewer::ClickAction action, bool doubleClick = false,
Qt::MouseButtons buttonsBefore = Qt::NoButton);
void setWheelBinding(Qt::KeyboardModifiers modifiers, MouseHandler handler,
MouseAction action, bool withConstraint = true);
void setWheelBinding(Qt::KeyboardModifiers modifiers, qglviewer::MouseHandler handler,
qglviewer::MouseAction action, bool withConstraint = true);
void
setMouseBindingDescription(Qt::KeyboardModifiers modifiers,
Qt::MouseButton button, QString description,
@ -1038,14 +963,14 @@ public Q_SLOTS:
Qt::MouseButtons buttonsBefore = Qt::NoButton);
void setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers,
Qt::MouseButton buttons, MouseHandler handler,
MouseAction action, bool withConstraint = true);
Qt::MouseButton buttons, qglviewer::MouseHandler handler,
qglviewer::MouseAction action, bool withConstraint = true);
void setMouseBinding(Qt::Key key, Qt::KeyboardModifiers modifiers,
Qt::MouseButton button, ClickAction action,
Qt::MouseButton button, qglviewer::ClickAction action,
bool doubleClick = false,
Qt::MouseButtons buttonsBefore = Qt::NoButton);
void setWheelBinding(Qt::Key key, Qt::KeyboardModifiers modifiers,
MouseHandler handler, MouseAction action,
qglviewer::MouseHandler handler, qglviewer::MouseAction action,
bool withConstraint = true);
void
setMouseBindingDescription(Qt::Key key, Qt::KeyboardModifiers modifiers,
@ -1056,18 +981,18 @@ public Q_SLOTS:
void clearMouseBindings();
#ifndef DOXYGEN
MouseAction wheelAction(Qt::KeyboardModifiers modifiers) const;
qglviewer::MouseAction wheelAction(Qt::KeyboardModifiers modifiers) const;
int wheelHandler(Qt::KeyboardModifiers modifiers) const;
void setHandlerKeyboardModifiers(MouseHandler handler,
void setHandlerKeyboardModifiers(qglviewer::MouseHandler handler,
Qt::KeyboardModifiers modifiers);
void setHandlerStateKey(MouseHandler handler, unsigned int buttonState);
void setMouseStateKey(MouseHandler handler, unsigned int buttonState);
void setHandlerStateKey(qglviewer::MouseHandler handler, unsigned int buttonState);
void setMouseStateKey(qglviewer::MouseHandler handler, unsigned int buttonState);
#endif
private:
static QString mouseActionString(QGLViewer::MouseAction ma);
static QString clickActionString(QGLViewer::ClickAction ca);
static QString mouseActionString(qglviewer::MouseAction ma);
static QString clickActionString(qglviewer::ClickAction ca);
//@}
/*! @name State persistence */
@ -1119,12 +1044,8 @@ public:
foreach (QGLViewer* viewer, QGLViewer::QGLViewerPool())
connect(myObject, SIGNAL(IHaveChangedSignal()), viewer, SLOT(update()));
\endcode
\attention With Qt version 3, this method returns a \c QPtrList instead. Use a
\c QPtrListIterator to iterate on the list instead.*/
static const QList<QGLViewer *> &QGLViewerPool() {
return QGLViewer::QGLViewerPool_;
}
*/
static QList<QGLViewer *> &QGLViewerPool();
/*! Returns the index of the QGLViewer \p viewer in the QGLViewerPool(). This
index in unique and can be used to identify the different created QGLViewers
@ -1135,7 +1056,7 @@ public:
available position in that list. Returns -1 if the QGLViewer could not be
found (which should not be possible). */
static int QGLViewerIndex(const QGLViewer *const viewer) {
return QGLViewer::QGLViewerPool_.indexOf(const_cast<QGLViewer *>(viewer));
return QGLViewer::QGLViewerPool().indexOf(const_cast<QGLViewer *>(viewer));
}
//@}
@ -1168,7 +1089,7 @@ private:
// Set parameters to their default values. Called by the constructors.
void defaultConstructor();
void handleKeyboardAction(KeyboardAction id);
void handleKeyboardAction(qglviewer::KeyboardAction id);
// C a m e r a
qglviewer::Camera *camera_;
@ -1227,8 +1148,8 @@ private:
// S h o r t c u t k e y s
void setDefaultShortcuts();
QString cameraPathKeysString() const;
QMap<KeyboardAction, QString> keyboardActionDescription_;
QMap<KeyboardAction, unsigned int> keyboardBinding_;
QMap<qglviewer::KeyboardAction, QString> keyboardActionDescription_;
QMap<qglviewer::KeyboardAction, unsigned int> keyboardBinding_;
QMap<unsigned int, QString> keyDescription_;
// K e y F r a m e s s h o r t c u t s
@ -1246,8 +1167,8 @@ private:
#ifndef DOXYGEN
// M o u s e a c t i o n s
struct MouseActionPrivate {
MouseHandler handler;
MouseAction action;
qglviewer::MouseHandler handler;
qglviewer::MouseAction action;
bool withConstraint;
};
@ -1319,15 +1240,12 @@ private:
QMap<ClickBindingPrivate, QString> mouseDescription_;
void setDefaultMouseBindings();
void performClickAction(ClickAction ca, const QMouseEvent *const e);
void performClickAction(qglviewer::ClickAction ca, const QMouseEvent *const e);
QMap<MouseBindingPrivate, MouseActionPrivate> mouseBinding_;
QMap<WheelBindingPrivate, MouseActionPrivate> wheelBinding_;
QMap<ClickBindingPrivate, ClickAction> clickBinding_;
QMap<ClickBindingPrivate, qglviewer::ClickAction> clickBinding_;
Qt::Key currentlyPressedKey_;
// Q G L V i e w e r p o o l
static QList<QGLViewer *> QGLViewerPool_;
// S t a t e F i l e
QString stateFileName_;
@ -1371,5 +1289,8 @@ public:
bool isOpenGL_4_3()const {return is_ogl_4_3; }
};
#ifdef CGAL_HEADER_ONLY
#include <CGAL/Qt/qglviewer_impl_list.h>
#endif // CGAL_HEADER_ONLY
#endif // QGLVIEWER_QGLVIEWER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
#ifndef QGLVIEWER_IMPL_LIST_H
#define QGLVIEWER_IMPL_LIST_H
#include <CGAL/Qt/vec_impl.h>
#include <CGAL/Qt/quaternion_impl.h>
#include <CGAL/Qt/frame_impl.h>
#include <CGAL/Qt/constraint_impl.h>
#include <CGAL/Qt/manipulatedFrame_impl.h>
#include <CGAL/Qt/manipulatedCameraFrame_impl.h>
#include <CGAL/Qt/camera_impl.h>
#include <CGAL/Qt/keyFrameInterpolator_impl.h>
#include <CGAL/Qt/qglviewer_impl.h>
#include <CGAL/Qt/mouseGrabber_impl.h>
#endif

View File

@ -22,7 +22,7 @@
#ifndef QGLVIEWER_QUATERNION_H
#define QGLVIEWER_QUATERNION_H
#include <CGAL/Qt/config.h>
#include <CGAL/Qt/vec.h>
#include <iostream>
#include <math.h>

View File

@ -0,0 +1,566 @@
/****************************************************************************
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
This file is part of the QGLViewer library version 2.7.0.
http://www.libqglviewer.com - contact@libqglviewer.com
This file may be used under the terms of the GNU General Public License
versions 2.0 or 3.0 as published by the Free Software Foundation and
appearing in the LICENSE file included in the packaging of this file.
In addition, as a special exception, Gilles Debunne gives you certain
additional rights, described in the file GPL_EXCEPTION in this package.
libQGLViewer uses dual licensing. Commercial/proprietary software must
purchase a libQGLViewer Commercial License.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#include <CGAL/license/GraphicsView.h>
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/Qt/quaternion.h>
#include <CGAL/Qt/domUtils.h>
#include <stdlib.h> // RAND_MAX
// All the methods are declared inline in Quaternion.h
using namespace qglviewer;
using namespace std;
/*! Constructs a Quaternion that will rotate from the \p from direction to the
\p to direction.
Note that this rotation is not uniquely defined. The selected axis is usually
orthogonal to \p from and \p to, minimizing the rotation angle. This method is
robust and can handle small or almost identical vectors. */
CGAL_INLINE_FUNCTION
Quaternion::Quaternion(const Vec &from, const Vec &to) {
const qreal epsilon = 1E-10;
const qreal fromSqNorm = from.squaredNorm();
const qreal toSqNorm = to.squaredNorm();
// Identity Quaternion when one vector is null
if ((fromSqNorm < epsilon) || (toSqNorm < epsilon)) {
q[0] = q[1] = q[2] = 0.0;
q[3] = 1.0;
} else {
Vec axis = cross(from, to);
const qreal axisSqNorm = axis.squaredNorm();
// Aligned vectors, pick any axis, not aligned with from or to
if (axisSqNorm < epsilon)
axis = from.orthogonalVec();
qreal angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm)));
if (from * to < 0.0)
angle = M_PI - angle;
setAxisAngle(axis, angle);
}
}
/*! Returns the image of \p v by the Quaternion inverse() rotation.
rotate() performs an inverse transformation. Same as inverse().rotate(v). */
CGAL_INLINE_FUNCTION
Vec Quaternion::inverseRotate(const Vec &v) const {
return inverse().rotate(v);
}
/*! Returns the image of \p v by the Quaternion rotation.
See also inverseRotate() and operator*(const Quaternion&, const Vec&). */
CGAL_INLINE_FUNCTION
Vec Quaternion::rotate(const Vec &v) const {
const qreal q00 = 2.0 * q[0] * q[0];
const qreal q11 = 2.0 * q[1] * q[1];
const qreal q22 = 2.0 * q[2] * q[2];
const qreal q01 = 2.0 * q[0] * q[1];
const qreal q02 = 2.0 * q[0] * q[2];
const qreal q03 = 2.0 * q[0] * q[3];
const qreal q12 = 2.0 * q[1] * q[2];
const qreal q13 = 2.0 * q[1] * q[3];
const qreal q23 = 2.0 * q[2] * q[3];
return Vec((1.0 - q11 - q22) * v[0] + (q01 - q23) * v[1] + (q02 + q13) * v[2],
(q01 + q23) * v[0] + (1.0 - q22 - q00) * v[1] + (q12 - q03) * v[2],
(q02 - q13) * v[0] + (q12 + q03) * v[1] +
(1.0 - q11 - q00) * v[2]);
}
/*! Set the Quaternion from a (supposedly correct) 3x3 rotation matrix.
The matrix is expressed in European format: its three \e columns are the
images by the rotation of the three vectors of an orthogonal basis. Note that
OpenGL uses a symmetric representation for its matrices.
setFromRotatedBasis() sets a Quaternion from the three axis of a rotated
frame. It actually fills the three columns of a matrix with these rotated
basis vectors and calls this method. */
CGAL_INLINE_FUNCTION
void Quaternion::setFromRotationMatrix(const qreal m[3][3]) {
// Compute one plus the trace of the matrix
const qreal onePlusTrace = 1.0 + m[0][0] + m[1][1] + m[2][2];
if (onePlusTrace > 1E-5) {
// Direct computation
const qreal s = sqrt(onePlusTrace) * 2.0;
q[0] = (m[2][1] - m[1][2]) / s;
q[1] = (m[0][2] - m[2][0]) / s;
q[2] = (m[1][0] - m[0][1]) / s;
q[3] = 0.25 * s;
} else {
// Computation depends on major diagonal term
if ((m[0][0] > m[1][1]) & (m[0][0] > m[2][2])) {
const qreal s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2.0;
q[0] = 0.25 * s;
q[1] = (m[0][1] + m[1][0]) / s;
q[2] = (m[0][2] + m[2][0]) / s;
q[3] = (m[1][2] - m[2][1]) / s;
} else if (m[1][1] > m[2][2]) {
const qreal s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2.0;
q[0] = (m[0][1] + m[1][0]) / s;
q[1] = 0.25 * s;
q[2] = (m[1][2] + m[2][1]) / s;
q[3] = (m[0][2] - m[2][0]) / s;
} else {
const qreal s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2.0;
q[0] = (m[0][2] + m[2][0]) / s;
q[1] = (m[1][2] + m[2][1]) / s;
q[2] = 0.25 * s;
q[3] = (m[0][1] - m[1][0]) / s;
}
}
normalize();
}
#ifndef DOXYGEN
CGAL_INLINE_FUNCTION
void Quaternion::setFromRotatedBase(const Vec &X, const Vec &Y, const Vec &Z) {
qWarning("setFromRotatedBase is deprecated, use setFromRotatedBasis instead");
setFromRotatedBasis(X, Y, Z);
}
#endif
/*! Sets the Quaternion from the three rotated vectors of an orthogonal basis.
The three vectors do not have to be normalized but must be orthogonal and
direct (X^Y=k*Z, with k>0).
\code
Quaternion q;
q.setFromRotatedBasis(X, Y, Z);
// Now q.rotate(Vec(1,0,0)) == X and q.inverseRotate(X) == Vec(1,0,0)
// Same goes for Y and Z with Vec(0,1,0) and Vec(0,0,1).
\endcode
See also setFromRotationMatrix() and Quaternion(const Vec&, const Vec&). */
CGAL_INLINE_FUNCTION
void Quaternion::setFromRotatedBasis(const Vec &X, const Vec &Y, const Vec &Z) {
qreal m[3][3];
qreal normX = X.norm();
qreal normY = Y.norm();
qreal normZ = Z.norm();
for (int i = 0; i < 3; ++i) {
m[i][0] = X[i] / normX;
m[i][1] = Y[i] / normY;
m[i][2] = Z[i] / normZ;
}
setFromRotationMatrix(m);
}
/*! Returns the axis vector and the angle (in radians) of the rotation
represented by the Quaternion. See the axis() and angle() documentations. */
CGAL_INLINE_FUNCTION
void Quaternion::getAxisAngle(Vec &axis, qreal &angle) const {
angle = 2.0 * acos(q[3]);
axis = Vec(q[0], q[1], q[2]);
const qreal sinus = axis.norm();
if (sinus > 1E-8)
axis /= sinus;
if (angle > M_PI) {
angle = 2.0 * qreal(M_PI) - angle;
axis = -axis;
}
}
/*! Returns the normalized axis direction of the rotation represented by the
Quaternion.
It is null for an identity Quaternion. See also angle() and getAxisAngle(). */
CGAL_INLINE_FUNCTION
Vec Quaternion::axis() const {
Vec res = Vec(q[0], q[1], q[2]);
const qreal sinus = res.norm();
if (sinus > 1E-8)
res /= sinus;
return (acos(q[3]) <= M_PI / 2.0) ? res : -res;
}
/*! Returns the angle (in radians) of the rotation represented by the
Quaternion.
This value is always in the range [0-pi]. Larger rotational angles are obtained
by inverting the axis() direction.
See also axis() and getAxisAngle(). */
CGAL_INLINE_FUNCTION
qreal Quaternion::angle() const {
const qreal angle = 2.0 * acos(q[3]);
return (angle <= M_PI) ? angle : 2.0 * M_PI - angle;
}
/*! Returns an XML \c QDomElement that represents the Quaternion.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
When output to a file, the resulting QDomElement will look like:
\code
<name q0=".." q1=".." q2=".." q3=".." />
\endcode
Use initFromDOMElement() to restore the Quaternion state from the resulting \c
QDomElement. See also the Quaternion(const QDomElement&) constructor.
CGAL_INLINE_FUNCTION
See the Vec::domElement() documentation for a complete QDomDocument creation
and saving example.
CGAL_INLINE_FUNCTION
See also Frame::domElement(), Camera::domElement(),
CGAL_INLINE_FUNCTION
KeyFrameInterpolator::domElement()... */
CGAL_INLINE_FUNCTION
QDomElement Quaternion::domElement(const QString &name,
QDomDocument &document) const {
QDomElement de = document.createElement(name);
de.setAttribute("q0", QString::number(q[0]));
de.setAttribute("q1", QString::number(q[1]));
de.setAttribute("q2", QString::number(q[2]));
de.setAttribute("q3", QString::number(q[3]));
return de;
}
/*! Restores the Quaternion state from a \c QDomElement created by domElement().
The \c QDomElement should contain the \c q0, \c q1 , \c q2 and \c q3
attributes. If one of these attributes is missing or is not a number, a warning
is displayed and these fields are respectively set to 0.0, 0.0, 0.0 and 1.0
(identity Quaternion).
See also the Quaternion(const QDomElement&) constructor. */
CGAL_INLINE_FUNCTION
void Quaternion::initFromDOMElement(const QDomElement &element) {
Quaternion q(element);
*this = q;
}
/*! Constructs a Quaternion from a \c QDomElement representing an XML code of
the form \code< anyTagName q0=".." q1=".." q2=".." q3=".." />\endcode
If one of these attributes is missing or is not a number, a warning is
displayed and the associated value is respectively set to 0, 0, 0 and 1
(identity Quaternion).
See also domElement() and initFromDOMElement(). */
CGAL_INLINE_FUNCTION
Quaternion::Quaternion(const QDomElement &element) {
QStringList attribute;
attribute << "q0"
<< "q1"
<< "q2"
<< "q3";
for (int i = 0; i < attribute.size(); ++i)
q[i] = DomUtils::qrealFromDom(element, attribute[i], ((i < 3) ? 0.0 : 1.0));
}
/*! Returns the Quaternion associated 4x4 OpenGL rotation matrix.
Use \c glMultMatrixd(q.matrix()) to apply the rotation represented by
Quaternion \c q to the current OpenGL matrix.
See also getMatrix(), getRotationMatrix() and inverseMatrix().
\attention The result is only valid until the next call to matrix(). Use it
immediately (as shown above) or consider using getMatrix() instead.
\attention The matrix is given in OpenGL format (row-major order) and is the
transpose of the actual mathematical European representation. Consider using
getRotationMatrix() instead. */
CGAL_INLINE_FUNCTION
const GLdouble *Quaternion::matrix() const {
static GLdouble m[4][4];
getMatrix(m);
return (const GLdouble *)(m);
}
/*! Fills \p m with the OpenGL representation of the Quaternion rotation.
Use matrix() if you do not need to store this matrix and simply want to alter
the current OpenGL matrix. See also getInverseMatrix() and Frame::getMatrix().
*/
CGAL_INLINE_FUNCTION
void Quaternion::getMatrix(GLdouble m[4][4]) const {
const qreal q00 = 2.0 * q[0] * q[0];
const qreal q11 = 2.0 * q[1] * q[1];
const qreal q22 = 2.0 * q[2] * q[2];
const qreal q01 = 2.0 * q[0] * q[1];
const qreal q02 = 2.0 * q[0] * q[2];
const qreal q03 = 2.0 * q[0] * q[3];
const qreal q12 = 2.0 * q[1] * q[2];
const qreal q13 = 2.0 * q[1] * q[3];
const qreal q23 = 2.0 * q[2] * q[3];
m[0][0] = 1.0 - q11 - q22;
m[1][0] = q01 - q23;
m[2][0] = q02 + q13;
m[0][1] = q01 + q23;
m[1][1] = 1.0 - q22 - q00;
m[2][1] = q12 - q03;
m[0][2] = q02 - q13;
m[1][2] = q12 + q03;
m[2][2] = 1.0 - q11 - q00;
m[0][3] = 0.0;
m[1][3] = 0.0;
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}
/*! Same as getMatrix(), but with a \c GLdouble[16] parameter. See also
* getInverseMatrix() and Frame::getMatrix(). */
CGAL_INLINE_FUNCTION
void Quaternion::getMatrix(GLdouble m[16]) const {
static GLdouble mat[4][4];
getMatrix(mat);
int count = 0;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
m[count++] = mat[i][j];
}
/*! Fills \p m with the 3x3 rotation matrix associated with the Quaternion.
See also getInverseRotationMatrix().
\attention \p m uses the European mathematical representation of the rotation
matrix. Use matrix() and getMatrix() to retrieve the OpenGL transposed
version. */
CGAL_INLINE_FUNCTION
void Quaternion::getRotationMatrix(qreal m[3][3]) const {
static GLdouble mat[4][4];
getMatrix(mat);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
// Beware of transposition
m[i][j] = qreal(mat[j][i]);
}
/*! Returns the associated 4x4 OpenGL \e inverse rotation matrix. This is simply
the matrix() of the inverse().
\attention The result is only valid until the next call to inverseMatrix().
Use it immediately (as in \c glMultMatrixd(q.inverseMatrix())) or use
getInverseMatrix() instead.
\attention The matrix is given in OpenGL format (row-major order) and is the
transpose of the actual mathematical European representation. Consider using
getInverseRotationMatrix() instead. */
CGAL_INLINE_FUNCTION
const GLdouble *Quaternion::inverseMatrix() const {
static GLdouble m[4][4];
getInverseMatrix(m);
return (const GLdouble *)(m);
}
/*! Fills \p m with the OpenGL matrix corresponding to the inverse() rotation.
Use inverseMatrix() if you do not need to store this matrix and simply want to
alter the current OpenGL matrix. See also getMatrix(). */
CGAL_INLINE_FUNCTION
void Quaternion::getInverseMatrix(GLdouble m[4][4]) const {
inverse().getMatrix(m);
}
/*! Same as getInverseMatrix(), but with a \c GLdouble[16] parameter. See also
* getMatrix(). */
CGAL_INLINE_FUNCTION
void Quaternion::getInverseMatrix(GLdouble m[16]) const {
inverse().getMatrix(m);
}
/*! \p m is set to the 3x3 \e inverse rotation matrix associated with the
Quaternion.
\attention This is the classical mathematical rotation matrix. The OpenGL
format uses its transposed version. See inverseMatrix() and getInverseMatrix().
*/
CGAL_INLINE_FUNCTION
void Quaternion::getInverseRotationMatrix(qreal m[3][3]) const {
static GLdouble mat[4][4];
getInverseMatrix(mat);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
// Beware of transposition
m[i][j] = qreal(mat[j][i]);
}
/*! Returns the slerp interpolation of Quaternions \p a and \p b, at time \p t.
\p t should range in [0,1]. Result is \p a when \p t=0 and \p b when \p t=1.
When \p allowFlip is \c true (default) the slerp interpolation will always use
the "shortest path" between the Quaternions' orientations, by "flipping" the
source Quaternion if needed (see negate()). */
CGAL_INLINE_FUNCTION
Quaternion Quaternion::slerp(const Quaternion &a, const Quaternion &b, qreal t,
bool allowFlip) {
qreal cosAngle = Quaternion::dot(a, b);
qreal c1, c2;
// Linear interpolation for close orientations
if ((1.0 - fabs(cosAngle)) < 0.01) {
c1 = 1.0 - t;
c2 = t;
} else {
// Spherical interpolation
qreal angle = acos(fabs(cosAngle));
qreal sinAngle = sin(angle);
c1 = sin(angle * (1.0 - t)) / sinAngle;
c2 = sin(angle * t) / sinAngle;
}
// Use the shortest path
if (allowFlip && (cosAngle < 0.0))
c1 = -c1;
return Quaternion(c1 * a[0] + c2 * b[0], c1 * a[1] + c2 * b[1],
c1 * a[2] + c2 * b[2], c1 * a[3] + c2 * b[3]);
}
/*! Returns the slerp interpolation of the two Quaternions \p a and \p b, at
time \p t, using tangents \p tgA and \p tgB.
The resulting Quaternion is "between" \p a and \p b (result is \p a when \p
t=0 and \p b for \p t=1).
Use squadTangent() to define the Quaternion tangents \p tgA and \p tgB. */
CGAL_INLINE_FUNCTION
Quaternion Quaternion::squad(const Quaternion &a, const Quaternion &tgA,
const Quaternion &tgB, const Quaternion &b,
qreal t) {
Quaternion ab = Quaternion::slerp(a, b, t);
Quaternion tg = Quaternion::slerp(tgA, tgB, t, false);
return Quaternion::slerp(ab, tg, 2.0 * t * (1.0 - t), false);
}
/*! Returns the logarithm of the Quaternion. See also exp(). */
CGAL_INLINE_FUNCTION
Quaternion Quaternion::log() {
qreal len = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
if (len < 1E-6)
return Quaternion(q[0], q[1], q[2], 0.0);
else {
qreal coef = acos(q[3]) / len;
return Quaternion(q[0] * coef, q[1] * coef, q[2] * coef, 0.0);
}
}
/*! Returns the exponential of the Quaternion. See also log(). */
CGAL_INLINE_FUNCTION
Quaternion Quaternion::exp() {
qreal theta = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
if (theta < 1E-6)
return Quaternion(q[0], q[1], q[2], cos(theta));
else {
qreal coef = sin(theta) / theta;
return Quaternion(q[0] * coef, q[1] * coef, q[2] * coef, cos(theta));
}
}
/*! Returns log(a. inverse() * b). Useful for squadTangent(). */
CGAL_INLINE_FUNCTION
Quaternion Quaternion::lnDif(const Quaternion &a, const Quaternion &b) {
Quaternion dif = a.inverse() * b;
dif.normalize();
return dif.log();
}
/*! Returns a tangent Quaternion for \p center, defined by \p before and \p
after Quaternions.
Useful for smooth spline interpolation of Quaternion with squad() and slerp().
*/
CGAL_INLINE_FUNCTION
Quaternion Quaternion::squadTangent(const Quaternion &before,
const Quaternion &center,
const Quaternion &after) {
Quaternion l1 = Quaternion::lnDif(center, before);
Quaternion l2 = Quaternion::lnDif(center, after);
Quaternion e;
for (int i = 0; i < 4; ++i)
e.q[i] = -0.25 * (l1.q[i] + l2.q[i]);
e = center * (e.exp());
// if (Quaternion::dot(e,b) < 0.0)
// e.negate();
return e;
}
CGAL_INLINE_FUNCTION
ostream &operator<<(ostream &o, const Quaternion &Q) {
return o << Q[0] << '\t' << Q[1] << '\t' << Q[2] << '\t' << Q[3];
}
/*! Returns a random unit Quaternion.
You can create a randomly directed unit vector using:
\code
CGAL_INLINE_FUNCTION
Vec randomDir = Quaternion::randomQuaternion() * Vec(1.0, 0.0, 0.0); // or any
other Vec \endcode
\note This function uses rand() to create pseudo-random numbers and the random
number generator can be initialized using srand().*/
CGAL_INLINE_FUNCTION
Quaternion Quaternion::randomQuaternion() {
// The rand() function is not very portable and may not be available on your
// system. Add the appropriate include or replace by an other random function
// in case of problem.
qreal seed = rand() / (qreal)RAND_MAX;
qreal r1 = sqrt(1.0 - seed);
qreal r2 = sqrt(seed);
qreal t1 = 2.0 * M_PI * (rand() / (qreal)RAND_MAX);
qreal t2 = 2.0 * M_PI * (rand() / (qreal)RAND_MAX);
return Quaternion(sin(t1) * r1, cos(t1) * r1, sin(t2) * r2, cos(t2) * r2);
}

View File

@ -0,0 +1,181 @@
/****************************************************************************
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
This file is part of the QGLViewer library version 2.7.0.
http://www.libqglviewer.com - contact@libqglviewer.com
This file may be used under the terms of the GNU General Public License
versions 2.0 or 3.0 as published by the Free Software Foundation and
appearing in the LICENSE file included in the packaging of this file.
In addition, as a special exception, Gilles Debunne gives you certain
additional rights, described in the file GPL_EXCEPTION in this package.
libQGLViewer uses dual licensing. Commercial/proprietary software must
purchase a libQGLViewer Commercial License.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#include <CGAL/license/GraphicsView.h>
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/Qt/vec.h>
#include <CGAL/Qt/domUtils.h>
// Most of the methods are declared inline in vec.h
using namespace qglviewer;
using namespace std;
/*! Projects the Vec on the axis of direction \p direction that passes through
the origin.
\p direction does not need to be normalized (but must be non null). */
CGAL_INLINE_FUNCTION
void Vec::projectOnAxis(const Vec &direction) {
#ifndef QT_NO_DEBUG
if (direction.squaredNorm() < 1.0E-10)
qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).",
direction.norm());
#endif
*this = (((*this) * direction) / direction.squaredNorm()) * direction;
}
/*! Projects the Vec on the plane whose normal is \p normal that passes through
the origin.
\p normal does not need to be normalized (but must be non null). */
CGAL_INLINE_FUNCTION
void Vec::projectOnPlane(const Vec &normal) {
#ifndef QT_NO_DEBUG
if (normal.squaredNorm() < 1.0E-10)
qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).",
normal.norm());
#endif
*this -= (((*this) * normal) / normal.squaredNorm()) * normal;
}
/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is
zero only for a null Vec. Note that the function that associates an
orthogonalVec() to a Vec is not continous. */
CGAL_INLINE_FUNCTION
Vec Vec::orthogonalVec() const {
// Find smallest component. Keep equal case for null values.
if ((fabs(y) >= 0.9 * fabs(x)) && (fabs(z) >= 0.9 * fabs(x)))
return Vec(0.0, -z, y);
else if ((fabs(x) >= 0.9 * fabs(y)) && (fabs(z) >= 0.9 * fabs(y)))
return Vec(-z, 0.0, x);
else
return Vec(-y, x, 0.0);
}
/*! Constructs a Vec from a \c QDomElement representing an XML code of the form
\code< anyTagName x=".." y=".." z=".." />\endcode
If one of these attributes is missing or is not a number, a warning is displayed
and the associated value is set to 0.0.
See also domElement() and initFromDOMElement(). */
CGAL_INLINE_FUNCTION
Vec::Vec(const QDomElement &element) {
QStringList attribute;
attribute << "x"
<< "y"
<< "z";
for (int i = 0; i < attribute.size(); ++i)
#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
this->operator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#else
v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#endif
}
/*! Returns an XML \c QDomElement that represents the Vec.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
When output to a file, the resulting QDomElement will look like:
\code
<name x=".." y=".." z=".." />
\endcode
Use initFromDOMElement() to restore the Vec state from the resulting \c
QDomElement. See also the Vec(const QDomElement&) constructor.
Here is complete example that creates a QDomDocument and saves it into a file:
\code
Vec sunPos;
QDomDocument document("myDocument");
QDomElement sunElement = document.createElement("Sun");
document.appendChild(sunElement);
sunElement.setAttribute("brightness", sunBrightness());
sunElement.appendChild(sunPos.domElement("sunPosition", document));
// Other additions to the document hierarchy...
// Save doc document
QFile f("myFile.xml");
if (f.open(IO_WriteOnly))
{
QTextStream out(&f);
document.save(out, 2);
f.close();
}
\endcode
CGAL_INLINE_FUNCTION
See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()...
*/
CGAL_INLINE_FUNCTION
QDomElement Vec::domElement(const QString &name, QDomDocument &document) const {
QDomElement de = document.createElement(name);
de.setAttribute("x", QString::number(x));
de.setAttribute("y", QString::number(y));
de.setAttribute("z", QString::number(z));
return de;
}
/*! Restores the Vec state from a \c QDomElement created by domElement().
The \c QDomElement should contain \c x, \c y and \c z attributes. If one of
these attributes is missing or is not a number, a warning is displayed and the
associated value is set to 0.0.
To restore the Vec state from an xml file, use:
\code
// Load DOM from file
QDomDocument doc;
QFile f("myFile.xml");
if (f.open(IO_ReadOnly))
{
doc.setContent(&f);
f.close();
}
// Parse the DOM tree and initialize
QDomElement main=doc.documentElement();
myVec.initFromDOMElement(main);
\endcode
See also the Vec(const QDomElement&) constructor. */
CGAL_INLINE_FUNCTION
void Vec::initFromDOMElement(const QDomElement &element) {
const Vec v(element);
*this = v;
}
CGAL_INLINE_FUNCTION
ostream &operator<<(ostream &o, const Vec &v) {
return o << v.x << '\t' << v.y << '\t' << v.z;
}

View File

@ -0,0 +1,75 @@
#ifndef VIEWER_ACTIONS_H
#define VIEWER_ACTIONS_H
namespace qglviewer {
/*! Defines the different actions that can be associated with a keyboard
shortcut using setShortcut().
See the <a href="../keyboard.html">keyboard page</a> for details. */
enum KeyboardAction {
DRAW_AXIS,
DRAW_GRID,
DISPLAY_FPS,
ENABLE_TEXT,
EXIT_VIEWER,
CAMERA_MODE,
FULL_SCREEN,
STEREO,
ANIMATION,
HELP,
EDIT_CAMERA,
MOVE_CAMERA_LEFT,
MOVE_CAMERA_RIGHT,
MOVE_CAMERA_UP,
MOVE_CAMERA_DOWN,
INCREASE_FLYSPEED,
DECREASE_FLYSPEED
};
/*! Defines the different mouse handlers: camera() or manipulatedFrame().
Used by setMouseBinding(), setMouseBinding(Qt::KeyboardModifiers modifiers,
Qt::MouseButtons, ClickAction, bool, int) and setWheelBinding() to define
which handler receives the mouse events. */
enum MouseHandler { CAMERA, FRAME };
/*! Defines the possible actions that can be binded to a mouse click using
setMouseBinding(Qt::KeyboardModifiers, Qt::MouseButtons, ClickAction, bool,
int).
See the <a href="../mouse.html">mouse page</a> for details. */
enum ClickAction {
NO_CLICK_ACTION,
ZOOM_ON_PIXEL,
ZOOM_TO_FIT,
SELECT,
RAP_FROM_PIXEL,
RAP_IS_CENTER,
CENTER_FRAME,
CENTER_SCENE,
SHOW_ENTIRE_SCENE,
ALIGN_FRAME,
ALIGN_CAMERA
};
/*! Defines the possible actions that can be binded to a mouse action (a
click, followed by a mouse displacement).
These actions may be binded to the camera() or to the manipulatedFrame() (see
QGLViewer::MouseHandler) using setMouseBinding(). */
enum MouseAction {
NO_MOUSE_ACTION,
ROTATE,
ZOOM,
TRANSLATE,
MOVE_FORWARD,
LOOK_AROUND,
MOVE_BACKWARD,
SCREEN_ROTATE,
ROLL,
DRIVE,
SCREEN_TRANSLATE,
ZOOM_ON_REGION
};
}
#endif // VIEWER_ACTIONS_H

File diff suppressed because it is too large Load Diff

View File

@ -19,262 +19,9 @@
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifndef CGAL_HEADER_ONLY
#include <CGAL/Qt/constraint.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/Qt/frame.h>
#include <CGAL/Qt/manipulatedCameraFrame.h>
#include <CGAL/Qt/constraint_impl.h>
using namespace qglviewer;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Constraint //
////////////////////////////////////////////////////////////////////////////////
/*! Default constructor.
translationConstraintType() and rotationConstraintType() are set to
AxisPlaneConstraint::FREE. translationConstraintDirection() and
rotationConstraintDirection() are set to (0,0,0). */
AxisPlaneConstraint::AxisPlaneConstraint()
: translationConstraintType_(FREE), rotationConstraintType_(FREE) {
// Do not use set since setRotationConstraintType needs a read.
}
/*! Simply calls setTranslationConstraintType() and
* setTranslationConstraintDirection(). */
void AxisPlaneConstraint::setTranslationConstraint(Type type,
const Vec &direction) {
setTranslationConstraintType(type);
setTranslationConstraintDirection(direction);
}
/*! Defines the translationConstraintDirection(). The coordinate system where \p
* direction is expressed depends on your class implementation. */
void AxisPlaneConstraint::setTranslationConstraintDirection(
const Vec &direction) {
if ((translationConstraintType() != AxisPlaneConstraint::FREE) &&
(translationConstraintType() != AxisPlaneConstraint::FORBIDDEN)) {
const qreal norm = direction.norm();
if (norm < 1E-8) {
qWarning("AxisPlaneConstraint::setTranslationConstraintDir: null vector "
"for translation constraint");
translationConstraintType_ = AxisPlaneConstraint::FREE;
} else
translationConstraintDir_ = direction / norm;
}
}
/*! Simply calls setRotationConstraintType() and
* setRotationConstraintDirection(). */
void AxisPlaneConstraint::setRotationConstraint(Type type,
const Vec &direction) {
setRotationConstraintType(type);
setRotationConstraintDirection(direction);
}
/*! Defines the rotationConstraintDirection(). The coordinate system where \p
* direction is expressed depends on your class implementation. */
void AxisPlaneConstraint::setRotationConstraintDirection(const Vec &direction) {
if ((rotationConstraintType() != AxisPlaneConstraint::FREE) &&
(rotationConstraintType() != AxisPlaneConstraint::FORBIDDEN)) {
const qreal norm = direction.norm();
if (norm < 1E-8) {
qWarning("AxisPlaneConstraint::setRotationConstraintDir: null vector for "
"rotation constraint");
rotationConstraintType_ = AxisPlaneConstraint::FREE;
} else
rotationConstraintDir_ = direction / norm;
}
}
/*! Set the Type() of the rotationConstraintType(). Default is
AxisPlaneConstraint::FREE.
Depending on this value, the Frame will freely rotate
(AxisPlaneConstraint::FREE), will only be able to rotate around an axis
(AxisPlaneConstraint::AXIS), or will not able to rotate at all
(AxisPlaneConstraint::FORBIDDEN).
Use Frame::setOrientation() to define the orientation of the constrained Frame
before it gets constrained.
\attention An AxisPlaneConstraint::PLANE Type() is not meaningful for
rotational constraints and will be ignored. */
void AxisPlaneConstraint::setRotationConstraintType(Type type) {
if (rotationConstraintType() == AxisPlaneConstraint::PLANE) {
qWarning("AxisPlaneConstraint::setRotationConstraintType: the PLANE type "
"cannot be used for a rotation constraints");
return;
}
rotationConstraintType_ = type;
}
////////////////////////////////////////////////////////////////////////////////
// LocalConstraint //
////////////////////////////////////////////////////////////////////////////////
/*! Depending on translationConstraintType(), constrain \p translation to be
along an axis or limited to a plane defined in the Frame local coordinate
system by translationConstraintDirection(). */
void LocalConstraint::constrainTranslation(Vec &translation,
Frame *const frame) {
Vec proj;
switch (translationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
proj = frame->rotation().rotate(translationConstraintDirection());
translation.projectOnPlane(proj);
break;
case AxisPlaneConstraint::AXIS:
proj = frame->rotation().rotate(translationConstraintDirection());
translation.projectOnAxis(proj);
break;
case AxisPlaneConstraint::FORBIDDEN:
translation = Vec(0.0, 0.0, 0.0);
break;
}
}
/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p
rotation to be a rotation around an axis whose direction is defined in the
Frame local coordinate system by rotationConstraintDirection(). */
void LocalConstraint::constrainRotation(Quaternion &rotation, Frame *const) {
switch (rotationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
break;
case AxisPlaneConstraint::AXIS: {
Vec axis = rotationConstraintDirection();
Vec quat = Vec(rotation[0], rotation[1], rotation[2]);
quat.projectOnAxis(axis);
rotation = Quaternion(quat, 2.0 * acos(rotation[3]));
} break;
case AxisPlaneConstraint::FORBIDDEN:
rotation = Quaternion(); // identity
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// WorldConstraint //
////////////////////////////////////////////////////////////////////////////////
/*! Depending on translationConstraintType(), constrain \p translation to be
along an axis or limited to a plane defined in the world coordinate system by
translationConstraintDirection(). */
void WorldConstraint::constrainTranslation(Vec &translation,
Frame *const frame) {
Vec proj;
switch (translationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
if (frame->referenceFrame()) {
proj = frame->referenceFrame()->transformOf(
translationConstraintDirection());
translation.projectOnPlane(proj);
} else
translation.projectOnPlane(translationConstraintDirection());
break;
case AxisPlaneConstraint::AXIS:
if (frame->referenceFrame()) {
proj = frame->referenceFrame()->transformOf(
translationConstraintDirection());
translation.projectOnAxis(proj);
} else
translation.projectOnAxis(translationConstraintDirection());
break;
case AxisPlaneConstraint::FORBIDDEN:
translation = Vec(0.0, 0.0, 0.0);
break;
}
}
/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p
rotation to be a rotation around an axis whose direction is defined in the
world coordinate system by rotationConstraintDirection(). */
void WorldConstraint::constrainRotation(Quaternion &rotation,
Frame *const frame) {
switch (rotationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
break;
case AxisPlaneConstraint::AXIS: {
Vec quat(rotation[0], rotation[1], rotation[2]);
Vec axis = frame->transformOf(rotationConstraintDirection());
quat.projectOnAxis(axis);
rotation = Quaternion(quat, 2.0 * acos(rotation[3]));
break;
}
case AxisPlaneConstraint::FORBIDDEN:
rotation = Quaternion(); // identity
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// CameraConstraint //
////////////////////////////////////////////////////////////////////////////////
/*! Creates a CameraConstraint, whose constrained directions are defined in the
\p camera coordinate system. */
CameraConstraint::CameraConstraint(const Camera *const camera)
: AxisPlaneConstraint(), camera_(camera) {}
/*! Depending on translationConstraintType(), constrain \p translation to be
along an axis or limited to a plane defined in the camera() coordinate system
by translationConstraintDirection(). */
void CameraConstraint::constrainTranslation(Vec &translation,
Frame *const frame) {
Vec proj;
switch (translationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
proj =
camera()->frame()->inverseTransformOf(translationConstraintDirection());
if (frame->referenceFrame())
proj = frame->referenceFrame()->transformOf(proj);
translation.projectOnPlane(proj);
break;
case AxisPlaneConstraint::AXIS:
proj =
camera()->frame()->inverseTransformOf(translationConstraintDirection());
if (frame->referenceFrame())
proj = frame->referenceFrame()->transformOf(proj);
translation.projectOnAxis(proj);
break;
case AxisPlaneConstraint::FORBIDDEN:
translation = Vec(0.0, 0.0, 0.0);
break;
}
}
/*! When rotationConstraintType() is AxisPlaneConstraint::AXIS, constrain \p
rotation to be a rotation around an axis whose direction is defined in the
camera() coordinate system by rotationConstraintDirection(). */
void CameraConstraint::constrainRotation(Quaternion &rotation,
Frame *const frame) {
switch (rotationConstraintType()) {
case AxisPlaneConstraint::FREE:
break;
case AxisPlaneConstraint::PLANE:
break;
case AxisPlaneConstraint::AXIS: {
Vec axis = frame->transformOf(
camera()->frame()->inverseTransformOf(rotationConstraintDirection()));
Vec quat = Vec(rotation[0], rotation[1], rotation[2]);
quat.projectOnAxis(axis);
rotation = Quaternion(quat, 2.0 * acos(rotation[3]));
} break;
case AxisPlaneConstraint::FORBIDDEN:
rotation = Quaternion(); // identity
break;
}
}
#endif // CGAL_HEADER_ONLY

File diff suppressed because it is too large Load Diff

View File

@ -19,693 +19,9 @@
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifndef CGAL_HEADER_ONLY
#include <CGAL/Qt/domUtils.h>
#include <CGAL/Qt/qglviewer.h> // for QGLViewer::drawAxis and Camera::drawCamera
#include <CGAL/Qt/keyFrameInterpolator.h>
#include <CGAL/Qt/keyFrameInterpolator_impl.h>
using namespace qglviewer;
using namespace std;
/*! Creates a KeyFrameInterpolator, with \p frame as associated frame().
The frame() can be set or changed using setFrame().
interpolationTime(), interpolationSpeed() and interpolationPeriod() are set to
their default values. */
KeyFrameInterpolator::KeyFrameInterpolator(Frame *frame)
: frame_(NULL), period_(40), interpolationTime_(0.0),
interpolationSpeed_(1.0), interpolationStarted_(false),
closedPath_(false), loopInterpolation_(false), pathIsValid_(false),
valuesAreValid_(true), currentFrameValid_(false)
// #CONNECTION# Values cut pasted initFromDOMElement()
{
setFrame(frame);
for (int i = 0; i < 4; ++i)
currentFrame_[i] = new QMutableListIterator<KeyFrame *>(keyFrame_);
connect(&timer_, SIGNAL(timeout()), SLOT(update()));
}
/*! Virtual destructor. Clears the keyFrame path. */
KeyFrameInterpolator::~KeyFrameInterpolator() {
deletePath();
for (int i = 0; i < 4; ++i)
delete currentFrame_[i];
}
/*! Sets the frame() associated to the KeyFrameInterpolator. */
void KeyFrameInterpolator::setFrame(Frame *const frame) {
if (this->frame())
disconnect(this, SIGNAL(interpolated()), this->frame(),
SIGNAL(interpolated()));
frame_ = frame;
if (this->frame())
connect(this, SIGNAL(interpolated()), this->frame(),
SIGNAL(interpolated()));
}
/*! Updates frame() state according to current interpolationTime(). Then adds
interpolationPeriod()*interpolationSpeed() to interpolationTime().
This internal method is called by a timer when interpolationIsStarted(). It
can be used for debugging purpose. stopInterpolation() is called when
interpolationTime() reaches firstTime() or lastTime(), unless
loopInterpolation() is \c true. */
void KeyFrameInterpolator::update() {
interpolateAtTime(interpolationTime());
interpolationTime_ += interpolationSpeed() * interpolationPeriod() / 1000.0;
if (interpolationTime() > keyFrame_.last()->time()) {
if (loopInterpolation())
setInterpolationTime(keyFrame_.first()->time() + interpolationTime_ -
keyFrame_.last()->time());
else {
// Make sure last KeyFrame is reached and displayed
interpolateAtTime(keyFrame_.last()->time());
stopInterpolation();
}
Q_EMIT endReached();
} else if (interpolationTime() < keyFrame_.first()->time()) {
if (loopInterpolation())
setInterpolationTime(keyFrame_.last()->time() -
keyFrame_.first()->time() + interpolationTime_);
else {
// Make sure first KeyFrame is reached and displayed
interpolateAtTime(keyFrame_.first()->time());
stopInterpolation();
}
Q_EMIT endReached();
}
}
/*! Starts the interpolation process.
A timer is started with an interpolationPeriod() period that updates the
frame()'s position and orientation. interpolationIsStarted() will return \c
true until stopInterpolation() or toggleInterpolation() is called.
If \p period is positive, it is set as the new interpolationPeriod(). The
previous interpolationPeriod() is used otherwise (default).
If interpolationTime() is larger than lastTime(), interpolationTime() is reset
to firstTime() before interpolation starts (and inversely for negative
interpolationSpeed()).
Use setInterpolationTime() before calling this method to change the starting
interpolationTime().
See the <a href="../examples/keyFrames.html">keyFrames example</a> for an
illustration.
You may also be interested in QGLViewer::animate() and
QGLViewer::startAnimation().
\attention The keyFrames must be defined (see addKeyFrame()) \e before you
startInterpolation(), or else the interpolation will naturally immediately
stop. */
void KeyFrameInterpolator::startInterpolation(int period) {
if (period >= 0)
setInterpolationPeriod(period);
if (!keyFrame_.isEmpty()) {
if ((interpolationSpeed() > 0.0) &&
(interpolationTime() >= keyFrame_.last()->time()))
setInterpolationTime(keyFrame_.first()->time());
if ((interpolationSpeed() < 0.0) &&
(interpolationTime() <= keyFrame_.first()->time()))
setInterpolationTime(keyFrame_.last()->time());
timer_.start(interpolationPeriod());
interpolationStarted_ = true;
update();
}
}
/*! Stops an interpolation started with startInterpolation(). See
* interpolationIsStarted() and toggleInterpolation(). */
void KeyFrameInterpolator::stopInterpolation() {
timer_.stop();
interpolationStarted_ = false;
}
/*! Stops the interpolation and resets interpolationTime() to the firstTime().
If desired, call interpolateAtTime() after this method to actually move the
frame() to firstTime(). */
void KeyFrameInterpolator::resetInterpolation() {
stopInterpolation();
setInterpolationTime(firstTime());
}
/*! Appends a new keyFrame to the path, with its associated \p time (in
seconds).
The keyFrame is given as a pointer to a Frame, which will be connected to the
KeyFrameInterpolator: when \p frame is modified, the KeyFrameInterpolator path
is updated accordingly. This allows for dynamic paths, where keyFrame can be
edited, even during the interpolation. See the <a
href="../examples/keyFrames.html">keyFrames example</a> for an illustration.
\c NULL \p frame pointers are silently ignored. The keyFrameTime() has to be
monotonously increasing over keyFrames.
Use addKeyFrame(const Frame&, qreal) to add keyFrame by values. */
void KeyFrameInterpolator::addKeyFrame(const Frame *const frame, qreal time) {
if (!frame)
return;
if (keyFrame_.isEmpty())
interpolationTime_ = time;
if ((!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time))
qWarning(
"Error in KeyFrameInterpolator::addKeyFrame: time is not monotone");
else
keyFrame_.append(new KeyFrame(frame, time));
connect(frame, SIGNAL(modified()), SLOT(invalidateValues()));
valuesAreValid_ = false;
pathIsValid_ = false;
currentFrameValid_ = false;
resetInterpolation();
}
/*! Appends a new keyFrame to the path, with its associated \p time (in
seconds).
The path will use the current \p frame state. If you want the path to change
when \p frame is modified, you need to pass a \e pointer to the Frame instead
(see addKeyFrame(const Frame*, qreal)).
The keyFrameTime() have to be monotonously increasing over keyFrames. */
void KeyFrameInterpolator::addKeyFrame(const Frame &frame, qreal time) {
if (keyFrame_.isEmpty())
interpolationTime_ = time;
if ((!keyFrame_.isEmpty()) && (keyFrame_.last()->time() > time))
qWarning(
"Error in KeyFrameInterpolator::addKeyFrame: time is not monotone");
else
keyFrame_.append(new KeyFrame(frame, time));
valuesAreValid_ = false;
pathIsValid_ = false;
currentFrameValid_ = false;
resetInterpolation();
}
/*! Appends a new keyFrame to the path.
Same as addKeyFrame(const Frame* frame, qreal), except that the keyFrameTime()
is set to the previous keyFrameTime() plus one second (or 0.0 if there is no
previous keyFrame). */
void KeyFrameInterpolator::addKeyFrame(const Frame *const frame) {
qreal time;
if (keyFrame_.isEmpty())
time = 0.0;
else
time = lastTime() + 1.0;
addKeyFrame(frame, time);
}
/*! Appends a new keyFrame to the path.
Same as addKeyFrame(const Frame& frame, qreal), except that the keyFrameTime()
is automatically set to previous keyFrameTime() plus one second (or 0.0 if
there is no previous keyFrame). */
void KeyFrameInterpolator::addKeyFrame(const Frame &frame) {
qreal time;
if (keyFrame_.isEmpty())
time = 0.0;
else
time = keyFrame_.last()->time() + 1.0;
addKeyFrame(frame, time);
}
/*! Removes all keyFrames from the path. The numberOfKeyFrames() is set to 0. */
void KeyFrameInterpolator::deletePath() {
stopInterpolation();
qDeleteAll(keyFrame_);
keyFrame_.clear();
pathIsValid_ = false;
valuesAreValid_ = false;
currentFrameValid_ = false;
}
static void drawCamera(qreal scale) {
glDisable(GL_LIGHTING);
const qreal halfHeight = scale * 0.07;
const qreal halfWidth = halfHeight * 1.3;
const qreal dist = halfHeight / tan(qreal(M_PI) / 8.0);
const qreal arrowHeight = 1.5 * halfHeight;
const qreal baseHeight = 1.2 * halfHeight;
const qreal arrowHalfWidth = 0.5 * halfWidth;
const qreal baseHalfWidth = 0.3 * halfWidth;
// Frustum outline
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_LINE_STRIP);
glVertex3d(-halfWidth, halfHeight, -dist);
glVertex3d(-halfWidth, -halfHeight, -dist);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(halfWidth, -halfHeight, -dist);
glVertex3d(-halfWidth, -halfHeight, -dist);
glEnd();
glBegin(GL_LINE_STRIP);
glVertex3d(halfWidth, -halfHeight, -dist);
glVertex3d(halfWidth, halfHeight, -dist);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(-halfWidth, halfHeight, -dist);
glVertex3d(halfWidth, halfHeight, -dist);
glEnd();
// Up arrow
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// Base
glBegin(GL_QUADS);
glVertex3d(-baseHalfWidth, halfHeight, -dist);
glVertex3d(baseHalfWidth, halfHeight, -dist);
glVertex3d(baseHalfWidth, baseHeight, -dist);
glVertex3d(-baseHalfWidth, baseHeight, -dist);
glEnd();
// Arrow
glBegin(GL_TRIANGLES);
glVertex3d(0.0, arrowHeight, -dist);
glVertex3d(-arrowHalfWidth, baseHeight, -dist);
glVertex3d(arrowHalfWidth, baseHeight, -dist);
glEnd();
}
/*! Draws the path used to interpolate the frame().
\p mask controls what is drawn: if (mask & 1) (default), the position path is
drawn. If (mask & 2), a camera representation is regularly drawn and if (mask
& 4), an oriented axis is regularly drawn. Examples:
\code
drawPath(); // Simply draws the interpolation path
drawPath(3); // Draws path and cameras
drawPath(5); // Draws path and axis
\endcode
In the case where camera or axis is drawn, \p nbFrames controls the number of
objects (axis or camera) drawn between two successive keyFrames. When \p
nbFrames=1, only the path KeyFrames are drawn. \p nbFrames=2 also draws the
intermediate orientation, etc. The maximum value is 30. \p nbFrames should
divide 30 so that an object is drawn for each KeyFrame. Default value is 6.
\p scale (default=1.0) controls the scaling of the camera and axis drawing. A
value of QGLViewer::sceneRadius() should give good results.
See the <a href="../examples/keyFrames.html">keyFrames example</a> for an
illustration.
The color of the path is the current \c glColor().
\attention The OpenGL state is modified by this method: GL_LIGHTING is
disabled and line width set to 2. Use this code to preserve your current
OpenGL state: \code glPushAttrib(GL_ALL_ATTRIB_BITS);
drawPathModifyGLState(mask, nbFrames, scale);
glPopAttrib();
\endcode */
void KeyFrameInterpolator::drawPath(int mask, int nbFrames, qreal scale) {
const int nbSteps = 30;
if (!pathIsValid_) {
path_.clear();
if (keyFrame_.isEmpty())
return;
if (!valuesAreValid_)
updateModifiedFrameValues();
if (keyFrame_.first() == keyFrame_.last())
path_.push_back(Frame(keyFrame_.first()->position(),
keyFrame_.first()->orientation()));
else {
static Frame fr;
KeyFrame *kf_[4];
kf_[0] = keyFrame_.first();
kf_[1] = kf_[0];
int index = 1;
kf_[2] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
index++;
kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
while (kf_[2]) {
Vec diff = kf_[2]->position() - kf_[1]->position();
Vec v1 = 3.0 * diff - 2.0 * kf_[1]->tgP() - kf_[2]->tgP();
Vec v2 = -2.0 * diff + kf_[1]->tgP() + kf_[2]->tgP();
// cout << kf_[0]->time() << " , " << kf_[1]->time() << " , " <<
// kf_[2]->time() << " , " << kf_[3]->time() << endl;
for (int step = 0; step < nbSteps; ++step) {
qreal alpha = step / static_cast<qreal>(nbSteps);
fr.setPosition(kf_[1]->position() +
alpha * (kf_[1]->tgP() + alpha * (v1 + alpha * v2)));
fr.setOrientation(Quaternion::squad(kf_[1]->orientation(),
kf_[1]->tgQ(), kf_[2]->tgQ(),
kf_[2]->orientation(), alpha));
path_.push_back(fr);
}
// Shift
kf_[0] = kf_[1];
kf_[1] = kf_[2];
kf_[2] = kf_[3];
index++;
kf_[3] = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
}
// Add last KeyFrame
path_.push_back(Frame(kf_[1]->position(), kf_[1]->orientation()));
}
pathIsValid_ = true;
}
if (mask) {
glDisable(GL_LIGHTING);
glLineWidth(2);
if (mask & 1) {
glBegin(GL_LINE_STRIP);
Q_FOREACH (Frame fr, path_)
glVertex3fv(fr.position());
glEnd();
}
if (mask & 6) {
int count = 0;
if (nbFrames > nbSteps)
nbFrames = nbSteps;
qreal goal = 0.0;
Q_FOREACH (Frame fr, path_)
if ((count++) >= goal) {
goal += nbSteps / static_cast<qreal>(nbFrames);
glPushMatrix();
glMultMatrixd(fr.matrix());
if (mask & 2)
drawCamera(scale);
//if (mask & 4)
// QGLViewer::drawAxis(scale / 10.0);
glPopMatrix();
}
}
}
}
void KeyFrameInterpolator::updateModifiedFrameValues() {
Quaternion prevQ = keyFrame_.first()->orientation();
KeyFrame *kf;
for (int i = 0; i < keyFrame_.size(); ++i) {
kf = keyFrame_.at(i);
if (kf->frame())
kf->updateValuesFromPointer();
kf->flipOrientationIfNeeded(prevQ);
prevQ = kf->orientation();
}
KeyFrame *prev = keyFrame_.first();
kf = keyFrame_.first();
int index = 1;
while (kf) {
KeyFrame *next = (index < keyFrame_.size()) ? keyFrame_.at(index) : NULL;
index++;
if (next)
kf->computeTangent(prev, next);
else
kf->computeTangent(prev, kf);
prev = kf;
kf = next;
}
valuesAreValid_ = true;
}
/*! Returns the Frame associated with the keyFrame at index \p index.
See also keyFrameTime(). \p index has to be in the range
0..numberOfKeyFrames()-1.
\note If this keyFrame was defined using a pointer to a Frame (see
addKeyFrame(const Frame* const)), the \e current pointed Frame state is
returned. */
Frame KeyFrameInterpolator::keyFrame(int index) const {
const KeyFrame *const kf = keyFrame_.at(index);
return Frame(kf->position(), kf->orientation());
}
/*! Returns the time corresponding to the \p index keyFrame.
See also keyFrame(). \p index has to be in the range 0..numberOfKeyFrames()-1.
*/
qreal KeyFrameInterpolator::keyFrameTime(int index) const {
return keyFrame_.at(index)->time();
}
/*! Returns the duration of the KeyFrameInterpolator path, expressed in seconds.
Simply corresponds to lastTime() - firstTime(). Returns 0.0 if the path has
less than 2 keyFrames. See also keyFrameTime(). */
qreal KeyFrameInterpolator::duration() const {
return lastTime() - firstTime();
}
/*! Returns the time corresponding to the first keyFrame, expressed in seconds.
Returns 0.0 if the path is empty. See also lastTime(), duration() and
keyFrameTime(). */
qreal KeyFrameInterpolator::firstTime() const {
if (keyFrame_.isEmpty())
return 0.0;
else
return keyFrame_.first()->time();
}
/*! Returns the time corresponding to the last keyFrame, expressed in seconds.
Returns 0.0 if the path is empty. See also firstTime(), duration() and
keyFrameTime(). */
qreal KeyFrameInterpolator::lastTime() const {
if (keyFrame_.isEmpty())
return 0.0;
else
return keyFrame_.last()->time();
}
void KeyFrameInterpolator::updateCurrentKeyFrameForTime(qreal time) {
// Assertion: times are sorted in monotone order.
// Assertion: keyFrame_ is not empty
// TODO: Special case for loops when closed path is implemented !!
if (!currentFrameValid_)
// Recompute everything from scrach
currentFrame_[1]->toFront();
while (currentFrame_[1]->peekNext()->time() > time) {
currentFrameValid_ = false;
if (!currentFrame_[1]->hasPrevious())
break;
currentFrame_[1]->previous();
}
if (!currentFrameValid_)
*currentFrame_[2] = *currentFrame_[1];
while (currentFrame_[2]->peekNext()->time() < time) {
currentFrameValid_ = false;
if (!currentFrame_[2]->hasNext())
break;
currentFrame_[2]->next();
}
if (!currentFrameValid_) {
*currentFrame_[1] = *currentFrame_[2];
if ((currentFrame_[1]->hasPrevious()) &&
(time < currentFrame_[2]->peekNext()->time()))
currentFrame_[1]->previous();
*currentFrame_[0] = *currentFrame_[1];
if (currentFrame_[0]->hasPrevious())
currentFrame_[0]->previous();
*currentFrame_[3] = *currentFrame_[2];
if (currentFrame_[3]->hasNext())
currentFrame_[3]->next();
currentFrameValid_ = true;
splineCacheIsValid_ = false;
}
// cout << "Time = " << time << " : " << currentFrame_[0]->peekNext()->time()
// << " , " << currentFrame_[1]->peekNext()->time() << " , " <<
// currentFrame_[2]->peekNext()->time() << " , " <<
// currentFrame_[3]->peekNext()->time() << endl;
}
void KeyFrameInterpolator::updateSplineCache() {
Vec delta = currentFrame_[2]->peekNext()->position() -
currentFrame_[1]->peekNext()->position();
v1 = 3.0 * delta - 2.0 * currentFrame_[1]->peekNext()->tgP() -
currentFrame_[2]->peekNext()->tgP();
v2 = -2.0 * delta + currentFrame_[1]->peekNext()->tgP() +
currentFrame_[2]->peekNext()->tgP();
splineCacheIsValid_ = true;
}
/*! Interpolate frame() at time \p time (expressed in seconds).
interpolationTime() is set to \p time and frame() is set accordingly.
If you simply want to change interpolationTime() but not the frame() state,
use setInterpolationTime() instead.
Emits the interpolated() signal and makes the frame() emit the
Frame::interpolated() signal. */
void KeyFrameInterpolator::interpolateAtTime(qreal time) {
setInterpolationTime(time);
if ((keyFrame_.isEmpty()) || (!frame()))
return;
if (!valuesAreValid_)
updateModifiedFrameValues();
updateCurrentKeyFrameForTime(time);
if (!splineCacheIsValid_)
updateSplineCache();
qreal alpha;
qreal dt = currentFrame_[2]->peekNext()->time() -
currentFrame_[1]->peekNext()->time();
if (dt == 0.0)
alpha = 0.0;
else
alpha = (time - currentFrame_[1]->peekNext()->time()) / dt;
// Linear interpolation - debug
// Vec pos = alpha*(currentFrame_[2]->peekNext()->position()) +
// (1.0-alpha)*(currentFrame_[1]->peekNext()->position());
Vec pos =
currentFrame_[1]->peekNext()->position() +
alpha * (currentFrame_[1]->peekNext()->tgP() + alpha * (v1 + alpha * v2));
Quaternion q = Quaternion::squad(
currentFrame_[1]->peekNext()->orientation(),
currentFrame_[1]->peekNext()->tgQ(), currentFrame_[2]->peekNext()->tgQ(),
currentFrame_[2]->peekNext()->orientation(), alpha);
frame()->setPositionAndOrientationWithConstraint(pos, q);
Q_EMIT interpolated();
}
/*! Returns an XML \c QDomElement that represents the KeyFrameInterpolator.
The resulting QDomElement holds the KeyFrameInterpolator parameters as well as
the path keyFrames (if the keyFrame is defined by a pointer to a Frame, use its
current value).
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
Use initFromDOMElement() to restore the ManipulatedFrame state from the
resulting QDomElement.
See Vec::domElement() for a complete example. See also
Quaternion::domElement(), Camera::domElement()...
Note that the Camera::keyFrameInterpolator() are automatically saved by
QGLViewer::saveStateToFile() when a QGLViewer is closed. */
QDomElement KeyFrameInterpolator::domElement(const QString &name,
QDomDocument &document) const {
QDomElement de = document.createElement(name);
int count = 0;
Q_FOREACH (KeyFrame *kf, keyFrame_) {
Frame fr(kf->position(), kf->orientation());
QDomElement kfNode = fr.domElement("KeyFrame", document);
kfNode.setAttribute("index", QString::number(count));
kfNode.setAttribute("time", QString::number(kf->time()));
de.appendChild(kfNode);
++count;
}
de.setAttribute("nbKF", QString::number(keyFrame_.count()));
de.setAttribute("time", QString::number(interpolationTime()));
de.setAttribute("speed", QString::number(interpolationSpeed()));
de.setAttribute("period", QString::number(interpolationPeriod()));
DomUtils::setBoolAttribute(de, "closedPath", closedPath());
DomUtils::setBoolAttribute(de, "loop", loopInterpolation());
return de;
}
/*! Restores the KeyFrameInterpolator state from a \c QDomElement created by
domElement().
Note that the frame() pointer is not included in the domElement(): you need to
setFrame() after this method to attach a Frame to the KeyFrameInterpolator.
See Vec::initFromDOMElement() for a complete code example.
See also Camera::initFromDOMElement() and Frame::initFromDOMElement(). */
void KeyFrameInterpolator::initFromDOMElement(const QDomElement &element) {
qDeleteAll(keyFrame_);
keyFrame_.clear();
QDomElement child = element.firstChild().toElement();
while (!child.isNull()) {
if (child.tagName() == "KeyFrame") {
Frame fr;
fr.initFromDOMElement(child);
qreal time = DomUtils::qrealFromDom(child, "time", 0.0);
addKeyFrame(fr, time);
}
child = child.nextSibling().toElement();
}
// #CONNECTION# Values cut pasted from constructor
setInterpolationTime(DomUtils::qrealFromDom(element, "time", 0.0));
setInterpolationSpeed(DomUtils::qrealFromDom(element, "speed", 1.0));
setInterpolationPeriod(DomUtils::intFromDom(element, "period", 40));
setClosedPath(DomUtils::boolFromDom(element, "closedPath", false));
setLoopInterpolation(DomUtils::boolFromDom(element, "loop", false));
// setFrame(NULL);
pathIsValid_ = false;
valuesAreValid_ = false;
currentFrameValid_ = false;
stopInterpolation();
}
#ifndef DOXYGEN
//////////// KeyFrame private class implementation /////////
KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame &fr, qreal t)
: time_(t), frame_(NULL) {
p_ = fr.position();
q_ = fr.orientation();
}
KeyFrameInterpolator::KeyFrame::KeyFrame(const Frame *fr, qreal t)
: time_(t), frame_(fr) {
updateValuesFromPointer();
}
void KeyFrameInterpolator::KeyFrame::updateValuesFromPointer() {
p_ = frame()->position();
q_ = frame()->orientation();
}
void KeyFrameInterpolator::KeyFrame::computeTangent(
const KeyFrame *const prev, const KeyFrame *const next) {
tgP_ = 0.5 * (next->position() - prev->position());
tgQ_ = Quaternion::squadTangent(prev->orientation(), q_, next->orientation());
}
void KeyFrameInterpolator::KeyFrame::flipOrientationIfNeeded(
const Quaternion &prev) {
if (Quaternion::dot(prev, q_) < 0.0)
q_.negate();
}
#endif // DOXYGEN
#endif // CGAL_HEADER_ONLY

View File

@ -19,456 +19,9 @@
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifndef CGAL_HEADER_ONLY
#include <CGAL/Qt/manipulatedCameraFrame.h>
#include <CGAL/Qt/domUtils.h>
#include <CGAL/Qt/qglviewer.h>
#include <CGAL/Qt/manipulatedCameraFrame_impl.h>
#include <QMouseEvent>
using namespace qglviewer;
using namespace std;
/*! Default constructor.
flySpeed() is set to 0.0 and sceneUpVector() is (0,1,0). The pivotPoint() is
set to (0,0,0).
\attention Created object is removeFromMouseGrabberPool(). */
ManipulatedCameraFrame::ManipulatedCameraFrame()
: driveSpeed_(0.0), sceneUpVector_(0.0, 1.0, 0.0),
rotatesAroundUpVector_(false), zoomsOnPivotPoint_(false) {
setFlySpeed(0.0);
removeFromMouseGrabberPool();
connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate()));
}
/*! Equal operator. Calls ManipulatedFrame::operator=() and then copy
* attributes. */
ManipulatedCameraFrame &ManipulatedCameraFrame::
operator=(const ManipulatedCameraFrame &mcf) {
ManipulatedFrame::operator=(mcf);
setFlySpeed(mcf.flySpeed());
setSceneUpVector(mcf.sceneUpVector());
setRotatesAroundUpVector(mcf.rotatesAroundUpVector_);
setZoomsOnPivotPoint(mcf.zoomsOnPivotPoint_);
return *this;
}
/*! Copy constructor. Performs a deep copy of all members using operator=(). */
ManipulatedCameraFrame::ManipulatedCameraFrame(
const ManipulatedCameraFrame &mcf)
: ManipulatedFrame(mcf) {
removeFromMouseGrabberPool();
connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate()));
(*this) = (mcf);
}
////////////////////////////////////////////////////////////////////////////////
/*! Overloading of ManipulatedFrame::spin().
Rotates the ManipulatedCameraFrame around its pivotPoint() instead of its
origin. */
void ManipulatedCameraFrame::spin() {
rotateAroundPoint(spinningQuaternion(), pivotPoint());
}
#ifndef DOXYGEN
/*! Called for continuous frame motion in fly mode (see
QGLViewer::MOVE_FORWARD). Emits manipulated(). */
void ManipulatedCameraFrame::flyUpdate() {
static Vec flyDisp(0.0, 0.0, 0.0);
switch (action_) {
case QGLViewer::MOVE_FORWARD:
flyDisp.z = -flySpeed();
translate(localInverseTransformOf(flyDisp));
break;
case QGLViewer::MOVE_BACKWARD:
flyDisp.z = flySpeed();
translate(localInverseTransformOf(flyDisp));
break;
case QGLViewer::DRIVE:
flyDisp.z = flySpeed() * driveSpeed_;
translate(localInverseTransformOf(flyDisp));
break;
default:
break;
}
// Needs to be out of the switch since ZOOM/fastDraw()/wheelEvent use this
// callback to trigger a final draw(). #CONNECTION# wheelEvent.
Q_EMIT manipulated();
}
Vec ManipulatedCameraFrame::flyUpVector() const {
qWarning("flyUpVector() is deprecated. Use sceneUpVector() instead.");
return sceneUpVector();
}
void ManipulatedCameraFrame::setFlyUpVector(const Vec &up) {
qWarning("setFlyUpVector() is deprecated. Use setSceneUpVector() instead.");
setSceneUpVector(up);
}
#endif
/*! This method will be called by the Camera when its orientation is changed, so
that the sceneUpVector (private) is changed accordingly. You should not need to
call this method. */
void ManipulatedCameraFrame::updateSceneUpVector() {
sceneUpVector_ = inverseTransformOf(Vec(0.0, 1.0, 0.0));
}
////////////////////////////////////////////////////////////////////////////////
// S t a t e s a v i n g a n d r e s t o r i n g //
////////////////////////////////////////////////////////////////////////////////
/*! Returns an XML \c QDomElement that represents the ManipulatedCameraFrame.
Adds to the ManipulatedFrame::domElement() the ManipulatedCameraFrame specific
informations in a \c ManipulatedCameraParameters child QDomElement.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
Use initFromDOMElement() to restore the ManipulatedCameraFrame state from the
resulting \c QDomElement.
See Vec::domElement() for a complete example. See also
Quaternion::domElement(), Frame::domElement(), Camera::domElement()... */
QDomElement ManipulatedCameraFrame::domElement(const QString &name,
QDomDocument &document) const {
QDomElement e = ManipulatedFrame::domElement(name, document);
QDomElement mcp = document.createElement("ManipulatedCameraParameters");
mcp.setAttribute("flySpeed", QString::number(flySpeed()));
DomUtils::setBoolAttribute(mcp, "rotatesAroundUpVector",
rotatesAroundUpVector());
DomUtils::setBoolAttribute(mcp, "zoomsOnPivotPoint", zoomsOnPivotPoint());
mcp.appendChild(sceneUpVector().domElement("sceneUpVector", document));
e.appendChild(mcp);
return e;
}
/*! Restores the ManipulatedCameraFrame state from a \c QDomElement created by
domElement().
First calls ManipulatedFrame::initFromDOMElement() and then initializes
ManipulatedCameraFrame specific parameters. */
void ManipulatedCameraFrame::initFromDOMElement(const QDomElement &element) {
// No need to initialize, since default sceneUpVector and flySpeed are not
// meaningful. It's better to keep current ones. And it would destroy
// constraint() and referenceFrame(). *this = ManipulatedCameraFrame();
ManipulatedFrame::initFromDOMElement(element);
QDomElement child = element.firstChild().toElement();
while (!child.isNull()) {
if (child.tagName() == "ManipulatedCameraParameters") {
setFlySpeed(DomUtils::qrealFromDom(child, "flySpeed", flySpeed()));
setRotatesAroundUpVector(
DomUtils::boolFromDom(child, "rotatesAroundUpVector", false));
setZoomsOnPivotPoint(
DomUtils::boolFromDom(child, "zoomsOnPivotPoint", false));
QDomElement schild = child.firstChild().toElement();
while (!schild.isNull()) {
if (schild.tagName() == "sceneUpVector")
setSceneUpVector(Vec(schild));
schild = schild.nextSibling().toElement();
}
}
child = child.nextSibling().toElement();
}
}
////////////////////////////////////////////////////////////////////////////////
// M o u s e h a n d l i n g //
////////////////////////////////////////////////////////////////////////////////
#ifndef DOXYGEN
/*! Protected internal method used to handle mouse events. */
void ManipulatedCameraFrame::startAction(int ma, bool withConstraint) {
ManipulatedFrame::startAction(ma, withConstraint);
switch (action_) {
case QGLViewer::MOVE_FORWARD:
case QGLViewer::MOVE_BACKWARD:
case QGLViewer::DRIVE:
flyTimer_.setSingleShot(false);
flyTimer_.start(10);
break;
case QGLViewer::ROTATE:
constrainedRotationIsReversed_ = transformOf(sceneUpVector_).y < 0.0;
break;
default:
break;
}
}
void ManipulatedCameraFrame::zoom(qreal delta, const Camera *const camera) {
const qreal sceneRadius = camera->sceneRadius();
if (zoomsOnPivotPoint_) {
Vec direction = position() - camera->pivotPoint();
if (direction.norm() > 0.02 * sceneRadius || delta > 0.0)
translate(delta * direction);
} else {
const qreal coef =
qMax(fabs((camera->frame()->coordinatesOf(camera->pivotPoint())).z),
qreal(0.2) * sceneRadius);
Vec trans(0.0, 0.0, -coef * delta);
translate(inverseTransformOf(trans));
}
}
#endif
/*! Overloading of ManipulatedFrame::mouseMoveEvent().
Motion depends on mouse binding (see <a href="../mouse.html">mouse page</a> for
details). The resulting displacements are basically inverted from those of a
ManipulatedFrame. */
void ManipulatedCameraFrame::mouseMoveEvent(QMouseEvent *const event,
Camera *const camera) {
// #CONNECTION# QGLViewer::mouseMoveEvent does the update().
switch (action_) {
case QGLViewer::TRANSLATE: {
const QPoint delta = prevPos_ - event->pos();
Vec trans(delta.x(), -delta.y(), 0.0);
// Scale to fit the screen mouse displacement
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(pivotPoint())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
translate(inverseTransformOf(translationSensitivity() * trans));
break;
}
case QGLViewer::MOVE_FORWARD: {
Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
rotate(rot);
//#CONNECTION# wheelEvent MOVE_FORWARD case
// actual translation is made in flyUpdate().
// translate(inverseTransformOf(Vec(0.0, 0.0, -flySpeed())));
break;
}
case QGLViewer::MOVE_BACKWARD: {
Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
rotate(rot);
// actual translation is made in flyUpdate().
// translate(inverseTransformOf(Vec(0.0, 0.0, flySpeed())));
break;
}
case QGLViewer::DRIVE: {
Quaternion rot = turnQuaternion(event->x(), camera);
rotate(rot);
// actual translation is made in flyUpdate().
driveSpeed_ = 0.01 * (event->y() - pressPos_.y());
break;
}
case QGLViewer::ZOOM: {
zoom(deltaWithPrevPos(event, camera), camera);
break;
}
case QGLViewer::LOOK_AROUND: {
Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
rotate(rot);
break;
}
case QGLViewer::ROTATE: {
Quaternion rot;
if (rotatesAroundUpVector_) {
// Multiply by 2.0 to get on average about the same speed as with the
// deformed ball
qreal dx = 2.0 * rotationSensitivity() * (prevPos_.x() - event->x()) /
camera->screenWidth();
qreal dy = 2.0 * rotationSensitivity() * (prevPos_.y() - event->y()) /
camera->screenHeight();
if (constrainedRotationIsReversed_)
dx = -dx;
Vec verticalAxis = transformOf(sceneUpVector_);
rot = Quaternion(verticalAxis, dx) * Quaternion(Vec(1.0, 0.0, 0.0), dy);
} else {
Vec trans = camera->projectedCoordinatesOf(pivotPoint());
rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1],
camera);
}
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
break;
}
case QGLViewer::SCREEN_ROTATE: {
Vec trans = camera->projectedCoordinatesOf(pivotPoint());
const qreal angle = atan2(event->y() - trans[1], event->x() - trans[0]) -
atan2(prevPos_.y() - trans[1], prevPos_.x() - trans[0]);
Quaternion rot(Vec(0.0, 0.0, 1.0), angle);
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
updateSceneUpVector();
break;
}
case QGLViewer::ROLL: {
const qreal angle =
M_PI * (event->x() - prevPos_.x()) / camera->screenWidth();
Quaternion rot(Vec(0.0, 0.0, 1.0), angle);
rotate(rot);
setSpinningQuaternion(rot);
updateSceneUpVector();
break;
}
case QGLViewer::SCREEN_TRANSLATE: {
Vec trans;
int dir = mouseOriginalDirection(event);
if (dir == 1)
trans.setValue(prevPos_.x() - event->x(), 0.0, 0.0);
else if (dir == -1)
trans.setValue(0.0, event->y() - prevPos_.y(), 0.0);
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(pivotPoint())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
translate(inverseTransformOf(translationSensitivity() * trans));
break;
}
case QGLViewer::ZOOM_ON_REGION:
case QGLViewer::NO_MOUSE_ACTION:
break;
}
if (action_ != QGLViewer::NO_MOUSE_ACTION) {
prevPos_ = event->pos();
if (action_ != QGLViewer::ZOOM_ON_REGION)
// ZOOM_ON_REGION should not emit manipulated().
// prevPos_ is used to draw rectangle feedback.
Q_EMIT manipulated();
}
}
/*! This is an overload of ManipulatedFrame::mouseReleaseEvent(). The
QGLViewer::MouseAction is terminated. */
void ManipulatedCameraFrame::mouseReleaseEvent(QMouseEvent *const event,
Camera *const camera) {
if ((action_ == QGLViewer::MOVE_FORWARD) ||
(action_ == QGLViewer::MOVE_BACKWARD) || (action_ == QGLViewer::DRIVE))
flyTimer_.stop();
if (action_ == QGLViewer::ZOOM_ON_REGION)
camera->fitScreenRegion(QRect(pressPos_, event->pos()));
ManipulatedFrame::mouseReleaseEvent(event, camera);
}
/*! This is an overload of ManipulatedFrame::wheelEvent().
The wheel behavior depends on the wheel binded action. Current possible actions
are QGLViewer::ZOOM, QGLViewer::MOVE_FORWARD, QGLViewer::MOVE_BACKWARD.
QGLViewer::ZOOM speed depends on wheelSensitivity() while
QGLViewer::MOVE_FORWARD and QGLViewer::MOVE_BACKWARD depend on flySpeed(). See
QGLViewer::setWheelBinding() to customize the binding. */
void ManipulatedCameraFrame::wheelEvent(QWheelEvent *const event,
Camera *const camera) {
//#CONNECTION# QGLViewer::setWheelBinding, ManipulatedFrame::wheelEvent.
switch (action_) {
case QGLViewer::ZOOM: {
zoom(wheelDelta(event), camera);
Q_EMIT manipulated();
break;
}
case QGLViewer::MOVE_FORWARD:
case QGLViewer::MOVE_BACKWARD:
//#CONNECTION# mouseMoveEvent() MOVE_FORWARD case
translate(
inverseTransformOf(Vec(0.0, 0.0, 0.2 * flySpeed() * event->delta())));
Q_EMIT manipulated();
break;
default:
break;
}
// #CONNECTION# startAction should always be called before
if (previousConstraint_)
setConstraint(previousConstraint_);
// The wheel triggers a fastDraw. A final update() is needed after the last
// wheel event to polish the rendering using draw(). Since the last wheel
// event does not say its name, we use the flyTimer_ to trigger flyUpdate(),
// which emits manipulated. Two wheel events separated by more than this delay
// milliseconds will trigger a draw().
const int finalDrawAfterWheelEventDelay = 400;
// Starts (or prolungates) the timer.
flyTimer_.setSingleShot(true);
flyTimer_.start(finalDrawAfterWheelEventDelay);
// This could also be done *before* manipulated is emitted, so that
// isManipulated() returns false. But then fastDraw would not be used with
// wheel. Detecting the last wheel event and forcing a final draw() is done
// using the timer_.
action_ = QGLViewer::NO_MOUSE_ACTION;
}
////////////////////////////////////////////////////////////////////////////////
/*! Returns a Quaternion that is a rotation around current camera Y,
* proportionnal to the horizontal mouse position. */
Quaternion ManipulatedCameraFrame::turnQuaternion(int x,
const Camera *const camera) {
return Quaternion(Vec(0.0, 1.0, 0.0), rotationSensitivity() *
(prevPos_.x() - x) /
camera->screenWidth());
}
/*! Returns a Quaternion that is the composition of two rotations, inferred from
the mouse pitch (X axis) and yaw (sceneUpVector() axis). */
Quaternion
ManipulatedCameraFrame::pitchYawQuaternion(int x, int y,
const Camera *const camera) {
const Quaternion rotX(Vec(1.0, 0.0, 0.0), rotationSensitivity() *
(prevPos_.y() - y) /
camera->screenHeight());
const Quaternion rotY(transformOf(sceneUpVector()),
rotationSensitivity() * (prevPos_.x() - x) /
camera->screenWidth());
return rotY * rotX;
}
#endif // CGAL_HEADER_ONLY

View File

@ -19,543 +19,9 @@
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifndef CGAL_HEADER_ONLY
#include <CGAL/Qt/manipulatedFrame.h>
#include <CGAL/Qt/camera.h>
#include <CGAL/Qt/domUtils.h>
#include <CGAL/Qt/manipulatedCameraFrame.h>
#include <CGAL/Qt/qglviewer.h>
#include <CGAL/Qt/manipulatedFrame_impl.h>
#include <cstdlib>
#include <QMouseEvent>
using namespace qglviewer;
using namespace std;
/*! Default constructor.
The translation is set to (0,0,0), with an identity rotation (0,0,0,1) (see
Frame constructor for details).
The different sensitivities are set to their default values (see
rotationSensitivity(), translationSensitivity(), spinningSensitivity() and
wheelSensitivity()). */
ManipulatedFrame::ManipulatedFrame()
: action_(QGLViewer::NO_MOUSE_ACTION), keepsGrabbingMouse_(false) {
// #CONNECTION# initFromDOMElement and accessor docs
setRotationSensitivity(1.0);
setTranslationSensitivity(1.0);
setSpinningSensitivity(0.3);
setWheelSensitivity(1.0);
setZoomSensitivity(1.0);
isSpinning_ = false;
previousConstraint_ = NULL;
connect(&spinningTimer_, SIGNAL(timeout()), SLOT(spinUpdate()));
}
/*! Equal operator. Calls Frame::operator=() and then copy attributes. */
ManipulatedFrame &ManipulatedFrame::operator=(const ManipulatedFrame &mf) {
Frame::operator=(mf);
setRotationSensitivity(mf.rotationSensitivity());
setTranslationSensitivity(mf.translationSensitivity());
setSpinningSensitivity(mf.spinningSensitivity());
setWheelSensitivity(mf.wheelSensitivity());
setZoomSensitivity(mf.zoomSensitivity());
mouseSpeed_ = 0.0;
dirIsFixed_ = false;
keepsGrabbingMouse_ = false;
action_ = QGLViewer::NO_MOUSE_ACTION;
return *this;
}
/*! Copy constructor. Performs a deep copy of all attributes using operator=().
*/
ManipulatedFrame::ManipulatedFrame(const ManipulatedFrame &mf)
: Frame(mf), MouseGrabber() {
(*this) = mf;
}
////////////////////////////////////////////////////////////////////////////////
/*! Implementation of the MouseGrabber main method.
The ManipulatedFrame grabsMouse() when the mouse is within a 10 pixels region
around its Camera::projectedCoordinatesOf() position().
See the <a href="../examples/mouseGrabber.html">mouseGrabber example</a> for an
illustration. */
void ManipulatedFrame::checkIfGrabsMouse(int x, int y,
const Camera *const camera) {
const int thresold = 10;
const Vec proj = camera->projectedCoordinatesOf(position());
setGrabsMouse(keepsGrabbingMouse_ || ((fabs(x - proj.x) < thresold) &&
(fabs(y - proj.y) < thresold)));
}
////////////////////////////////////////////////////////////////////////////////
// S t a t e s a v i n g a n d r e s t o r i n g //
////////////////////////////////////////////////////////////////////////////////
/*! Returns an XML \c QDomElement that represents the ManipulatedFrame.
Adds to the Frame::domElement() the ManipulatedFrame specific informations in a
\c ManipulatedParameters child QDomElement.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
Use initFromDOMElement() to restore the ManipulatedFrame state from the
resulting \c QDomElement.
See Vec::domElement() for a complete example. See also
Quaternion::domElement(), Camera::domElement()... */
QDomElement ManipulatedFrame::domElement(const QString &name,
QDomDocument &document) const {
QDomElement e = Frame::domElement(name, document);
QDomElement mp = document.createElement("ManipulatedParameters");
mp.setAttribute("rotSens", QString::number(rotationSensitivity()));
mp.setAttribute("transSens", QString::number(translationSensitivity()));
mp.setAttribute("spinSens", QString::number(spinningSensitivity()));
mp.setAttribute("wheelSens", QString::number(wheelSensitivity()));
mp.setAttribute("zoomSens", QString::number(zoomSensitivity()));
e.appendChild(mp);
return e;
}
/*! Restores the ManipulatedFrame state from a \c QDomElement created by
domElement().
Fields that are not described in \p element are set to their default values (see
ManipulatedFrame()).
First calls Frame::initFromDOMElement() and then initializes ManipulatedFrame
specific parameters. Note that constraint() and referenceFrame() are not
restored and are left unchanged.
See Vec::initFromDOMElement() for a complete code example. */
void ManipulatedFrame::initFromDOMElement(const QDomElement &element) {
// Not called since it would set constraint() and referenceFrame() to NULL.
// *this = ManipulatedFrame();
Frame::initFromDOMElement(element);
stopSpinning();
QDomElement child = element.firstChild().toElement();
while (!child.isNull()) {
if (child.tagName() == "ManipulatedParameters") {
// #CONNECTION# constructor default values and accessor docs
setRotationSensitivity(DomUtils::qrealFromDom(child, "rotSens", 1.0));
setTranslationSensitivity(
DomUtils::qrealFromDom(child, "transSens", 1.0));
setSpinningSensitivity(DomUtils::qrealFromDom(child, "spinSens", 0.3));
setWheelSensitivity(DomUtils::qrealFromDom(child, "wheelSens", 1.0));
setZoomSensitivity(DomUtils::qrealFromDom(child, "zoomSens", 1.0));
}
child = child.nextSibling().toElement();
}
}
////////////////////////////////////////////////////////////////////////////////
// M o u s e h a n d l i n g //
////////////////////////////////////////////////////////////////////////////////
/*! Returns \c true when the ManipulatedFrame is being manipulated with the
mouse.
Can be used to change the display of the manipulated object during
manipulation.
When Camera::frame() of the QGLViewer::camera() isManipulated(),
QGLViewer::fastDraw() is used in place of QGLViewer::draw() for scene
rendering. A simplified drawing will then allow for interactive camera
displacements. */
bool ManipulatedFrame::isManipulated() const {
return action_ != QGLViewer::NO_MOUSE_ACTION;
}
/*! Starts the spinning of the ManipulatedFrame.
This method starts a timer that will call spin() every \p updateInterval
milliseconds. The ManipulatedFrame isSpinning() until you call stopSpinning().
*/
void ManipulatedFrame::startSpinning(int updateInterval) {
isSpinning_ = true;
spinningTimer_.start(updateInterval);
}
/*! Rotates the ManipulatedFrame by its spinningQuaternion(). Called by a timer
when the ManipulatedFrame isSpinning(). */
void ManipulatedFrame::spin() { rotate(spinningQuaternion()); }
/* spin() and spinUpdate() differ since spin can be used by itself (for instance
by QGLViewer::SCREEN_ROTATE) without a spun emission. Much nicer to use the
spinningQuaternion() and hence spin() for these incremental updates. Nothing
special to be done for continuous spinning with this design. */
void ManipulatedFrame::spinUpdate() {
spin();
Q_EMIT spun();
}
#ifndef DOXYGEN
/*! Protected internal method used to handle mouse events. */
void ManipulatedFrame::startAction(int ma, bool withConstraint) {
action_ = (QGLViewer::MouseAction)(ma);
// #CONNECTION# manipulatedFrame::wheelEvent,
// manipulatedCameraFrame::wheelEvent and mouseReleaseEvent() restore previous
// constraint
if (withConstraint)
previousConstraint_ = NULL;
else {
previousConstraint_ = constraint();
setConstraint(NULL);
}
switch (action_) {
case QGLViewer::ROTATE:
case QGLViewer::SCREEN_ROTATE:
mouseSpeed_ = 0.0;
stopSpinning();
break;
case QGLViewer::SCREEN_TRANSLATE:
dirIsFixed_ = false;
break;
default:
break;
}
}
/*! Updates mouse speed, measured in pixels/milliseconds. Should be called by
any method which wants to use mouse speed. Currently used to trigger spinning in
mouseReleaseEvent(). */
void ManipulatedFrame::computeMouseSpeed(const QMouseEvent *const e) {
const QPoint delta = (e->pos() - prevPos_);
const qreal dist = sqrt(qreal(delta.x() * delta.x() + delta.y() * delta.y()));
delay_ = last_move_time.restart();
if (delay_ == 0)
// Less than a millisecond: assume delay = 1ms
mouseSpeed_ = dist;
else
mouseSpeed_ = dist / delay_;
}
/*! Return 1 if mouse motion was started horizontally and -1 if it was more
vertical. Returns 0 if this could not be determined yet (perfect diagonal
motion, rare). */
int ManipulatedFrame::mouseOriginalDirection(const QMouseEvent *const e) {
static bool horiz =
true; // Two simultaneous manipulatedFrame require two mice !
if (!dirIsFixed_) {
const QPoint delta = e->pos() - pressPos_;
dirIsFixed_ = abs(delta.x()) != abs(delta.y());
horiz = abs(delta.x()) > abs(delta.y());
}
if (dirIsFixed_)
if (horiz)
return 1;
else
return -1;
else
return 0;
}
qreal ManipulatedFrame::deltaWithPrevPos(QMouseEvent *const event,
Camera *const camera) const {
qreal dx = qreal(event->x() - prevPos_.x()) / camera->screenWidth();
qreal dy = qreal(event->y() - prevPos_.y()) / camera->screenHeight();
qreal value = fabs(dx) > fabs(dy) ? dx : dy;
return value * zoomSensitivity();
}
qreal ManipulatedFrame::wheelDelta(const QWheelEvent *event) const {
static const qreal WHEEL_SENSITIVITY_COEF = 8E-4;
return event->delta() * wheelSensitivity() * WHEEL_SENSITIVITY_COEF;
}
void ManipulatedFrame::zoom(qreal delta, const Camera *const camera) {
Vec trans(0.0, 0.0, (camera->position() - position()).norm() * delta);
trans = camera->frame()->orientation().rotate(trans);
if (referenceFrame())
trans = referenceFrame()->transformOf(trans);
translate(trans);
}
#endif // DOXYGEN
/*! Initiates the ManipulatedFrame mouse manipulation.
Overloading of MouseGrabber::mousePressEvent(). See also mouseMoveEvent() and
mouseReleaseEvent().
The mouse behavior depends on which button is pressed. See the <a
href="../mouse.html">QGLViewer mouse page</a> for details. */
void ManipulatedFrame::mousePressEvent(QMouseEvent *const event,
Camera *const camera) {
Q_UNUSED(camera);
if (grabsMouse())
keepsGrabbingMouse_ = true;
// #CONNECTION setMouseBinding
// action_ should no longer possibly be NO_MOUSE_ACTION since this value is
// not inserted in mouseBinding_
// if (action_ == QGLViewer::NO_MOUSE_ACTION)
// event->ignore();
prevPos_ = pressPos_ = event->pos();
}
/*! Modifies the ManipulatedFrame according to the mouse motion.
Actual behavior depends on mouse bindings. See the QGLViewer::MouseAction enum
and the <a href="../mouse.html">QGLViewer mouse page</a> for details.
The \p camera is used to fit the mouse motion with the display parameters (see
Camera::screenWidth(), Camera::screenHeight(), Camera::fieldOfView()).
Emits the manipulated() signal. */
void ManipulatedFrame::mouseMoveEvent(QMouseEvent *const event,
Camera *const camera) {
switch (action_) {
case QGLViewer::TRANSLATE: {
const QPoint delta = event->pos() - prevPos_;
Vec trans(delta.x(), -delta.y(), 0.0);
// Scale to fit the screen mouse displacement
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(position())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
// Transform to world coordinate system.
trans =
camera->frame()->orientation().rotate(translationSensitivity() * trans);
// And then down to frame
if (referenceFrame())
trans = referenceFrame()->transformOf(trans);
translate(trans);
break;
}
case QGLViewer::ZOOM: {
zoom(deltaWithPrevPos(event, camera), camera);
break;
}
case QGLViewer::SCREEN_ROTATE: {
Vec trans = camera->projectedCoordinatesOf(position());
const qreal prev_angle =
atan2(prevPos_.y() - trans[1], prevPos_.x() - trans[0]);
const qreal angle = atan2(event->y() - trans[1], event->x() - trans[0]);
const Vec axis =
transformOf(camera->frame()->inverseTransformOf(Vec(0.0, 0.0, -1.0)));
Quaternion rot(axis, angle - prev_angle);
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
break;
}
case QGLViewer::SCREEN_TRANSLATE: {
Vec trans;
int dir = mouseOriginalDirection(event);
if (dir == 1)
trans.setValue(event->x() - prevPos_.x(), 0.0, 0.0);
else if (dir == -1)
trans.setValue(0.0, prevPos_.y() - event->y(), 0.0);
switch (camera->type()) {
case Camera::PERSPECTIVE:
trans *= 2.0 * tan(camera->fieldOfView() / 2.0) *
fabs((camera->frame()->coordinatesOf(position())).z) /
camera->screenHeight();
break;
case Camera::ORTHOGRAPHIC: {
GLdouble w, h;
camera->getOrthoWidthHeight(w, h);
trans[0] *= 2.0 * w / camera->screenWidth();
trans[1] *= 2.0 * h / camera->screenHeight();
break;
}
}
// Transform to world coordinate system.
trans =
camera->frame()->orientation().rotate(translationSensitivity() * trans);
// And then down to frame
if (referenceFrame())
trans = referenceFrame()->transformOf(trans);
translate(trans);
break;
}
case QGLViewer::ROTATE: {
Vec trans = camera->projectedCoordinatesOf(position());
Quaternion rot = deformedBallQuaternion(event->x(), event->y(), trans[0],
trans[1], camera);
trans = Vec(-rot[0], -rot[1], -rot[2]);
trans = camera->frame()->orientation().rotate(trans);
trans = transformOf(trans);
rot[0] = trans[0];
rot[1] = trans[1];
rot[2] = trans[2];
//#CONNECTION# These two methods should go together (spinning detection and
// activation)
computeMouseSpeed(event);
setSpinningQuaternion(rot);
spin();
break;
}
case QGLViewer::MOVE_FORWARD:
case QGLViewer::MOVE_BACKWARD:
case QGLViewer::LOOK_AROUND:
case QGLViewer::ROLL:
case QGLViewer::DRIVE:
case QGLViewer::ZOOM_ON_REGION:
// These MouseAction values make no sense for a manipulatedFrame
break;
case QGLViewer::NO_MOUSE_ACTION:
// Possible when the ManipulatedFrame is a MouseGrabber. This method is then
// called without startAction because of mouseTracking.
break;
}
if (action_ != QGLViewer::NO_MOUSE_ACTION) {
prevPos_ = event->pos();
Q_EMIT manipulated();
}
}
/*! Stops the ManipulatedFrame mouse manipulation.
Overloading of MouseGrabber::mouseReleaseEvent().
If the action was a QGLViewer::ROTATE QGLViewer::MouseAction, a continuous
spinning is possible if the speed of the mouse cursor is larger than
spinningSensitivity() when the button is released. Press the rotate button again
to stop spinning. See startSpinning() and isSpinning(). */
void ManipulatedFrame::mouseReleaseEvent(QMouseEvent *const event,
Camera *const camera) {
Q_UNUSED(event);
Q_UNUSED(camera);
keepsGrabbingMouse_ = false;
if (previousConstraint_)
setConstraint(previousConstraint_);
if (((action_ == QGLViewer::ROTATE) ||
(action_ == QGLViewer::SCREEN_ROTATE)) &&
(mouseSpeed_ >= spinningSensitivity()))
startSpinning(delay_);
action_ = QGLViewer::NO_MOUSE_ACTION;
}
/*! Overloading of MouseGrabber::mouseDoubleClickEvent().
Left button double click aligns the ManipulatedFrame with the \p camera axis
(see alignWithFrame() and QGLViewer::ALIGN_FRAME). Right button projects the
ManipulatedFrame on the \p camera view direction. */
void ManipulatedFrame::mouseDoubleClickEvent(QMouseEvent *const event,
Camera *const camera) {
if (event->modifiers() == Qt::NoModifier)
switch (event->button()) {
case Qt::LeftButton:
alignWithFrame(camera->frame());
break;
case Qt::RightButton:
projectOnLine(camera->position(), camera->viewDirection());
break;
default:
break;
}
}
/*! Overloading of MouseGrabber::wheelEvent().
Using the wheel is equivalent to a QGLViewer::ZOOM QGLViewer::MouseAction. See
QGLViewer::setWheelBinding(), setWheelSensitivity(). */
void ManipulatedFrame::wheelEvent(QWheelEvent *const event,
Camera *const camera) {
//#CONNECTION# QGLViewer::setWheelBinding
if (action_ == QGLViewer::ZOOM) {
zoom(wheelDelta(event), camera);
Q_EMIT manipulated();
}
// #CONNECTION# startAction should always be called before
if (previousConstraint_)
setConstraint(previousConstraint_);
action_ = QGLViewer::NO_MOUSE_ACTION;
}
////////////////////////////////////////////////////////////////////////////////
/*! Returns "pseudo-distance" from (x,y) to ball of radius size.
\arg for a point inside the ball, it is proportional to the euclidean distance
to the ball \arg for a point outside the ball, it is proportional to the inverse
of this distance (tends to zero) on the ball, the function is continuous. */
static qreal projectOnBall(qreal x, qreal y) {
// If you change the size value, change angle computation in
// deformedBallQuaternion().
const qreal size = 1.0;
const qreal size2 = size * size;
const qreal size_limit = size2 * 0.5;
const qreal d = x * x + y * y;
return d < size_limit ? sqrt(size2 - d) : size_limit / sqrt(d);
}
#ifndef DOXYGEN
/*! Returns a quaternion computed according to the mouse motion. Mouse positions
are projected on a deformed ball, centered on (\p cx,\p cy). */
Quaternion
ManipulatedFrame::deformedBallQuaternion(int x, int y, qreal cx, qreal cy,
const Camera *const camera) {
// Points on the deformed ball
qreal px =
rotationSensitivity() * (prevPos_.x() - cx) / camera->screenWidth();
qreal py =
rotationSensitivity() * (cy - prevPos_.y()) / camera->screenHeight();
qreal dx = rotationSensitivity() * (x - cx) / camera->screenWidth();
qreal dy = rotationSensitivity() * (cy - y) / camera->screenHeight();
const Vec p1(px, py, projectOnBall(px, py));
const Vec p2(dx, dy, projectOnBall(dx, dy));
// Approximation of rotation angle
// Should be divided by the projectOnBall size, but it is 1.0
const Vec axis = cross(p2, p1);
const qreal angle =
5.0 *
asin(sqrt(axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm()));
return Quaternion(axis, angle);
}
#endif // DOXYGEN
#endif // CGAL_HEADER_ONLY

View File

@ -19,55 +19,9 @@
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifndef CGAL_HEADER_ONLY
#include <CGAL/Qt/mouseGrabber.h>
#include <CGAL/Qt/mouseGrabber_impl.h>
using namespace qglviewer;
// Static private variable
QList<MouseGrabber *> MouseGrabber::MouseGrabberPool_;
/*! Default constructor.
Adds the created MouseGrabber in the MouseGrabberPool(). grabsMouse() is set to
\c false. */
MouseGrabber::MouseGrabber() : grabsMouse_(false) { addInMouseGrabberPool(); }
/*! Adds the MouseGrabber in the MouseGrabberPool().
All created MouseGrabber are automatically added in the MouseGrabberPool() by
the constructor. Trying to add a MouseGrabber that already
isInMouseGrabberPool() has no effect.
Use removeFromMouseGrabberPool() to remove the MouseGrabber from the list, so
that it is no longer tested with checkIfGrabsMouse() by the QGLViewer, and hence
can no longer grab mouse focus. Use isInMouseGrabberPool() to know the current
state of the MouseGrabber. */
void MouseGrabber::addInMouseGrabberPool() {
if (!isInMouseGrabberPool())
MouseGrabber::MouseGrabberPool_.append(this);
}
/*! Removes the MouseGrabber from the MouseGrabberPool().
See addInMouseGrabberPool() for details. Removing a MouseGrabber that is not in
MouseGrabberPool() has no effect. */
void MouseGrabber::removeFromMouseGrabberPool() {
if (isInMouseGrabberPool())
MouseGrabber::MouseGrabberPool_.removeAll(const_cast<MouseGrabber *>(this));
}
/*! Clears the MouseGrabberPool().
Use this method only if it is faster to clear the MouseGrabberPool() and then
to add back a few MouseGrabbers than to remove each one independently. Use
QGLViewer::setMouseTracking(false) instead if you want to disable mouse
grabbing.
When \p autoDelete is \c true, the MouseGrabbers of the MouseGrabberPool() are
actually deleted (use this only if you're sure of what you do). */
void MouseGrabber::clearMouseGrabberPool(bool autoDelete) {
if (autoDelete)
qDeleteAll(MouseGrabber::MouseGrabberPool_);
MouseGrabber::MouseGrabberPool_.clear();
}
#endif // CGAL_HEADER_ONLY

View File

@ -1,359 +0,0 @@
/* XPM */
static const char * qglviewer_icon[] = {
"100 100 256 2",
" c None",
". c #0A0B27",
"+ c #090B2C",
"@ c #150C12",
"# c #080F34",
"$ c #1A0E1A",
"% c #220D0B",
"& c #260B0B",
"* c #230E1C",
"= c #12113E",
"- c #2C0D10",
"; c #2F0D09",
"> c #310D14",
", c #1A123A",
"' c #261025",
") c #17134B",
"! c #151453",
"~ c #1B1733",
"{ c #14135E",
"] c #281430",
"^ c #0E1867",
"/ c #3B1215",
"( c #32132A",
"_ c #1D1849",
": c #121C58",
"< c #431014",
"[ c #141974",
"} c #3A152E",
"| c #201A5E",
"1 c #1D204C",
"2 c #401431",
"3 c #261960",
"4 c #48171C",
"5 c #411B21",
"6 c #371B45",
"7 c #2A1C6B",
"8 c #0E229B",
"9 c #52171D",
"0 c #441A35",
"a c #1B2582",
"b c #65150F",
"c c #2D2076",
"d c #4D1B3A",
"e c #57182F",
"f c #3E1F54",
"g c #5E1924",
"h c #2E2567",
"i c #002BD1",
"j c #002AD9",
"k c #6D1A13",
"l c #36237A",
"m c #002FCD",
"n c #701A0D",
"o c #462060",
"p c #651C23",
"q c #322581",
"r c #552429",
"s c #581E41",
"t c #671E1B",
"u c #771911",
"v c #6C1B2B",
"w c #562341",
"x c #342A79",
"y c #3C2484",
"z c #062FE6",
"A c #68212B",
"B c #4D236B",
"C c #612045",
"D c #42267B",
"E c #811B10",
"F c #7C1E0E",
"G c #0033F1",
"H c #0032F9",
"I c #3A298E",
"J c #472872",
"K c #72202A",
"L c #4F2774",
"M c #652449",
"N c #442890",
"O c #1F37A8",
"P c #87200E",
"Q c #852014",
"R c #402B98",
"S c #6C244D",
"T c #7D2230",
"U c #8F1F12",
"V c #70254A",
"W c #542A7E",
"X c #212FF2",
"Y c #6E2E28",
"Z c #442E9B",
"` c #772834",
" . c #971E15",
".. c #552B86",
"+. c #693132",
"@. c #702A46",
"#. c #7B2645",
"$. c #862435",
"%. c #79264E",
"&. c #5A2B88",
"*. c #1B3AE9",
"=. c #9A2211",
"-. c #4E2EA0",
";. c #1E3BDE",
">. c #722F3D",
",. c #5E2C91",
"'. c #592F91",
"). c #7A322A",
"!. c #1D42D7",
"~. c #902539",
"{. c #7D2A52",
"]. c #862E26",
"^. c #822853",
"/. c #922B20",
"(. c #4E34AA",
"_. c #A62411",
":. c #5D309A",
"<. c #59387B",
"[. c #5631AB",
"}. c #5533A6",
"|. c #912840",
"1. c #8C2B3F",
"2. c #AE2215",
"3. c #862C57",
"4. c #5D32A8",
"5. c #882C53",
"6. c #5C34A2",
"7. c #6231A2",
"8. c #A32A18",
"9. c #5C398B",
"0. c #4D4480",
"a. c #982A3F",
"b. c #8D2B5A",
"c. c #962C44",
"d. c #902C56",
"e. c #7A3B43",
"f. c #3249C3",
"g. c #B42812",
"h. c #583E9B",
"i. c #BA2516",
"j. c #524297",
"k. c #55448B",
"l. c #5E3BA3",
"m. c #9E2C47",
"n. c #5A4676",
"o. c #873847",
"p. c #404E94",
"q. c #932F59",
"r. c #BE2810",
"s. c #992D5B",
"t. c #5941A4",
"u. c #8A3F36",
"v. c #9D2F58",
"w. c #78415D",
"x. c #A72D4D",
"y. c #A2304B",
"z. c #C72815",
"A. c #C12C13",
"B. c #654298",
"C. c #654780",
"D. c #8F385F",
"E. c #98345D",
"F. c #2F51E3",
"G. c #A93724",
"H. c #A0325B",
"I. c #CA2B10",
"J. c #A93054",
"K. c #A6305D",
"L. c #D42A00",
"M. c #D22914",
"N. c #89415D",
"O. c #6546A5",
"P. c #AB3255",
"Q. c #DC2806",
"R. c #A3355D",
"S. c #AA325A",
"T. c #A13F2F",
"U. c #6A4A8E",
"V. c #A53754",
"W. c #DE2A00",
"X. c #CF300A",
"Y. c #D62C0E",
"Z. c #A8385B",
"`. c #4B54C3",
" + c #964356",
".+ c #E82903",
"++ c #8F4757",
"@+ c #DF2C14",
"#+ c #D93011",
"$+ c #A23D62",
"%+ c #8C4E44",
"&+ c #E32F00",
"*+ c #6E4CA5",
"=+ c #6E4F9B",
"-+ c #A04259",
";+ c #9D4266",
">+ c #D03716",
",+ c #E3300D",
"'+ c #6A51A7",
")+ c #BA3F2F",
"!+ c #EC2E07",
"~+ c #A9405F",
"{+ c #EB2E13",
"]+ c #EF3100",
"^+ c #4A5CDC",
"/+ c #984A68",
"(+ c #B54536",
"_+ c #4563C9",
":+ c #F62E03",
"<+ c #EF310B",
"[+ c #E73411",
"}+ c #AA4B3E",
"|+ c #F62E10",
"1+ c #CE401F",
"2+ c #D33D23",
"3+ c #7455A7",
"4+ c #C54426",
"5+ c #A5496A",
"6+ c #F93106",
"7+ c #A45048",
"8+ c #CD412C",
"9+ c #F2350E",
"0+ c #AA4A64",
"a+ c #5266C7",
"b+ c #DE411E",
"c+ c #EF3C18",
"d+ c #755FAD",
"e+ c #C94C34",
"f+ c #C14F3F",
"g+ c #DB452E",
"h+ c #AB526E",
"i+ c #EB421F",
"j+ c #AA566A",
"k+ c #A55B6B",
"l+ c #AA5873",
"m+ c #E94824",
"n+ c #D94D35",
"o+ c #DB4F31",
"p+ c #5B71DE",
"q+ c #A85F76",
"r+ c #EC4C31",
"s+ c #E2522E",
"t+ c #E84F30",
"u+ c #CD5D42",
"v+ c #6976CD",
"w+ c #D9583F",
"x+ c #E55537",
"y+ c #E7573E",
"z+ c #D65F4C",
"A+ c #CA6457",
"B+ c #E35C3E",
"C+ c #D1634E",
"D+ c #E26447",
"E+ c #E1674E",
"F+ c #DE6F57",
"G+ c #DE705E",
" ",
" ",
" C+ ",
" ` >.o. 1+X.u+ ",
" e.A K K T $.T ++ 1+L.L.X. ",
" A A v ` T T T 1.~.++ X.L.L.L.W.1+ ",
" g A K K T T $.$.1.$.1. >+L.L.L.L.L.L. ",
" r g A v v T T $.1.$.$.|.|. + u+X.L.L.L.L.W.W.W.2+ ",
" f r g g K K v T T T |.|.1.1.c.-+ u+X.L.L.L.Q.L.Q.Q.W.W. ",
" 6 o B C. 4 9 p p v T T T 1.~.$.1.~.a.~.1. u+X.L.L.L.Q.L.W.L.W.W.W.o+ ",
" f o B C. 4 9 9 g v v T T $.1.1.~.|.c.c.c.m. 4+L.L.L.Q.L.Q.Q.W.&+W.W.,+b+ ",
" f o J L U. 9 9 A v K T $.1.1.$.|.|.c.c.c.a.a.q+ 4+L.L.L.L.L.Q.W.W.&+L.&+&+&+W. ",
" f o B W L <. < 9 g A e.` ` $.$.|.$.1.~.a.a.c.c.a.k+ 1+L.L.Q.Q.W.L.W.L.&+&+&+,+&+&+w+ ",
" 6 f B L L .. 4 4 9 o.$.|.$.c.a.c.c.m.m.y.c.q+ u+L.W.Q.L.W.&+&+W.&+,+&+&+&+.+s+ ",
" p. f o L W W .. / < r 1.|.|.c.c.c.c.y.m.y.a.k+ X.L.W.L.,+,+&+,+&+&+&+[+&+&+b+ ",
" 3 6 B L W W &.9. / o.|.|.c.a.m.y.a.a.y.y.q+ e+W.W.&+W.W.,+&+&+&+&+.+&+!+b+ ",
" a : f o L L ....&.B. / ++a.a.m.c.a.y.y.a.y.y.q+ u+W.W.W.&+.+&+{+&+[+&+!+&+]+&+ ",
" O ^ 1 f J W ....&.'.U. / 5 k+c.m.c.m.y.m.y.y.y.y. L.&+&+&+&+&+&+!+]+!+[+!+!+!+ ",
" f.[ ) $ <.L W ..&.'.'. / k+c.m.a.m.y.a.y.y.y.y. b+&+,+&+.+&+&+&+[+]+&+!+&+!+E+ ",
" `.8 ! = $ <.W ..&.'.'.B. - k+y.a.y.y.a.y.x.y.x.V. b+.+&+!+&+[+!+!+]+!+!+!+9+!+B+ ",
" a+m { = # $ ....'.'.'.,.=+ - k+m.y.y.y.V.y.x.y.x.V. w+!+&+!+]+&+[+&+!+[+<+!+]+&+B+ ",
" v+m 8 ) # $ U...'.'.'.,.:. - -+m.m.y.V.x.y.y.x.m.0+ s+&+!+[+&+!+]+<+!+]+]+[+<+9+B+ ",
" ;.m ) = + $ 9.&.'.l.l.,.*+ & -+y.y.x.x.J.x.y.x.y.0+ B+&+]+!+<+!+!+[+]+!+]+<+]+<+B+ ",
" ;.i [ = + . $ &.'.,.,.,.:.*+ & 0+y.y.x.y.y.y.J.V.x.l+ s+!+!+!+[+<+]+]+!+]+]+]+!+]+B+ ",
" ;.z ^+1 # + $ =+l.'.l.7.:.'. % y.x.y.x.x.P.y.x.P.y. B+.+[+]+!+[+]+]+<+]+]+]+]+<+B+ ",
" ;.z ;. + + . $ '.:.:.:.:.:.3+ & V.y.x.y.x.J.P.P.V.Z. x+<+]+]+]+:+]+]+]+9+<+9+9+]+ ",
" p+*.G G p+ + . @ U.:.:.7.:.6.7. % h+P.V.P.P.y.J.P.x.y.0+ s+]+9+]+]+9+9+]+]+]+]+]+9+<+ ",
" f. p+F.H H G F. . . . $ l.:.:.:.6.:.O. & 0+x.J.J.V.P.x.x.P.P.h+ x+<+]+<+]+]+]+9+]+]+]+9+]+<+ ",
" i G X X X G H ;. . . $ =+:.:.6.l.6.:.3+ % V.y.y.x.P.V.V.P.P.J. m+!+]+]+]+9+]+|+9+|+]+9+]+c+ ",
" m z G H G H G p+ . . * O.6.6.:.7.6.:. & V.P.P.P.x.P.P.V.V.V. i+]+]+<+|+:+]+]+:+]+:+:+]+m+ ",
" i z G G G G F. . . * 3+7.7.6.6.6.6.3+ % 0+x.P.x.V.x.x.x.x.P.0+ [+9+]+]+]+|+]+]+]+9+9+9+]+m+ ",
" i z G G H *. . . * :.6.6.7.6.7.:. & 0+P.P.P.P.P.P.P.P.V. :+:+]+]+9+]+9+9+|+:+:+:+]+B+ ",
" i z G G G p+ . * *+7.}.6.4.6.6.*+ % V.y.P.x.P.x.P.P.P.V. F+]+|+9+:+]+:+:+]+]+:+|+|+:+B+ ",
" i z G G ^+ . ' n.4.6.7.4.7.4.6. & 0+x.P.P.P.P.P.P.P.P.~+ s+9+]+:+]+|+6+]+]+|+9+]+]+9+ ",
" i z G F. . * O.4.6.6.6.6.4.*+ & ~+P.P.P.P.P.P.P.P.Z.l+ s+6+9+|+]+9+|+|+]+6+:+6+6+9+ ",
" j z !. . ] J 4.6.4.[.4.[.l. & P.P.P.P.P.P.P.P.P.V. c+9+6+]+|+6+9+]+6+9+|+9+|+i+ ",
" a+i ;. . ' l.[.(.6.6.6.4.*+ & h+P.P.S.P.S.P.P.P.P.0+ :+|+]+]+|+6+|+9+6+]+6+]+9+t+ ",
" a+!. . ] t.(.6.7.4.4.[.6. & S.P.P.P.P.P.S.S.S.S.q+ D+9+9+|+6+]+9+]+6+|+6+9+6+:+E+ ",
" . 3+7.[.6.(.6.6.6.*+ & h+S.S.P.S.~+P.P.P.P.~+ r+6+]+9+6+6+6+9+]+9+6+9+6+9+ ",
" . 6.(.6.4.4.4.(.6. & ~+P.P.P.P.P.P.P.P.P.h+ c+6+|+6+9+6+9+6+|+6+|+6+9+9+ ",
" . l.[.[.(.6.(.4.(.3+ % l+S.V.~+P.P.P.~+P.P.S. 9+]+|+6+9+6+|+9+9+]+|+6+9+t+ ",
" ~ *+(.6.4.4.4.6.4.l. % ~+P.S.P.S.P.S.P.S.S.0+ B+9+6+9+9+6+|+9+6+6+|+]+]+|+D+ ",
" ~ '+(.[.(.(.(.4.4.6.d+ & S.P.S.P.S.P.S.P.P.~+ i+9+6+6+9+6+6+:+9+:+6+|+6+c+ ",
" = '+(.[.(.(.[.4.[.(.O. % ~+~+S.Z.S.Z.S.P.Z.S.~+ 9+6+6+9+6+9+:+9+6+6+9+6+]+m+ ",
" _ '+Z }.}.4.6.(.(.[.4. & q+S.S.S.~+S.~+S.S.S.S.l+ x+]+9+6+9+6+9+6+9+9+6+9+|+6+B+ ",
" ) h h.Z -.-.}.(.(.[.[.(.'+ & R.Z.Z.S.S.S.S.~+Z.Z.R. r+|+6+|+6+9+6+|+6+6+9+6+9+]+F+ ",
" _ 3 x k.j.I Z -.Z Z }.4.(.(.4.t. % l+S.S.Z.Z.Z.S.S.S.S.Z.h+ F+]+9+6+9+6+9+6+9+9+6+9+6+6+c+ ",
" ) 3 7 q I I Z N }.}.}.(.}.}.(. & Z.Z.S.Z.Z.S.Z.Z.Z.Z.~+ B+6+6+9+6+|+6+9+6+6+|+6+6+9+y+ ",
" = ! 7 c q I N Z Z Z Z -.}.}.}.'+ % l+S.Z.S.S.Z.S.S.S.S.Z.h+ c+9+6+9+6+9+6+|+9+6+9+9+6+6+ ",
" _ ) 3 l q N N Z N -.}.Z -.(.O. & R.R.R.S.K.S.Z.Z.Z.V.$+ D+6+6+9+6+9+6+9+6+6+9+6+6+9+m+ ",
" _ 3 3 l q I N Z Z -.-.}.}.Z & $+S.S.Z.Z.Z.K.K.K.K.S.h+ i+9+6+9+6+9+6+9+9+6+9+9+6+9+B+ ",
" _ | 7 l y I I N N Z -.(.-.d+ % l+R.R.R.R.S.K.Z.S.S.S.~+ F+9+6+9+|+6+6+9+6+6+9+|+6+6+9+ ",
" _ 3 7 c q I R Z :.Z Z -.'+ & R.K.K.K.R.Z.S.Z.Z.Z.K.l+ r+9+6+6+9+6+6+6+9+6+6+9+9+6+t+ ",
" ) | 7 l y y I N R Z -.D & ;+R.Z.Z.S.K.K.R.Z.S.S.5+ G+6+6+9+9+6+9+9+9+6+6+9+6+6+]+E+ ",
" 3 x c I y I Z Z Z h.' & 5+K.K.R.R.S.K.S.K.R.R.S. t+9+6+|+9+6+6+6+6+9+6+9+|+|+i+ ",
" | c l q I R I Z h. $ & $+R.s.K.R.R.Z.R.K.K.K.5+ 9+6+9+6+6+6+c+6+9+6+9+|+6+6+x+ ",
" h 7 l q y N N j. * & H.H.R.s.K.H.H.K.Z.K.S.Z. r+9+6+9+6+6+6+6+6+6+6+9+9+9+c+ ",
" 0.l q y I y '+ ' ; ;+v.v.K.R.H.K.K.v.H.Z.R.5+ G+9+|+6+c+6+c+6+c+6+6+9+6+|+6+B+ ",
" 0.x D j. ' & ;+s.R.s.K.H.s.s.R.K.K.K.$+ m+9+9+|+9+6+9+6+6+c+6+6+9+9+6+ ",
" ( ( ; ;+v.$+s.R.v.H.R.K.K.R.s.R. E+9+|+9+6+6+c+6+c+6+6+9+9+6+6+t+ ",
" ( } & ; /+5.v.v.v.s.H.R.H.H.s.K.R.5+ i+9+|+9+9+6+6+6+c+6+6+6+9+6+9+ ",
" ( } - ; /+q.s.s.s.E.H.v.K.v.R.K.R.$+ y+|+|+9+9+|+9+c+6+6+c+9+9+|+9+x+ ",
" ( 2 0 - ; D.d.q.q.E.v.v.s.s.H.s.R.v.$+ 9+9+|+|+9+6+6+9+c+6+6+6+c+6+9+ ",
" } 0 0 ; ; 3.q.b.q.q.s.E.s.H.H.v.K.v.H.5+ r+9+|+9+9+6+c+9+6+6+c+9+9+|+|+x+ ",
" } 0 d d ; < N.5.3.q.q.q.q.s.E.E.E.s.v.s.H.5+ D+9+9+|+9+9+6+c+9+6+|+6+9+9+9+9+ ",
" } 2 s s s M w.w.e @.{.^.3.3.b.d.q.q.q.s.v.v.s.H.s.$+ i+9+|+9+|+c+6+|+6+9+9+9+9+6+|+y+ ",
" 0 0 d s C M V V V ^.^.5.5.5.3.d.q.q.q.q.s.v.E.R.E. r+9+c+|+9+|+9+c+c+|+|+9+6+9+6+i+ ",
" 2 2 s w C C V V %.{.{.5.b.5.q.3.d.q.q.s.E.E.v.s.q+ w+9+9+9+9+9+9+|+|+|+9+9+|+9+|+9+E+ ",
" 0 0 d w C C S V V {.%.#.3.5.d.d.d.q.q.s.s.E.E.q+ E+c+9+9+c+9+c+9+|+9+|+9+9+9+9+|+i+ ",
" } d s s C M V S %.%.^.3.3.3.3.3.d.d.q.d.q.s./+ i+!+c+9+9+9+|+9+9+|+9+|+9+|+|+9+G+ ",
" 0 d d e M M V S {.{.^.3.3.d.d.D.d.d.q.q.v./+ r+[+|+{+9+c+9+9+9+9+9+9+|+9+9+9+B+ ",
" d s s s V S V S %.{.{.5.3.3.d.d.q.q.q./+ o+[+!+c+9+|+9+c+9+c+9+c+9+9+|+9+m+ ",
" 0 s C s V V %.V {.^.{.5.5.3.3.D.d.q./+ n+{+[+{+[+c+c+|+9+9+9+|+9+c+9+|+|+G+ ",
" d w s M M M V %.%.{.3.{.3.d.d.d.q./+ w+[+[+{+&+{+{+{+9+c+9+c+9+c+|+9+c+B+ ",
" w s @.S S S %.%.{.5.5.^.3.b.D. G+@+[+[+[+c+[+<+[+9+c+|+c+9+9+c+|+m+ ",
" w s C M V V S %.^.{.{.3.5.N. C+@+[+{+&+{+&+<+[+{+{+{+9+9+9+c+9+c+G+ ",
" w M M S V {.V ^.5.5.{. w+,+,+@+[+[+{+[+{+c+9+<+[+9+9+9+9+{+D+ ",
" M @.V V {.{.#.++ w+@+@+@+[+{+[+[+{+[+&+[+[+{+c+{+{+{+x+ ",
" w.>.p t b ). 8+@+,+[+,+@+{+[+[+&+{+{+{+[+!+[+9+9+b+ ",
" +.b b n u %+ 2+#+,+@+Q.@+[+@+,+[+[+[+[+[+<+[+<+{+i+ ",
" b b k u u u+M.M.#+#+@+,+@+[+@+[+{+[+[+{+[+[+[+[+{+z+ ",
" b b n u u /. A+2+M.#+#+#+,+@+@+,+,+[+@+,+[+{+[+{+{+[+<+w+ ",
" t k k F u P /.7+ A+e+z.#+#+@+M.#+#+,+#+@+Q.[+@+@+,+{+&+[+{+[+B+ ",
" Y n u u E Q U U T.7+ f+4+I.M.>+M.M.Y.@+M.@+#+@+,+@+@+[+[+[+[+[+[+[+n+ ",
" k n F Q Q U .=._.8.G.(+(+)+g.i.z.r.I.M.I.>+I.#+#+#+#+#+#+,+,+Q.,+@+,+@+{+{+o+ ",
" k u u E U U U =.=._.2.g.i.i.i.A.r.z.z.I.M.Y.#+>+#+#+#+Q.@+@+@+@+,+[+@+[+,+s+ ",
" ).n E E P U =.=.=.8._._.g.g.i.i.A.A.z.I.z.M.Y.M.M.M.#+#+#+,+@+@+@+[+,+@+g+ ",
" u u Q U U U =._._.2.g.g.g.A.A.A.z.A.z.M.I.I.Y.#+#+#+#+@+#+,+,+,+,+@+o+ ",
" ).F Q U U =.=.=.8._.2.2.g.r.r.r.I.I.I.z.M.I.M.#+M.#+#+#+#+@+@+@+,+w+ ",
" Q Q P U U =._._.2._.g.g.g.i.A.A.A.A.I.I.M.X.M.#+@+#+@+@+@+,+#+z+ ",
" u.U /.U U 8._.8._.2.2.g.g.i.A.A.I.z.I.I.M.I.Y.>+@+#+#+#+#+#+A+ ",
" ].U U =.=.=.2.2._.g.i.i.A.i.A.A.I.z.I.>+Y.>+Y.Y.#+#+#+n+ ",
" /.U .=.=._._.2.2.g.i.A.A.z.A.I.I.M.I.M.M.M.M.Y.M.z+ ",
" /.=.8._._.2._.g.g.g.g.i.A.z.A.z.I.I.Y.I.X.#+8+ ",
" /.8.8._._.2.2.i.i.A.i.A.z.z.I.I.I.M.M.8+A+ ",
" }+8._.2.2.g.2.A.i.A.A.A.>+z.z.z.4+A+ ",
" T.)+_.g.2.A.r.A.A.r.A.4+z+ ",
" }+}+(+(+f+f+A+ ",
" ",
" "};

File diff suppressed because it is too large Load Diff

View File

@ -19,507 +19,9 @@
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifndef CGAL_HEADER_ONLY
#include <CGAL/Qt/quaternion.h>
#include <CGAL/Qt/domUtils.h>
#include <stdlib.h> // RAND_MAX
#include <CGAL/Qt/quaternion_impl.h>
// All the methods are declared inline in Quaternion.h
using namespace qglviewer;
using namespace std;
/*! Constructs a Quaternion that will rotate from the \p from direction to the
\p to direction.
Note that this rotation is not uniquely defined. The selected axis is usually
orthogonal to \p from and \p to, minimizing the rotation angle. This method is
robust and can handle small or almost identical vectors. */
Quaternion::Quaternion(const Vec &from, const Vec &to) {
const qreal epsilon = 1E-10;
const qreal fromSqNorm = from.squaredNorm();
const qreal toSqNorm = to.squaredNorm();
// Identity Quaternion when one vector is null
if ((fromSqNorm < epsilon) || (toSqNorm < epsilon)) {
q[0] = q[1] = q[2] = 0.0;
q[3] = 1.0;
} else {
Vec axis = cross(from, to);
const qreal axisSqNorm = axis.squaredNorm();
// Aligned vectors, pick any axis, not aligned with from or to
if (axisSqNorm < epsilon)
axis = from.orthogonalVec();
qreal angle = asin(sqrt(axisSqNorm / (fromSqNorm * toSqNorm)));
if (from * to < 0.0)
angle = M_PI - angle;
setAxisAngle(axis, angle);
}
}
/*! Returns the image of \p v by the Quaternion inverse() rotation.
rotate() performs an inverse transformation. Same as inverse().rotate(v). */
Vec Quaternion::inverseRotate(const Vec &v) const {
return inverse().rotate(v);
}
/*! Returns the image of \p v by the Quaternion rotation.
See also inverseRotate() and operator*(const Quaternion&, const Vec&). */
Vec Quaternion::rotate(const Vec &v) const {
const qreal q00 = 2.0 * q[0] * q[0];
const qreal q11 = 2.0 * q[1] * q[1];
const qreal q22 = 2.0 * q[2] * q[2];
const qreal q01 = 2.0 * q[0] * q[1];
const qreal q02 = 2.0 * q[0] * q[2];
const qreal q03 = 2.0 * q[0] * q[3];
const qreal q12 = 2.0 * q[1] * q[2];
const qreal q13 = 2.0 * q[1] * q[3];
const qreal q23 = 2.0 * q[2] * q[3];
return Vec((1.0 - q11 - q22) * v[0] + (q01 - q23) * v[1] + (q02 + q13) * v[2],
(q01 + q23) * v[0] + (1.0 - q22 - q00) * v[1] + (q12 - q03) * v[2],
(q02 - q13) * v[0] + (q12 + q03) * v[1] +
(1.0 - q11 - q00) * v[2]);
}
/*! Set the Quaternion from a (supposedly correct) 3x3 rotation matrix.
The matrix is expressed in European format: its three \e columns are the
images by the rotation of the three vectors of an orthogonal basis. Note that
OpenGL uses a symmetric representation for its matrices.
setFromRotatedBasis() sets a Quaternion from the three axis of a rotated
frame. It actually fills the three columns of a matrix with these rotated
basis vectors and calls this method. */
void Quaternion::setFromRotationMatrix(const qreal m[3][3]) {
// Compute one plus the trace of the matrix
const qreal onePlusTrace = 1.0 + m[0][0] + m[1][1] + m[2][2];
if (onePlusTrace > 1E-5) {
// Direct computation
const qreal s = sqrt(onePlusTrace) * 2.0;
q[0] = (m[2][1] - m[1][2]) / s;
q[1] = (m[0][2] - m[2][0]) / s;
q[2] = (m[1][0] - m[0][1]) / s;
q[3] = 0.25 * s;
} else {
// Computation depends on major diagonal term
if ((m[0][0] > m[1][1]) & (m[0][0] > m[2][2])) {
const qreal s = sqrt(1.0 + m[0][0] - m[1][1] - m[2][2]) * 2.0;
q[0] = 0.25 * s;
q[1] = (m[0][1] + m[1][0]) / s;
q[2] = (m[0][2] + m[2][0]) / s;
q[3] = (m[1][2] - m[2][1]) / s;
} else if (m[1][1] > m[2][2]) {
const qreal s = sqrt(1.0 + m[1][1] - m[0][0] - m[2][2]) * 2.0;
q[0] = (m[0][1] + m[1][0]) / s;
q[1] = 0.25 * s;
q[2] = (m[1][2] + m[2][1]) / s;
q[3] = (m[0][2] - m[2][0]) / s;
} else {
const qreal s = sqrt(1.0 + m[2][2] - m[0][0] - m[1][1]) * 2.0;
q[0] = (m[0][2] + m[2][0]) / s;
q[1] = (m[1][2] + m[2][1]) / s;
q[2] = 0.25 * s;
q[3] = (m[0][1] - m[1][0]) / s;
}
}
normalize();
}
#ifndef DOXYGEN
void Quaternion::setFromRotatedBase(const Vec &X, const Vec &Y, const Vec &Z) {
qWarning("setFromRotatedBase is deprecated, use setFromRotatedBasis instead");
setFromRotatedBasis(X, Y, Z);
}
#endif
/*! Sets the Quaternion from the three rotated vectors of an orthogonal basis.
The three vectors do not have to be normalized but must be orthogonal and
direct (X^Y=k*Z, with k>0).
\code
Quaternion q;
q.setFromRotatedBasis(X, Y, Z);
// Now q.rotate(Vec(1,0,0)) == X and q.inverseRotate(X) == Vec(1,0,0)
// Same goes for Y and Z with Vec(0,1,0) and Vec(0,0,1).
\endcode
See also setFromRotationMatrix() and Quaternion(const Vec&, const Vec&). */
void Quaternion::setFromRotatedBasis(const Vec &X, const Vec &Y, const Vec &Z) {
qreal m[3][3];
qreal normX = X.norm();
qreal normY = Y.norm();
qreal normZ = Z.norm();
for (int i = 0; i < 3; ++i) {
m[i][0] = X[i] / normX;
m[i][1] = Y[i] / normY;
m[i][2] = Z[i] / normZ;
}
setFromRotationMatrix(m);
}
/*! Returns the axis vector and the angle (in radians) of the rotation
represented by the Quaternion. See the axis() and angle() documentations. */
void Quaternion::getAxisAngle(Vec &axis, qreal &angle) const {
angle = 2.0 * acos(q[3]);
axis = Vec(q[0], q[1], q[2]);
const qreal sinus = axis.norm();
if (sinus > 1E-8)
axis /= sinus;
if (angle > M_PI) {
angle = 2.0 * qreal(M_PI) - angle;
axis = -axis;
}
}
/*! Returns the normalized axis direction of the rotation represented by the
Quaternion.
It is null for an identity Quaternion. See also angle() and getAxisAngle(). */
Vec Quaternion::axis() const {
Vec res = Vec(q[0], q[1], q[2]);
const qreal sinus = res.norm();
if (sinus > 1E-8)
res /= sinus;
return (acos(q[3]) <= M_PI / 2.0) ? res : -res;
}
/*! Returns the angle (in radians) of the rotation represented by the
Quaternion.
This value is always in the range [0-pi]. Larger rotational angles are obtained
by inverting the axis() direction.
See also axis() and getAxisAngle(). */
qreal Quaternion::angle() const {
const qreal angle = 2.0 * acos(q[3]);
return (angle <= M_PI) ? angle : 2.0 * M_PI - angle;
}
/*! Returns an XML \c QDomElement that represents the Quaternion.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
When output to a file, the resulting QDomElement will look like:
\code
<name q0=".." q1=".." q2=".." q3=".." />
\endcode
Use initFromDOMElement() to restore the Quaternion state from the resulting \c
QDomElement. See also the Quaternion(const QDomElement&) constructor.
See the Vec::domElement() documentation for a complete QDomDocument creation
and saving example.
See also Frame::domElement(), Camera::domElement(),
KeyFrameInterpolator::domElement()... */
QDomElement Quaternion::domElement(const QString &name,
QDomDocument &document) const {
QDomElement de = document.createElement(name);
de.setAttribute("q0", QString::number(q[0]));
de.setAttribute("q1", QString::number(q[1]));
de.setAttribute("q2", QString::number(q[2]));
de.setAttribute("q3", QString::number(q[3]));
return de;
}
/*! Restores the Quaternion state from a \c QDomElement created by domElement().
The \c QDomElement should contain the \c q0, \c q1 , \c q2 and \c q3
attributes. If one of these attributes is missing or is not a number, a warning
is displayed and these fields are respectively set to 0.0, 0.0, 0.0 and 1.0
(identity Quaternion).
See also the Quaternion(const QDomElement&) constructor. */
void Quaternion::initFromDOMElement(const QDomElement &element) {
Quaternion q(element);
*this = q;
}
/*! Constructs a Quaternion from a \c QDomElement representing an XML code of
the form \code< anyTagName q0=".." q1=".." q2=".." q3=".." />\endcode
If one of these attributes is missing or is not a number, a warning is
displayed and the associated value is respectively set to 0, 0, 0 and 1
(identity Quaternion).
See also domElement() and initFromDOMElement(). */
Quaternion::Quaternion(const QDomElement &element) {
QStringList attribute;
attribute << "q0"
<< "q1"
<< "q2"
<< "q3";
for (int i = 0; i < attribute.size(); ++i)
q[i] = DomUtils::qrealFromDom(element, attribute[i], ((i < 3) ? 0.0 : 1.0));
}
/*! Returns the Quaternion associated 4x4 OpenGL rotation matrix.
Use \c glMultMatrixd(q.matrix()) to apply the rotation represented by
Quaternion \c q to the current OpenGL matrix.
See also getMatrix(), getRotationMatrix() and inverseMatrix().
\attention The result is only valid until the next call to matrix(). Use it
immediately (as shown above) or consider using getMatrix() instead.
\attention The matrix is given in OpenGL format (row-major order) and is the
transpose of the actual mathematical European representation. Consider using
getRotationMatrix() instead. */
const GLdouble *Quaternion::matrix() const {
static GLdouble m[4][4];
getMatrix(m);
return (const GLdouble *)(m);
}
/*! Fills \p m with the OpenGL representation of the Quaternion rotation.
Use matrix() if you do not need to store this matrix and simply want to alter
the current OpenGL matrix. See also getInverseMatrix() and Frame::getMatrix().
*/
void Quaternion::getMatrix(GLdouble m[4][4]) const {
const qreal q00 = 2.0 * q[0] * q[0];
const qreal q11 = 2.0 * q[1] * q[1];
const qreal q22 = 2.0 * q[2] * q[2];
const qreal q01 = 2.0 * q[0] * q[1];
const qreal q02 = 2.0 * q[0] * q[2];
const qreal q03 = 2.0 * q[0] * q[3];
const qreal q12 = 2.0 * q[1] * q[2];
const qreal q13 = 2.0 * q[1] * q[3];
const qreal q23 = 2.0 * q[2] * q[3];
m[0][0] = 1.0 - q11 - q22;
m[1][0] = q01 - q23;
m[2][0] = q02 + q13;
m[0][1] = q01 + q23;
m[1][1] = 1.0 - q22 - q00;
m[2][1] = q12 - q03;
m[0][2] = q02 - q13;
m[1][2] = q12 + q03;
m[2][2] = 1.0 - q11 - q00;
m[0][3] = 0.0;
m[1][3] = 0.0;
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}
/*! Same as getMatrix(), but with a \c GLdouble[16] parameter. See also
* getInverseMatrix() and Frame::getMatrix(). */
void Quaternion::getMatrix(GLdouble m[16]) const {
static GLdouble mat[4][4];
getMatrix(mat);
int count = 0;
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
m[count++] = mat[i][j];
}
/*! Fills \p m with the 3x3 rotation matrix associated with the Quaternion.
See also getInverseRotationMatrix().
\attention \p m uses the European mathematical representation of the rotation
matrix. Use matrix() and getMatrix() to retrieve the OpenGL transposed
version. */
void Quaternion::getRotationMatrix(qreal m[3][3]) const {
static GLdouble mat[4][4];
getMatrix(mat);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
// Beware of transposition
m[i][j] = qreal(mat[j][i]);
}
/*! Returns the associated 4x4 OpenGL \e inverse rotation matrix. This is simply
the matrix() of the inverse().
\attention The result is only valid until the next call to inverseMatrix().
Use it immediately (as in \c glMultMatrixd(q.inverseMatrix())) or use
getInverseMatrix() instead.
\attention The matrix is given in OpenGL format (row-major order) and is the
transpose of the actual mathematical European representation. Consider using
getInverseRotationMatrix() instead. */
const GLdouble *Quaternion::inverseMatrix() const {
static GLdouble m[4][4];
getInverseMatrix(m);
return (const GLdouble *)(m);
}
/*! Fills \p m with the OpenGL matrix corresponding to the inverse() rotation.
Use inverseMatrix() if you do not need to store this matrix and simply want to
alter the current OpenGL matrix. See also getMatrix(). */
void Quaternion::getInverseMatrix(GLdouble m[4][4]) const {
inverse().getMatrix(m);
}
/*! Same as getInverseMatrix(), but with a \c GLdouble[16] parameter. See also
* getMatrix(). */
void Quaternion::getInverseMatrix(GLdouble m[16]) const {
inverse().getMatrix(m);
}
/*! \p m is set to the 3x3 \e inverse rotation matrix associated with the
Quaternion.
\attention This is the classical mathematical rotation matrix. The OpenGL
format uses its transposed version. See inverseMatrix() and getInverseMatrix().
*/
void Quaternion::getInverseRotationMatrix(qreal m[3][3]) const {
static GLdouble mat[4][4];
getInverseMatrix(mat);
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
// Beware of transposition
m[i][j] = qreal(mat[j][i]);
}
/*! Returns the slerp interpolation of Quaternions \p a and \p b, at time \p t.
\p t should range in [0,1]. Result is \p a when \p t=0 and \p b when \p t=1.
When \p allowFlip is \c true (default) the slerp interpolation will always use
the "shortest path" between the Quaternions' orientations, by "flipping" the
source Quaternion if needed (see negate()). */
Quaternion Quaternion::slerp(const Quaternion &a, const Quaternion &b, qreal t,
bool allowFlip) {
qreal cosAngle = Quaternion::dot(a, b);
qreal c1, c2;
// Linear interpolation for close orientations
if ((1.0 - fabs(cosAngle)) < 0.01) {
c1 = 1.0 - t;
c2 = t;
} else {
// Spherical interpolation
qreal angle = acos(fabs(cosAngle));
qreal sinAngle = sin(angle);
c1 = sin(angle * (1.0 - t)) / sinAngle;
c2 = sin(angle * t) / sinAngle;
}
// Use the shortest path
if (allowFlip && (cosAngle < 0.0))
c1 = -c1;
return Quaternion(c1 * a[0] + c2 * b[0], c1 * a[1] + c2 * b[1],
c1 * a[2] + c2 * b[2], c1 * a[3] + c2 * b[3]);
}
/*! Returns the slerp interpolation of the two Quaternions \p a and \p b, at
time \p t, using tangents \p tgA and \p tgB.
The resulting Quaternion is "between" \p a and \p b (result is \p a when \p
t=0 and \p b for \p t=1).
Use squadTangent() to define the Quaternion tangents \p tgA and \p tgB. */
Quaternion Quaternion::squad(const Quaternion &a, const Quaternion &tgA,
const Quaternion &tgB, const Quaternion &b,
qreal t) {
Quaternion ab = Quaternion::slerp(a, b, t);
Quaternion tg = Quaternion::slerp(tgA, tgB, t, false);
return Quaternion::slerp(ab, tg, 2.0 * t * (1.0 - t), false);
}
/*! Returns the logarithm of the Quaternion. See also exp(). */
Quaternion Quaternion::log() {
qreal len = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
if (len < 1E-6)
return Quaternion(q[0], q[1], q[2], 0.0);
else {
qreal coef = acos(q[3]) / len;
return Quaternion(q[0] * coef, q[1] * coef, q[2] * coef, 0.0);
}
}
/*! Returns the exponential of the Quaternion. See also log(). */
Quaternion Quaternion::exp() {
qreal theta = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
if (theta < 1E-6)
return Quaternion(q[0], q[1], q[2], cos(theta));
else {
qreal coef = sin(theta) / theta;
return Quaternion(q[0] * coef, q[1] * coef, q[2] * coef, cos(theta));
}
}
/*! Returns log(a. inverse() * b). Useful for squadTangent(). */
Quaternion Quaternion::lnDif(const Quaternion &a, const Quaternion &b) {
Quaternion dif = a.inverse() * b;
dif.normalize();
return dif.log();
}
/*! Returns a tangent Quaternion for \p center, defined by \p before and \p
after Quaternions.
Useful for smooth spline interpolation of Quaternion with squad() and slerp().
*/
Quaternion Quaternion::squadTangent(const Quaternion &before,
const Quaternion &center,
const Quaternion &after) {
Quaternion l1 = Quaternion::lnDif(center, before);
Quaternion l2 = Quaternion::lnDif(center, after);
Quaternion e;
for (int i = 0; i < 4; ++i)
e.q[i] = -0.25 * (l1.q[i] + l2.q[i]);
e = center * (e.exp());
// if (Quaternion::dot(e,b) < 0.0)
// e.negate();
return e;
}
ostream &operator<<(ostream &o, const Quaternion &Q) {
return o << Q[0] << '\t' << Q[1] << '\t' << Q[2] << '\t' << Q[3];
}
/*! Returns a random unit Quaternion.
You can create a randomly directed unit vector using:
\code
Vec randomDir = Quaternion::randomQuaternion() * Vec(1.0, 0.0, 0.0); // or any
other Vec \endcode
\note This function uses rand() to create pseudo-random numbers and the random
number generator can be initialized using srand().*/
Quaternion Quaternion::randomQuaternion() {
// The rand() function is not very portable and may not be available on your
// system. Add the appropriate include or replace by an other random function
// in case of problem.
qreal seed = rand() / (qreal)RAND_MAX;
qreal r1 = sqrt(1.0 - seed);
qreal r2 = sqrt(seed);
qreal t1 = 2.0 * M_PI * (rand() / (qreal)RAND_MAX);
qreal t2 = 2.0 * M_PI * (rand() / (qreal)RAND_MAX);
return Quaternion(sin(t1) * r1, cos(t1) * r1, sin(t2) * r2, cos(t2) * r2);
}
#endif // CGAL_HEADER_ONLY

View File

@ -19,146 +19,9 @@
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
#ifndef CGAL_HEADER_ONLY
#include <CGAL/Qt/vec.h>
#include <CGAL/Qt/domUtils.h>
#include <CGAL/Qt/vec_impl.h>
// Most of the methods are declared inline in vec.h
using namespace qglviewer;
using namespace std;
/*! Projects the Vec on the axis of direction \p direction that passes through
the origin.
\p direction does not need to be normalized (but must be non null). */
void Vec::projectOnAxis(const Vec &direction) {
#ifndef QT_NO_DEBUG
if (direction.squaredNorm() < 1.0E-10)
qWarning("Vec::projectOnAxis: axis direction is not normalized (norm=%f).",
direction.norm());
#endif
*this = (((*this) * direction) / direction.squaredNorm()) * direction;
}
/*! Projects the Vec on the plane whose normal is \p normal that passes through
the origin.
\p normal does not need to be normalized (but must be non null). */
void Vec::projectOnPlane(const Vec &normal) {
#ifndef QT_NO_DEBUG
if (normal.squaredNorm() < 1.0E-10)
qWarning("Vec::projectOnPlane: plane normal is not normalized (norm=%f).",
normal.norm());
#endif
*this -= (((*this) * normal) / normal.squaredNorm()) * normal;
}
/*! Returns a Vec orthogonal to the Vec. Its norm() depends on the Vec, but is
zero only for a null Vec. Note that the function that associates an
orthogonalVec() to a Vec is not continous. */
Vec Vec::orthogonalVec() const {
// Find smallest component. Keep equal case for null values.
if ((fabs(y) >= 0.9 * fabs(x)) && (fabs(z) >= 0.9 * fabs(x)))
return Vec(0.0, -z, y);
else if ((fabs(x) >= 0.9 * fabs(y)) && (fabs(z) >= 0.9 * fabs(y)))
return Vec(-z, 0.0, x);
else
return Vec(-y, x, 0.0);
}
/*! Constructs a Vec from a \c QDomElement representing an XML code of the form
\code< anyTagName x=".." y=".." z=".." />\endcode
If one of these attributes is missing or is not a number, a warning is displayed
and the associated value is set to 0.0.
See also domElement() and initFromDOMElement(). */
Vec::Vec(const QDomElement &element) {
QStringList attribute;
attribute << "x"
<< "y"
<< "z";
for (int i = 0; i < attribute.size(); ++i)
#ifdef QGLVIEWER_UNION_NOT_SUPPORTED
this->operator[](i) = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#else
v_[i] = DomUtils::qrealFromDom(element, attribute[i], 0.0);
#endif
}
/*! Returns an XML \c QDomElement that represents the Vec.
\p name is the name of the QDomElement tag. \p doc is the \c QDomDocument
factory used to create QDomElement.
When output to a file, the resulting QDomElement will look like:
\code
<name x=".." y=".." z=".." />
\endcode
Use initFromDOMElement() to restore the Vec state from the resulting \c
QDomElement. See also the Vec(const QDomElement&) constructor.
Here is complete example that creates a QDomDocument and saves it into a file:
\code
Vec sunPos;
QDomDocument document("myDocument");
QDomElement sunElement = document.createElement("Sun");
document.appendChild(sunElement);
sunElement.setAttribute("brightness", sunBrightness());
sunElement.appendChild(sunPos.domElement("sunPosition", document));
// Other additions to the document hierarchy...
// Save doc document
QFile f("myFile.xml");
if (f.open(IO_WriteOnly))
{
QTextStream out(&f);
document.save(out, 2);
f.close();
}
\endcode
See also Quaternion::domElement(), Frame::domElement(), Camera::domElement()...
*/
QDomElement Vec::domElement(const QString &name, QDomDocument &document) const {
QDomElement de = document.createElement(name);
de.setAttribute("x", QString::number(x));
de.setAttribute("y", QString::number(y));
de.setAttribute("z", QString::number(z));
return de;
}
/*! Restores the Vec state from a \c QDomElement created by domElement().
The \c QDomElement should contain \c x, \c y and \c z attributes. If one of
these attributes is missing or is not a number, a warning is displayed and the
associated value is set to 0.0.
To restore the Vec state from an xml file, use:
\code
// Load DOM from file
QDomDocument doc;
QFile f("myFile.xml");
if (f.open(IO_ReadOnly))
{
doc.setContent(&f);
f.close();
}
// Parse the DOM tree and initialize
QDomElement main=doc.documentElement();
myVec.initFromDOMElement(main);
\endcode
See also the Vec(const QDomElement&) constructor. */
void Vec::initFromDOMElement(const QDomElement &element) {
const Vec v(element);
*this = v;
}
ostream &operator<<(ostream &o, const Vec &v) {
return o << v.x << '\t' << v.y << '\t' << v.z;
}
#endif // CGAL_HEADER_ONLY

View File

@ -3,8 +3,8 @@ if(CGAL_Qt5_moc_and_resource_files_included)
endif()
set(CGAL_Qt5_moc_and_resource_files_included TRUE)
qt5_wrap_cpp(_CGAL_Qt5_MOC_FILES_private
if(NOT CGAL_HEADER_ONLY)
qt5_wrap_cpp(_CGAL_Qt5_MOC_FILES_private
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/GraphicsViewNavigation.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/DemosMainWindow.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/GraphicsItem.h
@ -16,6 +16,7 @@ qt5_wrap_cpp(_CGAL_Qt5_MOC_FILES_private
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/manipulatedFrame.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/qglviewer.h
)
endif()#CGAL_HEADER_ONLY
# qrc files (resources files, that contain icons, at least)
if(EXISTS ${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/demo/resources/CGAL.qrc)

View File

@ -53,10 +53,24 @@ if(NOT CGAL_Qt5_MISSING_DEPS)
include(${CMAKE_CURRENT_LIST_DIR}/CGAL_Qt5_moc_and_resource_files.cmake)
if(CGAL_HEADER_ONLY AND (WITH_demos OR WITH_examples OR NOT CGAL_BUILDING_LIBS) AND NOT TARGET CGAL_Qt5_moc_and_resources)
add_library(CGAL_Qt5_moc_and_resources STATIC ${_CGAL_Qt5_MOC_FILES_private} ${_CGAL_Qt5_RESOURCE_FILES_private})
add_library(CGAL_Qt5_moc_and_resources STATIC
${_CGAL_Qt5_MOC_FILES_private}
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/GraphicsViewNavigation.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/DemosMainWindow.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/GraphicsItem.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/GraphicsViewInput.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/camera.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/frame.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/keyFrameInterpolator.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/manipulatedCameraFrame.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/manipulatedFrame.h
${CGAL_GRAPHICSVIEW_PACKAGE_DIR}/include/CGAL/Qt/qglviewer.h
${_CGAL_Qt5_RESOURCE_FILES_private})
set_target_properties(CGAL_Qt5_moc_and_resources PROPERTIES
POSITION_INDEPENDENT_CODE TRUE
EXCLUDE_FROM_ALL TRUE)
EXCLUDE_FROM_ALL TRUE
AUTOMOC TRUE)
target_link_libraries(CGAL_Qt5_moc_and_resources CGAL::CGAL Qt5::Widgets Qt5::OpenGL Qt5::Svg Qt5::Xml)
add_library(CGAL::CGAL_Qt5_moc_and_resources ALIAS CGAL_Qt5_moc_and_resources)

View File

@ -660,8 +660,8 @@ bool Volume_plane<T>::eventFilter(QObject *, QEvent *event)
viewer->setMouseBinding(
Qt::NoModifier,
Qt::LeftButton,
QGLViewer::FRAME,
QGLViewer::TRANSLATE);
qglviewer::FRAME,
qglviewer::TRANSLATE);
}
}
else if(event->type() == QEvent::MouseButtonRelease && is_grabbing)
@ -670,8 +670,8 @@ bool Volume_plane<T>::eventFilter(QObject *, QEvent *event)
viewer->setMouseBinding(
Qt::NoModifier,
Qt::LeftButton,
QGLViewer::CAMERA,
QGLViewer::ROTATE);
qglviewer::CAMERA,
qglviewer::ROTATE);
}
return false;
}

View File

@ -988,7 +988,7 @@ void Scene_edit_box_item_priv::reset_selection()
selection_on = false;
QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin();
viewer->setManipulatedFrame(frame);
viewer->setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, QGLViewer::SELECT);
viewer->setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, qglviewer::SELECT);
constraint.setTranslationConstraintType(qglviewer::AxisPlaneConstraint::FREE);
selected_vertices.clear();
}
@ -1060,8 +1060,8 @@ bool Scene_edit_box_item::eventFilter(QObject *obj, QEvent *event)
viewer->setMouseBinding(
Qt::NoModifier,
Qt::LeftButton,
QGLViewer::FRAME,
QGLViewer::TRANSLATE);
qglviewer::FRAME,
qglviewer::TRANSLATE);
}
else
{
@ -1108,8 +1108,8 @@ bool Scene_edit_box_item::eventFilter(QObject *obj, QEvent *event)
viewer->setMouseBinding(
Qt::NoModifier,
Qt::LeftButton,
QGLViewer::CAMERA,
QGLViewer::ROTATE);
qglviewer::CAMERA,
qglviewer::ROTATE);
}
else if(event->type() == QEvent::KeyRelease)
{

View File

@ -1,6 +1,6 @@
#include "Polyhedron_demo.h"
#include <clocale>
#include <CGAL/Qt/resources.h>
/*!
* \brief Defines the entry point of the demo.
* Creates the application and sets a main window.

View File

@ -2,7 +2,6 @@
#include <CGAL/Three/Scene_draw_interface.h>
#include <QMouseEvent>
#include <QKeyEvent>
#include <CGAL/Qt/manipulatedCameraFrame.h>
#include <QDebug>
#include <QOpenGLShader>
#include <QFileDialog>
@ -92,7 +91,7 @@ Viewer::Viewer(QWidget* parent, bool antialiasing)
connect( d->textRenderer, SIGNAL(sendMessage(QString,int)),
this, SLOT(printMessage(QString,int)) );
connect(&d->messageTimer, SIGNAL(timeout()), SLOT(hideMessage()));
setShortcut(EXIT_VIEWER, 0);
setShortcut(qglviewer::EXIT_VIEWER, 0);
setKeyDescription(Qt::Key_T,
tr("Turn the camera by 180 degrees"));
setKeyDescription(Qt::Key_M,
@ -107,12 +106,12 @@ Viewer::Viewer(QWidget* parent, bool antialiasing)
#if QGLVIEWER_VERSION >= 0x020501
//modify mouse bindings that have been updated
setMouseBinding(Qt::Key(0), Qt::NoModifier, Qt::LeftButton, RAP_FROM_PIXEL, true, Qt::RightButton);
setMouseBinding(Qt::Key(0), Qt::NoModifier, Qt::LeftButton, qglviewer::RAP_FROM_PIXEL, true, Qt::RightButton);
setMouseBindingDescription(Qt::ShiftModifier, Qt::RightButton,
tr("Select and pop context menu"));
setMouseBinding(Qt::Key_R, Qt::NoModifier, Qt::LeftButton, RAP_FROM_PIXEL);
setMouseBinding(Qt::Key_R, Qt::NoModifier, Qt::LeftButton, qglviewer::RAP_FROM_PIXEL);
//use the new API for these
setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, SELECT);
setMouseBinding(Qt::ShiftModifier, Qt::LeftButton, qglviewer::SELECT);
setMouseBindingDescription(Qt::Key(0), Qt::ShiftModifier, Qt::LeftButton,
tr("Selects and display context "

View File

@ -9,8 +9,6 @@
#include <QOpenGLVertexArrayObject>
#include <QOpenGLShaderProgram>
#include <CGAL/Three/Viewer_interface.h>
#include <CGAL/Qt/qglviewer.h>
#include <QPoint>
#include <QFont>
#include <QOpenGLFramebufferObject>
@ -112,7 +110,7 @@ public Q_SLOTS:
void setBindingSelect() Q_DECL_OVERRIDE
{
#if QGLVIEWER_VERSION >= 0x020501
setMouseBinding(::Qt::ShiftModifier, ::Qt::LeftButton, SELECT);
setMouseBinding(::Qt::ShiftModifier, ::Qt::LeftButton, qglviewer::SELECT);
#else
setMouseBinding(::Qt::SHIFT + ::Qt::LeftButton, SELECT);
#endif
@ -121,7 +119,7 @@ public Q_SLOTS:
virtual void setNoBinding() Q_DECL_OVERRIDE
{
#if QGLVIEWER_VERSION >= 0x020501
setMouseBinding(::Qt::ShiftModifier, ::Qt::LeftButton, NO_CLICK_ACTION);
setMouseBinding(::Qt::ShiftModifier, ::Qt::LeftButton, qglviewer::NO_CLICK_ACTION);
#else
setMouseBinding(::Qt::SHIFT + ::Qt::LeftButton, NO_CLICK_ACTION);
#endif