在不强制crs输入的情况下迁移到proj API 6+



我在这里发布这个问题,而不是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在内的几个项目中所做的,但有一个缺点:对于新代码,sourcetarget都必须是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转换为targetPJ对象(反之亦然(,我需要一个管道,但如果我的一个投影包含管道,那么这将不起作用,因为我不能嵌套管道。

那么,我如何将代码从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;
}

相关内容

最新更新