osgearth加载在线地图这里就不介绍了,比如osm、mapbox、天地图等,如果有哪位同学需要,我可以下次介绍一下~~~
众所周知,高程数据一直是比较珍贵的,之前是加载谷歌地球的高程,但是近期由于谷歌地址均无法访问,所以考虑加载mapbox的在线高程数据,说到这里,不得不感谢一下mapbox,不仅提供了丰富的可编辑的在线地图数据,还提供了高程数据~~~ https://www.mapbox.com/
首先先看一张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_OBJECT
public:
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官网自行申请~~~
最后看一下效果: