当前位置:   article > 正文

osgEarth改变投影方式(2D/3D互转),实现二三维数据同步_osgearth 2d

osgearth 2d

项目场景:

想通过osgViewer::CompositeViewer添加同一个.earth文件实现两个View一边显示二维一边显示三维,并且加载的shp之类的数据完全同步。

osgEarth有两种方式构建MapNode,一是通过.earth文件,二是通过代码。

通过代码方式示例如下(官方例子Example osgearth_minimap):

  1. MapNode* makeMiniMapNode( )
  2. {
  3. Map* map = new Map();
  4. map->setProfile(Profile::create(Profile::SPHERICAL_MERCATOR));
  5. // add a semi-transparent XYZ layer:
  6. XYZImageLayer* osm = new XYZImageLayer();
  7. //osm->setURL("http://[abc].tile.openstreetmap.org/{z}/{x}/{y}.png");
  8. osm->setURL("https://gac-geo.googlecnapps.cn/maps/vt?lyrs=y&gl=cn&x={x}&y={y}&z={z}");
  9. osm->setProfile(Profile::create(Profile::SPHERICAL_MERCATOR));
  10. map->addLayer(osm);
  11. TerrainOptions terrainOptions;
  12. terrainOptions.lodMethod() = TerrainLODMethod::SCREEN_SPACE;
  13. MapNode::Options mapNodeOptions;
  14. mapNodeOptions.terrain() = terrainOptions;
  15. MapNode* mapNode = new MapNode(map, mapNodeOptions);
  16. mapNode->setEnableLighting(false);
  17. return mapNode;
  18. }

 通过.earth文件示例如下:

方式1:

通过VS属性管理里调试菜单指定命令参数。

  1. //官方示例
  2. auto node = MapNodeHelper().load( arguments, &viewer );
  3. if (node.valid())
  4. {
  5. MapNode* mapNode = MapNode::get(node);
  6. if (!mapNode)
  7. return -1;
  8. }

 方式2:

直接使用osgDB::readNodeFile()方法进行动态转换。

m_p2DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));

问题描述

通过代码不难看出,通过Map和Layer各自的setProfile方法分别为地图和图层指定投影,不难想象,如果地图和图层的投影方式不一致时会将图层进行重投影。

通过.earth文件也是类似,通过<options>参数里的<profile>指定Map的投影,通过<XYZImage name="osm_mapnik">类似节点里的<profile>指定Layer的投影,如果地图和图层的投影方式不一致时会将图层进行重投影。

但是本文要解决的问题,是无论是通过代码还是.earth文件构建MapNode,并且已经构建成功后,如何修改投影,例如MapNode原本是三维现在转换为二维。或者原本是二维转换为三维。

通过代码加载方式的提示可以进行如下操作:

注:原本的MapNode是三维的球

  1. m_p2DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
  2. if (m_p2DMapNode)
  3. {
  4. m_p2DMapNode->getMap()->setProfile(osgEarth::Profile::create(osgEarth::Profile::PLATE_CARREE));
  5. }

结果如下: 

 

不难看出,代码确实可行,但是其实还有潜藏的问题 。

