例子学习第一天

今天是2019年2.26,接下来的一段时间开始研究关于在osgEarth中地形整(压平)的事儿,最后的应用就是开路,在osgEarth地球的表面,比如山上能自动生成道路之类的。
首先看下例子的效果介绍

还是很酷炫的,羡慕啊,开始干吧。
好久没摸oe了,只能一点一点来,在vs2010中随便选了个例子cpp,这里选择的是

但是里面有好多用不上的代码(应该吧),先注销掉。上面一堆包含都没管,菜鸟一只,也分辨不出来,啥Handler都留着,没管。

#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 <osgEarth/VerticalDatum>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/Controls>
#include <osgEarthUtil/LatLongFormatter>
#include <osgEarthUtil/ExampleResources>
#include <osgEarthAnnotation/PlaceNode>
#include <iomanip>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;
static LabelControl*  s_mslLabel    = 0L;
static LabelControl*  s_haeLabel    = 0L;
static LabelControl*  s_egm96Label  = 0L;
static LabelControl*  s_mapLabel    = 0L;
static LabelControl*  s_resLabel    = 0L;
static PlaceNode*     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() ),_query    ( s_mapNode->getMap() ){_map = s_mapNode->getMap();_query.setMaxTilesToCache(10);_query.setFallBackOnNoData( false );_path.push_back( s_mapNode->getTerrainEngine() );}void update( float x, float y, osgViewer::View* view ){bool yes = false;// look under the mouse:osg::Vec3d world;osgUtil::LineSegmentIntersector::Intersections hits;if ( view->computeIntersections(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; // max.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 );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) );s_mslLabel->setText( Stringify() << out_hamsl );s_haeLabel->setText( Stringify() << mapPointGeodetic.z() );s_resLabel->setText( Stringify() << out_resolution );double egm96z = mapPoint.z();VerticalDatum::transform(mapPointGeodetic.getSRS()->getVerticalDatum(),VerticalDatum::get("egm96"),mapPointGeodetic.y(),mapPointGeodetic.x(),egm96z);s_egm96Label->setText(Stringify() << egm96z);yes = true;}// finally, get a normal ISECT HAE point.GeoPoint isectPoint;isectPoint.fromWorld( _terrain->getSRS()->getGeodeticSRS(), world );s_mapLabel->setText( Stringify() << isectPoint.alt() );// and move the marker.s_marker->setPosition(mapPoint);}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<osgViewer::View*>(aa.asView());update( ea.getX(), ea.getY(), view );return true;}return false;}const Map*       _map;const Terrain*   _terrain;bool             _mouseDown;ElevationQuery   _query;osg::NodePath    _path;
};int main(int argc, char** argv)
{osg::ArgumentParser arguments(&argc,argv);osgViewer::Viewer viewer(arguments);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 );// 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();
}

然后再看一眼 feature_elevation.earth文件,用的是Nodepad++打开的。英文不太好,把所有的英文都翻译了中文。

