1. 概述

我在《OSG加载倾斜摄影数据》这篇博文中论述了如何通过OSG生成一个整体的索引文件,通过这个索引文件来正确显示ContextCapture(Smart3D)生成的倾斜摄影模型数据。这类倾斜摄影模型数据一般都会有个元数据metadata.xml,通过这个元数据,可以将其正确显示在osgEarth的数字地球上。

2. 详论

2.1. 位置

metadata.xml中的内容一般如下所示:

SRS就是空间坐标参考的意思,ENU表示是东北天站心坐标系,站心点的经纬度坐标为(108.9594, 34.2196)。这个站心点对应的应该是倾斜摄影模型的中心点,那么思路就很简单了,只需要平移旋转这个倾斜摄影模型,使模型的中心点对应于站心点。这其实是个地心坐标系于站心坐标系转换的问题:

在osgEarth中可以不用关心这个问题,其直接封装了一个类osgEarth::GeoTransform,可以直接通过这个类的接口来加载倾斜摄影模型:

std::string filePath = "D:/Data/scene/Dayanta/Data.osgb";
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(filePath); osg::ref_ptr<osgEarth::GeoTransform> xform = new osgEarth::GeoTransform();
xform->addChild(node);
xform->setTerrain(mapNode->getTerrain());
osgEarth::GeoPoint point(map->getSRS(), 108.9594, 34.2196, -410); //使用绝对高,正高
xform->setPosition(point); osg::ref_ptr<osgEarth::ModelLayer> modelLayer = new osgEarth::ModelLayer("oblic", xform);
map->addLayer(modelLayer);

给osgEarth::GeoTransform传入的osgEarth::GeoPoint就是站心点。不过这种类型的metadata.xml似乎都没有给出准确的高程值,所以需要自己调整高程来贴地。可能因为我这里试用的倾斜摄影数据都是网上找的,不太可能给出准确的地理坐标。

2.2. 着色

另外一点要注意的是直接读取加载的倾斜摄影模型是没有颜色信息的,这点和OSG还不太一样,在帮助文档里面论述了这个问题:

所以一定要记得加上着色器渲染,否则倾斜摄影模型会变成白模:

osgEarth::Registry::shaderGenerator().run(node);

2.3. 其他

有的metadata.xml里面的内容是这样的:

这个元数据的意思是这个倾斜摄影模型是根据EPSG编号为2384的空间参考坐标系下构建的。简单查了一下这个坐标系应该是xian80高斯克吕格平面投影直角坐标系,因为是用于三维数据,所以加上一个高程形成一个三维立体直角坐标系。严格意义上来讲,是需要将地球展成这个立体直角坐标系,将这个倾斜摄影模型放置到SRSOrigin的地理位置才是最准确的。但是一般的投影东向和北向的方向是不会变的,仍然可以将SRSOrigin的地理位置当成一个站心位置,只不过这个站心位置不再是经纬度而是EPSG:2384的平面坐标值(加上高程)。

所以像这种类型的数据,只需要将SRSOrigin的地理位置值转换成经纬度值,就变成2.1中描述的情况了。

3. 结果

具体的实现代码如下:

