前言

本节分析osgearth_minimap示例。在示例中,拖动三维地图,二维地图上的label标签会移动。二维地图支持拖动和缩放。

代码的目的是:让标签始终跟随三维视点的坐标进行更新。但是,运行过程中,感觉label标签的位置有时候会不对。因为当三维地球放大到中国地图内时,理论来讲label应该定位在中国区域内,但是并没有。目前还没有梳理清楚坐标转换的关系。

在加载三维地图时,采用的读取earth文件方式。而二维地图加载时,更改earth文件的 type=projected,直接读取tif文件。多次尝试直接读取earth文件方式创建二维地图,一直没有成功。如果哪位大佬恰好知道如何操作,烦请告知一下,不胜感激。

earth示例文件如下:

<!-- ----------三维地图的earth文件------------------ -->
<map name="Globe" type="geocentric" version = "2"><!--此为全球影像图--><image name="GlobeImage" driver="gdal"><url>./globe/globel.tif</url></image>
</map><!-- ----------二维地图的earth文件------------------ -->
<map name="Globe" type="projected" version = "2"><!--此为全球影像图--><image name="GlobeImage" driver="gdal"><url>./globe/globel.tif</url></image>
</map>

执行效果

左下角有二维图,二维图上有一个label,当转动地球时,二维地图的label会移动位置。二维地图可以缩放移动。正常运行情况如下:

当把地图放大,并且定位到局部区域时,会出现矩形框定位。

代码分析