<!--
osgEarth Sample - Feature to elevation driver.
--><map name="Feature Elevation Demo" type="geocentric" version="2"><image name="readymap_imagery" driver="gdal"><url>../data/world.tif</url></image>     <image name="readymap_imagery" driver="gdal"><url>../data/fujian.tif</url></image><!-- Add some base elevation 添加一些基本高程--><elevation name="readymap_elevation" driver="tms" enabled="true"><url>http://readymap.org/readymap/tiles/1.0.0/116/</url></elevation><!--Add a shapefile to flatten the underlying elevation. 添加shapefile以展平基础高程。--><elevation name="flatten" driver="feature_elevation" enabled="true" attr="ELEVATION"><!-- Specify a min_level so that we don't waste resources generating heightfields when they won't actually be visible 指定min_level,这样我们就不会浪费资源生成实际上不可见的高度字段--><min_level>7</min_level><!--Because a feature dataset has theoretically infinite pixels resolutions, we specify a max level to keep a cap on how far down it generates data.  This is also critical for any code that uses terrain clamping so that it won't try to generate unnecessarily highresolution heightfields 由于要素数据集在理论上具有无限的像素分辨率,因此我们指定最大级别以限制其生成数据的距离。 这对于使用地形钳位的任何代码来说也是至关重要的,这样它就不会试图产生不必要的高分辨率高度场--><max_level>17</max_level><!-- Specify a profile that matches the map's profile so no unnecssary reprojection and mosaicing occurs 指定与地图配置文件匹配的配置文件,以便不会发生不必要的重新投影和镶嵌--><profile>global-geodetic</profile><features name="flatten" driver="ogr"><url>../data/flatten_mt_rainier.shp</url><build_spatial_index>true</build_spatial_index></features></elevation><viewpoints><viewpoint><name>Mt Rainier</name><heading>-21.7843</heading><pitch>-27.566</pitch><range>38701.6m</range><long>-121.7706234748925</long><lat>46.84187674081022</lat><height>-0.002506599761545658</height></viewpoint></viewpoints></map>

这里要注意,添加地图的时候,精度低的要在前面,精度高的放下面,不然会遮挡掉。

这里福建省的在上,全球图在下就只会显示全球图了,如下

就完全看不到福建,反之调换顺序,结果如下

福建出来啦!图是在91卫图下的,有水印,拿来做实验哈哈。总之福建出来了。
还有一点,tif格式的图用的驱动器用gdal就行,驱动器是来决定如何解析图片的(应该hah)
现在很好奇,高程是怎么显示出来的,继续下载了福建省的高程数据,感觉着福建这地图太丑了,影响体验,先不显示它了!把名称➕个1,让编译器找不着,就不显示了哈哈

earth文件中添加地图的下一个就是添加高程,感觉有戏,从这里入手试试

就很奇怪,我下载的高程数据类型咋还是tif呢。。有点困惑

加载试试。把数据拷到path下的data,把名字改成英文 fujian_elevation.tif,把驱动器改成gdal

运行测试!可是,,有一种,,不详滴预感,,
果然,啥起伏都没,失败了

另想办法。
突然发现我url的斜杆写反了。。改回来之后测试还是不行~

从别人那儿拷一个能用的DEM试试,据说这种方法思路没问题,就是如果追求效率需要导入arcgis操作一番,建立索引。

等待dem中…

拿到了dem之后试了一下,是可以的,然后再回头测试,发现直接下载的tif应该是可以用的,只是下载的精度不够高,太不明显了。以下都用拷来的DEM来进行测试。

效果图如下

金线是边界,淮河流域边界,下面是拉近之后的图

底图精度太低,糊了吧唧的看不清,按W切换成格网就能看到了,如下

第一步成功!!!地形加载上啦!!

然后思考如何做出例子的那种下陷平台的效果。第一个想法,用arcgis弄一个线状要素shp,给加上一个高程值,然后就行了,因为手头刚好有淮河的边界,于是在arcgis进行一番操作,加载上之后,悲剧了
因为加了LOD,在拉近到差不多的地方开始加载金线时,控制台被

刷屏了,是如下的语句

没有深究,应该是feature_elevation驱动器不支持线状要素吧~那就
换成面!

又找了整个淮河流域的面进行测试,之前毫无经验,虽然是gis专业,但是对投影,地理坐标系一知半解,找到面状shp就直接糊上去用了,运行起来,毫无区别,按F变成窗口之后,发现控制台有提示,如下

Specified profile does not match feature profile, ignoring specified profile.
谷歌翻译为:
指定的配置文件与功能配置文件不匹配,忽略指定的配置文件。

思考了半天,指定的配置文件应该就是输入的那个shp,功能配置文件嘛。。往上看了一眼,发现有一行之前看不懂忽略了的代码:

本着多一事不如少一事的端正思想,直接把这行代码注释,果然!
还是不行

