1 引言
最近终于将使用的GDAL 2.X升级到成了3.X版本,总结一下遇到的各种问题。
2 详论
2.1 数据路径
GDAL 3.X以后深度依赖PROJ库,以前只是可选构建项,现在已经是必须构建项了。最直接的体现是如果涉及到空间参考相关的内容时,除了要配置GDAL_DATA环境变量,还必须配置PROJ_DATA环境变量。GDAL_DATA和PROJ_DATA分别是GDAL和PROJ库的数据,里面存储了一些空间参考相关的参数,因此一般在使用GDAL之前,需要配置一下相关的路径:- string gdalDir = shareDataDir + string("/gdal");
- CPLSetConfigOption("GDAL_DATA", gdalDir.c_str());
- std::string projDir = shareDataDir + string("/proj");
- CPLSetConfigOption("PROJ_DATA", projDir.c_str());
复制代码 这些数据一般在构建的时候会安装到指定的目录的share文件夹内,如下图所示:
注意以下几点:
- 经过笔者的测试,一般设置PROJ_DATA目录就可以了。但是有的资料显示还必须继续设置GDAL_DATA目录。因为GDAL_DATA目录中可能保存的不仅仅是空间参考信息,可能保存了很多GIS相关的数据。
- 另外,很多资料推荐直接设置操作系统的环境变量。这样做不是不行,前提是与操作系统的其他GDAL环境不冲突。如果你安装过QGIS或者PostGIS等环境就知道,这些程序也会在操作系统中设置GDAL_DATA、PROJ_DATA环境变量,那么就只能像笔者这样在程序中配置。
- 在PROJ 9.1版本以前,PROJ数据的环境变量名为PROJ_LIB;在后续版本中优先使用PROJ_DATA,PROJ_LIB还会使用一段时间,但是最好替换成PROJ_DATA,避免后续的版本废弃。
2.2 坐标顺序
GDAL升级到3.X后另外一个问题就是坐标顺序的问题。例如如果要进行空间参考坐标转换:- // CGCS2000
- gcs.importFromEPSG(4326);
- // Tm投影
- pcs.importFromEPSG(3857);
- OGRCoordinateTransformation* lonLat2XY =
- OGRCreateCoordinateTransformation(&gcs, &pcs);
- OGRCoordinateTransformation* xy2LonLat =
- OGRCreateCoordinateTransformation(&pcs, &gcs);
- if (!lonLat2XY || !xy2LonLat) {
- return 1;
- }
- double x = 113.6;
- double y = 38.8;
- printf("经纬度坐标:%.9lf\t%.9lf\n", x, y);
- if (!lonLat2XY->Transform(1, &x, &y)) {
- return 1;
- }
- printf("平面坐标:%.9lf\t%.9lf\n", x, y);
- if (!xy2LonLat->Transform(1, &x, &y)) {
- return 1;
- }
- printf("再次转换回的经纬度坐标:%.9lf\t%.9lf\n", x, y);
- OGRCoordinateTransformation::DestroyCT(lonLat2XY);
- lonLat2XY = nullptr;
- OGRCoordinateTransformation::DestroyCT(xy2LonLat);
- xy2LonLat = nullptr;
复制代码 这段代码在3.X的结果就不正确。原因是GDAL 3.X更换了坐标轴的顺序,认为y在前,x在后才是更加专业的坐标表达。不过这样就破坏了向后兼容性。解决方案是给空间参考设置轴策略为传统顺序[1]:- // CGCS2000
- gcs.importFromEPSG(4326);
- // Tm投影
- pcs.importFromEPSG(3857);
- gcs.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
- pcs.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
- //...
复制代码 想这样一个一个坐标参考修改很麻烦,另一个更加合适的办法是设置全局的坐标轴策略为传统顺序[2]:- // 设置全局坐标顺序为传统GIS顺序(经度,纬度)
- CPLSetConfigOption("OGR_CT_FORCE_TRADITIONAL_GIS_ORDER", "YES");
复制代码 3 总结
最好的办法就是在程序的最开始阶段执行一个初始化函数:- void Init(const char *shareDataDir) {
- GDALAllRegister(); //注册所有的格式
- CPLSetConfigOption("SHAPE_ENCODING", ""); //解决中文乱码问题
- string gdalDir = shareDataDir + string("/gdal");
- CPLSetConfigOption("GDAL_DATA", gdalDir.c_str());
- std::string projDir = shareDataDir + string("/proj");
- CPLSetConfigOption("PROJ_DATA", projDir.c_str());
- // 设置全局坐标顺序为传统GIS顺序(经度,纬度)
- CPLSetConfigOption("OGR_CT_FORCE_TRADITIONAL_GIS_ORDER", "YES");
- }
复制代码
- GDAL 3.0 Coordinate transformation (backwards compatibility (?)) ↩︎
- Problem with GDAL >= 3.0 ↩︎
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |