C++ libproj,交换坐标

问题描述 投票:0回答:1

我有一个 C++ 程序在 Linux 上运行多年。它使用一些坐标变换,我们使用

libproj
(版本 6.3.1)来实现此目的。

有趣的是,一位客户给出了输入参数

epsg:2180
然后一切都崩溃了。

看起来对于一些 epsg 转换,输出被交换了。以下是我用来证明这一点的命令:

首先获取投影字符串:

$ projinfo epsg:2180

PROJ.4 string:
+proj=tmerc +lat_0=0 +lon_0=19 +k=0.9993 +x_0=500000 +y_0=-5300000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs

如果我将它与如下所示的示例坐标(LatLon 格式)一起使用,我首先得到的结果是东距。 (基本上命令是

cs2cs epsg:4326 +to <projection string here> -f %.4f

echo "55.12578267 16.77291767" | cs2cs epsg:4326 +to +proj=tmerc +lat_0=0 +lon_0=19 +k=0.9993 +x_0=500000 +y_0=-5300000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs -f %.4f

大家期待的结果:

358037.8085 809219.1725 0.0000

但是,如果我使用简单的命令:

echo "55.12578267 16.77291767" | cs2cs epsg:4326 epsg:2180 -f %.4f

然后结果就翻转了(顾客不高兴):

809219.1725 358037.8085 0.0000

问题并不止于此,在 C++ 中,我使用相同的库,也遇到相同的问题。问题是,如何确保东距是第一个参数?

我已经尝试使用

proj_normalize_for_visualization
,因为文档建议它会在坐标上进行交换,但实际上它不会交换结果。

#include <cstdlib>
#include <cstdio>
#include <proj.h>
int main(int argc, char** argv)
{
    PJ_CONTEXT* projContext_m = proj_context_create();
    
    // hardcode epsg (in reality it is user defined)
    int epsg_p = 2180;
    
    char _buff[100];
    snprintf(_buff, sizeof (_buff), "EPSG:%d", epsg_p);
    PJ* projEPSG_m = proj_create_crs_to_crs(projContext_m,
                                            "EPSG:4326",
                                            _buff, NULL);

    if (projEPSG_m != nullptr)
    {   
        proj_normalize_for_visualization(projContext_m, projEPSG_m);
    }
    
    // fake input (in reality it is user defined)
    PJ_COORD input_p;
    input_p.xy.x = 55.12578267;
    input_p.xy.y = 16.77291767;
    
    PJ_COORD result = proj_trans(projEPSG_m, PJ_FWD, input_p);    // input_p is the coordinate we need to transform

    // we assume `result.x` is the Easting
    printf("Easting: %f, Northing %f", result.xy.x, result.xy.y);
    
    return 0;
}

输出:

东:809219.172518,北:358037.808510

我应该怎么做才能强制执行

result.x
始终是东方?

c++ coordinate-transformation proj
1个回答
0
投票

TLDR;
PROJ4 格式并不完美,使用

proj_as_projjson
获取 JSON 投影字符串并检查密钥
["target_crs"]["coordinate_system"]["axis"][0]["direction"]

const char* projInfoJson = proj_as_projjson(projContext_m, projEPSG_m, NULL);

json::parse(projInfoJson)["target_crs"]["coordinate_system"]["axis"][0]["direction"] == "north";

经过几天的调试和文档阅读,很明显 PROJ4 格式并未提供所有参数。

这就是为什么

cs2cs
在仅与 EPSG 或投影字符串一起使用时产生交换结果的原因。

此外,由于历史/传统原因,一些 EPSG(包括 2180)以“东东优先”以外的方式输出结果。
看看 epsg 的网站并检查“坐标系”部分(重点是我的):

笛卡尔二维 CS。轴:北向,东向 (x,y)。方位:北、东。计量单位:米。

不幸的是,无法从 PROJ4 类型的投影字符串中辨别出此信息。还有其他格式可以提供更多信息。

所以解决方案是,获取 JSON 投影字符串,提取轴信息,并在星星对齐时使用交换。
这是执行此操作的代码:

#include <cstdlib>
#include <cstdio>
#include <proj.h>
int main(int argc, char** argv)
{
    PJ_CONTEXT* projContext_m = proj_context_create();
    
    // hardcode epsg (in reality it is user defined)
    int epsg_p = 2180;
    
    char _buff[100];
    snprintf(_buff, sizeof (_buff), "EPSG:%d", epsg_p);
    PJ* projEPSG_m = proj_create_crs_to_crs(projContext_m,
                                            "EPSG:4326",
                                            _buff, NULL);
// ----- here comes the change
    bool swapNeeded = false;
    if (projEPSG_m != nullptr)
    {   
        const char* projInfoJson = proj_as_projjson(projContext_m, projEPSG_m, NULL);
        nlohmann::json projInfo = nlohmann::json::parse(projInfoJson);
        swapNeeded = projInfo["target_crs"]["coordinate_system"]["axis"][0]["direction"] == "north";
    }

    // fake input (in reality it is user defined)
    PJ_COORD input_p;
    input_p.xy.x = 55.12578267;
    input_p.xy.y = 16.77291767;
    
    PJ_COORD result = proj_trans(projEPSG_m, PJ_FWD, input_p);    // input_p is the coordinate we need to transform
    if (swapNeeded) {
        std::swap(result.xy.x, result.xy.y);
    }

    // we assume `result.x` is the Easting
    printf("Easting: %f, Northing %f", result.xy.x, result.xy.y);
    
    return 0;
}

我使用

nlohmann::json
库进行 JSON 解析,但可能会使用其他库来读取这几个字符。

© www.soinside.com 2019 - 2024. All rights reserved.