#include #include #include using namespace osg; using namespace osgGA; TrackballManipulator::TrackballManipulator() { _modelScale = 0.01f; _minimumZoomScale = 0.05f; _thrown = false; _distance = 1.0f; } TrackballManipulator::~TrackballManipulator() { } void TrackballManipulator::setNode(osg::Node* node) { _node = node; if (_node.get()) { const osg::BoundingSphere& boundingSphere=_node->getBound(); _modelScale = boundingSphere._radius; } } const osg::Node* TrackballManipulator::getNode() const { return _node.get(); } osg::Node* TrackballManipulator::getNode() { return _node.get(); } /*ea*/ void TrackballManipulator::home(const GUIEventAdapter& ,GUIActionAdapter& us) { if(_node.get()) { const osg::BoundingSphere& boundingSphere=_node->getBound(); computePosition(boundingSphere._center+osg::Vec3( 0.0,-3.5f * boundingSphere._radius,0.0f), boundingSphere._center, osg::Vec3(0.0f,0.0f,1.0f)); us.requestRedraw(); } } void TrackballManipulator::init(const GUIEventAdapter& ,GUIActionAdapter& ) { flushMouseEventStack(); } void TrackballManipulator::getUsage(osg::ApplicationUsage& usage) const { usage.addKeyboardMouseBinding("Trackball: Space","Reset the viewing position to home"); usage.addKeyboardMouseBinding("Trackball: +","When in stereo, increase the fusion distance"); usage.addKeyboardMouseBinding("Trackball: -","When in stereo, reduse the fusion distance"); } bool TrackballManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) { switch(ea.getEventType()) { case(GUIEventAdapter::PUSH): { flushMouseEventStack(); addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); us.requestContinuousUpdate(false); _thrown = false; return true; } case(GUIEventAdapter::RELEASE): { if (ea.getButtonMask()==0) { if (isMouseMoving()) { if (calcMovement()) { us.requestRedraw(); us.requestContinuousUpdate(true); _thrown = true; } } else { flushMouseEventStack(); addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); us.requestContinuousUpdate(false); _thrown = false; } } else { flushMouseEventStack(); addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); us.requestContinuousUpdate(false); _thrown = false; } return true; } case(GUIEventAdapter::DRAG): { addMouseEvent(ea); if (calcMovement()) us.requestRedraw(); us.requestContinuousUpdate(false); _thrown = false; return true; } case(GUIEventAdapter::MOVE): { return false; } case(GUIEventAdapter::KEYDOWN): if (ea.getKey()==' ') { flushMouseEventStack(); _thrown = false; home(ea,us); us.requestRedraw(); us.requestContinuousUpdate(false); return true; } return false; case(GUIEventAdapter::FRAME): if (_thrown) { if (calcMovement()) us.requestRedraw(); return true; } return false; default: return false; } } bool TrackballManipulator::isMouseMoving() { if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; static const float velocity = 0.1f; float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); float len = sqrtf(dx*dx+dy*dy); float dt = _ga_t0->time()-_ga_t1->time(); return (len>dt*velocity); } void TrackballManipulator::flushMouseEventStack() { _ga_t1 = NULL; _ga_t0 = NULL; } void TrackballManipulator::addMouseEvent(const GUIEventAdapter& ea) { _ga_t1 = _ga_t0; _ga_t0 = &ea; } void TrackballManipulator::setByMatrix(const osg::Matrix& matrix) { _center = osg::Vec3(0.0f,0.0f,-_distance)*matrix;//matrix.getTrans(); _rotation.set(matrix); osg::Matrix rotation_matrix; _rotation.get(rotation_matrix); // _center -= osg::Vec3(0.0f,0.0f,_distance)*rotation_matrix; } osg::Matrix TrackballManipulator::getMatrix() const { return osg::Matrix::translate(0.0f,0.0f,_distance)*osg::Matrix::rotate(_rotation)*osg::Matrix::translate(_center); } osg::Matrix TrackballManipulator::getInverseMatrix() const { return osg::Matrix::translate(-_center)*osg::Matrix::rotate(_rotation.inverse())*osg::Matrix::translate(0.0f,0.0f,-_distance); } void TrackballManipulator::computePosition(const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up) { osg::Vec3 lv(center-eye); osg::Vec3 f(lv); f.normalize(); osg::Vec3 s(f^up); s.normalize(); osg::Vec3 u(s^f); u.normalize(); osg::Matrix rotation_matrix(s[0], u[0], -f[0], 0.0f, s[1], u[1], -f[1], 0.0f, s[2], u[2], -f[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); _center = center; _distance = lv.length(); _rotation.set(rotation_matrix); _rotation = _rotation.inverse(); } bool TrackballManipulator::calcMovement() { // return if less then two events have been added. if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); // return if there is no movement. if (dx==0 && dy==0) return false; unsigned int buttonMask = _ga_t1->getButtonMask(); if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) { // rotate camera. osg::Vec3 axis; float angle; float px0 = _ga_t0->getXnormalized(); float py0 = _ga_t0->getYnormalized(); float px1 = _ga_t1->getXnormalized(); float py1 = _ga_t1->getYnormalized(); trackball(axis,angle,px1,py1,px0,py0); osg::Quat new_rotate; new_rotate.makeRotate(angle,axis); _rotation = _rotation*new_rotate; return true; } else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) { // pan model. float scale = -0.5f*_distance; osg::Matrix rotation_matrix; _rotation.get(rotation_matrix); osg::Vec3 dv(dx*scale,dy*scale,0.0f); _center += dv*rotation_matrix; return true; } else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) { // zoom model. float fd = _distance; float scale = 1.0f+dy; if (fd*scale>_modelScale*_minimumZoomScale) { _distance *= scale; } else { // notify(DEBUG_INFO) << "Pushing forward"< 1.0) t = 1.0; if (t < -1.0) t = -1.0; angle = inRadians(asin(t)); } /* * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet * if we are away from the center of the sphere. */ float TrackballManipulator::tb_project_to_sphere(float r, float x, float y) { float d, t, z; d = sqrt(x*x + y*y); /* Inside sphere */ if (d < r * 0.70710678118654752440) { z = sqrt(r*r - d*d); } /* On hyperbola */ else { t = r / 1.41421356237309504880; z = t*t / d; } return z; }