osgearth_elevation示例,展示了如何通过点击地球获取不同定义下的高程数据。包括:MSL高程、HAE高程、EGM96高程。点击按钮,可以移除高程图层。
执行命令:
osgearth_elevationd.exe earth_image\world.earth
earth文件,添加了高程数据。否则无法获取高程值。
双击地形某处,或获取到高程等信息,并展示再ui面板上,同时会添加一个坐标模型。Scene graph interssection 是 与地形交点处的高程。Query resolution 是分辨率。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace osgEarth;
using namespace osgEarth::Util;
using namespace osgEarth::Util::Controls;
using namespace osgEarth::Annotation;
// 创建一些全局静态对象
static MapNode* s_mapNode = 0L; // 地图根结点
static LabelControl* s_posLabel = 0L; // 显示经纬度
static LabelControl* s_vdaLabel = 0L; // 显示坐标系geodetic(wgs84)
static LabelControl* s_mslLabel = 0L; // 圆球之上的高度
static LabelControl* s_haeLabel = 0L; // 椭球之上的高度
static LabelControl* s_egm96Label = 0L; // EGM96的高度
static LabelControl* s_mapLabel = 0L; // 场景图交点的高度
static LabelControl* s_resLabel = 0L; // 输出分辨率结果
static ModelNode* s_marker = 0L; // 坐标模型节点
// An event handler that will print out the elevation at the clicked point
// 一个事件处理程序,它将打印出单击点处的高程
struct QueryElevationHandler : public osgGA::GUIEventHandler
{
QueryElevationHandler()
: _mouseDown( false ),
_terrain ( s_mapNode->getTerrain() )
{
_map = s_mapNode->getMap();
_path.push_back( s_mapNode->getTerrainEngine() );
_envelope = _map->getElevationPool()->createEnvelope(_map->getSRS(), 20u);// 20级LOD
}
// 重写update方法
void update( float x, float y, osgViewer::View* view )
{
bool yes = false;
// look under the mouse:查看鼠标下方
osg::Vec3d world;
osgUtil::LineSegmentIntersector::Intersections hits;// 保存与场景图 相交点的 std::multiset 表。
if ( view->computeIntersections(x, y, hits) )// 计算与(x,y)相交的点,并存入hits
{
world = hits.begin()->getWorldIntersectPoint();
// convert to map coords: 将交点转换到地形坐标
GeoPoint mapPoint;
mapPoint.fromWorld( _terrain->getSRS(), world );
// do an elevation query:执行高程查询
double query_resolution = 0.0; // max.全局并没有被用到
double actual_resolution = 0.0;
float elevation = 0.0f;
// 获取单个高程以及采样数据的分辨率。
std::pair result = _envelope->getElevationAndResolution(
mapPoint.x(), mapPoint.y());
elevation = result.first; // msl高程
actual_resolution = result.second; // 分辨率
if ( elevation != NO_DATA_VALUE )
{
// convert to geodetic to get the HAE:计算HAE下的高度
mapPoint.z() = elevation;
GeoPoint mapPointGeodetic( s_mapNode->getMapSRS()->getGeodeticSRS(), mapPoint );
static LatLongFormatter s_f;
s_posLabel->setText( Stringify()
<< std::fixed << std::setprecision(2)
<< s_f.format(mapPointGeodetic.y(), true)
<< ", "
<< s_f.format(mapPointGeodetic.x(), false) );
if (s_mapNode->getMapSRS()->isGeographic())// 判断是否为地心投影
{
double metersPerDegree = s_mapNode->getMapSRS()->getEllipsoid()->getRadiusEquator() / 360.0;
actual_resolution *= metersPerDegree * cos(osg::DegreesToRadians(mapPoint.y()));
}
s_mslLabel->setText( Stringify() << elevation << " m" );
s_haeLabel->setText( Stringify() << mapPointGeodetic.z() << " m" );
s_resLabel->setText( Stringify() << actual_resolution << " m" );// 分辨率
// 计算egm96下的高度
double egm96z = mapPoint.z();
VerticalDatum::transform(
mapPointGeodetic.getSRS()->getVerticalDatum(),
VerticalDatum::get("egm96"),
mapPointGeodetic.y(),
mapPointGeodetic.x(),
egm96z);
s_egm96Label->setText(Stringify() << egm96z << " m");
yes = true;
}
// now get a normal ISECT HAE point.ESECT规定的HAE高程
GeoPoint isectPoint;
isectPoint.fromWorld( _terrain->getSRS()->getGeodeticSRS(), world );
s_mapLabel->setText( Stringify() << isectPoint.alt() << " m");
// and move the marker.添加模型
s_marker->setPosition(mapPoint);
// normal test.法线测试
osg::Quat q;
q.makeRotate(osg::Vec3(0,0,1), hits.begin()->getLocalIntersectNormal());
s_marker->setLocalRotation(q);
}
// 根据yes 决定是否要更新标签
if (!yes)
{
s_posLabel->setText( "-" );
s_mslLabel->setText( "-" );
s_haeLabel->setText( "-" );
s_resLabel->setText( "-" );
s_egm96Label->setText("-");
}
}
// 接收左键点击、双击事件
bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
{
if (ea.getEventType() == ea.DOUBLECLICK &&
ea.getButton() == ea.LEFT_MOUSE_BUTTON)
{
osgViewer::View* view = static_cast(aa.asView());
// 获取到点击事件,则更新坐标
update( ea.getX(), ea.getY(), view );
return true;
}
return false;
}
const Map* _map; // 地图
const Terrain* _terrain; // 地形
bool _mouseDown;// 鼠标是否按下
osg::NodePath _path; // 路径
osg::ref_ptr _envelope;
};
// 点击移除高程
struct ClickToRemoveElevation : public ControlEventHandler
{
void onClick(Control*)
{
Map* map = s_mapNode->getMap();
ElevationLayerVector layers;
map->getLayers(layers);// 获取高程图层组
map->beginUpdate();
for (ElevationLayerVector::iterator i = layers.begin(); i != layers.end(); ++i) {
map->removeLayer(i->get());// 移除高程数据
}
map->endUpdate();
}
};
int main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc,argv);
osgViewer::Viewer viewer(arguments);
// mapNode 节点
s_mapNode = 0L;
osg::Node* earthFile = MapNodeHelper().load(arguments, &viewer);
if (earthFile)
s_mapNode = MapNode::get(earthFile);
if ( !s_mapNode )
{
OE_WARN << "Unable to load earth file." << std::endl;
return -1;
}
osg::Group* root = new osg::Group();
viewer.setSceneData( root );
// install the programmable manipulator.
viewer.setCameraManipulator( new osgEarth::Util::EarthManipulator() );
// The MapNode will render the Map object in the scene graph.
root->addChild( earthFile );
// Make the readout: 设置布局
Grid* grid = new Grid();
grid->setBackColor(osg::Vec4(0,0,0,0.5));
int r=0;
// 第一行,都是标签,仅1个按钮——移除地形事件
grid->setControl(0,r++,new LabelControl("Double-click to sample elevation", osg::Vec4(1,1,0,1)));
grid->setControl(0,r++,new LabelControl("Coords (Lat, Long):"));
grid->setControl(0,r++,new LabelControl("Map vertical datum:"));
grid->setControl(0,r++,new LabelControl("Height above geoid:"));
grid->setControl(0,r++,new LabelControl("Height above ellipsoid:"));
grid->setControl(0,r++,new LabelControl("Scene graph intersection:"));
grid->setControl(0,r++,new LabelControl("EGM96 elevation:"));
grid->setControl(0,r++,new LabelControl("Query resolution:"));
grid->setControl(0, r++, new ButtonControl("Click to remove all elevation data", new ClickToRemoveElevation()));
// 第二行,标签
r = 1;
s_posLabel = grid->setControl(1,r++,new LabelControl("")); // 显示经纬度
s_vdaLabel = grid->setControl(1,r++,new LabelControl("")); // 显示坐标系geodetic(wgs84)
s_mslLabel = grid->setControl(1,r++,new LabelControl("")); // 圆球之上的高度
s_haeLabel = grid->setControl(1,r++,new LabelControl("")); // 椭球之上的高度
s_mapLabel = grid->setControl(1,r++,new LabelControl("")); // 场景图交点的高度
s_egm96Label = grid->setControl(1,r++,new LabelControl(""));// EGM96的高度
s_resLabel = grid->setControl(1,r++,new LabelControl("")); // 请求的结果
Style markerStyle;
markerStyle.getOrCreate()->url()->setLiteral("D:/FreeXGIS/osgearth_gch/data/axes.osgt.64.scale");
markerStyle.getOrCreate()->autoScale() = true;
s_marker = new ModelNode(s_mapNode, markerStyle);// 模型对象
//s_marker->setMapNode( s_mapNode );
//s_marker->setIconImage(osgDB::readImageFile("../data/placemark32.png"));
s_marker->setDynamic(true);
s_mapNode->addChild( s_marker );
// 获取当前坐标系
const SpatialReference* mapSRS = s_mapNode->getMapSRS();
s_vdaLabel->setText( mapSRS->getVerticalDatum() ?
mapSRS->getVerticalDatum()->getName() :
Stringify() << "geodetic (" << mapSRS->getEllipsoid()->getName() << ")" );
// 画布控件
ControlCanvas* canvas = ControlCanvas::get(&viewer);
canvas->addControl( grid );
// An event handler that will respond to mouse clicks:
viewer.addEventHandler( new QueryElevationHandler() );
// add some stock OSG handlers:
viewer.addEventHandler(new osgViewer::StatsHandler());
viewer.addEventHandler(new osgViewer::WindowSizeHandler());
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
return viewer.run();
}