我在这里发布这个问题,而不是gis.stackeexchange.com,因为我认为这更像是一个编程问题,而非gis问题。
proj迁移指南解释了如何将代码转换为proj6及更高版本,方法是将代码转换成如下所示(为简洁起见,省略了错误处理(:
projPJ pj_longlat = pj_init_plus(source);
projPJ pj_merc = pj_init_plus(target);
pj_transform(pj_longlat, pj_merc, ...)
转换成如下代码:
PJ *P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, source, target, NULL);
proj_trans(P, PJ_FWD, ...);
这是在包括mapnik在内的几个项目中所做的,但有一个缺点:对于新代码,source
和target
都必须是CRS,否则proj_create_crs_to_crs
将失败:
proj_create_operations: source_crs is not a CRS
这意味着一些应用程序(例如,我成功地使用了带有+proj=pipeline
投影的mapnik渲染,这不是CRS(已经不可能了。
在项目问题报告中,开发人员指出,应该可以通过手动使用proj_create
来避免proj_create_crs_to_crs
。但如果我理解正确,那么要创建一个从source
转换为target
的PJ
对象(反之亦然(,我需要一个管道,但如果我的一个投影包含管道,那么这将不起作用,因为我不能嵌套管道。
那么,我如何将代码从PROJ 4转换为PROJ 6 API,而不删除输入任意转换的能力,即使这些转换不是CRS?
编辑
我在PROJ邮件列表上问了同样的问题,得到了Even Rouault非常有用的回复。我将用它来尝试并实现一个解决方案。
在Even Rouault的帮助下,我设法向mapnik提交了一个拉取请求,如果输入转换不是CRS:,它将使用替代代码路径
https://github.com/mapnik/mapnik/pull/4309
本质上,这是在做以下事情(为了简洁起见,省略了错误检查(:
ctx_ = proj_context_create();
std::string crs_source = pj_add_type_crs_if_needed(source);
PJ *src = proj_create(ctx_, crs_source.c_str());
std::string crs_dest = pj_add_type_crs_if_needed(dest);
PJ *dst = proj_create(ctx_, crs_dest.c_str());
if (proj_is_crs(src) && proj_is_crs(dst)) {
/* insert proj_create_crs_to_crs and friends from
* the official migration guide here */
} else {
/* either src or dst is not a crs, so we need to set
* up the pipeline ourselves */
auto formatter = osgeo::proj::io::PROJStringFormatter::create();
formatter->startInversion();
formatter->ingestPROJString(source);
formatter->stopInversion();
formatter->ingestPROJString(dest);
transform_ = proj_create(ctx_, formatter->toString().c_str());
}
proj_destroy(src);
proj_destroy(dst);
return transform_;
最值得注意的是,上述备选代码路径不调用proj_normalize_for_visualization
,因此在用户提供需要规范化的非CRS变换的情况下,用户是自己的。
函数pj_add_type_crs_if_needed
来自src/4D_api.cpp中的PROJ代码库,并为PROJ字符串添加+type=crs
后缀(如果它是PROJ字符串(,可以这样写:
std::string pj_add_type_crs_if_needed(const std::string &str) {
std::string ret(str);
if ((str.rfind("proj=", 0) == 0 || str.rfind("+proj=", 0) == 0 ||
str.rfind("+init=", 0) == 0 || str.rfind("+title=", 0) == 0) &&
str.find("type=crs") == std::string::npos) {
ret += " +type=crs";
}
return ret;
}