1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
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"
47 #include "OSGCamera.h"
48 #include "OSGBackground.h"
52 /***************************************************************************\
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.
68 /*! \var Real32 NavballEngine::_rRadius
70 The size of the trackball, relative to the screen size. Per default it is
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
100 /*! \var Pnt3f NavballEngine::_pAt
105 /*! \var Vec3f NavballEngine::_vUp
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)
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)
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)
155 /*! Get the current transformation matrix.
157 const Matrix
&NavballEngine::getMatrix(void)
164 Real32
NavballEngine::getDistance(void)
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
,
199 new_at
+ (new_at
- new_from
),
207 _rDistance
= (_pAt
- _pFrom
).length();
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
)
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
;
247 /*-------------------- navigator engine callbacks ------------------------*/
249 void NavballEngine::buttonPress(Int16 button
,
256 case Navigator::LEFT_MOUSE
:
257 _currentState
= Navigator::ROTATING
;
260 case Navigator::RIGHT_MOUSE
:
261 _currentState
= Navigator::TRANSLATING_Z
;
264 case Navigator::MIDDLE_MOUSE
:
265 _currentState
= Navigator::TRANSLATING_XY
;
266 getIntersectionPoint(x
,y
, nav
);
269 case Navigator::UP_MOUSE
:
270 _currentState
= Navigator::IDLE
;
271 translateZ(-nav
->getMotionFactor());
274 case Navigator::DOWN_MOUSE
:
275 _currentState
= Navigator::IDLE
;
276 translateZ(nav
->getMotionFactor());
280 FNOTICE(("NavballEngine: buttonPress, unknown button\n"));
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();
292 vp->getCamera()->calcViewRay(line, x, y, *vp);
294 Pnt3f lp1 = line.getPosition();
295 Vec3f ld1 = line.getDirection();
298 act->apply(vp->getRoot());
301 Pnt3f p1 = act->getHitPoint();
308 _currentState
= Navigator::IDLE
;
311 void NavballEngine::keyPress(Int16 key
, Int16
, Int16
, Navigator
*nav
)
315 case Navigator::LEFT
:
318 case Navigator::RIGHT
:
321 case Navigator::FORWARDS
:
322 translateZ(-nav
->getMotionFactor());
324 case Navigator::BACKWARDS
:
325 translateZ(nav
->getMotionFactor());
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
);
345 case Navigator::TRANSLATING_XY
:
349 Int16 lastX
= nav
->getLastX();
350 Int16 lastY
= nav
->getLastY();
352 calcDeltas(lastX
, lastY
, x
, y
, distX
, distY
, nav
);
353 translateXY(distX
, distY
);
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());
373 void NavballEngine::idle(Int16 buttons
, Int16 x
, Int16 y
, Navigator
* nav
)
378 /*-------------------- Navball Transformations --------------------------*/
380 /*! Rotate the trackball sphere for a mouse movement from \a fromX, \a fromY to
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
);
393 Vec3f Right
= Forward
.cross(Up
);
395 Quaternion
YRot(_vUp
,(fromX
- toX
)*0.8);
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
))
411 if(osgSgn(XRotAngle
) == osgSgn(CurAngle
) &&
412 osgAbs(CurAngle
) < osgAbs(XRotAngle
))
417 Quaternion
XRot(Right
,XRotAngle
);
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
);
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
)
452 Vec3f
Forward(_pAt
- _pFrom
);
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
) :
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
489 void NavballEngine::updateFinalMatrix()
491 MatrixLookAt(_finalMatrix
, _pFrom
, _pAt
, _vUp
);
494 static void myCalcCCtoWCMatrix( Matrix
& cctowc
,
496 Viewport
* const port
)
498 Matrix proj
, projtrans
;
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
);
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();
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();
539 IntersectActionRefPtr act
= IntersectAction::create();
541 act
->apply(vp
->getRoot());
544 Int16 width
= vp
->calcPixelWidth();
545 Int16 height
= vp
->calcPixelHeight();
547 vp
->getCamera()->getViewing(view
, width
, height
);
549 myCalcCCtoWCMatrix(cctowc
, view
, vp
);
553 cctowc
.multFull( Pnt3f( 0, 0, 0.5f
), to
);
554 cctowc
.multFull( Pnt3f( 0, 0, 1 ), at
);
560 _ip
= act
->getHitPoint();
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();
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
576 void NavballEngine::calcDeltas(Int16
,
584 Matrix view
= getMatrix();
585 Viewport
*vp
= nav
->getViewport();
590 Pnt3f
from( view
[3][0], view
[3][1], view
[3][2] );
594 myCalcCCtoWCMatrix(cctowc
, view
, vp
);
596 Real32
rx(0.f
), ry(0.f
);
597 vp
->calcNormalizedCoordinates(rx
, ry
, toX
, toY
);
600 cctowc
.multFull( Pnt3f( rx
, ry
, 1 ), at
);
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();
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];