本示例主要演示osgEarth的事件处理的用法,内容比较多,这部分功能也很重要。
输入命令依然采用china-simple.earth的示例,加上了模型,但是模型并没有看到,可能是因为模型没有放大太小的原因。在代码中设置了不加载模型的话,会绘制两个半圆。
// 加载模型,但是看不到,估计是模型太小,需要放大
osgearth_manipd.exe earth_image/china-simple.earth --model axes.osgt
// 并没有加载模型
osgearth_manipd.exe earth_image/china-simple.earth --model modelToLoad
// 不加载模型,会默认创建一个半球,距离太远的话,半球也看不到
osgearth_manipd.exe earth_image/china-simple.earth
按下W键,开启坐标,也就是黄色的两条线,交点始终跟随 Thing 1 节点。
* | 左键 | 按住左键拖动地球 | * | u | 看不出来,没啥变化 |
* | 中键 | 按住中键可以旋转地球 | * | o | 切换操作器,地球会有大小变化 |
* | 右键 | 按住右键前后移动,缩放地球 | * | 8 | 视角绑定thing 1,也可以说跟踪 |
* | 右键/左键 双击 |
越来越远/越来越近 | * | 9 | 视角绑定thing 2,也可以说跟踪 |
* | 滚轮滚动 | 视角远近控制 | * | t | 地球三种转动状态的切换 |
* | arrows | shift+上/下/左/右键, 好像没啥作用 |
* | b | 解除绑定 '8' ‘9’,,或者说解除跟踪 |
* | shift+左键 | 看不出来,没啥变化 | * | a | 看不出来,没啥变化 |
* | q | 看不出来,没啥变化 | |||
* | k | 看不出来,没啥变化 | |||
* | L | 看不出来,没啥变化 | |||
* | j | 定位到可以看见一组点的视点 | |||
* | W | 绘制两条线,交点始终定位在thing 1上,屏幕坐标系 |
[注] 必须在英文下输入,如果没有注意,在中文状态下输入字符,地球会被卡住。此时只能退出重新运行程序。
thing1 thing 2,这两个文本是移动的。
#include <string>
#include <osg/Notify>
#include <osg/Timer>
#include <osg/ShapeDrawable>
#include <osg/Depth>
#include <osg/PositionAttitudeTransform>
#include <osgGA/StateSetManipulator>
#include <osgGA/GUIEventHandler>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgEarth/GeoMath>
#include <osgEarth/GeoTransform>
#include <osgEarth/MapNode>
#include <osgEarth/TerrainEngineNode>
#include <osgEarth/Viewpoint>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/Controls>
#include <osgEarthUtil/ExampleResources>
#include <osgEarthUtil/LogarithmicDepthBuffer>
#include <osgEarthUtil/ViewFitter>
#include <osgEarthAnnotation/AnnotationUtils>
#include <osgEarthAnnotation/LabelNode>
#include <osgEarthSymbology/Style>
#include <osgEarth/ScreenSpaceLayout>
using namespace osgEarth::Util;
using namespace osgEarth::Util::Controls;
using namespace osgEarth::Annotation;
#define D2R (osg::PI/180.0)
#define R2D (180.0/osg::PI)
namespace
{
/**
* Tether callback test.是否绑定
*/
struct TetherCB : public EarthManipulator::TetherCallback
{
void operator()(osg::Node* node)
{
if ( node ) {
OE_WARN << "Tether on\n";
}
else {
OE_WARN << "Tether off\n";
}
}
};
/**
* Builds our help menu UI.创建左上角的说明文档
*/
Container* createHelp( osgViewer::View* view )
{
const char* text[] =
{
"left mouse :", "pan",
"middle mouse :", "rotate",
"right mouse :", "continuous zoom",
"double-click :", "zoom to point",
"scroll wheel :", "zoom in/out",
"arrows :", "pan",
//"1-6 :", "fly to preset viewpoints",
"shift-left-mouse :", "locked pan",
"u :", "toggle azimuth lock",
"o :", "toggle perspective/ortho",
"8 :", "Tether to thing 1",
"9 :", "Tether to thing 2",
"t :", "cycle tethermode",
"b :", "break tether",
"a :", "toggle viewpoint arcing",
"q :", "toggle throwing",
"k :", "toggle collision",
"L :", "toggle log depth buffer"
//"W :", "坐标系", // 源代码并没有这两个提示
//"j :", "定位到指定点组的视点",
};
Grid* g = new Grid();// 创建网格
unsigned i, c, r;
std::cout << sizeof(text) << std::endl; // 存储所有指针占位多少
std::cout << sizeof(text[0]) << std::endl; // 每个指针占位多少
for( i=0; i<sizeof(text)/sizeof(text[0]); ++i )
{
c = i % 2;
r = i / 2;
g->setControl( c, r, new LabelControl(text[i]) );// 两列c,i行r,显示label控件
}
VBox* v = new VBox();
v->addControl( g );// 将网格控件放入VBox控件中
return v;
}
/**
* Some preset viewpoints to show off the setViewpoint function.
*/
static Viewpoint VPs[] = {
Viewpoint( "Africa", 0.0, 0.0, 0.0, 0.0, -90.0, 10e6 ),
Viewpoint( "California", -121.0, 34.0, 0.0, 0.0, -90.0, 6e6 ),
Viewpoint( "Europe", 0.0, 45.0, 0.0, 0.0, -90.0, 4e6 ),
Viewpoint( "Washington DC", -77.0, 38.0, 0.0, 0.0, -90.0, 1e6 ),
Viewpoint( "Australia", 135.0, -20.0, 0.0, 0.0, -90.0, 2e6 ),
Viewpoint( "Boston", -71.096936, 42.332771, 0, 0.0, -90, 1e5 )
};
/**
* Handler that demonstrates the "viewpoint" functionality in
* osgEarthUtil::EarthManipulator. Press a number key to fly to a viewpoint.
*/
struct FlyToViewpointHandler : public osgGA::GUIEventHandler
{
FlyToViewpointHandler( EarthManipulator* manip ) : _manip(manip) { }
bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
{
if ( ea.getEventType() == ea.KEYDOWN && ea.getKey() >= '1' && ea.getKey() <= '6' )
{
_manip->setViewpoint( VPs[ea.getKey()-'1'], 4.0 );// 根据设置好的位置,123456定位不同的地点
aa.requestRedraw();
}
return false;
}
osg::observer_ptr<EarthManipulator> _manip;
};
/**
* Toggles the logarithmic depth buffer切换对数深度缓冲区
*/
struct ToggleLDB : public osgGA::GUIEventHandler
{
ToggleLDB(char key) : _key(key), _installed(false) { }// key=L
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
if ( !_installed )
{
_nfratio = aa.asView()->getCamera()->getNearFarRatio();// 获取到近/远率
_ldb.install(aa.asView()->getCamera());
aa.asView()->getCamera()->setNearFarRatio(0.00001);
}
else
{
_ldb.uninstall(aa.asView()->getCamera());
aa.asView()->getCamera()->setNearFarRatio(_nfratio);
}
_installed = !_installed;// 每次切换
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Toggle LDB"));
}
char _key;
float _nfratio;
bool _installed;
osgEarth::Util::LogarithmicDepthBuffer _ldb;
};
/**
* Toggles screen space layout on the sismulated objects 切换模拟对象的屏幕空间布局
*/
struct ToggleSSL : public osgGA::GUIEventHandler
{
ToggleSSL(osg::Group* g, char key) : _group(g), _key(key), _installed(false) { }// key=)
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
_installed = !_installed;
ScreenSpaceLayout::setDeclutteringEnabled(_installed);// 启动或禁用清理
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Toggle SSL"));
}
char _key;
osg::Group* _group;
bool _installed;
};
/**
* Handler to toggle "azimuth locking", which locks the camera's relative Azimuth
* while panning. For example, it can maintain "north-up" as you pan around. The
* caveat is that when azimuth is locked you cannot cross the poles.
*/
struct LockAzimuthHandler : public osgGA::GUIEventHandler // 锁定/解锁 方位角
{
LockAzimuthHandler(char key, EarthManipulator* manip) // 传入key = u
: _key(key), _manip(manip) { }
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
bool lockAzimuth = _manip->getSettings()->getLockAzimuthWhilePanning();
std::cout << "按下 u" << std::endl;// 确实收到消息,但是在操作上并没有看到所定方位角
_manip->getSettings()->setLockAzimuthWhilePanning(!lockAzimuth);// 设置为当前状态相反的状态
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Toggle azimuth locking"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* Handler to toggle "viewpoint transition arcing", which causes the camera to "arc"
* as it travels from one viewpoint to another.
*/
struct ToggleArcViewpointTransitionsHandler : public osgGA::GUIEventHandler
{
ToggleArcViewpointTransitionsHandler(char key, EarthManipulator* manip)
: _key(key), _manip(manip) { }// key=a
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
bool arc = _manip->getSettings()->getArcViewpointTransitions();
std::cout << "按下 a" << std::endl;// 确实收到消息,但是没看出什么变化
_manip->getSettings()->setArcViewpointTransitions(!arc);
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Arc viewpoint transitions"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* Toggles the throwing feature.切换投掷功能。
*/
struct ToggleThrowingHandler : public osgGA::GUIEventHandler
{
ToggleThrowingHandler(char key, EarthManipulator* manip)
: _key(key), _manip(manip)// key=q
{
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
bool throwing = _manip->getSettings()->getThrowingEnabled();
std::cout << "按下 q" << std::endl;// 确实收到消息,但是没看出什么变化
_manip->getSettings()->setThrowingEnabled( !throwing );
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Toggle throwing"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* Toggles the collision feature.切换碰撞功能。
*/
struct ToggleCollisionHandler : public osgGA::GUIEventHandler
{
ToggleCollisionHandler(char key, EarthManipulator* manip)
: _key(key), _manip(manip)// key=k
{
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
bool value = _manip->getSettings()->getTerrainAvoidanceEnabled();
std::cout << "按下 k" << std::endl;// 确实收到消息,但是没看出什么变化
_manip->getSettings()->setTerrainAvoidanceEnabled( !value );
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Toggle terrain avoidance"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* Breaks a tether.三种状态的切换
*/
struct CycleTetherMode : public osgGA::GUIEventHandler
{
CycleTetherMode(char key, EarthManipulator* manip)
: _key(key), _manip(manip) { }// key=t
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
EarthManipulator::TetherMode mode = _manip->getSettings()->getTetherMode();
if ( mode == _manip->TETHER_CENTER ) {
_manip->getSettings()->setTetherMode( _manip->TETHER_CENTER_AND_HEADING );// 相机将跟随节点,仅跟随方向旋转
OE_NOTICE << "Tether mode = TETHER_CENTER_AND_HEADING\n";
}
else if ( mode == _manip->TETHER_CENTER_AND_HEADING ) {
_manip->getSettings()->setTetherMode( _manip->TETHER_CENTER_AND_ROTATION ); // 摄影机将跟随节点和节点所做的所有旋转
OE_NOTICE << "Tether mode = TETHER_CENTER_AND_ROTATION\n";
}
else {
_manip->getSettings()->setTetherMode( _manip->TETHER_CENTER );// 摄影机将跟随节点的中心。
OE_NOTICE << "Tether mode = CENTER\n";
}
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Cycle Tether Mode"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* Breaks a tether.解绑
*/
struct BreakTetherHandler : public osgGA::GUIEventHandler
{
BreakTetherHandler(char key, EarthManipulator* manip)
: _key(key), _manip(manip) { }//key=b
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
_manip->clearViewpoint();// 解除所有操作器绑定,恢复自由状态。thing1和 thing2 的状态改变明显
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Break a tether"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* Adjusts the position offset.调整位置偏移。
*/
struct SetPositionOffset : public osgGA::GUIEventHandler
{
SetPositionOffset(EarthManipulator* manip)
: _manip(manip) { }
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && (ea.getModKeyMask() & ea.MODKEY_SHIFT) )
{
Viewpoint oldvp = _manip->getViewpoint();
double seconds = 0.5; // 时间秒。每次切换都需要0.5秒
if ( ea.getKey() == ea.KEY_Left )// 左键
{
Viewpoint vp;
vp.positionOffset() = oldvp.positionOffset().get() + osg::Vec3f(-1000,0,0);
_manip->setViewpoint( vp, seconds );
}
else if ( ea.getKey() == ea.KEY_Right )// 右键
{
Viewpoint vp;
vp.positionOffset() = oldvp.positionOffset().get() + osg::Vec3f(1000,0,0);
_manip->setViewpoint( vp, seconds );
}
else if ( ea.getKey() == ea.KEY_Up )// 上键
{
Viewpoint vp;
vp.positionOffset() = oldvp.positionOffset().get() + osg::Vec3f(0,0,1000);
_manip->setViewpoint( vp, seconds );
}
else if ( ea.getKey() == ea.KEY_Down )// 下键
{
Viewpoint vp;
vp.positionOffset() = oldvp.positionOffset().get() + osg::Vec3f(0,0,-1000);
_manip->setViewpoint( vp, seconds );
}
aa.requestRedraw();
return true;
}
return false;
}
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* Toggles perspective/ortho projection matrix. 切换投影矩阵,透视投影矩阵和正射投影矩阵
*/
struct ToggleProjMatrix : public osgGA::GUIEventHandler
{
ToggleProjMatrix(char key, EarthManipulator* manip)
: _key(key), _manip(manip)// ley=o
{
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
osg::Matrix proj = aa.asView()->getCamera()->getProjectionMatrix();
if ( proj(3,3) == 0 )
{
OE_NOTICE << "Switching to orthographc.\n";
proj.getPerspective(_vfov, _ar, _zn, _zf); // 获取值
aa.asView()->getCamera()->setProjectionMatrixAsOrtho(-1, 1, -1, 1, _zn, _zf);// 正射投影矩阵
}
else
{
OE_NOTICE << "Switching to perspective.\n";
aa.asView()->getCamera()->setProjectionMatrixAsPerspective(_vfov, _ar, _zn, _zf);// 透视矩阵
}
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Toggle projection matrix type"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
double _vfov, _ar, _zn, _zf;
};
// 定位到某组点的视点,一组点都可以看到
struct FitViewToPoints : public osgGA::GUIEventHandler
{
std::vector<GeoPoint> _points;
const SpatialReference* _mapSRS;
FitViewToPoints(char key, EarthManipulator* manip, const SpatialReference* mapSRS)
: _key(key), _manip(manip), _mapSRS(mapSRS)// key=j
{
// Set up a list of control points
const SpatialReference* srs = SpatialReference::get("wgs84");
_points.push_back(GeoPoint(srs, -120, 30, 0));
_points.push_back(GeoPoint(srs, -100, 45, 0));
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
// fitter 创建适合摄影机视图平截头体的视点,以尽可能紧密地包围一组地理空间点。
ViewFitter fitter(_mapSRS, aa.asView()->getCamera());
fitter.setBuffer( 100000.0 );
Viewpoint vp;
if (fitter.createViewpoint(_points, vp))// 根据_points重新生成一个vp视点
{
_manip->setViewpoint(vp);// 定位到vp视点
aa.requestRedraw();
}
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("FitViewToPoints"));
}
char _key;
osg::ref_ptr<EarthManipulator> _manip;
};
/**
* A simple simulator that moves an object around the Earth. We use this to
* demonstrate/test tethering.
*/
// 一个简单的模拟器,可以使物体绕地球运动。用来演示跟踪thing
struct Simulator : public osgGA::GUIEventHandler
{
Simulator( osg::Group* root, EarthManipulator* manip, MapNode* mapnode, osg::Node* model, const char* name, char key)
: _manip(manip), _mapnode(mapnode), _model(model), _name(name), _key(key) // key=8 或 9
{
if ( !model )
{
// 模型不存在,则创建一个半球,半径和颜色
_model = AnnotationUtils::createHemisphere(250.0, osg::Vec4(1,.7,.4,1));
std::cout << "no model" << std::endl;
}
_geo = new GeoPositionNode();
_geo->getPositionAttitudeTransform()->addChild(_model);
Style style;
TextSymbol* text = style.getOrCreate<TextSymbol>();
text->size() = 32.0f;
text->declutter() = false;
text->pixelOffset()->set(50, 50);// 文本偏移像素点
_label = new LabelNode(_name, style);// _name 即要显示的名称
_label->setDynamic( true );// 因为文本移动,所以此处设置为true
_label->setHorizonCulling(false);// 不需要裁剪
_geo->getPositionAttitudeTransform()->addChild(_label);
mapnode->addChild(_geo.get());
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if ( ea.getEventType() == ea.FRAME )// 此语段为标签添加了动画
{
double t0 = osg::Timer::instance()->time_s();// 儒略日时间
double t = fmod( t0, 6000.0 ) / 6000.0;// t0%6000/6000, 将数字控制在[0,1)范围内
GeoPoint p = _start.interpolate(_end, t);// 差值,在_end和t之间
// GeoMath::bearing 以弧度计算从一个点到下一个点的初始方位
double bearing = GeoMath::bearing(_start.y(), _start.x(), p.y(), p.x());
float a = sin(t0*0.2);// a值没有被用
float pitch = 0.0;
_geo->setPosition(p);
_geo->setLocalRotation(
osg::Quat(pitch, osg::Vec3d(1, 0, 0)) *
osg::Quat(bearing, osg::Vec3d(0, 0, -1)));
}
else if ( ea.getEventType() == ea.KEYDOWN )
{
if ( ea.getKey() == _key )// 8 或 9
{
Viewpoint vp = _manip->getViewpoint();
//vp.setNode( _pat.get() );
vp.setNode(_model);
vp.range() = 25000.0;
vp.pitch() = -45.0;
_manip->setViewpoint(vp, 2.0);// 2秒内飞到指定位置
}
return true;
}
return false;
}
std::string _name;
char _key;
MapNode* _mapnode;
EarthManipulator* _manip;
GeoPoint _start, _end;
LabelNode* _label;
osg::Node* _model;
float _heading;
float _pitch;
osg::ref_ptr<GeoPositionNode> _geo;
};
/**
* Place an X at the sim entity position, in screen space.
* The point of this is to test the EarthManipulator::UpdateCameraCallback
* which provides a frame-synched camera matrix (post-update traversal)
*/
// 创建一个十字坐标
struct CalculateWindowCoords : public osgGA::GUIEventHandler
{
CalculateWindowCoords(char key, EarthManipulator* manip, Simulator* sim)
: _key(key), _active(false), _sim(sim), _xform(0L)
{
//nop
}
void onUpdateCamera(const osg::Camera* cam)
{
if (_active)
{
if (!_xform)
{
osg::Geometry* geom = new osg::Geometry();
osg::Vec3Array* verts = new osg::Vec3Array();
verts->push_back(osg::Vec3(-10000, 0, 0));
verts->push_back(osg::Vec3( 10000, 0, 0));
verts->push_back(osg::Vec3( 0, -10000, 0));
verts->push_back(osg::Vec3( 0, 10000, 0));
verts->push_back(osg::Vec3( 0, 0, -10000));
verts->push_back(osg::Vec3( 0, 0, 10000));
geom->setVertexArray(verts);
osg::Vec4Array* colors = new osg::Vec4Array();
colors->push_back(osg::Vec4(1, 1, 0, 1));// 黄色线
colors->setBinding(colors->BIND_OVERALL);
geom->setColorArray(colors);
geom->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, 6));// 6个点,绘制3条线,但屏幕上仅能看出2条线,水平和垂直
geom->setCullingActive(false);// 不裁剪
geom->getOrCreateStateSet()->setAttributeAndModes(new osg::Depth(osg::Depth::ALWAYS, 0, 1, true), 1);//深度设置
_xform = new osg::MatrixTransform();
_xform->addChild(geom);
osg::View* view = const_cast<osg::View*>(cam->getView());
ControlCanvas::getOrCreate(view)->addChild(_xform);
}
/// 坐标变换 V_clip=M_projection⋅M_view⋅M_model⋅V_local 裁剪坐标=透视矩阵*观察矩阵*模型矩阵*本地坐标——来自OpenGL
GeoPoint p = _sim->_geo->getPosition();// 获取thing1的坐标点
osg::Vec3d world;
p.toWorld(world);// 转化为世界坐标
osg::Matrix worldToWindow =
cam->getViewMatrix() *
cam->getProjectionMatrix() *
cam->getViewport()->computeWindowMatrix();// 世界坐标转到窗口坐标
osg::Vec3d win = world * worldToWindow;// 得到窗口坐标
_xform->setMatrix(osg::Matrix::translate(win));
}
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == ea.KEYDOWN && ea.getKey() == _key)
{
_active = !_active;
aa.requestRedraw();
return true;
}
return false;
}
void getUsage(osg::ApplicationUsage& usage) const
{
using namespace std;
usage.addKeyboardMouseBinding(string(1, _key), string("Show Window Coords"));
}
osg::MatrixTransform* _xform;
Simulator* _sim;
bool _active;
char _key;
};
// 更新相机回调
struct CameraUpdater : public EarthManipulator::UpdateCameraCallback
{
CalculateWindowCoords* _calc;
CameraUpdater(CalculateWindowCoords* calc) : _calc(calc) { }
void onUpdateCamera(const osg::Camera* cam)
{
_calc->onUpdateCamera(cam);// 当物体运动时,需要让十字线跟随物体运动
}
};
}
int main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc,argv);
if (arguments.read("--help") || argc==1)
{
OE_WARN << "Usage: " << argv[0] << " [earthFile] [--model modelToLoad]"
<< std::endl;
return 0;
}
osgViewer::Viewer viewer(arguments);
// install the programmable manipulator.安装操作器
EarthManipulator* manip = new EarthManipulator();
viewer.setCameraManipulator( manip );
// UI: 创建帮助说明控件,在左上角的位置。当鼠标移动到控件上之后,是无法点击到地球上的,没有鼠标穿透功能。
Container* help = createHelp(&viewer);
// MapNodeHelper 显示帮助
// load() 加载earth映射文件并处理所有内置示例命令行参数和XML外部变量(help)。
osg::Node* earthNode = MapNodeHelper().load( arguments, &viewer, help );
if (!earthNode)
{
OE_WARN << "Unable to load earth model." << std::endl;
return -1;
}
osg::Group* root = new osg::Group();
root->addChild( earthNode );
// 获取mapNode
osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode( earthNode );
// user model?
// 加载模型,这里传入osg osgt格式的模型,并没有显示
osg::ref_ptr<osg::Node> model;
std::string modelFile;
if (arguments.read("--model", modelFile))
model = osgDB::readRefNodeFile(modelFile + ".osgearth_shadergen");
osg::Group* sims = new osg::Group();
root->addChild( sims );
const SpatialReference* wgs84 = SpatialReference::get("wgs84");// 坐标系
// Simulator for tethering: 系留模拟器
// thing 1 和 thing 2 会随着时间移动
Simulator* sim1 = new Simulator(sims, manip, mapNode, model.get(), "Thing 1", '8');// 8:绑住第一个物体
sim1->_name = "Thing 1";
sim1->_start = GeoPoint(wgs84, 45.0, 55.0, 10000);// 开始坐标点
sim1->_end = GeoPoint(wgs84, -45, -55.0, 10000); // 结束坐标点
viewer.addEventHandler(sim1); // 加入到操作器
Simulator* sim2 = new Simulator(sims, manip, mapNode, model.get(), "Thing 2", '9');// 9:绑住第二个物体
sim2->_name = "Thing 2";
sim2->_start = GeoPoint(wgs84, 45.0, 54.0, 10000);
sim2->_end = GeoPoint(wgs84, -44.0, -54.0, 10000);
viewer.addEventHandler(sim2);
manip->getSettings()->getBreakTetherActions().push_back( EarthManipulator::ACTION_GOTO ); // 操作器动作,直接过去
// Set the minimum distance to something larger than the default
// 距离物体小于最小距离时,物体会变大
manip->getSettings()->setMinMaxDistance(10.0, manip->getSettings()->getMaxDistance());
// Sets the maximum focal point offsets (usually for tethering)
manip->getSettings()->setMaxOffset(5000.0, 5000.0);
// Pitch limits. 俯仰角范围
manip->getSettings()->setMinMaxPitch(-90, 90);
viewer.setSceneData( root );
//为 鼠标左键按下、修改键、拖动鼠标的动作指定行为。
manip->getSettings()->bindMouse(
EarthManipulator::ACTION_EARTH_DRAG,
osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON,
osgGA::GUIEventAdapter::MODKEY_SHIFT );
manip->getSettings()->bindMouseClick(
EarthManipulator::ACTION_GOTO,
osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON,
osgGA::GUIEventAdapter::MODKEY_SHIFT);
manip->getSettings()->setArcViewpointTransitions( true );
// 设置tether连接和断裂时的动作回调
manip->setTetherCallback( new TetherCB() );
//viewer.addEventHandler(new FlyToViewpointHandler( manip ));
// 添加 自定义的各个事件处理
viewer.addEventHandler(new LockAzimuthHandler('u', manip));
viewer.addEventHandler(new ToggleArcViewpointTransitionsHandler('a', manip));
viewer.addEventHandler(new ToggleThrowingHandler('q', manip));
viewer.addEventHandler(new ToggleCollisionHandler('k', manip));
viewer.addEventHandler(new ToggleProjMatrix('o', manip));
viewer.addEventHandler(new BreakTetherHandler('b', manip));
viewer.addEventHandler(new CycleTetherMode('t', manip));
viewer.addEventHandler(new SetPositionOffset(manip));// 设置偏移
viewer.addEventHandler(new ToggleLDB('L'));
viewer.addEventHandler(new ToggleSSL(sims, ')'));
viewer.addEventHandler(new FitViewToPoints('j', manip, mapNode->getMapSRS()));
// 根据 thing 1 的位置,更新相机
CalculateWindowCoords* calc = new CalculateWindowCoords('W', manip, sim1);// 根据thing 1计算窗口坐标
viewer.addEventHandler(calc);
manip->setUpdateCameraCallback(new CameraUpdater(calc));// 相机回调
viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
while(!viewer.done())
{
viewer.frame();
// simulate slow frame rate
//OpenThreads::Thread::microSleep(1000*1000);
}
return 0;
}
文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目
文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析
文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat
文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集
文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception
文章浏览阅读358次。1.介绍图的相关概念 图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为: G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图
文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc
文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗
文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver
文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象
文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法
文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范