00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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
00054
00055
00120 TrackballEngineTransitPtr
00121 TrackballEngine::create(Real32 rSize)
00122 {
00123 return TrackballEngineTransitPtr(new TrackballEngine(rSize));
00124 }
00125
00126
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
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
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
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
00308 break;
00309 case Navigator::RIGHT:
00310
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
00358 break;
00359 }
00360 }
00361
00362 void TrackballEngine::idle(Int16 buttons, Int16 x, Int16 y, Navigator* nav)
00363 {
00364
00365 }
00366
00367
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
00423
00424
00425 }
00426
00427
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
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 {
00474 z = sqrt(rRadius * rRadius - d * d);
00475 }
00476 else
00477 {
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 }