diff --git a/include/osgGA/TerrainManipulator b/include/osgGA/TerrainManipulator index 756c8c958..6b7b9c636 100644 --- a/include/osgGA/TerrainManipulator +++ b/include/osgGA/TerrainManipulator @@ -27,6 +27,17 @@ class OSGGA_EXPORT TerrainManipulator : public MatrixManipulator virtual const char* className() const { return "Terrain"; } + + enum RotationMode + { + ELEVATION_AZIM_ROLL, + ELEVATION_AZIM, + }; + + void setRotationMode(RotationMode mode); + RotationMode getRotationMode() const { return _rotationMode; } + + /** set the minimum distance (as ratio) the eye point can be zoomed in towards the center before the center is pushed forward.*/ void setMinimumZoomScale(float minimumZoomScale) { _minimumZoomScale=minimumZoomScale; } @@ -34,6 +45,7 @@ class OSGGA_EXPORT TerrainManipulator : public MatrixManipulator /** get the minimum distance (as ratio) the eye point can be zoomed in */ float getMinimumZoomScale() const { return _minimumZoomScale; } + /** set the position of the matrix manipulator using a 4x4 Matrix.*/ virtual void setByMatrix(const osg::Matrixd& matrix); @@ -100,20 +112,26 @@ class OSGGA_EXPORT TerrainManipulator : public MatrixManipulator If speed is below a threshold then return false, otherwise return true.*/ bool isMouseMoving(); + + void clampOrientation(); + + // Internal event stack comprising last three mouse events. osg::ref_ptr _ga_t1; osg::ref_ptr _ga_t0; - osg::ref_ptr _node; + osg::ref_ptr _node; - float _modelScale; - float _minimumZoomScale; + float _modelScale; - bool _thrown; + RotationMode _rotationMode; + float _minimumZoomScale; + + bool _thrown; - osg::CoordinateFrame _coordinateFrame; - osg::Quat _rotation; - float _distance; + osg::CoordinateFrame _coordinateFrame; + osg::Quat _rotation; + float _distance; }; diff --git a/src/osgGA/TerrainManipulator.cpp b/src/osgGA/TerrainManipulator.cpp index 18b33b02d..863f0745a 100644 --- a/src/osgGA/TerrainManipulator.cpp +++ b/src/osgGA/TerrainManipulator.cpp @@ -9,10 +9,13 @@ using namespace osgGA; TerrainManipulator::TerrainManipulator() { _modelScale = 0.01f; + + _rotationMode =ELEVATION_AZIM; _minimumZoomScale = 0.0005f; + _distance = 1.0f; + _thrown = false; - _distance = 1.0f; } @@ -21,6 +24,13 @@ TerrainManipulator::~TerrainManipulator() } +void TerrainManipulator::setRotationMode(RotationMode mode) +{ + _rotationMode = mode; + + // need to correct rotation. +} + void TerrainManipulator::setNode(osg::Node* node) { _node = node; @@ -268,6 +278,8 @@ void TerrainManipulator::setByMatrix(const osg::Matrixd& matrix) } } + + clampOrientation(); } osg::Matrixd TerrainManipulator::getMatrix() const @@ -326,6 +338,8 @@ void TerrainManipulator::computePosition(const osg::Vec3& eye,const osg::Vec3& c rotation_matrix.get(_rotation); _rotation = _rotation.inverse(); + + clampOrientation(); } @@ -345,25 +359,50 @@ bool TerrainManipulator::calcMovement() if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) { - // rotate camera. + if (_rotationMode==ELEVATION_AZIM_ROLL) + { + // rotate camera. + osg::Vec3 axis; + float angle; - osg::Vec3 axis; - float angle; + float px0 = _ga_t0->getXnormalized(); + float py0 = _ga_t0->getYnormalized(); - 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; + } + else + { + osg::Matrix rotation_matrix; + rotation_matrix.set(_rotation); + + osg::Vec3 lookVector = -getUpVector(rotation_matrix); + osg::Vec3 sideVector = getSideVector(rotation_matrix); + osg::Vec3 upVector = getFrontVector(rotation_matrix); + + osg::Vec3 forwardVector =osg::Vec3(0.0f,0.0f,1.0f)^sideVector; + sideVector = forwardVector^osg::Vec3(0.0f,0.0f,1.0f); + + forwardVector.normalize(); + sideVector.normalize(); + + osg::Quat rotate_elevation; + rotate_elevation.makeRotate(dy,sideVector); + + osg::Quat rotate_azim; + rotate_azim.makeRotate(-dx,osg::Vec3(0.0f,0.0f,1.0f)); + + _rotation = _rotation * rotate_elevation * rotate_azim; + } - 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; } @@ -457,6 +496,37 @@ bool TerrainManipulator::calcMovement() return false; } +void TerrainManipulator::clampOrientation() +{ + if (_rotationMode==ELEVATION_AZIM) + { + osg::Matrix rotation_matrix; + rotation_matrix.set(_rotation); + + osg::Vec3 lookVector = -getUpVector(rotation_matrix); + osg::Vec3 upVector = getFrontVector(rotation_matrix); + + osg::Vec3 sideVector = lookVector ^ osg::Vec3(0.0f,0.0f,1.0f); + + if (sideVector.length()<0.1) + { + osg::notify(osg::NOTICE)<<"Side vector short "<