最近终于将使用的GDAL 2.X升级到成了3.X版本,总结一下遇到的各种问题。
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
文件夹内,如下图所示:
注意以下几点:
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");
最好的办法就是在程序的最开始阶段执行一个初始化函数:
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");
}