osg 自己写地面操作器

来源:互联网 发布:revit软件插件探索者 编辑:程序博客网 时间:2024/04/29 05:05



地面操作器,继承自osg自身的轨迹球操作器(osgGA::OrbitManipulator),参考osgEarth的操作器的实现。
特性:


放大缩小视点始终在指定的地面高度上。(旋转中心点一直在那个高度的平面上)
地面始终与视线平行,即在操作过程中地面上的物体不会歪。
放大到指定的视线距离后,距离不再放大;(即距离地面,实际上是距离视点一定距离后不再升高,改为后退)。
缩小到一定距离后,距离不再缩小;(即距离视点一定距离后不再变小,继续缩放的话,就是前进)。
下面给出类的实现




// 文件名:GroundManipulator.h// 作者:mingjun;日期:2015-11-05// 描述: 地面操作器// //////////////////////////////////////////////////////////////////////////// 历史记录/////////////////////////////////////////////////////////////////////////#ifndef _GROUNDMANIPULATOR_H_#define _GROUNDMANIPULATOR_H_class CGroundManipulator : public osgGA::OrbitManipulator{typedef OrbitManipulator inherited;public:COCSGroundManipulator();virtual ~COCSGroundManipulator(); // 见父类virtual void setCenter( const osg::Vec3d& center );// 见父类virtual void setByMatrix( const osg::Matrixd& matrix );// 见父类virtual void zoomModel( const float dy, bool pushForwardIfNeeded = true );// 见父类virtual bool performMovementLeftMouseButton( const double eventTimeDelta, const double dx, const double dy );// 见父类virtual bool performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy );// 见父类virtual void panModel( const float dx, const float dy, const float dz = 0.f );// 见父类virtual void rotateTrackball( const float px0, const float py0,const float px1, const float py1, const float scale );public:// 地面法向osg::Vec3d GetUpVector() const;void SetUpVector(const osg::Vec3d &vecUp);// 最大距离void SetMaxDistance(double dDistance);double GetMaxDistance() const;private:osg::Vec3d _upVector;// 垂直地面向上的向量    double _maxDistance;// 定义一个最大距离,当超过这个距离,就不在放大了};#endif

类的实现:
里面设置的视点距离地面高度为5000;假定y轴为地面法向设置的。如果你的不是则哪里需要修改一下。



