先看一下效果:
osgearth加载在线地图这里就不介绍了,比如osm、mapbox、天地图等,如果有哪位同学需要,我可以下次介绍一下~~~
众所周知,高程数据一直是比较珍贵的,之前是加载谷歌地球的高程,但是近期由于谷歌地址均无法访问,所以考虑加载mapbox的在线高程数据,说到这里,不得不感谢一下mapbox,不仅提供了丰富的可编辑的在线地图数据,还提供了高程数据~~~ Maps, geocoding, and navigation APIs & SDKs | Mapbox
首先先看一张mapbox的高程图:
可以看到,mapbox的高程数据数据是rgba四通道的png格式栅格图像数据,而一般的高程数据HeightField是单通道的,
因此,在请求到源数据之后只需要做一次osg::Image -> osg::HeightField 的转换即可。
转换公式官网就有,很贴心:
height = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)
通过继承 TileSource 重写 createImage 和 createHeightField 即可实现功能,继承了QObject是想后续完善功能,将数据保存至数据库中,便于后续离线读取,QObject可有可无,详细可参考 Plugin osgearth_tileindex:
using namespace osgEarth;
using namespace osgEarth::Drivers;class XYZExSource : public QObject, public TileSource
{Q_OBJECTpublic:XYZExSource(const TileSourceOptions& options);Status initialize(const osgDB::Options* dbOptions);osg::Image* createImage(const TileKey& key, ProgressCallback* progress);virtual std::string getExtension() const{return _format;}osg::HeightField* createHeightField(const TileKey& key, ProgressCallback* progress);
private:const XYZExOptions _options;std::string _format;std::string _template;std::string _rotateChoices;std::string _rotateString;std::string::size_type _rotateStart, _rotateEnd;OpenThreads::Atomic _rotate_iter;osg::ref_ptr<osgDB::Options> _dbOptions;
};
createImage函数与xyz驱动基本一致,照抄即可,这里介绍createHeightField函数:
osg::HeightField* XYZExSource::createHeightField(const TileKey& key, ProgressCallback* progress)
{// MapBox encoded elevation PNG.// https://www.mapbox.com/blog/terrain-rgb/if (1/*_options.elevationEncoding().value() == "mapbox"*/){if (getStatus().isError())return 0L;osg::HeightField *hf = 0;osg::ref_ptr<osg::Image> image = createImage(key, progress);if (image.valid()){// Allocate the heightfield.hf = new osg::HeightField();hf->allocate(image->s(), image->t());ImageUtils::PixelReader reader(image.get());for (unsigned int c = 0; c < image->s(); c++){for (unsigned int r = 0; r < image->t(); r++){osg::Vec4 pixel = reader(c, r);pixel.r() *= 255.0;pixel.g() *= 255.0;pixel.b() *= 255.0;float h = -10000.0f + ((pixel.r() * 256.0f * 256.0f + pixel.g() * 256.0f + pixel.b()) * 0.1f);hf->setHeight(c, r, h);}}}return hf;}else{return TileSource::createHeightField(key, progress);}
}
使用:
osgEarth::Drivers::XYZExOptions exyz;
exyz.url() = "http://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=pk.eyJ1IjoicnpvbGxlciIsImEiOiIzQ1V3clI4In0.2TF5_QTXSR3T7F_dyPd1rg";
exyz.profile()->namedProfile() = "spherical-mercator";
XYZExSource* etileSource = new XYZExSource(exyz);
auto eStatus = etileSource->open();
ElevationLayerOptions eoptions("mapboxEle");
map->addLayer(new ElevationLayer(eoptions, etileSource));
access_token可在mapbox官网自行申请~~~