zoukankan      html  css  js  c++  java
  • osgEarth基础入门

    osgEarth基础入门

    2015年3月21日

    16:19

    osgEarth是基于三维引擎osg开发的三维数字地球引擎库,在osg基础上实现了瓦片调度插件,可选的四叉树调度插件,更多的地理数据加载插件(包括GDAL,ogr,WMS,TMS,VPB,filesystem等),再结合一套地理投影转换插件,这样就能够实现高效处理加载调度地理数据在三维地球上的显示,实现三维虚拟地球。

    想要实现一个简单的基于osgEarth的三维地球,有两种方式,这两种方式是互通的。一种基于XML标签的earth文件加载,另外一种是采用C++代码,本质是一样的,osgEarth内部支持直接解析XML标签文件,转换为代码实现,具体参考tests文件夹例子,代码则参考application下面例子。但是大多数情况下,你需要更灵活掌控性更强的代码来实现功能,因为只有一个加载了基础数据的三维地球是只能看,不能解决实际问题的,需要界面通常采用QT,更多的三维渲染和仿真业务则由osg来完成。因此学好osg是做这一切的基础。

    osgEarth的特点:支持加载常见的栅格数据(影像和DEM),但是大数据必须建立金字塔,设置为地理投影,想要高效率最好处理为瓦片,这样也便于部署在服务端。矢量数据,最好尽可能的简化,因为大的矢量会十分影响渲染速度,当然也可以对矢量栅格化处理加快速度,对于模型的话,大数据量一定要做LOD或者pageLod。

    osgEarth程序的常规流程:

    创建osgViewer---->创建MapNode---->设置Earth操作器---->设置场景参数----->run

    MapNode是继承自osg的Node,是osgEarth中地球节点,你所添加的影像,DEM,模型都包含在MapNode中,因为它们都加入到Map中,Map则类似二维中的Map可以添加各种图层。剩余的不管是模型节点Node,或者是标注Node,还是其他的都是可以直接添加到MapNode中或者另外的Group中。

    Earth操作器则和其他osg操作器一样,只不过专门为三维地球浏览定制,具体参数可以设置。

    场景参数则主要有自动地形裁剪,最小裁剪像素等其他优化场景的参数。

    下面就简单阐述一个小例子说明:

    代码功能主要实现了查询实时高程,并显示XYZ坐标的功能。

    使用命令app.exe test.earth即可得到下面的效果。

    clip_image002

    //引入osg和osgEarth的头文件和命名空间
    #include <osgGA/StateSetManipulator>
    #include <osgGA/GUIEventHandler>
    #include <osgViewer/Viewer>
    #include <osgViewer/ViewerEventHandlers>
    #include <osgUtil/LineSegmentIntersector>
    #include <osgEarth/MapNode>
    #include <osgEarth/TerrainEngineNode>
    #include <osgEarth/ElevationQuery>
    #include <osgEarth/StringUtils>
    #include <osgEarth/Terrain>
    #include <osgEarthUtil/EarthManipulator>
    #include <osgEarthUtil/Controls>
    #include <osgEarthUtil/LatLongFormatter>
    #include <iomanip>
     
    using namespace osgEarth;
    using namespace osgEarth::Util;
    using namespace osgEarth::Util::Controls;
     
    static MapNode*       s_mapNode     = 0L;
    static LabelControl*  s_posLabel    = 0L;
    static LabelControl*  s_vdaLabel    = 0L;
    static LabelControl*  s_mslLabel    = 0L;
    static LabelControl*  s_haeLabel    = 0L;
    static LabelControl*  s_mapLabel    = 0L;
    static LabelControl*  s_resLabel    = 0L;
     
     
    // An event handler that will print out the elevation at the clicked point
    //查询高程的一个事件回调,在场景有事件更新触发时调用,详细参考osg或者osgGA::GUIEventHandler 
    struct QueryElevationHandler : public osgGA::GUIEventHandler 
    {
    //构造函数
    QueryElevationHandler()
    : _mouseDown( false ),
    _terrain  ( s_mapNode->getTerrain() ),
    _query    ( s_mapNode->getMap() )
    {
    _map = s_mapNode->getMap();
     
    //初始化最大查询LOD级别
    _query.setMaxTilesToCache(10);
     
    _path.push_back( s_mapNode->getTerrainEngine() );
    }
    //更新回调,具体的内容可以参考父类,传进来的参数是屏幕坐标xy,和osgViewer
    void update( float x, float y, osgViewer::View* view )
    {
    bool yes = false;
     
    // look under the mouse:
    //采用线去对地球做碰撞检测,根据鼠标点击点去检测,得到交点,就是当前点的xyz
    osg::Vec3d world;
    osgUtil::LineSegmentIntersector::Intersections hits;
    //判断求交结果是否为空
    if ( view->computeIntersections(x, y, hits) )
    {
    //得到世界坐标系下面的坐标,就是osg的xyz坐标
    world = hits.begin()->getWorldIntersectPoint();
     
    // convert to map coords:
    //将其转换为地球的地理坐标,转换方法都照抄即可
    GeoPoint mapPoint;
    mapPoint.fromWorld( _terrain->getSRS(), world );
     
    // do an elevation query:
    double query_resolution = 0; // 1/10th of a degree
    double out_hamsl        = 0.0;
    double out_resolution   = 0.0;
     
    //根据输入参数查询当前点位置的高程,需要设置分辨率,就是查询精度
    bool ok = _query.getElevation( 
    mapPoint,
    out_hamsl,
    query_resolution, 
    &out_resolution );
     
    //如果查询成功
    if ( ok )
    {
    // convert to geodetic to get the HAE:
    mapPoint.z() = out_hamsl;
    GeoPoint mapPointGeodetic( s_mapNode->getMapSRS()->getGeodeticSRS(), mapPoint );
     
    //经纬度坐标的格式化工具,也可以自己用字符串去拼接xyz数字
    static LatLongFormatter s_f;
     
    //更新显示的xyz值,label是传入的控件
    s_posLabel->setText( Stringify()
    << std::fixed << std::setprecision(2) 
    << s_f.format(mapPointGeodetic.y())
    << ", " 
    << s_f.format(mapPointGeodetic.x()) );
     
    //还可以输出分辨率,椭球体信息等
    s_mslLabel->setText( Stringify() << out_hamsl );
    s_haeLabel->setText( Stringify() << mapPointGeodetic.z() );
    s_resLabel->setText( Stringify() << out_resolution );
     
    yes = true;
    }
     
    // finally, get a normal ISECT HAE point.
    GeoPoint isectPoint;
    isectPoint.fromWorld( _terrain->getSRS()->getGeodeticSRS(), world );
    s_mapLabel->setText( Stringify() << isectPoint.alt() );
    }
     
    //如果查询不到高程的话
    if (!yes)
    {
    s_posLabel->setText( "-" );
    s_mslLabel->setText( "-" );
    s_haeLabel->setText( "-" );
    s_resLabel->setText( "-" );
    }
    }
     
    //参数一个是事件的动作,另外一个是对应的操作
    bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
    {
    //判断如果是移动鼠标事件才进行更新当前的坐标显示
    if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE &&
    aa.asView()->getFrameStamp()->getFrameNumber() % 10 == 0)
    {
    osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView());
    update( ea.getX(), ea.getY(), view );
    }
     
    return false;
    }
     
    //Map对象
    const Map*       _map;
    //地形对象
    const Terrain*   _terrain;
    bool             _mouseDown;
    //查询高程使用的对象
    ElevationQuery   _query;
    osg::NodePath    _path;
    };
     
    //main函数,
    int main(int argc, char** argv)
    {
    //这儿两个参数,第一个是命令参数的个数为,后面是字符串数组输入earth文件的路径osg::ArgumentParser arguments(&argc,argv);
     
    //osg的场景
    osgViewer::Viewer viewer(arguments);
    //构造MapNode,arguments里面有earth文件的路径,命令行输入
    s_mapNode = MapNode::load(arguments);
    //如果路径不正确或者earth文件错误,没有构造好MapNode
    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.
    //设置earth操作器
    viewer.setCameraManipulator( new osgEarth::Util::EarthManipulator() );
     
    // The MapNode will render the Map object in the scene graph.
    //将MapNode添加到组节点中去
    root->addChild( s_mapNode );
     
    //下面是设置一个控件,grid的意思是用格网去布局里面的小控件
    // Make the readout:
    Grid* grid = new Grid();
    //设置几个Label文字控件显示在场景中的第行
    grid->setControl(0,0,new LabelControl("Coords (Lat, Long):"));
    grid->setControl(0,1,new LabelControl("Vertical Datum:"));
    grid->setControl(0,2,new LabelControl("Height (MSL):"));
    grid->setControl(0,3,new LabelControl("Height (HAE):"));
    grid->setControl(0,4,new LabelControl("Isect  (HAE):"));
    grid->setControl(0,5,new LabelControl("Resolution:"));
    //设置几个Label文字控件显示在场景中的第行
    s_posLabel = grid->setControl(1,0,new LabelControl(""));
    s_vdaLabel = grid->setControl(1,1,new LabelControl(""));
    s_mslLabel = grid->setControl(1,2,new LabelControl(""));
    s_haeLabel = grid->setControl(1,3,new LabelControl(""));
    s_mapLabel = grid->setControl(1,4,new LabelControl(""));
    s_resLabel = grid->setControl(1,5,new LabelControl(""));
     
    //得到空间参考,椭球面信息,并显示对应上面的label
    const SpatialReference* mapSRS = s_mapNode->getMapSRS();
    s_vdaLabel->setText( mapSRS->getVerticalDatum() ? 
    mapSRS->getVerticalDatum()->getName() : 
    Stringify() << "geodetic (" << mapSRS->getEllipsoid()->getName() << ")" );
     
    //控件绘制容器
    ControlCanvas* canvas = new ControlCanvas();    
    //将要显示的控件加入到root组节点中去
    root->addChild(canvas);
    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()));
     
    //run
    return viewer.run();
    }
  • 相关阅读:
    Balance的数学思想构造辅助函数
    1663. Smallest String With A Given Numeric Value (M)
    1680. Concatenation of Consecutive Binary Numbers (M)
    1631. Path With Minimum Effort (M)
    1437. Check If All 1's Are at Least Length K Places Away (E)
    1329. Sort the Matrix Diagonally (M)
    1657. Determine if Two Strings Are Close (M)
    1673. Find the Most Competitive Subsequence (M)
    1641. Count Sorted Vowel Strings (M)
    1679. Max Number of K-Sum Pairs (M)
  • 原文地址:https://www.cnblogs.com/sunliming/p/4355966.html
Copyright © 2011-2022 走看看