#include <osg/Notify>
#include <osgViewer/Viewer>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/ExampleResources>
#include <osgEarthAnnotation/PlaceNode>
#include <osgEarthAnnotation/FeatureNode>
#include <osgViewer/CompositeViewer>
#include <osgEarthDrivers/gdal/GDALOptions>
#include <osgEarth/ImageLayer>#define LC "[viewer] "using namespace osgEarth;
using namespace osgEarth::Util;
using namespace osgEarth::Annotation;
using namespace osgEarth::Drivers;/*** Makes a simple projected MapNode that contains a basemap of the world*/
// 通过直接读取tif文件的方式,创建二维地图
MapNode* makeMiniMapNode( ) {    MapOptions mapOpt;mapOpt.coordSysType() = MapOptions::CSTYPE_PROJECTED;  // 二维地图时,此处需要设置为投影形式mapOpt.profile() = ProfileOptions("plate-carre");// 二维图属性Map* map = new Map( mapOpt );    GDALOptions basemapOpt;basemapOpt.url() = "../data/world.tif";map->addLayer( new ImageLayer( ImageLayerOptions("basemap", basemapOpt) ) );//"basemap" 自定义即可// That's it, the map is ready; now create a MapNode to render the Map:MapNodeOptions mapNodeOptions;mapNodeOptions.enableLighting() = false;    return new MapNode( map, mapNodeOptions );
}// 绘制小地图
// 当移动地球时,如果地球整个都在主视图区可见,则二维地图显示完整。
// 当放大地球时,仅地球的部分区域在主视图区域,则二维地图会出现红色矩形,且随着主窗口显示的地区区域进行标绘。
osg::Node* drawBounds(MapNode* mapNode, osgEarth::GeoExtent& bounds)
{// 当整个地球都呈献在主窗口时,执行if分支if (bounds.crossesAntimeridian()){// 当转动地球,在南北极拖动时,程序会运行此分支。GeoExtent first, second;bounds.splitAcrossAntimeridian(first, second);osg::Group* group = new osg::Group;group->addChild( drawBounds( mapNode, first ) );group->addChild( drawBounds( mapNode, second) );return group;}else{// 绘制矩形的坐标,定位osgEarth::Symbology::LineString* geom = new osgEarth::Symbology::LineString();geom->push_back(osg::Vec3d(bounds.xMin(), bounds.yMin(), 0));geom->push_back(osg::Vec3d(bounds.xMax(), bounds.yMin(), 0));geom->push_back(osg::Vec3d(bounds.xMax(), bounds.yMax(), 0));geom->push_back(osg::Vec3d(bounds.xMin(), bounds.yMax(), 0));geom->push_back(osg::Vec3d(bounds.xMin(), bounds.yMin(), 0));// 通过geom和坐标系,创建featureosgEarth::Features::Feature* feature = new osgEarth::Features::Feature(geom, osgEarth::SpatialReference::create("wgs84"));Style style;style.getOrCreateSymbol<LineSymbol>()->stroke()->color() = Color::Yellow;style.getOrCreateSymbol<LineSymbol>()->stroke()->width() = 3;style.getOrCreateSymbol<PolygonSymbol>()->fill() = Color::Red;feature->style() = style;FeatureNode* featureNode = new FeatureNode(feature);featureNode->setMapNode(mapNode);// 关闭深度测试,让此多边形一直浮在地图之上featureNode->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);return featureNode;}
}// 轴对齐的地理空间范围。与空间参照的坐标系对齐的边界框。
// 传入主视图view
osgEarth::GeoExtent getExtent(osgViewer::View* view)
{// Get the corners of all points on the view frustum.  Mostly modified from osgthirdpersonview// 获取视图平截头体上所有点的角点。大部分是从osgthirdpersview修改的。// 投影矩阵osg::Matrixd proj = view->getCamera()->getProjectionMatrix();// 视口矩阵osg::Matrixd mv = view->getCamera()->getViewMatrix();// 视口矩阵的逆矩阵osg::Matrixd invmv = osg::Matrixd::inverse( mv );// 以下计算,是为了获取拉进状态时,4个角点的位置,和拉远状态时,4个角点的位置double nearPlane = proj(3,2) / (proj(2,2)-1.0);double farPlane = proj(3,2) / (1.0+proj(2,2));// Get the sides of the near plane.double nLeft = nearPlane * (proj(2,0)-1.0) / proj(0,0);double nRight = nearPlane * (1.0+proj(2,0)) / proj(0,0);double nTop = nearPlane * (1.0+proj(2,1)) / proj(1,1);double nBottom = nearPlane * (proj(2,1)-1.0) / proj(1,1);// Get the sides of the far plane.double fLeft = farPlane * (proj(2,0)-1.0) / proj(0,0);double fRight = farPlane * (1.0+proj(2,0)) / proj(0,0);double fTop = farPlane * (1.0+proj(2,1)) / proj(1,1);double fBottom = farPlane * (proj(2,1)-1.0) / proj(1,1);double dist = farPlane - nearPlane;std::vector< osg::Vec3d > verts;verts.reserve(9);// Include origin?//verts.push_back(osg::Vec3d(0., 0., 0. ));verts.push_back(osg::Vec3d( nLeft, nBottom, -nearPlane ));verts.push_back(osg::Vec3d( nRight, nBottom, -nearPlane ));verts.push_back(osg::Vec3d( nRight, nTop, -nearPlane ));verts.push_back(osg::Vec3d( nLeft, nTop, -nearPlane ));verts.push_back(osg::Vec3d( fLeft, fBottom, -farPlane ));verts.push_back(osg::Vec3d( fRight, fBottom, -farPlane ));verts.push_back(osg::Vec3d( fRight, fTop, -farPlane ));verts.push_back(osg::Vec3d( fLeft, fTop, -farPlane ));// 设置空间参考坐标系 WGS84坐标系const osgEarth::SpatialReference* srs = osgEarth::SpatialReference::create("epsg:4326");// Compute the bounding sphere of the frustum.计算平截头体的边界球。// 声明包围球osg::BoundingSphered bs;for (unsigned int i = 0; i < verts.size(); i++){osg::Vec3d world = verts[i] * invmv;// 拓展这个包围球,使其能够容纳指定的顶点。bs.expandBy( world );}// Get the center of the bounding sphere// 根据坐标系和包围球,获取到中心点osgEarth::GeoPoint center;center.fromWorld(srs, bs.center());double radiusDegrees = bs.radius() /= 111000.0;double minLon = center.x() - radiusDegrees;double minLat = osg::clampAbove(center.y() - radiusDegrees, -90.0);double maxLon = center.x() + radiusDegrees;double maxLat = osg::clampBelow(center.y() + radiusDegrees, 90.0);// 最终根据坐标系、经纬度范围,创建extentosgEarth::GeoExtent extent(srs, minLon, minLat, maxLon, maxLat);return extent;
}int
main(int argc, char** argv)
{osg::ArgumentParser arguments(&argc,argv);//Setup a CompositeViewer,// 声明 多视景器类osgViewer::CompositeViewer viewer(arguments);//Setup our main view that will show the loaded earth file.// 声明主视景器,三维地球osgViewer::View* mainView = new osgViewer::View();// 设置 透视图的近远率mainView->getCamera()->setNearFarRatio(0.00002);// 添加操作器mainView->setCameraManipulator( new EarthManipulator() );      // 官方已经弃置setUpViewInWindow方法,建议采用 view.apply(new osgViewer::SingleWindow(x,y,width,screenNum))方法,设置窗口// 但是全局搜索,并未发现osgViewer::SingleWindow 此方法的声明和实现mainView->setUpViewInWindow( 50, 50, 800, 800 );// 主视景器,显示三维地球,添加到多视景器对象viewer.addView( mainView );//Setup a MiniMap View that will be embedded in the main view// 设置MiniMap视图,嵌入主视图int miniMapWidth = 400;int miniMapHeight = 200;osgViewer::View* miniMapView = new osgViewer::View();// 左下角小地图miniMapView->getCamera()->setNearFarRatio(0.00002);miniMapView->getCamera()->setViewport( 0, 0, miniMapWidth, miniMapHeight);  // 设置视景器大小  miniMapView->setCameraManipulator( new EarthManipulator() );    // 添加操作器miniMapView->getCamera()->setClearColor( osg::Vec4(0,0,0,0));// 设置适用于 该窗口尺寸的投影透视矩阵策略:// FIXED:保持投影矩阵固定,无论窗口大小如何。// HORIZONTAL:调整窗口大小时的水平视野。// VERTICAL:调整窗口大小时的垂直视野。miniMapView->getCamera()->setProjectionResizePolicy( osg::Camera::FIXED );// 透视矩阵参数设置miniMapView->getCamera()->setProjectionMatrixAsPerspective(30.0, double(miniMapWidth) / double(miniMapHeight), 1.0, 1000.0);//Share a graphics context with the main view// 将小地图绘制在主场景的绘图设备上下文中miniMapView->getCamera()->setGraphicsContext( mainView->getCamera()->getGraphicsContext());  // 添加到多视景器对象viewer.addView( miniMapView );// load an earth file, and support all or our example command-line options// and earth file <external> tags    osg::Node* node = MapNodeHelper().load( arguments, &viewer );if ( node ){// 三维地图通过earth文件读取,此句话多余了。MapNode* mapNode = MapNode::findMapNode(node);//Set the main view's scene data to the loaded earth filemainView->setSceneData( node );//Setup a group to hold the contents of the MiniMaposg::Group* miniMapGroup = new osg::Group;// 创建二维地图MapNode* miniMapNode = makeMiniMapNode();        miniMapGroup->addChild( miniMapNode );//Get the main MapNode so we can do transformations between it and our minimap// 三维地图通过earth文件读取MapNode* mainMapNode = MapNode::findMapNode( node );//Set the scene data for the minimap// 设置小地图场景地图miniMapView->setSceneData( miniMapGroup );        //Add a marker we can move around with the main view's eye point// 在小地图上添加标记,跟随主视图的视点移动Style markerStyle;markerStyle.getOrCreate<IconSymbol>()->url()->setLiteral( "../data/placemark32.png" );PlaceNode* eyeMarker = new PlaceNode("视点", markerStyle);// 设置初始位置eyeMarker->setPosition(GeoPoint(miniMapNode->getMapSRS(), 0, 0));// 添加到节点组管理miniMapGroup->addChild( eyeMarker );// 设置渲染细节模式miniMapGroup->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin");osg::Node* bounds = 0;while (!viewer.done()){//Reset the viewport so that the camera's viewport is static and doesn't resize with window resizes// 随窗口移动,小地图保持相对位置不变miniMapView->getCamera()->setViewport( 0, 0, miniMapWidth, miniMapHeight);    //Get the eye point of the main view// 获取视点信息osg::Vec3d eye, up, center;mainView->getCamera()->getViewMatrixAsLookAt( eye, center, up );//Turn the eye into a geopoint and transform it to the minimap's SRSGeoPoint eyeGeo;// 获取主视图的点,初始化eyeGeoeyeGeo.fromWorld( mainMapNode->getMapSRS(), eye );// std::cout << "三维状态坐标:" << eyeGeo.x() << ","<< eyeGeo.y() << "," << eyeGeo.z() << std::endl;// 转换到地图中,更改eyeGeoeyeGeo.transform( miniMapNode->getMapSRS());// std::cout << "二维状态坐标:" << eyeGeo.x() << "," << eyeGeo.y() << "," << eyeGeo.z() << std::endl;//We want the marker to be positioned at elevation 0, so zero out any elevation in the eye point// 高度值改为0eyeGeo.z() = 0;           //Set the position of the marker// 给标签设置坐标eyeMarker->setPosition( eyeGeo );if (bounds){miniMapGroup->removeChild( bounds );}// 轴对齐的地理空间范围。与空间参照的坐标系对齐的边界框。GeoExtent extent = getExtent( mainView );// 根据获取到的边框范围,设置地图的包围球范围bounds = drawBounds( miniMapNode, extent );miniMapGroup->addChild( bounds );viewer.frame();}        }else{OE_NOTICE << "\nUsage: " << argv[0] << " file.earth" << std::endl<< MapNodeHelper().usage() << std::endl;}return 0;
}