#include <Windows.h>
#include <iostream>
#include <string> #include <osgViewer/Viewer>
#include <osgDB/ReadFile> #include <osgEarth/MapNode> #include <osgEarthDrivers/gdal/GDALOptions>
#include <osgEarthDrivers/cache_filesystem/FileSystemCache>
#include <osgEarth/ImageLayer>
#include <osgEarth/Viewpoint>
#include <osgEarth/GeoTransform>
#include <osgEarth/ModelLayer>
#include <osgEarth/Registry> #include <osgEarthUtil/EarthManipulator> #include <gdal_priv.h> using namespace std; void AddModel(osg::ref_ptr<osgEarth::Map> map, osg::ref_ptr<osgEarth::MapNode> mapNode)
{
//
std::string filePath = "D:/Data/scene/Dayanta/Data.osgb";
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(filePath); osg::ref_ptr<osgEarth::GeoTransform> xform = new osgEarth::GeoTransform();
xform->addChild(node);
xform->setTerrain(mapNode->getTerrain());
osgEarth::GeoPoint point(map->getSRS(), 108.9594, 34.2196, -410); //使用绝对高,正高
xform->setPosition(point); osg::ref_ptr<osgEarth::ModelLayer> modelLayer = new osgEarth::ModelLayer("oblic", xform);
map->addLayer(modelLayer); osgEarth::Registry::shaderGenerator().run(node);
} int main()
{
CPLSetConfigOption("GDAL_DATA", "D:/Work/OSGNewBuild/OpenSceneGraph-3.6.4/3rdParty/x64/gdal-data"); //string wktString = "EPSG:3857"; //web墨卡托投影
//string wktString = "EPSG:4326"; //wgs84
osgEarth::ProfileOptions profileOpts;
//profileOpts.srsString() = wktString; //osgEarth::Bounds bs(535139, 3365107, 545139, 3375107);
//osgEarth::Bounds bs(73, 3, 135, 53);
//profileOpts.bounds() = bs; //地图配置:设置缓存目录
osgEarth::Drivers::FileSystemCacheOptions cacheOpts;
string cacheDir = "D:/Work/OSGNewBuild/tmp";
cacheOpts.rootPath() = cacheDir; //
osgEarth::MapOptions mapOpts;
mapOpts.cache() = cacheOpts;
//mapOpts.coordSysType() = osgEarth::MapOptions::CSTYPE_PROJECTED; mapOpts.profile() = profileOpts; //创建地图节点
osg::ref_ptr<osgEarth::Map> map = new osgEarth::Map(mapOpts);
osg::ref_ptr<osgEarth::MapNode> mapNode = new osgEarth::MapNode(map); osgEarth::Drivers::GDALOptions gdal;
//gdal.url() = "D:/Work/OSGNewBuild/osgearth-2.10.1/data/world.tif";
//gdal.url() = "D:/Work/SinianGIS/bin/Resource/BlueMarbleNASA.jpg";
gdal.url() = "D:/Work/SinianGIS/bin/Resource/baseMap.jpg";
osg::ref_ptr<osgEarth::ImageLayer> imgLayer = new osgEarth::ImageLayer("BlueMarble", gdal);
map->addLayer(imgLayer); AddModel(map, mapNode); osgViewer::Viewer viewer;
viewer.getCamera()->setClearColor(osg::Vec4(0, 0, 0, 0));
viewer.setSceneData(mapNode); osg::ref_ptr< osgEarth::Util::EarthManipulator> mainManipulator = new osgEarth::Util::EarthManipulator;
viewer.setCameraManipulator(mainManipulator); osgEarth::Viewpoint vp;
osgEarth::GeoPoint newPoint(map->getSRS(), 108.9594, 34.2196, 0);
vp.focalPoint() = newPoint;
vp.heading() = 0;
vp.pitch() = -90;
vp.range() = 1000;
mainManipulator->setViewpoint(vp); viewer.setUpViewInWindow(100, 100, 800, 600); return viewer.run();
}

运行结果如下:

4. 参考

  1. GNSS学习笔记-坐标转换

