osgearth_transform示例,是控制三维坐标轴的示例。通过控制面板的滑块,进而控制坐标轴的经度、纬度、高度、俯仰角、偏航角、旋转等操作。
执行命令 :osgearth_transformd.exe earth_image\world.earth
Lat | 南北移动 |
Long | 东西移动 |
Alt /Zero | 上下移动 / 高度置零 |
Heading | 绕Z轴旋转 |
Pitch | 绕X轴旋转 |
Roll | 绕Y轴旋转 |
Relative Z | 由于没有加载高程数据,所以无法看到效果 |
本节代码的重点:控制视点、以及在地球上如何操作模型的移动、旋转。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LC "[osgearth_transform] "
using namespace osgEarth;
using namespace osgEarth::Util;
namespace ui = osgEarth::Util::Controls;
int
usage(const char* name)
{
OE_NOTICE
<< "\nUsage: " << name << " file.earth" << std::endl;
return 0;
}
struct App
{
const osgEarth::SpatialReference* srs;// 坐标系
osgEarth::GeoTransform* geo;// 接受地理空间坐标的变换节点。
osg::PositionAttitudeTransform* pat;// 节点姿态控制
// 水平滑块控件
ui::HSliderControl* uiLat; // 控制纬度
ui::HSliderControl* uiLon; // 控制经度
ui::HSliderControl* uiAlt; // 控制高度
ui::HSliderControl* uiHeading; // 偏航角
ui::HSliderControl* uiPitch; // 俯仰角
ui::HSliderControl* uiRoll; // 旋转角
ui::CheckBoxControl* uiRelativeZ; // 相对值Z还是绝对值Z
void apply()
{
// altMode 指示如何解释Z坐标。地形之上的高度,还是绝对高度
AltitudeMode altMode = uiRelativeZ->getValue() ? ALTMODE_RELATIVE : ALTMODE_ABSOLUTE;
// 根据传入值,创建pos
GeoPoint pos(
srs,
uiLon->getValue(), uiLat->getValue(), uiAlt->getValue(),
altMode);
// 将坐标点pos添加到变换节点geo
geo->setPosition( pos );
// 四元数
osg::Quat ori =
osg::Quat(osg::DegreesToRadians(uiRoll->getValue()), osg::Vec3(0,1,0)) * // 角度和方向
osg::Quat(osg::DegreesToRadians(uiPitch->getValue()), osg::Vec3(1,0,0)) *
osg::Quat(osg::DegreesToRadians(uiHeading->getValue()), osg::Vec3(0,0,-1));
// 设置节点姿态
pat->setAttitude( ori );
}
};
struct Apply : public ui::ControlEventHandler
{
Apply(App& app) : _app(app) { }
void onValueChanged(ui::Control* control) {
_app.apply();
}
App& _app;
};
// 高度置零
struct ZeroAlt : public ui::ControlEventHandler {
ZeroAlt(App& app) : _app(app) { }
void onClick(ui::Control* control) {
_app.uiAlt->setValue(0.0f);
_app.apply();
}
App& _app;
};
// 创建控制面板的UI界面
ui::Control* makeUI(App& app)
{
ui::Grid* grid = new ui::Grid();
grid->setBackColor(0,0,0,0.5);
grid->setControl(0, 0, new ui::LabelControl("Lat:"));
grid->setControl(0, 1, new ui::LabelControl("Long:"));
grid->setControl(0, 2, new ui::LabelControl("Alt:"));
grid->setControl(0, 3, new ui::LabelControl("Heading:"));
grid->setControl(0, 4, new ui::LabelControl("Pitch:"));
grid->setControl(0, 5, new ui::LabelControl("Roll:"));
grid->setControl(0, 6, new ui::LabelControl("Relative Z:"));
// 设置滑块的起止值与当前值,添加Apply事件方法
app.uiLat = grid->setControl(1, 0, new ui::HSliderControl(40.0f, 50.0f, 44.7433f, new Apply(app)));
grid->setControl(2, 0, new LabelControl(app.uiLat));// 添加标签,标签内容会随着app的apply方法更改而更改
app.uiLon = grid->setControl(1, 1, new ui::HSliderControl(6.0f, 8.0f, 7.0f, new Apply(app)));
grid->setControl(2, 1, new LabelControl(app.uiLon));
app.uiAlt = grid->setControl(1, 2, new ui::HSliderControl(-3000.0f, 100000.0f, 25000.0f, new Apply(app)));
grid->setControl(2, 2, new LabelControl(app.uiAlt));
grid->setControl(3, 2, new ButtonControl("Zero", new ZeroAlt(app)));// 置零按钮
app.uiHeading = grid->setControl(1, 3, new ui::HSliderControl(-180.0f, 180.0f, 0.0f, new Apply(app)));
grid->setControl(2, 3, new LabelControl(app.uiHeading));
app.uiPitch = grid->setControl(1, 4, new ui::HSliderControl(-90.0f, 90.0f, 0.0f, new Apply(app)));
grid->setControl(2, 4, new LabelControl(app.uiPitch));
app.uiRoll = grid->setControl(1, 5, new ui::HSliderControl(-180.0f, 180.0f, 0.0f, new Apply(app)));
grid->setControl(2, 5, new LabelControl(app.uiRoll));
app.uiRelativeZ = grid->setControl(1, 6, new ui::CheckBoxControl(true, new Apply(app))); app.uiRelativeZ->setWidth(15.0f);
grid->setControl(2, 6, new LabelControl(app.uiRelativeZ));
app.uiLat->setHorizFill(true, 700.0f);
return grid;
}
int
main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc,argv);
// help?
if ( arguments.read("--help") )
return usage(argv[0]);
osgViewer::Viewer viewer(arguments);
EarthManipulator* em = new EarthManipulator();// 默认操作器
viewer.setCameraManipulator( em );
// load an earth file, and support all or our example command-line options
// and earth file tags
osg::Node* earth = MapNodeHelper().load( arguments, &viewer );
MapNode* mapNode = MapNode::get(earth);
if (!mapNode)
return usage(argv[0]);
// load the model file into the local coordinate frame, which will be
// +X=east, +Y=north, +Z=up. 模型一定要放大很多倍,才能容易发现,模型初始位置位于欧洲的某一处高山位置。
osg::ref_ptr model = osgDB::readRefNodeFile("axes.osgt.(10000).scale.osgearth_shadergen");
if (!model.valid())
return usage(argv[0]);
osg::Group* root = new osg::Group();
root->addChild( earth );
// 这个结构体设计的有点不合理
App app;
app.srs = mapNode->getMapSRS();
app.geo = new GeoTransform();
app.pat = new osg::PositionAttitudeTransform();// 位置和姿态
app.pat->addChild( model.get() );// 添加模型
app.geo->addChild( app.pat );
// Place your GeoTransform under the map node and it will automatically support clamping.
// If you don't do this, you must call setTerrain to get terrain clamping.
mapNode->addChild( app.geo );
viewer.setSceneData( root );
viewer.getCamera()->setNearFarRatio(0.00002);
viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
// 创建控制面板
ui::ControlCanvas::getOrCreate(&viewer)->addControl( makeUI(app) );
app.apply();// 遍历节点
osgEarth::Viewpoint vp;// 视点控制
vp.setNode( app.geo );
vp.heading()->set( -45.0, Units::DEGREES );// 偏航角
vp.pitch()->set( -20.0, Units::DEGREES );// 俯仰角
vp.range()->set( model->getBound().radius()*10.0, Units::METERS );// 模型可见范围
em->setViewpoint( vp );
return viewer.run();
}