osgEarth示例分析——osgearth_minimap相关推荐

  1. osgEarth示例分析——osgearth_annotation

    前言 本章为osgearth_annotation示例分析,示例中采用osgEarth提供的类,绘制标签.线.billboard.遮盖图.墙等内容. 运行时,在生成的可执行路径下,打开命令框,输入: ...

  2. osgEarth示例分析——osgearth_skyview

    前言 本示例分析osgearth操作深空场景,或者是银河系场景,可以想象人拿着相机站在地球表面上观看天空/银河系的场景. 重点是相机操作器的使用. 在命令框输入执行程序,在data路径下有加载的图,且 ...

  3. osgEarth示例分析——osgearth_manip

    前言 本示例主要演示osgEarth的事件处理的用法,内容比较多,这部分功能也很重要. 输入命令依然采用china-simple.earth的示例,加上了模型,但是模型并没有看到,可能是因为模型没有放 ...

  4. osgEarth示例分析——osgearth_elevation

    前言 osgearth_elevation示例,展示了如何通过点击地球获取不同定义下的高程数据.包括:MSL高程.HAE高程.EGM96高程.点击按钮,可以移除高程图层. MSL高程:是mean se ...

  5. osgEarth示例分析——osgearth_graticule

    前言 本示例最具有借鉴的功能:绘制网格.网格上的文字显示.拾取地球的坐标.在地球网格示例中,可以设置4种网格.执行命令如下: // --geodetic osgearth_graticuled.exe ...

  6. osgEarth示例分析——osgearth_srstest

    前言 osgearth_srstest示例,主要涉及到两个坐标系转换,wgs84→egm96  wgs84→plate-carre wgs84:World Geodetic System 1984,是 ...

  7. osgEarth示例分析——osgearth_eci

    前言 osgearth_eci示例,展示了J2000的天体坐标系和ECEF地固系的转换,绘制坐标系,以及读取卫星参数绘制卫星的功能.绘制卫星轨迹,添加差值效果和未添加差值的效果. 关于卫星两行根数的数 ...

  8. osgEarth示例分析——osgearth_terrainprofile

    前言 osgearth_terrainprofile示例,涉及到一个新的类 TerrainProfileCalculator(地形轮廓计算器类),用来计算两个点连线之间的地形数据.左下角会根据点击的起 ...

  9. osgEarth示例分析——osgearth_features

    前言 osgearth_features示例,主要演示如何通过代码方式加载shp文件,并设置其样式.在执行时,通过不同 的命令,得到不一样的效果. cmd执行命令: // rasterize 光栅化, ...

