TIFF文件
- TIFF为图像格式,以tif为后缀,是一种位图格式。
- 同BMP一样,包含文件头、信息头、数据区。
- 地球纹理和高程图用到了TIFF。
- 用Global Mapper打开高程图可导出等高线。
Shape文件
- Shape文件是以shp为后缀的二进制文件。
- 用arcview打开可以看到其信息为点线面的几何图形,还包括几何图形的坐标,同样也是一张数据表。
OSG文件
- OSG文件是以osg后缀的文本文件。
- 使用
osgviewer *.osg
可快速浏览osg文件定义的模型。 - OSG文件内规定了模型的节点层次,并设置了模型的属性,给出了模型各个顶点的坐标。
earth文件
-
earth文件本质是XML文本文件,后缀为earth。
-
map
:文件的最外层标签,可认为是一个OSG节点,在代码中是osgEarth::MapNode
。- type:给出使用的坐标,我设置为球心坐标
geocentric
,若平面投影为Projected
。 - version:osgEarth的大版本,我用的2.10,标记为
2
。 - name:map的名称。
- type:给出使用的坐标,我设置为球心坐标
-
heightfield
定义高程数据。- name:高程数据名称。
- driver:驱动。
- url:高程数据路径,可以是本地或网络,我在本地保存了一份30m的高程图,格式为.tif。
-
image
定义纹理,可以理解为一个图层。- name:高程数据名称。
- driver:驱动。
- url:高程数据路径,可以是本地或网络。
-
cache
数据量大,加载慢,因此需要设置缓存。- type:缓存类型,我设置filesystem,即本地文件系统。
- path:缓存路径。
<map name="globe" type="geocentric" version="2">
<!-- 定义全球影像-->
<image name="globeImage" driver="gdal">
<url>../data/globe/globe.tif</url>
</image>
<!-- 全球高程-->
<heightfield name="globeHeightfiled" driver="gdal">
<url>../data/heightfield/30m.tif</url>
</heightfield>
<image name="detail" driver="composite">
<!-- 局部高清纹理 复合影像(消除接缝、没有image数量限制)-->
<image name="zhejiangImage" driver="gdal">
<url>../data/detail/zhejiang.tif</url>
</image>
<image name="deqingImage" driver="gdal">
<url>../data/detail/deqing.tif</url>
</image>
<image name="plateauImage" driver="gdal">
<url>../data/detail/plateau.tif</url>
</image>
</image>
<!-- 国界线-->
<!-- agglite 将矢量文件栅格化 -->
<image name="countryBoundary" driver="agglite">
<!--子标签读取shape(画形状、贴图) ogr将shape换成纹理叠加到图上 -->
<features name="world" driver="ogr">
<url>../data/shpFile/world.shp</url>
<!-- 建立空间索引(加快加载速度) -->
<build_spatial_index>true</build_spatial_index>
</features>
<!-- 栅格化的类型(点线面) -->
<geomerty_type>line</geomerty_type>
<!-- 以像素为单位 -->
<relative_line_size>true</relative_line_size>
<!-- css设置风格 -->
<styles>
<style type="text/css">
world {
stroke: #ffff00;
stroke-opacity: 1.0;
stroke-width: 2.0;
}
</style>
</styles>
</image>
<!-- 省界线 -->
<image name="provinceBoundary" driver="agglite">
<features name="china" driver="ogr">
<url>../data/shpFile/china.shp</url>
<build_spatial_index>true</build_spatial_index>
</features>
<geomerty_type>line</geomerty_type>
<relative_line_size>true</relative_line_size>
<styles>
<style type="text/css">
china {
stroke: #ffffff;
stroke-opacity: 1.0;
stroke-width: 1.5;
}
</style>
</styles>
</image>
<!-- 等高线 -->
<image name="contour" driver="agglite">
<features name="contour" driver="ogr">
<url>../data/shpFile/plateau.shp</url>
<build_spatial_index>true</build_spatial_index>
</features>
<geomerty_type>line</geomerty_type>
<relative_line_size>true</relative_line_size>
<styles>
<style type="text/css">
china {
stroke: #000000;
stroke-opacity: 1.0;
stroke-width: 2;
}
</style>
</styles>
</image>
<!-- 文件缓存-->
<options>
<cache type="filesystem">
<path>./FileCache</path>
</cache>
</options>
</map>
OSG基本设置
-
图形显示设置
-
将OSG图形嵌入MFC单文档程序,用Traits类设置OSG窗口属性。
// 获取窗口的矩形区域 ::GetWindowRect(hWnd, &rect); // 创建窗口特征类 osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits; // 获取windata osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(hWnd); // 设置显示的各个属性 traits->x = 0; traits->y = 0; traits->width = rect.right - rect.left; traits->height = rect.bottom - rect.top; // 双缓冲 traits->doubleBuffer = true; // 共享的图形环境null traits->sharedContext = nullptr; // 继承窗口的像素格式 traits->setInheritedWindowPixelFormat = true; traits->inheritedWindowData = windata;
-
将traits作为参数可构造OSG的图形上下文,并进而设置摄像头、视口、投影。
// 创建上下文 osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits); // 创建摄像头 osg::ref_ptr<osg::Camera> camera = new osg::Camera; camera->setGraphicsContext(gc); // 设置视口 camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height)); // 设置视角 camera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(traits->width) / static_cast<double>(traits->height), 1.0, 1000.0); // 设置摄像头 viewer->setCamera(camera); // 设置场景 viewer->setSceneData(sceneRoot); // 激活窗口并关联线程 viewer->realize();
-
-
osgEarth操作器
-
将操作器的操作节点设置为mapNode,即地球。
earthManipulator = new osgEarth::Util::EarthManipulator; if (mapNode.valid()) { earthManipulator->setNode(mapNode); }
-
设置监视器的相机操作器。
viewer->setCameraManipulator(earthManipulator);
-
设置视点变换的平滑过渡。
earthManipulator->getSettings()->setArcViewpointTransitions(true); earthManipulator->setViewpoint(osgEarth::Viewpoint(nullptr, 112.44, 33.75, 404.06, -3.55, -84.59, 22935594.99), 5);
-
OSG节点树
-
定义
osg::ref_ptr<osg::Group> sceneRoot
为根节点。 -
用
osgDB::readNodeFile
读入.earth文件,作为一个节点,并将其向派生类转换为osgEarth特有的地球节点。mapNode包含坐标系信息、osgEarth定义的地图的指针等信息,通过mapNode可得到.earth文件中的信息,即省界线、国界线、高清纹理等图层。void COSGObject::initSceneGraph() { // 创建根节点对象 sceneRoot = new osg::Group; // 读取影像 osg::ref_ptr<osg::Node> mp = osgDB::readNodeFile("./earthfile/DigitalMap.earth"); // 添加子节点 sceneRoot->addChild(mp); // 父类向子类转换 mapNode = dynamic_cast<osgEarth::MapNode*>(mp.get()); }
-
星空节点:SkyNode类生成,直接连向根节点。
void COSGObject::initSky() { // 初始化天空 osg::ref_ptr<osgEarth::Util::SkyNode> skyNode = osgEarth::Util::SkyNode::create(mapNode); skyNode->setDateTime(osgEarth::DateTime(2021, 12, 11, 15)); skyNode->attach(viewer, 1); skyNode->setStarsVisible(true); skyNode->setSunVisible(true); sceneRoot->addChild(skyNode); }
-
国旗节点:读取国旗图像作为节点,直接连向根节点。
void COSGObject::initNationFlag() { // 初始化国旗标识 nationFlag = new osg::Group; sceneRoot->addChild(nationFlag); osg::Image* chinaIcon = osgDB::readImageFile("data/label/chinaYES.png"); osg::ref_ptr<osgEarth::Annotation::PlaceNode> placeNode = new osgEarth::Annotation::PlaceNode; placeNode->setIconImage(chinaIcon); placeNode->setPosition(osgEarth::GeoPoint(mapNode->getMapSRS()->getGeographicSRS(), 110, 34)); nationFlag->addChild(placeNode.get()); }
-
三维模型(cow.osg)
void COSGObject::init3DCow() { // 得到世界坐标下的转换矩阵 osg::Matrixd matrix; mapNode->getMapSRS()->getGeocentricSRS()->getEllipsoid()->computeLocalToWorldTransformFromLatLongHeight(osg::DegreesToRadians(30.58), osg::DegreesToRadians(119.99), 10, matrix); // 比例变换——放大一下 matrix.preMult(osg::Matrixd::scale(osg::Vec3d(29, 25, 25))); // transform节点 scenicSpot = new osg::MatrixTransform; scenicSpot->setMatrix(matrix); // 设置光照 osg::ref_ptr<osg::StateSet> state = scenicSpot->getOrCreateStateSet(); state->setMode(GL_LIGHTING, osg::StateAttribute::ON); state->setMode(GL_LIGHT0, osg::StateAttribute::ON); state->setMode(GL_LIGHT1, osg::StateAttribute::ON); osg::ref_ptr<osg::LightSource> lightSource0 = new osg::LightSource; osg::ref_ptr<osg::Light>light0 = new osg::Light; light0->setLightNum(0); light0->setDirection(osg::Vec3(0, -1, 0)); light0->setPosition(osg::Vec4(-4817129, -5391926, -141700, 0)); light0->setDiffuse(osg::Vec4(1.0, 1.0, 0.8, 1)); lightSource0->setLight(light0); osg::ref_ptr<osg::LightSource> lightSource1 = new osg::LightSource; osg::ref_ptr<osg::Light>light1 = new osg::Light; light1->setLightNum(0); light1->setDirection(osg::Vec3(0, 1, 0)); light1->setPosition(osg::Vec4(-4817129, 5391926, -141700, 0)); light1->setDiffuse(osg::Vec4(1.0, 1.0, 0.9, 1)); lightSource1->setLight(light1); // 读取osg文件 osg::ref_ptr<osg::Node>cow = osgDB::readNodeFile("./data/model/cow.osg"); // osg中光照只会对有法线的模型起作用,而模型经过缩放后法线不变。 // 所以需要手动设置属性,让法线随着模型大小变化而变化。 // If enabled, normal vectors specified with glNormal are scaled to unit length after transformation. cow->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON); scenicSpot->addChild(cow); scenicSpot->addChild(lightSource0); scenicSpot->addChild(lightSource1); sceneRoot->addChild(scenicSpot); }
操作osgEarth的元素
-
earth文件的图层
-
osgEarth提供了ImageLayer来操作图层。
-
通过mapNode获取earth文件信息。
void COSGObject::initLayer() { // 从earth文件中根据name获得图层 globeLayer = mapNode->getMap()->getLayerByName<osgEarth::ImageLayer>("globeImage"); provinceBoundaryLayer = mapNode->getMap()->getLayerByName<osgEarth::ImageLayer>("provinceBoundary"); countryBoundaryLayer = mapNode->getMap()->getLayerByName<osgEarth::ImageLayer>("countryBoundary"); contourLayer = mapNode->getMap()->getLayerByName<osgEarth::ImageLayer>("contour"); detailLayer = mapNode->getMap()->getLayerByName<osgEarth::ImageLayer>("detail"); }
-
用ImageLayer对象操作图层的属性,如透明度。
void COSGObject::setProvinceBoundaryOpacity(float opacity) { if (provinceBoundaryLayer.valid()) { provinceBoundaryLayer->setOpacity(opacity); } } void COSGObject::enableProvinceBoundary(bool flag) { provinceBoundaryLayer->setVisible(flag); }
-
-
OSG节点的显示
-
所有节点都继承自Node类。
-
将NodeMask设置为0可让节点及其子节点不可见。
void COSGObject::enableNationFlag(BOOL flag) { nationFlag->getChild(0)->setNodeMask(flag); }
-
坐标计算
-
经纬度
-
调用Viewer类的computeIntersections函数,求摄像头与焦点连线与地球的交点。
-
得到交点后转换为经纬度并显示在编辑框中。
// 求交点 if (viewer->computeIntersections(eventAdapter, res)) { osgUtil::LineSegmentIntersector::Intersection first = *res.begin(); // 取出交点坐标 osg::Vec3d point = first.getWorldIntersectPoint(); double latitude, longitude, altitude; // 转经纬度 osg::ref_ptr<osg::EllipsoidModel> ellipsoidModel = new osg::EllipsoidModel; ellipsoidModel->convertXYZToLatLongHeight(point.x(), point.y(), point.z(), latitude, longitude, altitude); latitude = osg::RadiansToDegrees(latitude); longitude= osg::RadiansToDegrees(longitude); CString str; str.Format(_T("%.2lf"), longitude); latitudeEdit->SetEditText(str); str.Format(_T("%.2lf"), latitude); longitudeEdit->SetEditText(str); str.Format(_T("%.2lfm"), altitude); altitudeEdit->SetEditText(str); }
-
-
视点
-
通过Viewer得到操作器,再获取当前视点。
-
视点的focalPoint即为焦点。
// 获取视点 osgEarth::Viewpoint viewpoint = dynamic_cast<osgEarth::Util::EarthManipulator*>(viewer->getCameraManipulator())->getViewpoint(); CString str; osgEarth::GeoPoint pos = viewpoint.focalPoint().value(); str.Format(_T("%.2lf"), pos.x()); viewLongitudeEdit->SetEditText(str); str.Format(_T("%.2lf"), pos.y()); viewLatitudeEdit->SetEditText(str); str.Format(_T("%.2lf"), pos.z()); viewZEdit->SetEditText(str); str.Format(_T("%.2lf"), viewpoint.getHeading()); viewHeadingEdit->SetEditText(str); str.Format(_T("%.2lf"), viewpoint.getPitch()); viewPitchEdit->SetEditText(str); str.Format(_T("%.2lf"), viewpoint.getRange()); viewRangeEdit->SetEditText(str);
-