.earth文件:

  1. <map name="locgis" type="geocentric" version="2" encoding="UTF-8">
  2. <image driver="gdal">
  3. <url>./data/world.tif</url>
  4. <profile>global-geodetic</profile>
  5. <visible>true</visible>
  6. </image>
  7. <ArcGISServerImage name="World Imagery">
  8. <url>https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/</url>
  9. <nodata_image>https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/100/0/0.jpeg</nodata_image>
  10. </ArcGISServerImage>
  11. <ArcGISServerImage name="Transportation" enabled="false">
  12. <url>https://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer</url>
  13. </ArcGISServerImage>
  14. <ArcGISServerImage name="Shaded Relief" enabled="false">
  15. <url>https://services.arcgisonline.com/arcgis/rest/services/World_Shaded_Relief/MapServer</url>
  16. </ArcGISServerImage>
  17. <ArcGISServerElevation name="Elevation layer" max_data_level="13" enabled="true">
  18. <url>https://services.arcgisonline.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer</url>
  19. </ArcGISServerElevation>
  20. <model name="buildings" driver="feature_geom">
  21. <features name="buildings" driver="ogr">
  22. <url>./data/chengdu.shp</url>
  23. <build_spatial_index>true</build_spatial_index>
  24. </features>
  25. <layout>
  26. <tile_size_factor>45</tile_size_factor>
  27. <level name="default" max_range="20000">
  28. <selector class="buildings"/>
  29. </level>
  30. </layout>
  31. <styles>
  32. <style type="text/css">
  33. buildings {
  34. extrusion-height: 3.5 * max([Floor], 1);
  35. extrusion-flatten: true;
  36. extrusion-wall-style: building-wall;
  37. extrusion-wall-gradient: 0.5;
  38. extrusion-roof-style: building-rooftop;
  39. altitude-clamping: terrain;
  40. altitude-technique: map;
  41. altitude-binding: vertex;
  42. }
  43. <!-- building-wall { -->
  44. <!-- skin-library: none; -->
  45. <!-- skin-tags: building; -->
  46. <!-- skin-random-seed: 1; -->
  47. <!-- fill: #ffffff; -->
  48. <!-- } -->
  49. <!-- building-rooftop { -->
  50. <!-- skin-library: none; -->
  51. <!-- skin-tags: rooftop; -->
  52. <!-- skin-tiled: true; -->
  53. <!-- skin-random-seed: 1; -->
  54. <!-- fill: #ffffff; -->
  55. <!-- } -->
  56. </style>
  57. <!--Exclude certain buildings from being rendered b/c they will be replaced with geospecific buildings -->
  58. <!-- <selector class="buildings"> -->
  59. <!-- <query> -->
  60. <!-- <expr><![CDATA[ OBJECTID_1 <> 91506 and OBJECTID_1 <> 12921 and OBJECTID_1 <> 11460 and OBJECTID_1 <> 11474 and OBJECTID_1 <> 11471 and OBJECTID_1 <> 11439 and OBJECTID_1 <> 11432 and OBJECTID_1 <> 91499 and OBJECTID_1 <> 10878 ]]> </expr> -->
  61. <!-- </query> -->
  62. <!-- </selector> -->
  63. </styles>
  64. <lighting>false</lighting>
  65. </model>
  66. <!-- <elevation driver="tms"> -->
  67. <!-- <url>./data/12/</url> -->
  68. <!-- <profile>global-geodetic</profile> -->
  69. <!-- <visible>true</visible> -->
  70. <!-- </elevation> -->
  71. <options>
  72. <!--cache_policy usage="cache_only"/-->
  73. <cache_policy usage="read_write"/>
  74. <elevation_tile_size>15</elevation_tile_size>
  75. <terrain>
  76. <first_lod>2</first_lod>
  77. <mind_lod>19</mind_lod>
  78. <min_tile_range_factor>7</min_tile_range_factor>
  79. </terrain>
  80. </options>
  81. </map>

 三维效果:

二维效果:

 使用osgViewer::CompositeViewer同时添加二三维做个对比:

 将三维转为二维后.earth下添加的shp文件并没有渲染出来。


原因分析:

Map下添加的Layer的投影并没有改变,即Map的setProfile方法虽然可以改变Map的投影方式但并不会改变其下Layer的投影方式。

 osgEarth源码:

  1. void
  2. Map::setProfile(const Profile* value)
  3. {
  4. bool notifyLayers = !_profile.valid();
  5. if (value)
  6. {
  7. _profile = value;
  8. // create a "proxy" profile to use when querying elevation layers with a vertical datum
  9. if (_profile.valid() && _profile->getSRS()->getVerticalDatum() != 0L )
  10. {
  11. ProfileOptions po = _profile->toProfileOptions();
  12. po.vsrsString().unset();
  13. _profileNoVDatum = Profile::create(po);
  14. }
  15. else
  16. {
  17. _profileNoVDatum = _profile;
  18. }
  19. // finally, fire an event if the profile has been set.
  20. OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl;
  21. }
  22. // If we just set the profile, tell all our layers they are now added
  23. // to a valid map.
  24. if (_profile.valid() && notifyLayers)
  25. {
  26. for(LayerVector::iterator i = _layers.begin(); i != _layers.end(); ++i)
  27. {
  28. Layer* layer = i->get();
  29. if (layer->isOpen())
  30. {
  31. layer->addedToMap(this);
  32. }
  33. }
  34. }
  35. }

解决方案:

还是通过代码添加MapNode的提示,把图层重新添加一次,通过添加图层时会对图层重投影来改变Layer的投影。