最新文章

  1. 2022-2028年中国封装用胶膜行业运营现状及投资发展潜力报告
  2. BZOJ 3573 米特运输
  3. JCIFS实现单点登录
  4. CentOS5.6配置salt节点minion
  5. 后端传前端中文显示都是问好_前后端分离,后台返回的数据前端没法写,怎么办?...
  6. LUA Metatables
  7. 1+X web中级 Laravel学习笔记——blade模版
  8. python解决列表IndexError: list index out of range
  9. 5-9 c语言之【初识win32编程】
  10. Spring Security:基于MySQL数据库的身份认证
  11. STM32F103:一.(2)STLINK的配置
  12. CCF201312-1 出现次数最多的数(100分)
  13. window.opener 与 window.dialogArguments的用法
  14. api调用实例python_基于Python的词典api调用代码实例
  15. Allegro各属性说明如 Clines或者Cline Segs
  16. Word排版技巧数模论文必备
  17. 计算机桌面曝光,win7电脑桌面壁纸曝光过高影响图标怎么办?亲测实用解决方法...
  18. 条码打印软件如何使用Excel表批量打印条码标签
  19. SpingBoot—微服务初始化资源方法
  20. ZZNUOJ_用C语言编写程序实现1217:统计立方数(附完整源码)

热门文章

  1. markdown语法及公式编辑
  2. C Primer Plus (第五版)中文版——第 10 章 数组和指针
  3. 有关结构体排序(在其内部利用运算符重新定义,比较器)
  4. 功能安全之故障(fault),错误(error),失效(failure)
  5. AES加密算法java实现
  6. kali系统与xshell远程连接
  7. 给你的UIView添加个炫彩边框
  8. Android冷启动白屏解析,带你一步步分析和解决问题
  9. uni-app无法触发onReachBottom事件
  10. 超详细!Codis 入门与实践