这回跳出的提示是

No profile specified; falling back on feature profile.
谷歌翻译:
未指定个人资料; 回到功能配置文件。
好嘛,还是不行,绕不过去了,盘它!

通过“南水之源”大大的详解文章(下附链接)
https://www.cnblogs.com/lyggqm/p/6371583.html?utm_source=itdadao&utm_medium=referral

其中对于标签的解释是:
<!—坐标投影属性,该属性相当于渲染数据的地理空间上下文,它决定了系统以哪种方式将世界坐标数据投影到屏幕像素。为了正确渲染影像数据以及高程数据,osgEarth需要知道数据源的profile以及渲染时的profile以进行必要的转换。–>

<!—由于WGS84比较著名,所以可以用下面的简化方式代替上面的定义–>
global-geodetic

这时候应该能明白这个标签的作用是指定一下来源数据的地理坐标系,遂打开好久好久不用的arcmap10.2,把shp文件丢进去,读取之后打开属性一看

管它是个啥,反正这玩意儿不是WGS84!改!

这时候才发现好多知识点缺失了,咋改啊。。百度大法走起!

搜索一番,找到了办法,本文中具体额外知识点会另起文章介绍,本文篇幅有限不再赘述。

总之,改了投影之后的数据长这样:

本来shp只是个平面,啥也没有,我添加了一个字段“Z”,数值使用默认值0,然后转化成3D数据集,想用这个大榔头把地形砸扁,具体操作另说!

这时候用这个加进去,发现控制台一片祥和,啥错也没报,然而地球上也一片祥和,啥起伏都没

又失败了。。

死马当活马医,把LOD注释掉,可能我没有拖到正确的缩放级别,电脑性能也慢了点,错了变化也说不定。

出现了!蜜汁突起!!可是这又是什么鬼啊。。我定的高程是0,该给我凹下去啊!!!

这时感谢师兄提点,弄个小一点的面试试,用arcgis扣一个小矩形。

听起来很美好,结果又触及了知识盲区。。扣啥。。好像之前学过,可是怎么做来着。。。

百度大法之后得到解决。


在一个地形起伏最大的地方扣了一个方块,扣的时候把投影设置为WGS84,起名“test5.shp”,看到这,大家应该想到啥了吧!配角是不配拥有姓名的!所以!!咱们的主角test5要来了!!!

加进去之后。。。

果然。。


啊!这美丽的竖线!!这美丽的断崖!!!

按下W键

啊!!!!!!!这美丽的绿色瀑布!!!!!!!!!!

改个格式加把火,用标签,在南水大大的贴之中,是这样解释的:
<!—定义模型数据,属性包括名称、驱动器driver、最小可视范围值min_range(层次节点LOD范围)、最大可视范围值max_range、是否以覆盖方式覆盖到地形上overlay,对于指定的可视范围值,如果指定了gridding,该范围将作用于被分割的一个个的网格而不是模型几何体本身–>

把画边框的代码复制一遍,改下数据源:

启动!!



终于把这一方天地给砸扁了 !

收工撒花~

第一天的工作结束,明天还有什么等着我的~

