added: helper to put chunk override groups in OSG files
[opensg.git] / Source / System / Window / Utilities / OSGNavballEngine.cpp
blobca69c41cdfa8e6ef6ac01e0de4509e5fd3052fef
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 #include "OSGConfig.h"
40 #include "OSGBaseTypes.h"
41 #include "OSGMatrix.h"
42 #include "OSGMatrixUtility.h"
44 #include "OSGNavballEngine.h"
45 #include "OSGNavigator.h"
46 #include "OSGNode.h"
47 #include "OSGCamera.h"
48 #include "OSGBackground.h"
50 OSG_USING_NAMESPACE
52 /***************************************************************************\
53 * Description *
54 \***************************************************************************/
56 /*! \class OSG::NavballEngine
57 \ingroup GrpSystemWindowNavigators
59 The NavballEngine models a navigation model based on a rotating sphere,
60 see \ref PageSystemWindowNavigatorsNavball for a description.
62 \dev
64 \enddev
68 /*! \var Real32 NavballEngine::_rRadius
70 The size of the trackball, relative to the screen size. Per default it is
71 0.8.
74 /*! \var Real32 NavballEngine::_rDistance
76 The distance of the viewer from the target point.
79 /*! \var Matrix NavballEngine::_tMatrix
81 Temporary matrix for calculation.
84 /*! \var Matrix NavballEngine::_finalMatrix
86 The resulting matrix for the final transformation.
89 /*! \var State NavballEngine::_currentState
91 The current state of the trackball, whether it is currently rotating,
92 translating in xy or in z.
95 /*! \var Pnt3f NavballEngine::_pFrom
97 The viewer position.
100 /*! \var Pnt3f NavballEngine::_pAt
102 The target position.
105 /*! \var Vec3f NavballEngine::_vUp
107 The Up direction.
110 /*! \var Navigator::_ip
112 Temporary hit point for intersection testing.
115 /*! \var Navigator::_dir
117 Temporary ray direction for intersection testing.
120 NavballEngineTransitPtr NavballEngine::create(Real32 rSize)
122 return NavballEngineTransitPtr(new NavballEngine(rSize));
125 /*------------------------------ get --------------------------------------*/
128 /*! Get the viewer position.
129 The final matrix needs to be valid for this to work, if in doubt, call
130 updateFinalMatrix() beforehand.
132 const Pnt3f &NavballEngine::getFrom(void)
134 return _pFrom;
137 /*! Get the target position.
138 The final matrix needs to be valid for this to work, if in doubt, call
139 updateFinalMatrix() beforehand.
141 const Pnt3f &NavballEngine::getAt(void)
143 return _pAt;
146 /*! Get the up direction.
147 The final matrix needs to be valid for this to work, if in doubt, call
148 updateFinalMatrix() beforehand.
150 const Vec3f &NavballEngine::getUp(void)
152 return _vUp;
155 /*! Get the current transformation matrix.
157 const Matrix &NavballEngine::getMatrix(void)
159 updateFinalMatrix();
161 return _finalMatrix;
164 Real32 NavballEngine::getDistance(void)
166 return _rDistance;
169 /*------------------------------ set --------------------------------------*/
171 /*! Sets the from point, i.e. the viewer position.
173 void NavballEngine::setFrom(Pnt3f new_from)
175 set(new_from, getAt(), getUp());
178 /*! Sets the at point, the target point and center of the window.
180 void NavballEngine::setAt(Pnt3f new_at)
182 set(getFrom(), new_at, getUp());
185 /*! Sets the up vector.
187 void NavballEngine::setUp(Vec3f new_up)
189 set(getFrom(), getAt(), new_up);
192 /*! Set all viewer parameters of the navigator separately.
194 void NavballEngine::set(Pnt3f new_from, Pnt3f new_at, Vec3f new_up)
196 bool b = MatrixLookAt(_finalMatrix,
198 new_at,
199 new_at + (new_at - new_from),
200 new_up );
201 if(!b)
203 _pFrom = new_from;
204 _pAt = new_at;
205 _vUp = new_up;
207 _rDistance = (_pAt - _pFrom).length();
209 updateFinalMatrix();
211 else
213 FNOTICE(("NavballEngine: set(.,.,.), failed"));
217 /*! Set all viewer parameters of the navigator with a single matrix.
219 \note The matrix does not contain all information needed for
220 the NavballNavigator, it is therefore preferable to use
221 NavballNavigator::set(Pnt3f,Pnt3f,Vec3f) to set the values, especially
222 when copying from one NavballNavigator to another one.
224 void NavballEngine::set(const Matrix &new_matrix)
226 // get distance
227 Vec3f translation( new_matrix[3][0], new_matrix[3][1], new_matrix[3][2]);
229 _rDistance = translation.length();
231 _pFrom = Pnt3f(new_matrix[3]);
232 _pAt = Pnt3f(new_matrix[3] - (_rDistance * new_matrix[2]));
233 _vUp = Vec3f(new_matrix[1]);
234 _vUp = Vec3f(0.0f, 1.0f, 0.0f);
237 /*! Sets the distance from the target point in the view direction.
239 void NavballEngine::setDistance(Real32 new_distance)
241 _rDistance = new_distance;
243 updateFinalMatrix();
247 /*-------------------- navigator engine callbacks ------------------------*/
249 void NavballEngine::buttonPress(Int16 button,
250 Int16 x,
251 Int16 y,
252 Navigator *nav )
254 switch (button)
256 case Navigator::LEFT_MOUSE :
257 _currentState = Navigator::ROTATING;
258 break;
260 case Navigator::RIGHT_MOUSE :
261 _currentState = Navigator::TRANSLATING_Z;
262 break;
264 case Navigator::MIDDLE_MOUSE:
265 _currentState = Navigator::TRANSLATING_XY;
266 getIntersectionPoint(x,y, nav);
267 break;
269 case Navigator::UP_MOUSE :
270 _currentState = Navigator::IDLE;
271 translateZ(-nav->getMotionFactor());
272 break;
274 case Navigator::DOWN_MOUSE :
275 _currentState = Navigator::IDLE;
276 translateZ(nav->getMotionFactor());
277 break;
279 default:
280 FNOTICE(("NavballEngine: buttonPress, unknown button\n"));
281 break;
285 void NavballEngine::buttonRelease(Int16, Int16 x, Int16 y, Navigator* nav)
287 /* if (!nav->getMoved() && nav->getClickCenter())
289 Viewport *vp = nav->getViewport();
290 IntersectAction *act = IntersectAction::create();
291 Line line;
292 vp->getCamera()->calcViewRay(line, x, y, *vp);
294 Pnt3f lp1 = line.getPosition();
295 Vec3f ld1 = line.getDirection();
297 act->setLine(line);
298 act->apply(vp->getRoot());
299 if (act->didHit())
301 Pnt3f p1 = act->getHitPoint();
302 setAt(p1);
305 delete act;
308 _currentState = Navigator::IDLE;
311 void NavballEngine::keyPress(Int16 key, Int16 , Int16, Navigator *nav)
313 switch (key)
315 case Navigator::LEFT:
316 /*undefined*/
317 break;
318 case Navigator::RIGHT:
319 /*undefined*/
320 break;
321 case Navigator::FORWARDS:
322 translateZ(-nav->getMotionFactor());
323 break;
324 case Navigator::BACKWARDS:
325 translateZ(nav->getMotionFactor());
326 break;
327 default:
328 FNOTICE(("NavballEngine: keyPress, unknown key\n"));
332 void NavballEngine::moveTo(Int16 x, Int16 y, Navigator* nav)
335 Real32 fromX, fromY, toX, toY;
337 nav->calcFromTo(x, y, fromX, fromY, toX, toY);
339 switch (_currentState)
341 case Navigator::ROTATING:
342 rotate(fromX, fromY, toX, toY);
343 break;
345 case Navigator::TRANSLATING_XY:
347 Real32 distX = 0.0f;
348 Real32 distY = 0.0f;
349 Int16 lastX = nav->getLastX();
350 Int16 lastY = nav->getLastY();
352 calcDeltas(lastX, lastY, x, y, distX, distY, nav);
353 translateXY(distX, distY);
355 break;
357 case Navigator::TRANSLATING_Z:
359 Real32 distance = osgSgn(toY-fromY) * 100.f;
361 distance *= osgPow(osgAbs(toY-fromY), 2.f);
363 translateZ(distance * nav->getMotionFactor());
365 break;
367 default:
368 //IDLE
369 break;
373 void NavballEngine::idle(Int16 buttons, Int16 x, Int16 y, Navigator* nav)
375 // nothing to do
378 /*-------------------- Navball Transformations --------------------------*/
380 /*! Rotate the trackball sphere for a mouse movement from \a fromX, \a fromY to
381 \a toX, \a toY.
383 void NavballEngine::rotate(Real32 fromX, Real32 fromY, Real32 toX, Real32 toY)
385 if(osgAbs(fromX - toX) > TypeTraits<Real32>::getDefaultEps() ||
386 osgAbs(fromY - toY) > TypeTraits<Real32>::getDefaultEps() )
389 Vec3f Up(0.0f,1.0f,0.0f);
390 Vec3f Forward(_pAt - _pFrom);
391 Forward.normalize();
392 //Up.normalize();
393 Vec3f Right = Forward.cross(Up);
395 Quaternion YRot(_vUp,(fromX - toX)*0.8);
396 Matrix YRotMat;
397 YRot.getValue(YRotMat);
399 Real32 XRotAngle((fromY - toY)*-0.5);
400 Real32 CurAngle(osgACos(Forward.dot(Up)));
401 if(CurAngle > 1.5707f)
403 if(osgSgn(XRotAngle) != osgSgn(CurAngle) &&
404 osgAbs(3.141592f - CurAngle) < osgAbs(XRotAngle))
406 XRotAngle = 0.0f;
409 else
411 if(osgSgn(XRotAngle) == osgSgn(CurAngle) &&
412 osgAbs(CurAngle) < osgAbs(XRotAngle))
414 XRotAngle = 0.0f;
417 Quaternion XRot(Right,XRotAngle);
418 Matrix XRotMat;
419 XRot.getValue(XRotMat);
421 Pnt3f PrevFrom(_pFrom);
422 Vec3f PrevForward(Forward);
423 _pFrom -= _pAt.subZero();
424 XRotMat.mult(_pFrom,_pFrom);
425 YRotMat.mult(_pFrom,_pFrom);
426 _pFrom += _pAt.subZero();
430 /*! Translate in the XY plane.
432 void NavballEngine::translateXY(Real32 distanceX, Real32 distanceY)
434 Vec3f Up(0.0f,1.0f,0.0f);
435 Vec3f Forward(_pAt - _pFrom);
436 Forward.normalize();
437 //Up.normalize();
438 Vec3f Right = Forward.cross(Up);
439 Up = Right.cross(Forward);
441 Vec3f Displacement(Right*distanceX + Up*distanceY);
442 _pFrom += Displacement;
443 _pAt += Displacement;
446 /*! Translate along the Z-axis.
449 void NavballEngine::translateZ(Real32 distance)
451 Vec3f Up(_vUp);
452 Vec3f Forward(_pAt - _pFrom);
453 Forward.normalize();
455 Vec3f Displacement(Forward*distance);
456 _pFrom += Displacement;
458 if(_pFrom.dist2(_pAt) < distance*distance)
460 _pAt += Displacement;
464 /*------------------------- constructors ----------------------------------*/
466 NavballEngine::NavballEngine(Real32 rSize) :
467 Inherited( ),
468 _ip (0, 0, 0),
469 _dir (0, 0, 0)
471 _finalMatrix.setIdentity();
473 _pFrom.setValues(0, 0, 0);
474 _pAt .setValues(0, 0, 1);
475 _vUp .setValues(0, 1, 0);
477 _rDistance=(_pAt - _pFrom).length();
480 /*-------------------------- destructors ----------------------------------*/
482 NavballEngine::~NavballEngine()
486 /*! Calculate the final matrix, the matrix that reflects the actual state of
487 the NavballEngine.
489 void NavballEngine::updateFinalMatrix()
491 MatrixLookAt(_finalMatrix, _pFrom, _pAt, _vUp);
494 static void myCalcCCtoWCMatrix( Matrix & cctowc,
495 const Matrix & view,
496 Viewport * const port )
498 Matrix proj, projtrans;
500 if(port == NULL)
501 return;
503 port->getCamera()->getProjection( proj, port->calcPixelWidth(),
504 port->calcPixelHeight());
506 port->getCamera()->getProjectionTranslation( projtrans,
507 port->calcPixelWidth(),
508 port->calcPixelHeight());
510 Matrix wctocc = proj;
511 wctocc.mult( projtrans );
512 wctocc.mult( view );
514 cctowc.invertFrom( wctocc );
517 /*! Calculates the intersection point of a ray that starts at from and goes
518 through the position on the screen given by x,y with the world, if no
519 intersection point exists the intersection is set to (0,0,0)
521 void NavballEngine::getIntersectionPoint(Int16 x, Int16 y, Navigator *nav)
523 Viewport *vp = nav->getViewport();
524 Line line;
526 if(vp == NULL)
527 return;
529 vp->getCamera()->calcViewRay(line, x, y, *vp);
531 if(nav->getClickNoIntersect())
533 Real32 u = (_dir.dot(Pnt3f(0.0f, 0.0f, 0.0f) - line.getPosition())) /
534 (_dir.dot(line.getDirection()));
535 _ip = line.getPosition() + u * line.getDirection();
536 return;
539 IntersectActionRefPtr act = IntersectAction::create();
540 act->setLine(line);
541 act->apply(vp->getRoot());
543 Matrix cctowc,view;
544 Int16 width = vp->calcPixelWidth();
545 Int16 height = vp->calcPixelHeight();
547 vp->getCamera()->getViewing(view, width, height);
549 myCalcCCtoWCMatrix(cctowc, view, vp);
551 Pnt3f at,to;
553 cctowc.multFull( Pnt3f( 0, 0, 0.5f ), to );
554 cctowc.multFull( Pnt3f( 0, 0, 1 ), at );
556 _dir = to - at;
558 if (act->didHit())
560 _ip = act->getHitPoint();
562 else
564 Real32 u = (_dir.dot(Pnt3f(0.0f, 0.0f, 0.0f) - line.getPosition())) /
565 (_dir.dot(line.getDirection()));
566 _ip = line.getPosition() + u * line.getDirection();
569 act = NULL;
572 /*! Calculate the real translation that has to be done, so that the
573 trackball can actually drag the object in the plane parallel to the
574 screen.
576 void NavballEngine::calcDeltas(Int16,
577 Int16,
578 Int16 toX,
579 Int16 toY,
580 Real32 &distanceX,
581 Real32 &distanceY,
582 Navigator *nav)
584 Matrix view = getMatrix();
585 Viewport *vp = nav->getViewport();
587 if(vp == NULL)
588 return;
590 Pnt3f from( view[3][0], view[3][1], view[3][2] );
592 view.invert();
593 Matrix cctowc;
594 myCalcCCtoWCMatrix(cctowc, view, vp);
596 Real32 rx(0.f), ry(0.f);
597 vp->calcNormalizedCoordinates(rx, ry, toX, toY);
599 Pnt3f at;
600 cctowc.multFull( Pnt3f( rx, ry, 1 ), at );
602 Line line2;
603 line2.setValue(from, at-from);
605 Real32 u = (_dir.dot(_ip-line2.getPosition())) /
606 (_dir.dot(line2.getDirection()));
608 Pnt3f p2 = line2.getPosition() + u * line2.getDirection();
610 Vec3f transl;
611 transl[0] = -p2[0] + _ip[0];
612 transl[1] = -p2[1] + _ip[1];
613 transl[2] = -p2[2] + _ip[2];
615 view.mult(transl, transl);
617 distanceX = transl[0];
618 distanceY = transl[1];