osgEarth使用笔记3——加载倾斜摄影数据的更多相关文章

  1. Cesium加载倾斜摄影数据

    (1)倾斜摄影数据仅支持 smart3d 格式的 osgb 组织方式, 数据目录必须有一个 “Data” 目录的总入口, “Data” 目录同级放置一个 metadata.xml 文件用来记录模型的位 ...

  2. osgEarth使用笔记4——加载矢量数据

    目录 1. 概述 2. 详论 2.1. 基本绘制 2.2. 矢量符号化 2.2.1. 可见性 2.2.2. 高度设置 2.2.3. 符号化 2.2.4. 显示标注 2.3. 其他 3. 结果 4. 问 ...

  3. OSG加载倾斜摄影数据

    目录 1. 概述 2. 实例 2.1. 代码 2.2. 解析 3. 结果 1. 概述 ContextCapture(Smart3D)生成的倾斜摄影模型数据一般都形如如下组织结构: 在Data目录下包含 ...

  4. 笔记-VUE滚动加载更多数据

    来源:https://blog.csdn.net/qq_17281881/article/details/87342403 VUE滚动加载更多数据 data() { return { loading: ...

  5. 配置vuejs加载模拟数据

    [个人笔记,非技术博客] 1.使用前确保安装axios插件,vuejs官方推荐,当然使用其他插件也可以 2.配置dev-server.js var router = express.Router(); ...

  6. geotrellis使用(二十三)动态加载时间序列数据

    目录 前言 实现方法 总结 一.前言        今天要介绍的绝对是华丽的干货.比如我们从互联网上下载到了一系列(每天或者月平均等)的MODIS数据,我们怎么能够对比同一区域不同时间的数据情况,采用 ...

  7. WPF DataGrid 性能加载大数据

    WPF(Windows Presentation Foundation)应用程序在没有图形加速设备的机器上运行速度很慢是个公开的秘密,给用户的感觉是它太吃资源了,WPF程序的性能和硬件确实有很大的关系 ...

  8. 基于zepto的H5/移动端tab切换触摸拖动加载更多数据

    以前实现移动端的滑动加载更多实现的方法是当滚动条快到页面底部时就自动加载更多的数据,在这方面很多人都用的是"西门的后花园"写的一个叫dropload的插件,这个插件用起来也很好,很 ...

  9. iOS --- UIWebView的加载本地数据的三种方式

    UIWebView是IOS内置的浏览器,可以浏览网页,打开文档  html/htm  pdf   docx  txt等格式的文件.  safari浏览器就是通过UIWebView做的. 服务器将MIM ...

  10. jQuery.ajax( options ) : 通过 HTTP 请求加载远程数据

    jQuery.ajax( options ) : 通过 HTTP 请求加载远程数据 这个是jQuery 的底层 AJAX 实现.简单易用的高层实现见 $.get, $.post 等. $.ajax() ...

随机推荐

  1. 如何用ppt打印9张一面,并且去除边距?

    如何用ppt打印9张一面,并且去除边距?      方法其实很简单,答主不要在ppt软件的打印选项里设置[每页打印9张幻灯片],而是使用默认的[每页打印1张幻灯片]. 然后去[打印机属性]里设置,我是 ...

  2. 【题解】《PTA-Python程序设计》题目集分享

    第1章-1 从键盘输入两个数,求它们的和并输出 (30 分) 本题目要求读入2个整数A和B,然后输出它们的和. 输入格式: 在一行中给出一个被加数在另一行中给出一个加数 输出格式: 在一行中输出和值. ...

  3. 第六单元《管理学进展》单元测试 mooc

    第六单元<管理学进展>单元测试 返回 本次得分为:10.00/10.00, 本次测试的提交时间为:2020-08-30, 如果你认为本次测试成绩不理想,你可以选择 再做一次 . 1 判断( ...

  4. Oracle和达梦:连接多行查询结果

    Oracle和达梦:LISTAGG连接查询结果 LISTAGG介绍 使用LISTAGG函数,您可以将多行数据连接成一个字符串,并指定分隔符进行分隔.这在需要将多行数据合并为单个字符串的情况下非常有用, ...

  5. Linux 在多个文件中搜索关键字

    摘要:使用grep或者rg在当前目录下所有文件中查找关键字.   在Linux操作系统下,搜索文件中的关键字可帮助用户快速找到所需的信息,满足快速排查问题的需求.在大型系统中,文件可能被保存在多个目录 ...

  6. [AHOI2002] Kitty猫基因突变

    我们不妨将所有权值打到一棵树上,这很容易想到. 考虑暴力,如果我们选择了 \(w\) 个点,修改后我们会从叶子节点依次合并去计算贡献. 很显然我们可以动态规划维护. \(f[p][w][0/1/2]\ ...

  7. Vue之键盘事件

    1.使用keydown触发事件 <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  8. 多维评测指标解读第17届MSU世界编码器大赛全高清10bit赛道结果

    超高清视频纤毫毕现的关键一环. 01 主要指标多项第一,带宽节省48% 近日,第17届MSU世界编码器大赛全高清10bit赛道成绩揭晓,阿里自研的H.266/VVC编码器Ali266在该赛道最高效的1 ...

  9. Unity - Windows获取屏幕分辨率、可用区域

    直接搜索最多的就是使用System.Windows.Form.Screen类,但因为unity用的是mono,不能正常使用这个方法 可使用win32api获取,这里只尝试了获取主要屏幕的分辨率,而且没 ...

  10. 【爬虫】一次爬取某瓣top电影前250的学习记录

    先贴上爬取的脚本: import requests import re for i in range(1,11):     num=(i-1)*25     url=f"https://mo ...