代码如下:

  1. osgEarth::MapNode* p2DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
  2. p2DMapNode->getMap()->setProfile(osgEarth::Profile::create(osgEarth::Profile::PLATE_CARREE));
  3. osgEarth::LayerVector layers;
  4. p2DMapNode->getMap()->getLayers(layers);
  5. for (auto itr : layers)
  6. {
  7. p2DMapNode->getMap()->removeLayer(itr);
  8. }
  9. p2DMapNode->getMap()->addLayers(layers);

结果展示: 

 这样有什么作用呢?就是可以实现二三维加载同一个.earth文件,实现二三维数据同步。

完整代码:

  1. #include <osgDB/ReadFile>
  2. #include <osgEarth/Common>
  3. #include <osgEarth/EarthManipulator>
  4. #include <osgViewer/CompositeViewer>
  5. #include <osgEarth/GLUtils>
  6. #include <osgEarth/Registry>
  7. #include <osgEarth/GeoTransform>
  8. #include <windows.h>
  9. namespace osgEarth
  10. {
  11. class ImageLayer;
  12. }
  13. const std::string strEarthFile = R"(E:\OSGEarth\osgearth\tests\chengdu_building.earth)";
  14. int main()
  15. {
  16. osgEarth::initialize();
  17. osgViewer::CompositeViewer viewer;
  18. viewer.setThreadingModel(viewer.SingleThreaded);// 设置单线程
  19. osgViewer::View* p3DView = new osgViewer::View();
  20. p3DView->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);
  21. p3DView->getCamera()->setNearFarRatio(0.00002);
  22. osgEarth::EarthManipulator* p3DEarthManipulator = new osgEarth::EarthManipulator();
  23. p3DView->setCameraManipulator(p3DEarthManipulator);
  24. p3DView->setUpViewInWindow(50, 50, 1600, 800, 0);
  25. p3DView->getCamera()->setViewport(800, 0, 800, 800);
  26. p3DView->getCamera()->setProjectionMatrixAsOrtho2D(osgEarth::MERC_MINX, osgEarth::MERC_MAXX, osgEarth::MERC_MINY, osgEarth::MERC_MAXY);
  27. viewer.addView(p3DView);
  28. osgViewer::View* p2DView = new osgViewer::View();
  29. p2DView->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);
  30. p2DView->getCamera()->setNearFarRatio(0.00002);
  31. osgEarth::EarthManipulator* p2DEarthManipulator = new osgEarth::EarthManipulator();
  32. p2DEarthManipulator->getSettings()->bindMouse(osgEarth::Util::EarthManipulator::ACTION_NULL, osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON, 0);
  33. p2DView->setCameraManipulator(p2DEarthManipulator);
  34. p2DView->getCamera()->setViewport(0, 0, 800, 800);
  35. p2DView->getCamera()->setProjectionMatrixAsOrtho2D(osgEarth::MERC_MINX, osgEarth::MERC_MAXX, osgEarth::MERC_MINY, osgEarth::MERC_MAXY);
  36. p2DView->getCamera()->setGraphicsContext(p3DView->getCamera()->getGraphicsContext());
  37. osgEarth::GLUtils::setGlobalDefaults(p3DView->getCamera()->getOrCreateStateSet());
  38. viewer.addView(p2DView);
  39. osgEarth::MapNode* p3DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
  40. p3DMapNode->setEnableLighting(false);
  41. osg::Group* p3MapGroup = new osg::Group;
  42. p3MapGroup->addChild(p3DMapNode);
  43. p3DView->setSceneData(p3MapGroup);
  44. osgEarth::MapNode* p2DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
  45. p2DMapNode->getMap()->setProfile(osgEarth::Profile::create(osgEarth::Profile::PLATE_CARREE));
  46. osgEarth::LayerVector layers;
  47. p2DMapNode->getMap()->getLayers(layers);
  48. for (auto itr : layers)
  49. {
  50. p2DMapNode->getMap()->removeLayer(itr);
  51. }
  52. p2DMapNode->getMap()->addLayers(layers);
  53. osg::Group* p2DMapGroup = new osg::Group;
  54. p2DMapGroup->addChild(p2DMapNode);
  55. p2DView->setSceneData(p2DMapGroup);
  56. viewer.run();
  57. }

运行结果:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/347994
推荐阅读
相关标签
  

闽ICP备14008679号