00001 #include <gfx/TrackballManipulator>
00002
00003 #include <osg/Quat>
00004 #include <osg/Notify>
00005
00006 using namespace osg;
00007 using namespace osgGA;
00008
00009 using gfx::TrackballManipulator;
00010
00011
00012 TrackballManipulator::TrackballManipulator()
00013 {
00014 _modelScale = 0.01f;
00015 _minimumZoomScale = 0.05f;
00016 _thrown = false;
00017
00018 _distance = 1.0f;
00019 }
00020
00021
00022 TrackballManipulator::~TrackballManipulator()
00023 {
00024 }
00025
00026
00027 void TrackballManipulator::setNode(osg::Node* node)
00028 {
00029 _node = node;
00030 if (_node.get())
00031 {
00032 const osg::BoundingSphere& boundingSphere=_node->getBound();
00033 _modelScale = boundingSphere._radius;
00034 }
00035 }
00036
00037
00038 const osg::Node* TrackballManipulator::getNode() const
00039 {
00040 return _node.get();
00041 }
00042
00043
00044 osg::Node* TrackballManipulator::getNode()
00045 {
00046 return _node.get();
00047 }
00048
00049
00050
00051 void TrackballManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us)
00052 {
00053 if(_node.get())
00054 {
00055
00056 const osg::BoundingSphere& boundingSphere=_node->getBound();
00057
00058 computePosition(osg::Vec3( 0.0,-3.5f * _modelScale,0.0f),
00059 osg::Vec3(0,0,0),
00060 osg::Vec3(0.0f,0.0f,1.0f));
00061
00062 us.requestRedraw();
00063 }
00064
00065 }
00066
00067
00068 void TrackballManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& )
00069 {
00070 flushMouseEventStack();
00071 }
00072
00073
00074 void TrackballManipulator::getUsage(osg::ApplicationUsage& usage) const
00075 {
00076 usage.addKeyboardMouseBinding("Trackball: Space","Reset the viewing position to home");
00077 usage.addKeyboardMouseBinding("Trackball: +","When in stereo, increase the fusion distance");
00078 usage.addKeyboardMouseBinding("Trackball: -","When in stereo, reduse the fusion distance");
00079 }
00080
00081 bool TrackballManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
00082 {
00083 switch(ea.getEventType())
00084 {
00085 case(GUIEventAdapter::PUSH):
00086 {
00087 flushMouseEventStack();
00088 addMouseEvent(ea);
00089 if (calcMovement()) us.requestRedraw();
00090 us.requestContinuousUpdate(false);
00091 _thrown = false;
00092 return true;
00093 }
00094
00095 case(GUIEventAdapter::RELEASE):
00096 {
00097 if (ea.getButtonMask()==0)
00098 {
00099
00100 if (isMouseMoving())
00101 {
00102 if (calcMovement())
00103 {
00104 us.requestRedraw();
00105 us.requestContinuousUpdate(true);
00106 _thrown = true;
00107 }
00108 }
00109 else
00110 {
00111 flushMouseEventStack();
00112 addMouseEvent(ea);
00113 if (calcMovement()) us.requestRedraw();
00114 us.requestContinuousUpdate(false);
00115 _thrown = false;
00116 }
00117
00118 }
00119 else
00120 {
00121 flushMouseEventStack();
00122 addMouseEvent(ea);
00123 if (calcMovement()) us.requestRedraw();
00124 us.requestContinuousUpdate(false);
00125 _thrown = false;
00126 }
00127 return true;
00128 }
00129
00130 case(GUIEventAdapter::DRAG):
00131 {
00132 addMouseEvent(ea);
00133 if (calcMovement()) us.requestRedraw();
00134 us.requestContinuousUpdate(false);
00135 _thrown = false;
00136 return true;
00137 }
00138
00139 case(GUIEventAdapter::MOVE):
00140 {
00141 return false;
00142 }
00143
00144 case(GUIEventAdapter::KEYDOWN):
00145 if (ea.getKey()==' ')
00146 {
00147 flushMouseEventStack();
00148 _thrown = false;
00149 home(ea,us);
00150 us.requestRedraw();
00151 us.requestContinuousUpdate(false);
00152 return true;
00153 }
00154 return false;
00155 case(GUIEventAdapter::FRAME):
00156 if (_thrown)
00157 {
00158 if (calcMovement()) us.requestRedraw();
00159 return true;
00160 }
00161 return false;
00162 default:
00163 return false;
00164 }
00165 }
00166
00167
00168 bool TrackballManipulator::isMouseMoving()
00169 {
00170 if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
00171
00172 static const float velocity = 0.1f;
00173
00174 float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized();
00175 float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized();
00176 float len = sqrtf(dx*dx+dy*dy);
00177 float dt = _ga_t0->time()-_ga_t1->time();
00178
00179 return (len>dt*velocity);
00180 }
00181
00182
00183 void TrackballManipulator::flushMouseEventStack()
00184 {
00185 _ga_t1 = NULL;
00186 _ga_t0 = NULL;
00187 }
00188
00189
00190 void TrackballManipulator::addMouseEvent(const GUIEventAdapter& ea)
00191 {
00192 _ga_t1 = _ga_t0;
00193 _ga_t0 = &ea;
00194 }
00195
00196 void TrackballManipulator::setByMatrix(const osg::Matrixd& matrix)
00197 {
00198 _center = osg::Vec3(0.0f,0.0f,-_distance)*matrix;
00199 matrix.get(_rotation);
00200 }
00201
00202 osg::Matrixd TrackballManipulator::getMatrix() const
00203 {
00204 return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_center);
00205 }
00206
00207 osg::Matrixd TrackballManipulator::getInverseMatrix() const
00208 {
00209 return osg::Matrixd::translate(-_center)*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance);
00210 }
00211
00212 void TrackballManipulator::computePosition(const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up)
00213 {
00214 osg::Vec3 e(eye);
00215 if (e.z() < 0) e.z() = 0;
00216
00217 osg::Vec3 lv(center-e);
00218
00219 osg::Vec3 f(lv);
00220 f.normalize();
00221 osg::Vec3 s(f^up);
00222 s.normalize();
00223 osg::Vec3 u(s^f);
00224 u.normalize();
00225
00226 osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0f,
00227 s[1], u[1], -f[1], 0.0f,
00228 s[2], u[2], -f[2], 0.0f,
00229 0.0f, 0.0f, 0.0f, 1.0f);
00230
00231 _center = center;
00232 _distance = lv.length();
00233 rotation_matrix.get(_rotation);
00234 _rotation = _rotation.inverse();
00235 }
00236
00237
00238 bool TrackballManipulator::calcMovement()
00239 {
00240
00241
00242 if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
00243
00244 float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized();
00245 float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized();
00246
00247
00248
00249 if (dx==0 && dy==0) return false;
00250
00251 unsigned int buttonMask = _ga_t1->getButtonMask();
00252 if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
00253 {
00254
00255
00256
00257 osg::Vec3 axis;
00258 float angle;
00259
00260 float px0 = _ga_t0->getXnormalized();
00261 float py0 = _ga_t0->getYnormalized();
00262
00263 float px1 = _ga_t1->getXnormalized();
00264 float py1 = _ga_t1->getYnormalized();
00265
00266
00267 trackball(axis,angle,px1,py1,px0,py0);
00268
00269 osg::Quat new_rotate;
00270 new_rotate.makeRotate(angle,axis);
00271
00272 _rotation = _rotation*new_rotate;
00273
00274 return true;
00275
00276 }
00277 else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
00278 buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
00279 {
00280
00281
00282
00283 float scale = -0.5f*_distance;
00284
00285 osg::Matrix rotation_matrix;
00286 rotation_matrix.set(_rotation);
00287
00288 osg::Vec3 dv(dx*scale,dy*scale,0.0f);
00289
00290 _center += dv*rotation_matrix;
00291
00292 return true;
00293
00294 }
00295 else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
00296 {
00297
00298
00299
00300 float fd = _distance;
00301 float scale = 1.0f+dy;
00302 if (fd*scale>_modelScale*_minimumZoomScale)
00303 {
00304
00305 _distance *= scale;
00306
00307 }
00308 else
00309 {
00310
00311
00312
00313 float scale = -fd;
00314
00315 osg::Matrix rotation_matrix(_rotation);
00316
00317 osg::Vec3 dv = (osg::Vec3(0.0f,0.0f,-1.0f)*rotation_matrix)*(dy*scale);
00318
00319 _center += dv;
00320
00321 }
00322
00323 return true;
00324
00325 }
00326
00327 return false;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 const float TRACKBALLSIZE = 0.8f;
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 void TrackballManipulator::trackball(osg::Vec3& axis,float& angle, float p1x, float p1y, float p2x, float p2y)
00353 {
00354
00355
00356
00357
00358
00359 osg::Matrix rotation_matrix(_rotation);
00360
00361
00362 osg::Vec3 uv = osg::Vec3(0.0f,1.0f,0.0f)*rotation_matrix;
00363 osg::Vec3 sv = osg::Vec3(1.0f,0.0f,0.0f)*rotation_matrix;
00364 osg::Vec3 lv = osg::Vec3(0.0f,0.0f,-1.0f)*rotation_matrix;
00365
00366 osg::Vec3 p1 = sv*p1x+uv*p1y-lv*tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y);
00367 osg::Vec3 p2 = sv*p2x+uv*p2y-lv*tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y);
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379 axis = p2^p1;
00380 axis.normalize();
00381
00382
00383
00384
00385 float t = (p2-p1).length() / (2.0*TRACKBALLSIZE);
00386
00387
00388
00389
00390 if (t > 1.0) t = 1.0;
00391 if (t < -1.0) t = -1.0;
00392 angle = inRadians(asin(t));
00393
00394 }
00395
00396
00397
00398
00399
00400
00401 float TrackballManipulator::tb_project_to_sphere(float r, float x, float y)
00402 {
00403 float d, t, z;
00404
00405 d = sqrt(x*x + y*y);
00406
00407 if (d < r * 0.70710678118654752440)
00408 {
00409 z = sqrt(r*r - d*d);
00410 }
00411 else
00412 {
00413 t = r / 1.41421356237309504880;
00414 z = t*t / d;
00415 }
00416 return z;
00417 }