OSGTrackballEngine.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038
00039 #include "OSGConfig.h"
00040 #include "OSGBaseTypes.h"
00041 #include "OSGMatrix.h"
00042 #include "OSGMatrixUtility.h"
00043
00044 #include "OSGTrackballEngine.h"
00045 #include "OSGNavigator.h"
00046 #include "OSGNode.h"
00047 #include "OSGCamera.h"
00048 #include "OSGBackground.h"
00049
00050 OSG_USING_NAMESPACE
00051
00052 /***************************************************************************\
00053  *                            Description                                  *
00054 \***************************************************************************/
00055
00120 TrackballEngineTransitPtr
00121 TrackballEngine::create(Real32 rSize)
00122 {
00123     return TrackballEngineTransitPtr(new TrackballEngine(rSize));
00124 }
00125
00126 /*------------------------------ get --------------------------------------*/
00127
00128
00133 const Pnt3f& TrackballEngine::getFrom(void)
00134 {
00135     _pFrom = Pnt3f(_finalMatrix[3]);
00136     return _pFrom;
00137 }
00138
00143 const Pnt3f& TrackballEngine::getAt(void)
00144 {
00145     _pAt = Pnt3f(_finalMatrix[3] - (_rDistance*_finalMatrix[2]));
00146     return _pAt;
00147 }
00148
00153 const Vec3f& TrackballEngine::getUp(void)
00154 {
00155     _vUp = Vec3f(_finalMatrix[1]);
00156     return _vUp;
00157 }
00158
00161 const Matrix& TrackballEngine::getMatrix(void)
00162 {
00163     updateFinalMatrix();
00164     return _finalMatrix;
00165 }
00166
00167 Real32 TrackballEngine::getDistance(void)
00168 {
00169     return _rDistance;
00170 }
00171
00172 /*------------------------------ set --------------------------------------*/
00173
00176 void TrackballEngine::setFrom(Pnt3f new_from)
00177 {
00178     set(new_from, getAt(), getUp());
00179 }
00180
00183 void TrackballEngine::setAt(Pnt3f new_at)
00184 {
00185     set(getFrom(),new_at,getUp());
00186 }
00187
00190 void TrackballEngine::setUp(Vec3f new_up)
00191 {
00192     set(getFrom(),getAt(),new_up);
00193 }
00194
00197 void TrackballEngine::set(Pnt3f new_from, Pnt3f new_at, Vec3f new_up)
00198 {
00199     bool b = MatrixLookAt(_tMatrix, new_at, new_at+(new_at-new_from), new_up);
00200     if(!b)
00201     {
00202         _rDistance = (new_at - new_from).length();
00203         updateFinalMatrix();
00204     }
00205     else
00206     {
00207         FNOTICE(("TrackballEngine: set(.,.,.), failed"));
00208     }
00209 }
00210
00218 void TrackballEngine::set(const Matrix & new_matrix)
00219 {
00220     // get distance
00221     Vec3f translation( new_matrix[3][0], new_matrix[3][1], new_matrix[3][2] );
00222
00223     _rDistance = translation.length();
00224
00225     _pFrom = Pnt3f(new_matrix[3]);
00226     _pAt   = Pnt3f(new_matrix[3] - (_rDistance * new_matrix[2]));
00227     _vUp   = Vec3f(new_matrix[1]);
00228
00229     set(_pFrom, _pAt, _vUp);
00230 }
00231
00234 void TrackballEngine::setDistance(Real32 new_distance)
00235 {
00236     _rDistance = new_distance;
00237     updateFinalMatrix();
00238 }
00239
00240
00241 /*--------------------  navigator engine callbacks ------------------------*/
00242
00243 void TrackballEngine::buttonPress(Int16 button, Int16 x, Int16 y,
00244                                   Navigator* nav)
00245 {
00246     switch (button)
00247     {
00248         case Navigator::LEFT_MOUSE  :
00249             _currentState = Navigator::ROTATING;
00250             break;
00251
00252         case Navigator::RIGHT_MOUSE :
00253             _currentState = Navigator::TRANSLATING_Z;
00254             break;
00255
00256         case Navigator::MIDDLE_MOUSE:
00257             _currentState = Navigator::TRANSLATING_XY;
00258             getIntersectionPoint(x,y, nav);
00259             break;
00260
00261         case Navigator::UP_MOUSE    :
00262             _currentState = Navigator::IDLE;
00263             translateZ(-nav->getMotionFactor());
00264             break;
00265
00266         case Navigator::DOWN_MOUSE  :
00267             _currentState = Navigator::IDLE;
00268             translateZ(nav->getMotionFactor());
00269             break;
00270
00271         default:
00272             FNOTICE(("TrackballEngine: buttonPress, unknown button\n"));
00273             break;
00274     }
00275 }
00276
00277 void TrackballEngine::buttonRelease(Int16, Int16 x, Int16 y, Navigator* nav)
00278 {
00279     if (!nav->getMoved() && nav->getClickCenter())
00280     {
00281         Viewport        *vp  = nav->getViewport();
00282         IntersectAction *act = IntersectAction::create();
00283         Line line;
00284         vp->getCamera()->calcViewRay(line, x, y, *vp);
00285
00286         Pnt3f lp1 = line.getPosition();
00287         Vec3f ld1 = line.getDirection();
00288
00289         act->setLine(line);
00290         act->apply(vp->getRoot());
00291         if (act->didHit())
00292         {
00293             Pnt3f p1 = act->getHitPoint();
00294             setAt(p1);
00295         }
00296
00297         delete act;
00298     }
00299     _currentState = Navigator::IDLE;
00300 }
00301
00302 void TrackballEngine::keyPress(Int16 key, Int16 , Int16, Navigator* nav)
00303 {
00304     switch (key)
00305     {
00306         case Navigator::LEFT:
00307             /*undefined*/
00308             break;
00309         case Navigator::RIGHT:
00310             /*undefined*/
00311             break;
00312         case Navigator::FORWARDS:
00313             translateZ(-nav->getMotionFactor());
00314             break;
00315         case Navigator::BACKWARDS:
00316             translateZ(nav->getMotionFactor());
00317             break;
00318         default:
00319             FNOTICE(("TrackballEngine: keyPress, unknown key\n"));
00320     }
00321 }
00322
00323 void TrackballEngine::moveTo(Int16 x, Int16 y, Navigator* nav)
00324 {
00325
00326     Real32 fromX, fromY, toX, toY;
00327     nav->calcFromTo(x, y, fromX, fromY, toX, toY);
00328
00329     switch (_currentState)
00330     {
00331         case Navigator::ROTATING:
00332             rotate(fromX, fromY, toX, toY);
00333             break;
00334
00335         case Navigator::TRANSLATING_XY:
00336         {
00337             Real32 distX = 0.0f;
00338             Real32 distY = 0.0f;
00339             Int16  lastX = nav->getLastX();
00340             Int16  lastY = nav->getLastY();
00341
00342             calcDeltas(lastX, lastY, x, y, distX, distY, nav);
00343             translateXY(distX, distY);
00344         }
00345         break;
00346
00347         case Navigator::TRANSLATING_Z:
00348         {
00349             Real32 distance = osgSgn(toY-fromY) * 100.f;
00350
00351             distance *= osgPow(osgAbs(toY-fromY), 2.f);
00352             translateZ(distance * nav->getMotionFactor());
00353         }
00354         break;
00355
00356         default:
00357             //IDLE
00358             break;
00359     }
00360 }
00361
00362 void TrackballEngine::idle(Int16 buttons, Int16 x, Int16 y, Navigator* nav)
00363 {
00364     // nothing to do
00365 }
00366
00367 /*-------------------- Trackball Transformations --------------------------*/
00368
00372 void TrackballEngine::rotate(Real32 fromX, Real32 fromY, Real32 toX, Real32 toY)
00373 {
00374     Quaternion qCurrVal;
00375
00376     Vec3f  vAxis;
00377     Real32 rPhi;
00378
00379     Vec3f  vP1, vP2, vDiff;
00380
00381     Real32 rTmp;
00382
00383     if(osgAbs(fromX - toX) > Eps || osgAbs(fromY - toY) > Eps)
00384     {
00385         vP1.setValues(fromX, fromY, projectToSphere(_rRadius, fromX, fromY));
00386         vP2.setValues(toX, toY, projectToSphere(_rRadius, toX, toY));
00387
00388         vAxis = vP2;
00389         vAxis.crossThis(vP1);
00390
00391         vDiff  = vP1;
00392         vDiff -= vP2;
00393
00394         rTmp = osgClamp(-1.0f, vDiff.length() / (2.0f * _rRadius), 1.0f);
00395
00396         rPhi = 2.0f * osgASin(rTmp);
00397         qCurrVal.setValueAsAxisRad(vAxis, rPhi);
00398
00399         Matrix temp;
00400         qCurrVal.getValue(temp);
00401
00402         _tMatrix.mult(temp);
00403     }
00404 }
00405
00408 void TrackballEngine::translateXY(Real32 distanceX, Real32 distanceY)
00409 {
00410     Matrix temp;
00411     temp.setIdentity();
00412     temp.setTranslate(distanceX,distanceY,0);
00413     _tMatrix.mult(temp);
00414 }
00415
00419 void TrackballEngine::translateZ(Real32 distance)
00420 {
00421     _rDistance+=distance;
00422     // don't navigate beyond the at point.
00423     //if(_rDistance < 0.0f)
00424     //    _rDistance = 0.0f;
00425 }
00426
00427 /*------------------------- constructors ----------------------------------*/
00428
00429 TrackballEngine::TrackballEngine(Real32 rSize) :
00430     Inherited(),
00431     _rRadius(rSize),
00432     _ip(0,0,0),
00433     _dir(0,0,0)
00434 {
00435     _finalMatrix.setIdentity();
00436     _tMatrix.setIdentity();
00437     _pFrom.setValues(0,0,0);
00438     _pAt  .setValues(0,0,1);
00439     _vUp  .setValues(0,1,0);
00440     _rDistance=(_pAt-_pFrom).length();
00441 }
00442
00443 /*-------------------------- destructors ----------------------------------*/
00444
00445 TrackballEngine::~TrackballEngine()
00446 {
00447 }
00448
00452 void TrackballEngine::updateFinalMatrix()
00453 {
00454     Matrix temp;
00455     _finalMatrix=_tMatrix;
00456     temp.setIdentity();
00457     temp.setTranslate(0,0,_rDistance);
00458
00459     _finalMatrix.mult(temp);
00460 }
00461
00466 Real32 TrackballEngine::projectToSphere(Real32 rRadius, Real32 rX, Real32 rY)
00467 {
00468     Real32 d, t, z;
00469
00470     d = sqrt(rX * rX + rY * rY);
00471
00472     if (d < rRadius * 0.70710678118654752440f)
00473     {    /* Inside sphere */
00474         z = sqrt(rRadius * rRadius - d * d);
00475     }
00476     else
00477     {    /* On hyperbola */
00478         t = rRadius / 1.41421356237309504880f;
00479         z = t * t / d;
00480     }
00481
00482     return z;
00483 }
00484
00485 static void myCalcCCtoWCMatrix(Matrix &cctowc, const Matrix &view,
00486                                Viewport * const port)
00487 {
00488     Matrix proj, projtrans;
00489
00490     port->getCamera()->getProjection( proj, port->getPixelWidth(),
00491                                             port->getPixelHeight());
00492     port->getCamera()->getProjectionTranslation( projtrans,
00493                                                  port->getPixelWidth(),
00494                                                  port->getPixelHeight());
00495
00496     Matrix wctocc = proj;
00497     wctocc.mult( projtrans );
00498     wctocc.mult( view );
00499
00500     cctowc.invertFrom( wctocc );
00501 }
00502
00507 void TrackballEngine::getIntersectionPoint(Int16 x, Int16 y, Navigator* nav)
00508 {
00509     Viewport *vp  = nav->getViewport();
00510     Line line;
00511
00512     vp->getCamera()->calcViewRay(line, x, y, *vp);
00513
00514     if(nav->getClickNoIntersect())
00515     {
00516         Real32 u = (_dir.dot(Pnt3f(0.0f, 0.0f, 0.0f) - line.getPosition())) /
00517                    (_dir.dot(line.getDirection()));
00518         _ip = line.getPosition() + u * line.getDirection();
00519         return;
00520     }
00521
00522     IntersectAction *act = IntersectAction::create();
00523     act->setLine(line);
00524     act->apply(vp->getRoot());
00525
00526     Matrix cctowc,view;
00527     Int16 width  = vp->getPixelWidth();
00528     Int16 height = vp->getPixelHeight();
00529
00530     vp->getCamera()->getViewing(view, width, height);
00531
00532     myCalcCCtoWCMatrix(cctowc, view, vp);
00533
00534     Pnt3f at,to;
00535
00536     cctowc.multFull( Pnt3f( 0, 0, 0.5f ), to );
00537     cctowc.multFull( Pnt3f( 0, 0, 1    ), at );
00538
00539     _dir = to - at;
00540
00541     if (act->didHit())
00542     {
00543         _ip = act->getHitPoint();
00544     }
00545     else
00546     {
00547         Real32 u = (_dir.dot(Pnt3f(0.0f, 0.0f, 0.0f) - line.getPosition())) /
00548                    (_dir.dot(line.getDirection()));
00549         _ip = line.getPosition() + u * line.getDirection();
00550     }
00551
00552     delete act;
00553 }
00554
00559 void TrackballEngine::calcDeltas(Int16 , Int16 , Int16 toX, Int16 toY,
00560                                  Real32 &distanceX, Real32 &distanceY,
00561                                  Navigator* nav)
00562 {
00563     Matrix    view = getMatrix();
00564     Viewport *vp   = nav->getViewport();
00565
00566     Pnt3f from( view[3][0], view[3][1], view[3][2] );
00567
00568     view.invert();
00569     Matrix cctowc;
00570     myCalcCCtoWCMatrix(cctowc, view, vp);
00571
00572     Real32 rx(0.f), ry(0.f);
00573     vp->getNormalizedCoordinates(rx, ry, toX, toY);
00574
00575     Pnt3f at;
00576     cctowc.multFull( Pnt3f( rx, ry, 1 ), at );
00577
00578     Line line2;
00579     line2.setValue(from, at-from);
00580
00581     Real32 u = (_dir.dot(_ip-line2.getPosition())) /
00582                (_dir.dot(line2.getDirection()));
00583
00584     Pnt3f p2 = line2.getPosition() + u * line2.getDirection();
00585
00586     Vec3f transl;
00587     transl[0] = -p2[0] + _ip[0];
00588     transl[1] = -p2[1] + _ip[1];
00589     transl[2] = -p2[2] + _ip[2];
00590
00591     view.mult(transl, transl);
00592
00593     distanceX = transl[0];
00594     distanceY = transl[1];
00595 }