quaternion_demo.cpp
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
00005 //
00006 // Eigen is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 3 of the License, or (at your option) any later version.
00010 //
00011 // Alternatively, you can redistribute it and/or
00012 // modify it under the terms of the GNU General Public License as
00013 // published by the Free Software Foundation; either version 2 of
00014 // the License, or (at your option) any later version.
00015 //
00016 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
00017 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00018 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
00019 // GNU General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License and a copy of the GNU General Public License along with
00023 // Eigen. If not, see <http://www.gnu.org/licenses/>.
00024 
00025 #include "quaternion_demo.h"
00026 #include "icosphere.h"
00027 
00028 #include <Eigen/Geometry>
00029 #include <Eigen/QR>
00030 #include <Eigen/LU>
00031 
00032 #include <iostream>
00033 #include <QEvent>
00034 #include <QMouseEvent>
00035 #include <QInputDialog>
00036 #include <QGridLayout>
00037 #include <QButtonGroup>
00038 #include <QRadioButton>
00039 #include <QDockWidget>
00040 #include <QPushButton>
00041 #include <QGroupBox>
00042 
00043 using namespace Eigen;
00044 
00045 class FancySpheres
00046 {
00047   public:
00048     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00049     
00050     FancySpheres()
00051     {
00052       const int levels = 4;
00053       const float scale = 0.33;
00054       float radius = 100;
00055       std::vector<int> parents;
00056 
00057       // leval 0
00058       mCenters.push_back(Vector3f::Zero());
00059       parents.push_back(-1);
00060       mRadii.push_back(radius);
00061 
00062       // generate level 1 using icosphere vertices
00063       radius *= 0.45;
00064       {
00065         float dist = mRadii[0]*0.9;
00066         for (int i=0; i<12; ++i)
00067         {
00068           mCenters.push_back(mIcoSphere.vertices()[i] * dist);
00069           mRadii.push_back(radius);
00070           parents.push_back(0);
00071         }
00072       }
00073 
00074       static const float angles [10] = {
00075         0, 0,
00076         M_PI, 0.*M_PI,
00077         M_PI, 0.5*M_PI,
00078         M_PI, 1.*M_PI,
00079         M_PI, 1.5*M_PI
00080       };
00081 
00082       // generate other levels
00083       int start = 1;
00084       for (int l=1; l<levels; l++)
00085       {
00086         radius *= scale;
00087         int end = mCenters.size();
00088         for (int i=start; i<end; ++i)
00089         {
00090           Vector3f c = mCenters[i];
00091           Vector3f ax0 = (c - mCenters[parents[i]]).normalized();
00092           Vector3f ax1 = ax0.unitOrthogonal();
00093           Quaternionf q;
00094           q.setFromTwoVectors(Vector3f::UnitZ(), ax0);
00095           Affine3f t = Translation3f(c) * q * Scaling(mRadii[i]+radius);
00096           for (int j=0; j<5; ++j)
00097           {
00098             Vector3f newC = c + ( (AngleAxisf(angles[j*2+1], ax0)
00099                                 * AngleAxisf(angles[j*2+0] * (l==1 ? 0.35 : 0.5), ax1)) * ax0)
00100                                 * (mRadii[i] + radius*0.8);
00101             mCenters.push_back(newC);
00102             mRadii.push_back(radius);
00103             parents.push_back(i);
00104           }
00105         }
00106         start = end;
00107       }
00108     }
00109 
00110     void draw()
00111     {
00112       int end = mCenters.size();
00113       glEnable(GL_NORMALIZE);
00114       for (int i=0; i<end; ++i)
00115       {
00116         Affine3f t = Translation3f(mCenters[i]) * Scaling(mRadii[i]);
00117         gpu.pushMatrix(GL_MODELVIEW);
00118         gpu.multMatrix(t.matrix(),GL_MODELVIEW);
00119         mIcoSphere.draw(2);
00120         gpu.popMatrix(GL_MODELVIEW);
00121       }
00122       glDisable(GL_NORMALIZE);
00123     }
00124   protected:
00125     std::vector<Vector3f> mCenters;
00126     std::vector<float> mRadii;
00127     IcoSphere mIcoSphere;
00128 };
00129 
00130 
00131 // generic linear interpolation method
00132 template<typename T> T lerp(float t, const T& a, const T& b)
00133 {
00134   return a*(1-t) + b*t;
00135 }
00136 
00137 // quaternion slerp
00138 template<> Quaternionf lerp(float t, const Quaternionf& a, const Quaternionf& b)
00139 { return a.slerp(t,b); }
00140 
00141 // linear interpolation of a frame using the type OrientationType
00142 // to perform the interpolation of the orientations
00143 template<typename OrientationType>
00144 inline static Frame lerpFrame(float alpha, const Frame& a, const Frame& b)
00145 {
00146   return Frame(lerp(alpha,a.position,b.position),
00147                Quaternionf(lerp(alpha,OrientationType(a.orientation),OrientationType(b.orientation))));
00148 }
00149 
00150 template<typename _Scalar> class EulerAngles
00151 {
00152 public:
00153   enum { Dim = 3 };
00154   typedef _Scalar Scalar;
00155   typedef Matrix<Scalar,3,3> Matrix3;
00156   typedef Matrix<Scalar,3,1> Vector3;
00157   typedef Quaternion<Scalar> QuaternionType;
00158 
00159 protected:
00160 
00161   Vector3 m_angles;
00162 
00163 public:
00164 
00165   EulerAngles() {}
00166   inline EulerAngles(Scalar a0, Scalar a1, Scalar a2) : m_angles(a0, a1, a2) {}
00167   inline EulerAngles(const QuaternionType& q) { *this = q; }
00168 
00169   const Vector3& coeffs() const { return m_angles; }
00170   Vector3& coeffs() { return m_angles; }
00171 
00172   EulerAngles& operator=(const QuaternionType& q)
00173   {
00174     Matrix3 m = q.toRotationMatrix();
00175     return *this = m;
00176   }
00177 
00178   EulerAngles& operator=(const Matrix3& m)
00179   {
00180     // mat =  cy*cz          -cy*sz           sy
00181     //        cz*sx*sy+cx*sz  cx*cz-sx*sy*sz -cy*sx
00182     //       -cx*cz*sy+sx*sz  cz*sx+cx*sy*sz  cx*cy
00183     m_angles.coeffRef(1) = std::asin(m.coeff(0,2));
00184     m_angles.coeffRef(0) = std::atan2(-m.coeff(1,2),m.coeff(2,2));
00185     m_angles.coeffRef(2) = std::atan2(-m.coeff(0,1),m.coeff(0,0));
00186     return *this;
00187   }
00188 
00189   Matrix3 toRotationMatrix(void) const
00190   {
00191     Vector3 c = m_angles.array().cos();
00192     Vector3 s = m_angles.array().sin();
00193     Matrix3 res;
00194     res <<  c.y()*c.z(),                    -c.y()*s.z(),                   s.y(),
00195             c.z()*s.x()*s.y()+c.x()*s.z(),  c.x()*c.z()-s.x()*s.y()*s.z(),  -c.y()*s.x(),
00196             -c.x()*c.z()*s.y()+s.x()*s.z(), c.z()*s.x()+c.x()*s.y()*s.z(),  c.x()*c.y();
00197     return res;
00198   }
00199 
00200   operator QuaternionType() { return QuaternionType(toRotationMatrix()); }
00201 };
00202 
00203 // Euler angles slerp
00204 template<> EulerAngles<float> lerp(float t, const EulerAngles<float>& a, const EulerAngles<float>& b)
00205 {
00206   EulerAngles<float> res;
00207   res.coeffs() = lerp(t, a.coeffs(), b.coeffs());
00208   return res;
00209 }
00210 
00211 
00212 RenderingWidget::RenderingWidget()
00213 {
00214   mAnimate = false;
00215   mCurrentTrackingMode = TM_NO_TRACK;
00216   mNavMode = NavTurnAround;
00217   mLerpMode = LerpQuaternion;
00218   mRotationMode = RotationStable;
00219   mTrackball.setCamera(&mCamera);
00220 
00221   // required to capture key press events
00222   setFocusPolicy(Qt::ClickFocus);
00223 }
00224 
00225 void RenderingWidget::grabFrame(void)
00226 {
00227     // ask user for a time
00228     bool ok = false;
00229     double t = 0;
00230     if (!m_timeline.empty())
00231       t = (--m_timeline.end())->first + 1.;
00232     t = QInputDialog::getDouble(this, "Eigen's RenderingWidget", "time value: ",
00233       t, 0, 1e3, 1, &ok);
00234     if (ok)
00235     {
00236       Frame aux;
00237       aux.orientation = mCamera.viewMatrix().linear();
00238       aux.position = mCamera.viewMatrix().translation();
00239       m_timeline[t] = aux;
00240     }
00241 }
00242 
00243 void RenderingWidget::drawScene()
00244 {
00245   static FancySpheres sFancySpheres;
00246   float length = 50;
00247   gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitX(), Color(1,0,0,1));
00248   gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitY(), Color(0,1,0,1));
00249   gpu.drawVector(Vector3f::Zero(), length*Vector3f::UnitZ(), Color(0,0,1,1));
00250 
00251   // draw the fractal object
00252   float sqrt3 = internal::sqrt(3.);
00253   glLightfv(GL_LIGHT0, GL_AMBIENT, Vector4f(0.5,0.5,0.5,1).data());
00254   glLightfv(GL_LIGHT0, GL_DIFFUSE, Vector4f(0.5,1,0.5,1).data());
00255   glLightfv(GL_LIGHT0, GL_SPECULAR, Vector4f(1,1,1,1).data());
00256   glLightfv(GL_LIGHT0, GL_POSITION, Vector4f(-sqrt3,-sqrt3,sqrt3,0).data());
00257 
00258   glLightfv(GL_LIGHT1, GL_AMBIENT, Vector4f(0,0,0,1).data());
00259   glLightfv(GL_LIGHT1, GL_DIFFUSE, Vector4f(1,0.5,0.5,1).data());
00260   glLightfv(GL_LIGHT1, GL_SPECULAR, Vector4f(1,1,1,1).data());
00261   glLightfv(GL_LIGHT1, GL_POSITION, Vector4f(-sqrt3,sqrt3,-sqrt3,0).data());
00262 
00263   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Vector4f(0.7, 0.7, 0.7, 1).data());
00264   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Vector4f(0.8, 0.75, 0.6, 1).data());
00265   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Vector4f(1, 1, 1, 1).data());
00266   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64);
00267 
00268   glEnable(GL_LIGHTING);
00269   glEnable(GL_LIGHT0);
00270   glEnable(GL_LIGHT1);
00271 
00272   sFancySpheres.draw();
00273   glVertexPointer(3, GL_FLOAT, 0, mVertices[0].data());
00274   glNormalPointer(GL_FLOAT, 0, mNormals[0].data());
00275   glEnableClientState(GL_VERTEX_ARRAY);
00276   glEnableClientState(GL_NORMAL_ARRAY);
00277   glDrawArrays(GL_TRIANGLES, 0, mVertices.size());
00278   glDisableClientState(GL_VERTEX_ARRAY);
00279   glDisableClientState(GL_NORMAL_ARRAY);
00280 
00281   glDisable(GL_LIGHTING);
00282 }
00283 
00284 void RenderingWidget::animate()
00285 {
00286   m_alpha += double(m_timer.interval()) * 1e-3;
00287 
00288   TimeLine::const_iterator hi = m_timeline.upper_bound(m_alpha);
00289   TimeLine::const_iterator lo = hi;
00290   --lo;
00291 
00292   Frame currentFrame;
00293 
00294   if(hi==m_timeline.end())
00295   {
00296     // end
00297     currentFrame = lo->second;
00298     stopAnimation();
00299   }
00300   else if(hi==m_timeline.begin())
00301   {
00302     // start
00303     currentFrame = hi->second;
00304   }
00305   else
00306   {
00307     float s = (m_alpha - lo->first)/(hi->first - lo->first);
00308     if (mLerpMode==LerpEulerAngles)
00309       currentFrame = ::lerpFrame<EulerAngles<float> >(s, lo->second, hi->second);
00310     else if (mLerpMode==LerpQuaternion)
00311       currentFrame = ::lerpFrame<Eigen::Quaternionf>(s, lo->second, hi->second);
00312     else
00313     {
00314       std::cerr << "Invalid rotation interpolation mode (abort)\n";
00315       exit(2);
00316     }
00317     currentFrame.orientation.coeffs().normalize();
00318   }
00319 
00320   currentFrame.orientation = currentFrame.orientation.inverse();
00321   currentFrame.position = - (currentFrame.orientation * currentFrame.position);
00322   mCamera.setFrame(currentFrame);
00323 
00324   updateGL();
00325 }
00326 
00327 void RenderingWidget::keyPressEvent(QKeyEvent * e)
00328 {
00329     switch(e->key())
00330     {
00331       case Qt::Key_Up:
00332         mCamera.zoom(2);
00333         break;
00334       case Qt::Key_Down:
00335         mCamera.zoom(-2);
00336         break;
00337       // add a frame
00338       case Qt::Key_G:
00339         grabFrame();
00340         break;
00341       // clear the time line
00342       case Qt::Key_C:
00343         m_timeline.clear();
00344         break;
00345       // move the camera to initial pos
00346       case Qt::Key_R:
00347         resetCamera();
00348         break;
00349       // start/stop the animation
00350       case Qt::Key_A:
00351         if (mAnimate)
00352         {
00353           stopAnimation();
00354         }
00355         else
00356         {
00357           m_alpha = 0;
00358           connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
00359           m_timer.start(1000/30);
00360           mAnimate = true;
00361         }
00362         break;
00363       default:
00364         break;
00365     }
00366 
00367     updateGL();
00368 }
00369 
00370 void RenderingWidget::stopAnimation()
00371 {
00372   disconnect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
00373   m_timer.stop();
00374   mAnimate = false;
00375   m_alpha = 0;
00376 }
00377 
00378 void RenderingWidget::mousePressEvent(QMouseEvent* e)
00379 {
00380   mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
00381   bool fly = (mNavMode==NavFly) || (e->modifiers()&Qt::ControlModifier);
00382   switch(e->button())
00383   {
00384     case Qt::LeftButton:
00385       if(fly)
00386       {
00387         mCurrentTrackingMode = TM_LOCAL_ROTATE;
00388         mTrackball.start(Trackball::Local);
00389       }
00390       else
00391       {
00392         mCurrentTrackingMode = TM_ROTATE_AROUND;
00393         mTrackball.start(Trackball::Around);
00394       }
00395       mTrackball.track(mMouseCoords);
00396       break;
00397     case Qt::MidButton:
00398       if(fly)
00399         mCurrentTrackingMode = TM_FLY_Z;
00400       else
00401         mCurrentTrackingMode = TM_ZOOM;
00402       break;
00403     case Qt::RightButton:
00404         mCurrentTrackingMode = TM_FLY_PAN;
00405       break;
00406     default:
00407       break;
00408   }
00409 }
00410 void RenderingWidget::mouseReleaseEvent(QMouseEvent*)
00411 {
00412     mCurrentTrackingMode = TM_NO_TRACK;
00413     updateGL();
00414 }
00415 
00416 void RenderingWidget::mouseMoveEvent(QMouseEvent* e)
00417 {
00418     // tracking
00419     if(mCurrentTrackingMode != TM_NO_TRACK)
00420     {
00421         float dx =   float(e->x() - mMouseCoords.x()) / float(mCamera.vpWidth());
00422         float dy = - float(e->y() - mMouseCoords.y()) / float(mCamera.vpHeight());
00423 
00424         // speedup the transformations
00425         if(e->modifiers() & Qt::ShiftModifier)
00426         {
00427           dx *= 10.;
00428           dy *= 10.;
00429         }
00430 
00431         switch(mCurrentTrackingMode)
00432         {
00433           case TM_ROTATE_AROUND:
00434           case TM_LOCAL_ROTATE:
00435             if (mRotationMode==RotationStable)
00436             {
00437               // use the stable trackball implementation mapping
00438               // the 2D coordinates to 3D points on a sphere.
00439               mTrackball.track(Vector2i(e->pos().x(), e->pos().y()));
00440             }
00441             else
00442             {
00443               // standard approach mapping the x and y displacements as rotations
00444               // around the camera's X and Y axes.
00445               Quaternionf q = AngleAxisf( dx*M_PI, Vector3f::UnitY())
00446                             * AngleAxisf(-dy*M_PI, Vector3f::UnitX());
00447               if (mCurrentTrackingMode==TM_LOCAL_ROTATE)
00448                 mCamera.localRotate(q);
00449               else
00450                 mCamera.rotateAroundTarget(q);
00451             }
00452             break;
00453           case TM_ZOOM :
00454             mCamera.zoom(dy*100);
00455             break;
00456           case TM_FLY_Z :
00457             mCamera.localTranslate(Vector3f(0, 0, -dy*200));
00458             break;
00459           case TM_FLY_PAN :
00460             mCamera.localTranslate(Vector3f(dx*200, dy*200, 0));
00461             break;
00462           default:
00463             break;
00464         }
00465 
00466         updateGL();
00467     }
00468 
00469     mMouseCoords = Vector2i(e->pos().x(), e->pos().y());
00470 }
00471 
00472 void RenderingWidget::paintGL()
00473 {
00474   glEnable(GL_DEPTH_TEST);
00475   glDisable(GL_CULL_FACE);
00476   glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
00477   glDisable(GL_COLOR_MATERIAL);
00478   glDisable(GL_BLEND);
00479   glDisable(GL_ALPHA_TEST);
00480   glDisable(GL_TEXTURE_1D);
00481   glDisable(GL_TEXTURE_2D);
00482   glDisable(GL_TEXTURE_3D);
00483 
00484   // Clear buffers
00485   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00486 
00487   mCamera.activateGL();
00488 
00489   drawScene();
00490 }
00491 
00492 void RenderingWidget::initializeGL()
00493 {
00494   glClearColor(1., 1., 1., 0.);
00495   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
00496   glDepthMask(GL_TRUE);
00497   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00498 
00499   mCamera.setPosition(Vector3f(-200, -200, -200));
00500   mCamera.setTarget(Vector3f(0, 0, 0));
00501   mInitFrame.orientation = mCamera.orientation().inverse();
00502   mInitFrame.position = mCamera.viewMatrix().translation();
00503 }
00504 
00505 void RenderingWidget::resizeGL(int width, int height)
00506 {
00507     mCamera.setViewport(width,height);
00508 }
00509 
00510 void RenderingWidget::setNavMode(int m)
00511 {
00512   mNavMode = NavMode(m);
00513 }
00514 
00515 void RenderingWidget::setLerpMode(int m)
00516 {
00517   mLerpMode = LerpMode(m);
00518 }
00519 
00520 void RenderingWidget::setRotationMode(int m)
00521 {
00522   mRotationMode = RotationMode(m);
00523 }
00524 
00525 void RenderingWidget::resetCamera()
00526 {
00527   if (mAnimate)
00528     stopAnimation();
00529   m_timeline.clear();
00530   Frame aux0 = mCamera.frame();
00531   aux0.orientation = aux0.orientation.inverse();
00532   aux0.position = mCamera.viewMatrix().translation();
00533   m_timeline[0] = aux0;
00534 
00535   Vector3f currentTarget = mCamera.target();
00536   mCamera.setTarget(Vector3f::Zero());
00537 
00538   // compute the rotation duration to move the camera to the target
00539   Frame aux1 = mCamera.frame();
00540   aux1.orientation = aux1.orientation.inverse();
00541   aux1.position = mCamera.viewMatrix().translation();
00542   float duration = aux0.orientation.angularDistance(aux1.orientation) * 0.9;
00543   if (duration<0.1) duration = 0.1;
00544 
00545   // put the camera at that time step:
00546   aux1 = aux0.lerp(duration/2,mInitFrame);
00547   // and make it look at the target again
00548   aux1.orientation = aux1.orientation.inverse();
00549   aux1.position = - (aux1.orientation * aux1.position);
00550   mCamera.setFrame(aux1);
00551   mCamera.setTarget(Vector3f::Zero());
00552 
00553   // add this camera keyframe
00554   aux1.orientation = aux1.orientation.inverse();
00555   aux1.position = mCamera.viewMatrix().translation();
00556   m_timeline[duration] = aux1;
00557 
00558   m_timeline[2] = mInitFrame;
00559   m_alpha = 0;
00560   animate();
00561   connect(&m_timer, SIGNAL(timeout()), this, SLOT(animate()));
00562   m_timer.start(1000/30);
00563   mAnimate = true;
00564 }
00565 
00566 QWidget* RenderingWidget::createNavigationControlWidget()
00567 {
00568   QWidget* panel = new QWidget();
00569   QVBoxLayout* layout = new QVBoxLayout();
00570 
00571   {
00572     QPushButton* but = new QPushButton("reset");
00573     but->setToolTip("move the camera to initial position (with animation)");
00574     layout->addWidget(but);
00575     connect(but, SIGNAL(clicked()), this, SLOT(resetCamera()));
00576   }
00577   {
00578     // navigation mode
00579     QGroupBox* box = new QGroupBox("navigation mode");
00580     QVBoxLayout* boxLayout = new QVBoxLayout;
00581     QButtonGroup* group = new QButtonGroup(panel);
00582     QRadioButton* but;
00583     but = new QRadioButton("turn around");
00584     but->setToolTip("look around an object");
00585     group->addButton(but, NavTurnAround);
00586     boxLayout->addWidget(but);
00587     but = new QRadioButton("fly");
00588     but->setToolTip("free navigation like a spaceship\n(this mode can also be enabled pressing the \"shift\" key)");
00589     group->addButton(but, NavFly);
00590     boxLayout->addWidget(but);
00591     group->button(mNavMode)->setChecked(true);
00592     connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setNavMode(int)));
00593     box->setLayout(boxLayout);
00594     layout->addWidget(box);
00595   }
00596   {
00597     // track ball, rotation mode
00598     QGroupBox* box = new QGroupBox("rotation mode");
00599     QVBoxLayout* boxLayout = new QVBoxLayout;
00600     QButtonGroup* group = new QButtonGroup(panel);
00601     QRadioButton* but;
00602     but = new QRadioButton("stable trackball");
00603     group->addButton(but, RotationStable);
00604     boxLayout->addWidget(but);
00605     but->setToolTip("use the stable trackball implementation mapping\nthe 2D coordinates to 3D points on a sphere");
00606     but = new QRadioButton("standard rotation");
00607     group->addButton(but, RotationStandard);
00608     boxLayout->addWidget(but);
00609     but->setToolTip("standard approach mapping the x and y displacements\nas rotations around the camera's X and Y axes");
00610     group->button(mRotationMode)->setChecked(true);
00611     connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setRotationMode(int)));
00612     box->setLayout(boxLayout);
00613     layout->addWidget(box);
00614   }
00615   {
00616     // interpolation mode
00617     QGroupBox* box = new QGroupBox("spherical interpolation");
00618     QVBoxLayout* boxLayout = new QVBoxLayout;
00619     QButtonGroup* group = new QButtonGroup(panel);
00620     QRadioButton* but;
00621     but = new QRadioButton("quaternion slerp");
00622     group->addButton(but, LerpQuaternion);
00623     boxLayout->addWidget(but);
00624     but->setToolTip("use quaternion spherical interpolation\nto interpolate orientations");
00625     but = new QRadioButton("euler angles");
00626     group->addButton(but, LerpEulerAngles);
00627     boxLayout->addWidget(but);
00628     but->setToolTip("use Euler angles to interpolate orientations");
00629     group->button(mNavMode)->setChecked(true);
00630     connect(group, SIGNAL(buttonClicked(int)), this, SLOT(setLerpMode(int)));
00631     box->setLayout(boxLayout);
00632     layout->addWidget(box);
00633   }
00634   layout->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum,QSizePolicy::Expanding));
00635   panel->setLayout(layout);
00636   return panel;
00637 }
00638 
00639 QuaternionDemo::QuaternionDemo()
00640 {
00641   mRenderingWidget = new RenderingWidget();
00642   setCentralWidget(mRenderingWidget);
00643 
00644   QDockWidget* panel = new QDockWidget("navigation", this);
00645   panel->setAllowedAreas((QFlags<Qt::DockWidgetArea>)(Qt::RightDockWidgetArea | Qt::LeftDockWidgetArea));
00646   addDockWidget(Qt::RightDockWidgetArea, panel);
00647   panel->setWidget(mRenderingWidget->createNavigationControlWidget());
00648 }
00649 
00650 int main(int argc, char *argv[])
00651 {
00652   std::cout << "Navigation:\n";
00653   std::cout << "  left button:           rotate around the target\n";
00654   std::cout << "  middle button:         zoom\n";
00655   std::cout << "  left button + ctrl     quake rotate (rotate around camera position)\n";
00656   std::cout << "  middle button + ctrl   walk (progress along camera's z direction)\n";
00657   std::cout << "  left button:           pan (translate in the XY camera's plane)\n\n";
00658   std::cout << "R : move the camera to initial position\n";
00659   std::cout << "A : start/stop animation\n";
00660   std::cout << "C : clear the animation\n";
00661   std::cout << "G : add a key frame\n";
00662 
00663   QApplication app(argc, argv);
00664   QuaternionDemo demo;
00665   demo.resize(600,500);
00666   demo.show();
00667   return app.exec();
00668 }
00669 
00670 #include "quaternion_demo.moc"
00671 


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:32:17