osgEarth例子学习-feature_elevation.earth相关推荐

  1. 数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇

    HT 是啥:Everything you need to create cutting-edge 2D and 3D visualization. 这口号是当年心目中的产品方向,接着就朝这个方向慢慢打 ...

  2. Liferay例子学习,如何部署简单的jsp portlet

    http://blog.chinaunix.net/space.php?uid=9195812&do=blog&id=2006478 Liferay例子学习 (2007-07-23 1 ...

  3. 质量属性效用树例子_数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇

    HT 是啥:Everything you need to create cutting-edge 2D and 3D visualization. 这口号是当年心目中的产品方向,接着就朝这个方向慢慢打 ...

  4. PyTorch 1.0 中文官方教程:用例子学习 PyTorch

    译者:bat67 最新版会在译者仓库首先同步. 作者:Justin Johnson 这个教程通过自洽的示例介绍了PyTorch的基本概念. PyTorch主要是提供了两个核心的功能特性: 一个类似于n ...

  5. C#坏习惯:通过不好的例子学习如何制作好的代码——第5部分

    目录 介绍 定义和历史 我如何理解OCP? 我如何理解OCP? 3个级别 当代码关闭时 预测未来和YAGNI 让我们编码 不好的例子 更好的方法 SOLID恰当的结合在一起 更多例子 修改或扩展 什么 ...

  6. C#坏习惯:通过不好的例子学习如何制作好的代码——第4部分

    目录 介绍 没有"一个真正的来源" 它为什么如此重要? 文章的形式 1.吃异常 2.不正确的日志记录 3.重新抛出异常和方法上下文日志记录 4.控制程序流程的异常 全局异常处理 总 ...

  7. C#坏习惯:通过不好的例子学习如何制作好的代码——第3部分

    目录 这篇文章的目标 什么是c#中的静态类? 我们去看看代码 问题 单元测试 未来的变化 如何修复?? !! 第一步 第二步 第三步 第四步 这次改变后我们获得了什么? 单元测试问题--已解决 未来的 ...

  8. C#坏习惯:通过不好的例子学习如何制作好的代码——第2部分

    目录 介绍 这篇文章的目标 Switch case与字典模式 第一个问题 第二个问题 更有力的例子 了解对象的生命周期 有用的字典 每次调用相同的实例 基础(Basic)版本 代码外的配置 在单独的源 ...

  9. C#坏习惯:通过不好的例子学习如何制作好的代码——第1部分

    目录 介绍 类写得那么糟糕...... 1.命名 2.神奇数字      ​ 3.不明显的错误 4.不可读 5.神奇数字--又一次 6.DRY--不要重复自己 7.每类多重责任 重构... I STE ...

最新文章

  1. 用递归和非递归的方法求解n的k次方
  2. 计算机事业单位专技岗考什么区别,事业单位管理和专技岗位有什么区别?哪个有前途?...
  3. vue的post请求data可以传两个参吗_我知道的HTTP请求
  4. centos7.3 编译安装 git 2.13
  5. pg加密扩展的安装_postgresql的加密扩展插件pgcrypto
  6. 户外lisp导向牌如何安装_聚焦热点、难点,持续开展户外广告(招牌)专项整治...
  7. jdk8 cms g1gc_JDK 14:CMS GC是OBE
  8. python绝对导入_[编程基础] Python中的绝对导入与相对导入
  9. Matplotlib 中文用户指南 6 自定义 matplotlib
  10. xstart连不上linux_Xstart远程连接Linux图形用户界面
  11. 2018 OpenInfra Days China 大咖来袭——开源,我们是认真的
  12. SQL 增删改查语句
  13. 使用 CP2102通过串口下载程序到STM32F103中 (MCUISP)
  14. laravel文档链接
  15. 计算机发展史上一些重要的著作
  16. MinIO-linux-amd64下载
  17. html页面中汉字上面显示拼音
  18. python 连接数据库导数_python – 使用MongoDB聚合框架计算一阶导数
  19. Mysql information_schema库
  20. 2021周记11:慢慢自律和追剧

热门文章

  1. 北大教授王汉生论述数据治理(非常有思想,非常好理解)
  2. php水解蛋白技术,乳蛋白部分水解配方奶粉:美赞臣亲舒
  3. day02【Collection、泛型】-笔记
  4. 使用 assembly 打包报错
  5. mac使用php无法写入文件,mac移动硬盘无法写入怎么办
  6. SQL数据库脚本操作(WINCC VBS脚本)
  7. 云服务平台有哪些?云算力网络哪家强?
  8. sklearn - Dimensionality reduction
  9. kettle基本概念
  10. 华科世界第六,北邮碾压伯克利:USNews世界大学CS榜发布