快速启动

这是对projapi的简短介绍。在下一节中,我们将创建一个简单的程序,将大地坐标转换为UTM,然后再转换回来。这个程序一次解释几行。完整的程序可以在本节末尾看到。

有关项目的详细信息,请参阅API的以下部分 API reference 具体情况。

在可以使用Proj API之前,必须包含 proj.h 头文件。这里 stdio.h 也包括在内,以便我们可以将一些文本打印到屏幕上:

#include <stdio.h>
#include <proj.h>

让我们声明几个变量,稍后将在程序中使用。下面将讨论每个变量。看到了吗 reference for more info on data types .

PJ_CONTEXT *C;
PJ *P;
PJ *norm;
PJ_COORD a, b;

为了在多线程程序中使用 PJ_CONTEXT 线程-使用上下文。在这个特定的例子中,它不是必需的,但是为了完整起见,我们在这里演示了它的用法。

C = proj_context_create();

接下来,我们创建 PJ 变换对象 P 使用函数 proj_create_crs_to_crs()

P = proj_create_crs_to_crs (C,
                            "EPSG:4326",
                            "+proj=utm +zone=32 +datum=WGS84", /* or EPSG:32632 */
                            NULL);

if (0 == P) {
    fprintf(stderr, "Failed to create transformation object.\n");
    return 1;
}

在这里,我们建立了从地理坐标到UTM区域32N的转换。

proj_create_crs_to_crs() 以以下内容为论据:

  • 线程上下文 C 上面创建的,

  • 描述源坐标参考系(CRS)的字符串,

  • 描述目标CRS的字符串和

  • 使用区域的可选描述。

建议为程序使用的每个线程创建一个线程上下文。这确保了所有 PJ 在相同上下文中创建的对象将共享资源,如错误号和加载的栅格。

如果你确定 P 将仅由单个程序线程使用,您可以传递 NULL 用于线程上下文。这会将默认线程上下文分配给 P

源和目标CR的字符串可以是以下任意一个:

  • 投影字符串,例如 +proj=longlat +datum=WGS84 +type=crs

  • 由他们的代码标识的CR,例如 EPSG:4326urn:ogc:def:crs:EPSG::4326 ,或

  • 熟知文本(WKT)字符串,例如:

GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
        SCOPE["unknown"],
        AREA["World"],
        BBOX[-90,-180,90,180]],
    ID["EPSG",4326]]

警告

不建议使用Proj字符串来描述CRS。Proj字符串的主要缺点之一是它们无法描述大地基准面,除了在 +datum 参数。

proj_create_crs_to_crs() 将返回一个指向 PJ 对象,或者在出错的情况下为空指针。可以使用以下命令检索错误的详细信息 proj_context_errno() 。看见 错误处理 了解更多详细信息。

现在我们在中有了标准化的转换对象 P ,我们可以将其与 proj_trans() 将坐标从源CRS转换到目标CRS,但首先我们将讨论坐标的解释。

默认情况下,一个 PJ 转换对象接受以源CRS的单位和轴顺序表示的坐标,并返回以目标CRS的单位和轴顺序表示的转换后的坐标。

对于大多数地理CRS,单位将以度为单位。在极少数情况下,例如EPSG:4807/NTF(巴黎),这可能是梯度。对于EPSG当局定义的地理CRS,坐标的顺序是纬度第一,经度第二。当使用投影字符串时,顺序是相反的;经度第一,纬度第二。

对于投影的CRS,单位可能有所不同(米、美英尺等)。对于EPSG授权机构定义的投影CR,对于东/北方向,顺序可能是先向东、后向北或相反。使用投影字符串时,顺序将是先向东,然后向北,除非 +axis 参数会对其进行修改。

如果您希望使用统一的轴顺序,而不考虑源和目标CRS要求的轴顺序,则可以使用 proj_normalize_for_visualization() 功能。

proj_normalize_for_visualization() 获取线程上下文和现有的 PJ 对象,并从它生成一个新的 PJ 它接受作为输入,并使用传统的地理信息系统顺序返回作为输出坐标。也就是说,经度后跟纬度,对于地理CRS,可以选择后跟海拔和时间,对于大多数投影的CRS,可以选择东经和北纬。

norm = proj_normalize_for_visualization(C, P);
if (0 == norm) {
    fprintf(stderr, "Failed to normalize transformation object.\n");
    return 1;
}
proj_destroy(P);
P = norm;

接下来,我们创建一个 PJ_COORD 坐标对象,使用函数 proj_coord()

下例创建了北纬55°12°E(哥本哈根)的坐标。

因为我们已经将转换对象标准化为 proj_normalize_for_visualization() ,坐标的顺序是经度后跟纬度,单位是度。

a = proj_coord(12, 55, 0, 0);

现在,我们可以使用函数将坐标转换为UTM区域32 proj_trans()

b = proj_trans(P, PJ_FWD, a);
printf("easting: %.3f, northing: %.3f\n", b.enu.e, b.enu.n);

proj_trans() 以以下内容为论据:

方向参数可以是以下参数之一:

  • PJ_FWD --从源CRS到目标CRS的前向转换。

  • PJ_IDENT --“Identity”,原样返回源坐标。

  • PJ_INV --目标CRS到源CRS的逆转换。

它返回新转换的 PJ_COORD 协调。

我们可以反向执行转换(从UTM区域32返回到地理区域),如下所示:

b = proj_trans(P, PJ_INV, b);
printf("longitude: %g, latitude: %g\n", b.lp.lam, b.lp.phi);

在结束程序之前,我们需要释放分配给对象的内存:

proj_destroy(P);
proj_context_destroy(C); /* may be omitted in the single threaded case */

示例代码的完整可编译版本如下所示:

 1#include <stdio.h>
 2#include <proj.h>
 3
 4int main (void) {
 5    PJ_CONTEXT *C;
 6    PJ *P;
 7    PJ *norm;
 8    PJ_COORD a, b;
 9
10    /* or you may set C=PJ_DEFAULT_CTX if you are sure you will     */
11    /* use PJ objects from only one thread                          */
12    C = proj_context_create();
13
14    P = proj_create_crs_to_crs (C,
15                                "EPSG:4326",
16                                "+proj=utm +zone=32 +datum=WGS84", /* or EPSG:32632 */
17                                NULL);
18
19    if (0 == P) {
20        fprintf(stderr, "Failed to create transformation object.\n");
21        return 1;
22    }
23
24    /* This will ensure that the order of coordinates for the input CRS */
25    /* will be longitude, latitude, whereas EPSG:4326 mandates latitude, */
26    /* longitude */
27    norm = proj_normalize_for_visualization(C, P);
28    if (0 == norm) {
29        fprintf(stderr, "Failed to normalize transformation object.\n");
30        return 1;
31    }
32    proj_destroy(P);
33    P = norm;
34
35    /* a coordinate union representing Copenhagen: 55d N, 12d E    */
36    /* Given that we have used proj_normalize_for_visualization(), the order of
37    /* coordinates is longitude, latitude, and values are expressed in degrees. */
38    a = proj_coord(12, 55, 0, 0);
39
40    /* transform to UTM zone 32, then back to geographical */
41    b = proj_trans(P, PJ_FWD, a);
42    printf("easting: %.3f, northing: %.3f\n", b.enu.e, b.enu.n);
43
44    b = proj_trans(P, PJ_INV, b);
45    printf("longitude: %g, latitude: %g\n", b.lp.lam, b.lp.phi);
46
47    /* Clean up */
48    proj_destroy(P);
49    proj_context_destroy(C); /* may be omitted in the single threaded case */
50    return 0;
51}