赞
踩
想通过osgViewer::CompositeViewer添加同一个.earth文件实现两个View一边显示二维一边显示三维,并且加载的shp之类的数据完全同步。
osgEarth有两种方式构建MapNode,一是通过.earth文件,二是通过代码。
通过代码方式示例如下(官方例子Example osgearth_minimap):
- MapNode* makeMiniMapNode( )
- {
- Map* map = new Map();
- map->setProfile(Profile::create(Profile::SPHERICAL_MERCATOR));
-
- // add a semi-transparent XYZ layer:
- XYZImageLayer* osm = new XYZImageLayer();
- //osm->setURL("http://[abc].tile.openstreetmap.org/{z}/{x}/{y}.png");
- osm->setURL("https://gac-geo.googlecnapps.cn/maps/vt?lyrs=y&gl=cn&x={x}&y={y}&z={z}");
- osm->setProfile(Profile::create(Profile::SPHERICAL_MERCATOR));
- map->addLayer(osm);
-
- TerrainOptions terrainOptions;
- terrainOptions.lodMethod() = TerrainLODMethod::SCREEN_SPACE;
-
- MapNode::Options mapNodeOptions;
- mapNodeOptions.terrain() = terrainOptions;
-
- MapNode* mapNode = new MapNode(map, mapNodeOptions);
- mapNode->setEnableLighting(false);
-
- return mapNode;
- }
通过.earth文件示例如下:
方式1:
通过VS属性管理里调试菜单指定命令参数。
- //官方示例
- auto node = MapNodeHelper().load( arguments, &viewer );
- if (node.valid())
- {
- MapNode* mapNode = MapNode::get(node);
- if (!mapNode)
- return -1;
- }
方式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是三维的球
- m_p2DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
- if (m_p2DMapNode)
- {
- m_p2DMapNode->getMap()->setProfile(osgEarth::Profile::create(osgEarth::Profile::PLATE_CARREE));
- }
结果如下:
不难看出,代码确实可行,但是其实还有潜藏的问题 。
.earth文件:
- <map name="locgis" type="geocentric" version="2" encoding="UTF-8">
-
- <image driver="gdal">
- <url>./data/world.tif</url>
- <profile>global-geodetic</profile>
- <visible>true</visible>
- </image>
-
- <ArcGISServerImage name="World Imagery">
- <url>https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/</url>
- <nodata_image>https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/100/0/0.jpeg</nodata_image>
- </ArcGISServerImage>
-
- <ArcGISServerImage name="Transportation" enabled="false">
- <url>https://services.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer</url>
- </ArcGISServerImage>
-
- <ArcGISServerImage name="Shaded Relief" enabled="false">
- <url>https://services.arcgisonline.com/arcgis/rest/services/World_Shaded_Relief/MapServer</url>
- </ArcGISServerImage>
-
- <ArcGISServerElevation name="Elevation layer" max_data_level="13" enabled="true">
- <url>https://services.arcgisonline.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer</url>
- </ArcGISServerElevation>
-
- <model name="buildings" driver="feature_geom">
-
- <features name="buildings" driver="ogr">
- <url>./data/chengdu.shp</url>
- <build_spatial_index>true</build_spatial_index>
- </features>
-
- <layout>
- <tile_size_factor>45</tile_size_factor>
- <level name="default" max_range="20000">
- <selector class="buildings"/>
- </level>
- </layout>
-
- <styles>
-
- <style type="text/css">
- buildings {
- extrusion-height: 3.5 * max([Floor], 1);
- extrusion-flatten: true;
- extrusion-wall-style: building-wall;
- extrusion-wall-gradient: 0.5;
- extrusion-roof-style: building-rooftop;
- altitude-clamping: terrain;
- altitude-technique: map;
- altitude-binding: vertex;
- }
- <!-- building-wall { -->
- <!-- skin-library: none; -->
- <!-- skin-tags: building; -->
- <!-- skin-random-seed: 1; -->
- <!-- fill: #ffffff; -->
- <!-- } -->
- <!-- building-rooftop { -->
- <!-- skin-library: none; -->
- <!-- skin-tags: rooftop; -->
- <!-- skin-tiled: true; -->
- <!-- skin-random-seed: 1; -->
- <!-- fill: #ffffff; -->
- <!-- } -->
- </style>
-
-
- <!--Exclude certain buildings from being rendered b/c they will be replaced with geospecific buildings -->
- <!-- <selector class="buildings"> -->
- <!-- <query> -->
- <!-- <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> -->
- <!-- </query> -->
- <!-- </selector> -->
-
- </styles>
-
- <lighting>false</lighting>
- </model>
-
- <!-- <elevation driver="tms"> -->
- <!-- <url>./data/12/</url> -->
- <!-- <profile>global-geodetic</profile> -->
- <!-- <visible>true</visible> -->
- <!-- </elevation> -->
-
- <options>
- <!--cache_policy usage="cache_only"/-->
- <cache_policy usage="read_write"/>
- <elevation_tile_size>15</elevation_tile_size>
-
- <terrain>
- <first_lod>2</first_lod>
- <mind_lod>19</mind_lod>
- <min_tile_range_factor>7</min_tile_range_factor>
- </terrain>
-
- </options>
-
- </map>
三维效果:
二维效果:
使用osgViewer::CompositeViewer同时添加二三维做个对比:
将三维转为二维后.earth下添加的shp文件并没有渲染出来。
Map下添加的Layer的投影并没有改变,即Map的setProfile方法虽然可以改变Map的投影方式但并不会改变其下Layer的投影方式。
osgEarth源码:
- void
- Map::setProfile(const Profile* value)
- {
- bool notifyLayers = !_profile.valid();
-
- if (value)
- {
- _profile = value;
-
- // create a "proxy" profile to use when querying elevation layers with a vertical datum
- if (_profile.valid() && _profile->getSRS()->getVerticalDatum() != 0L )
- {
- ProfileOptions po = _profile->toProfileOptions();
- po.vsrsString().unset();
- _profileNoVDatum = Profile::create(po);
- }
- else
- {
- _profileNoVDatum = _profile;
- }
-
- // finally, fire an event if the profile has been set.
- OE_INFO << LC << "Map profile is: " << _profile->toString() << std::endl;
- }
-
- // If we just set the profile, tell all our layers they are now added
- // to a valid map.
- if (_profile.valid() && notifyLayers)
- {
- for(LayerVector::iterator i = _layers.begin(); i != _layers.end(); ++i)
- {
- Layer* layer = i->get();
- if (layer->isOpen())
- {
- layer->addedToMap(this);
- }
- }
- }
- }
还是通过代码添加MapNode的提示,把图层重新添加一次,通过添加图层时会对图层重投影来改变Layer的投影。
代码如下:
- osgEarth::MapNode* p2DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
-
- p2DMapNode->getMap()->setProfile(osgEarth::Profile::create(osgEarth::Profile::PLATE_CARREE));
- osgEarth::LayerVector layers;
- p2DMapNode->getMap()->getLayers(layers);
- for (auto itr : layers)
- {
- p2DMapNode->getMap()->removeLayer(itr);
- }
- p2DMapNode->getMap()->addLayers(layers);
结果展示:
这样有什么作用呢?就是可以实现二三维加载同一个.earth文件,实现二三维数据同步。
完整代码:
- #include <osgDB/ReadFile>
- #include <osgEarth/Common>
- #include <osgEarth/EarthManipulator>
- #include <osgViewer/CompositeViewer>
- #include <osgEarth/GLUtils>
- #include <osgEarth/Registry>
- #include <osgEarth/GeoTransform>
-
- #include <windows.h>
-
- namespace osgEarth
- {
- class ImageLayer;
- }
-
- const std::string strEarthFile = R"(E:\OSGEarth\osgearth\tests\chengdu_building.earth)";
-
- int main()
- {
- osgEarth::initialize();
-
- osgViewer::CompositeViewer viewer;
- viewer.setThreadingModel(viewer.SingleThreaded);// 设置单线程
-
- osgViewer::View* p3DView = new osgViewer::View();
- p3DView->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);
- p3DView->getCamera()->setNearFarRatio(0.00002);
-
- osgEarth::EarthManipulator* p3DEarthManipulator = new osgEarth::EarthManipulator();
- p3DView->setCameraManipulator(p3DEarthManipulator);
- p3DView->setUpViewInWindow(50, 50, 1600, 800, 0);
-
- p3DView->getCamera()->setViewport(800, 0, 800, 800);
- p3DView->getCamera()->setProjectionMatrixAsOrtho2D(osgEarth::MERC_MINX, osgEarth::MERC_MAXX, osgEarth::MERC_MINY, osgEarth::MERC_MAXY);
-
- viewer.addView(p3DView);
-
- osgViewer::View* p2DView = new osgViewer::View();
- p2DView->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(true, false);
- p2DView->getCamera()->setNearFarRatio(0.00002);
- osgEarth::EarthManipulator* p2DEarthManipulator = new osgEarth::EarthManipulator();
- p2DEarthManipulator->getSettings()->bindMouse(osgEarth::Util::EarthManipulator::ACTION_NULL, osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON, 0);
- p2DView->setCameraManipulator(p2DEarthManipulator);
-
- p2DView->getCamera()->setViewport(0, 0, 800, 800);
- p2DView->getCamera()->setProjectionMatrixAsOrtho2D(osgEarth::MERC_MINX, osgEarth::MERC_MAXX, osgEarth::MERC_MINY, osgEarth::MERC_MAXY);
- p2DView->getCamera()->setGraphicsContext(p3DView->getCamera()->getGraphicsContext());
- osgEarth::GLUtils::setGlobalDefaults(p3DView->getCamera()->getOrCreateStateSet());
- viewer.addView(p2DView);
-
- osgEarth::MapNode* p3DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
- p3DMapNode->setEnableLighting(false);
- osg::Group* p3MapGroup = new osg::Group;
- p3MapGroup->addChild(p3DMapNode);
- p3DView->setSceneData(p3MapGroup);
-
- osgEarth::MapNode* p2DMapNode = dynamic_cast<osgEarth::MapNode*>(osgDB::readNodeFile(strEarthFile));
-
- p2DMapNode->getMap()->setProfile(osgEarth::Profile::create(osgEarth::Profile::PLATE_CARREE));
- osgEarth::LayerVector layers;
- p2DMapNode->getMap()->getLayers(layers);
- for (auto itr : layers)
- {
- p2DMapNode->getMap()->removeLayer(itr);
- }
- p2DMapNode->getMap()->addLayers(layers);
-
- osg::Group* p2DMapGroup = new osg::Group;
- p2DMapGroup->addChild(p2DMapNode);
- p2DView->setSceneData(p2DMapGroup);
-
- viewer.run();
- }
-
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。