// 文件名:GroundManipulator.cpp// 作者:mingjun;日期:2015-11-05// 描述:// //////////////////////////////////////////////////////////////////////////// 历史记录/////////////////////////////////////////////////////////////////////////#include "StdAfx.h"#include "GroundManipulator.h"COCSGroundManipulator::COCSGroundManipulator():inherited(DEFAULT_SETTINGS){_upVector = osg::Vec3d(0.0, 1.0, 0.0);setVerticalAxisFixed( false );setAllowThrow(false);// 设置其放大缩小方式与cad一样double dOld = getWheelZoomFactor();setWheelZoomFactor(-1.0 * dOld);//  设置当缩放到这个大小后,在缩放的时候,同时移动centersetMinimumDistance( 1000, false );SetMaxDistance(100000.0);}COCSGroundManipulator::~COCSGroundManipulator(){}osg::Vec3d COCSGroundManipulator::GetUpVector() const{return _upVector;}void COCSGroundManipulator::SetUpVector( const osg::Vec3d &vecUp ){_upVector = vecUp;}void COCSGroundManipulator::setByMatrix( const osg::Matrixd& matrix ){_center = osg::Vec3d( 0., 0., -_distance ) * matrix;_center.y() = 5000.0;// 应该让y轴投影到视平面上后,是竖直的 计算上比较麻烦,所以直接给一个osg::Vec3d f = -getUpVector(matrix);//( 1.0, -1.0, 0.0 );//f.normalize();osg::Vec3d s = getSideVector(matrix);//( 0.0, 0.0, 1.0 );osg::Vec3d u(_upVector);//u( 1.0, 1.0, 0.0 );s = f^u;//u.normalize();osg::Matrixd 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 );_rotation = rotation_matrix.getRotate().inverse();}void COCSGroundManipulator::zoomModel( const float dy, bool pushForwardIfNeeded /*= true */ ){// dy 放大为正,缩小为负// scalefloat scale = 1.0f + dy;// minimum distancefloat minDist = _minimumDistance;if( getRelativeFlag( _minimumDistanceFlagIndex ) )minDist *= _modelSize;double dResult = _distance * scale;if( dResult > minDist ){if ( dResult < GetMaxDistance()){_distance = dResult;}else{float scale = -_distance;osg::Matrix rotation_matrix;rotation_matrix.makeRotate( _rotation );osg::Vec3d sideVector = getSideVector(rotation_matrix);osg::Vec3d localUp(0.0f,1.0f,0.0f);osg::Vec3d forwardVector =localUp^sideVector;forwardVector.normalize();osg::Vec3d dv = forwardVector * (dy * scale);_center += dv;}// regular zoom//_distance *= scale;}else{if( pushForwardIfNeeded ){// push the camera forwardfloat scale = -_distance;osg::Matrix rotation_matrix;rotation_matrix.makeRotate( _rotation );osg::Vec3d sideVector = getSideVector(rotation_matrix);osg::Vec3d localUp(0.0f,1.0f,0.0f);osg::Vec3d forwardVector =localUp^sideVector;forwardVector.normalize();osg::Vec3d dv = forwardVector * (dy * scale);_center += dv;}else{// set distance on its minimum value_distance = minDist;}}}void COCSGroundManipulator::panModel( const float dx, const float dy, const float dz ){double scaley = 1;//0.001 * _distance;double scalex = 1;//0.0003 * _distance;osg::Matrix rotation_matrix;rotation_matrix.makeRotate( _rotation );// compute look vector.//osg::Vec3d lookVector = -getUpVector(rotation_matrix);osg::Vec3d sideVector = getSideVector(rotation_matrix);//osg::Vec3d upVector = getFrontVector(rotation_matrix);osg::Vec3d localUp(_upVector);osg::Vec3d forwardVector =localUp^sideVector;sideVector = forwardVector^localUp;forwardVector.normalize();sideVector.normalize();osg::Vec3d dv = forwardVector * (dy*scaley) + sideVector * (dx*scalex);_center += dv;}void COCSGroundManipulator::rotateTrackball( const float px0, const float py0,const float px1, const float py1, const float scale ){double dx = px0 - px1;double dy = py0 - py1;if ( ::fabs(dx) > ::fabs(dy) )dy = 0.0;elsedx = 0.0;osg::Matrix rotation_matrix;rotation_matrix.makeRotate(_rotation);//osg::Vec3d lookVector = -getUpVector(rotation_matrix);osg::Vec3d sideVector = getSideVector(rotation_matrix);//osg::Vec3d upVector = getFrontVector(rotation_matrix);osg::Vec3d localUp(_upVector);osg::Vec3d forwardVector = localUp^sideVector;sideVector = forwardVector^localUp;forwardVector.normalize();sideVector.normalize();osg::Quat rotate_elevation;rotate_elevation.makeRotate(dy,sideVector);osg::Quat rotate_azim;rotate_azim.makeRotate(-dx,localUp);_rotation = _rotation * rotate_elevation * rotate_azim;}bool COCSGroundManipulator::performMovementLeftMouseButton( const double eventTimeDelta,   const double dx, const double dy ){// pan modelfloat scale = -0.3f * _distance * getThrowScale( eventTimeDelta );panModel( dx*scale, dy*scale );return true;}bool COCSGroundManipulator::performMovementMiddleMouseButton( const double eventTimeDelta, const double dx, const double dy ){rotateTrackball( _ga_t0->getXnormalized(), _ga_t0->getYnormalized(),_ga_t1->getXnormalized(), _ga_t1->getYnormalized(),getThrowScale( eventTimeDelta ) );return true;}void COCSGroundManipulator::setCenter( const osg::Vec3d& center ){_center = center;_center.y() = 5000.0;}void COCSGroundManipulator::SetMaxDistance(double dValue){_maxDistance = dValue;}double COCSGroundManipulator::GetMaxDistance() const{return _maxDistance;}


0 0