16. 投影数据

地球不是平的,没有简单的方法可以把它放在一张平坦的纸质地图(或电脑屏幕)上,所以人们想出了各种巧妙的解决方案,每种方案都有其优缺点。一些投影保留了面积,因此所有物体都具有相对大小;其他投影保留了角度(保角),例如墨卡托投影;一些投影试图找到一个良好的中间混合,在几个参数上只有很小的失真。所有投影的共同点是它们将(球面)世界转换为平面笛卡尔坐标系,选择哪种投影取决于你将如何使用数据。

当我们 加载 nyc 数据 时,我们已经遇到了投影。(回想一下那个讨厌的 SRID 26918)。然而,有时你需要在空间参考系之间进行转换和重新投影。PostGIS 包含对更改数据投影的内置支持,使用 ST_Transform(geometry, srid) 函数。为了管理几何图形上的空间参考标识符,PostGIS 提供了 ST_SRID(geometry)ST_SetSRID(geometry, srid) 函数。

我们可以使用 ST_SRID 函数确认数据的 SRID

SELECT ST_SRID(geom) FROM nyc_streets LIMIT 1;
26918

那么“26918”的定义是什么?正如我们在“加载数据部分”中看到的,定义包含在 spatial_ref_sys 表中。事实上,那里有 **两个** 定义。“众所周知的文本” (WKT) 定义在 srtext 列中,在 proj4text 列中还有一个“proj.4”格式的定义。

SELECT * FROM spatial_ref_sys WHERE srid = 26918;

PostGIS 重新投影引擎将尝试从 spatial_ref_sys 表中找到最佳投影

  • auth_name / auth_srid 如果 proj 在其内部目录中找到有效的“授权名称”和“授权 srid”,它将使用它来生成投影定义。

  • srtext 如果 proj 可以从 srtext 中解析并形成定义对象,它将使用它。

  • proj4text 最后,proj 将尝试处理 proj4text

所有这些冗余意味着,要创建新的投影,您只需要一个有效的 srtext 字符串或 proj4text 字符串。所有常见的授权名称/代码对默认情况下已加载到表中。

如果您在创建自定义投影时有选择,请填写 srtext 列,因为该列也被外部程序使用,例如 GeoServerQGISFME 等。

16.1. 比较数据

总而言之,坐标和 SRID 定义了地球上的一个位置。没有 SRID,坐标只是一个抽象的概念。“笛卡尔”坐标系被定义为放置在地球表面的“平面”坐标系。由于 PostGIS 函数在这样的平面上工作,因此比较操作要求两个几何体都以相同的 SRID 表示。

如果您输入具有不同 SRID 的几何体,您只会得到错误。

SELECT ST_Equals(
         ST_GeomFromText('POINT(0 0)', 4326),
         ST_GeomFromText('POINT(0 0)', 26918)
         );
ERROR:  ST_Equals: Operation on mixed SRID geometries (Point, 4326) != (Point, 26918)

注意

小心不要过度使用 ST_Transform 进行动态转换。空间索引是使用存储的几何体的 SRID 构建的。如果比较是在不同的 SRID 中进行的,则空间索引(通常)不会被使用。最佳实践是为数据库中的所有表选择 **一个 SRID**。只有在读取或写入外部应用程序的数据时才使用转换函数。

16.2. 转换数据

如果我们回到 SRID 26918 的 proj4 定义,我们可以看到我们的工作投影是 UTM(通用横轴墨卡托)第 18 区,单位为米。

SELECT srtext FROM spatial_ref_sys WHERE srid = 26918;
PROJCS["NAD83 / UTM zone 18N",
  GEOGCS["NAD83",
    DATUM["North_American_Datum_1983",
      SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],
      TOWGS84[0,0,0,0,0,0,0],
      AUTHORITY["EPSG","6269"]],
    PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
    UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],
    AUTHORITY["EPSG","4269"]],
  PROJECTION["Transverse_Mercator"],
  PARAMETER["latitude_of_origin",0],
  PARAMETER["central_meridian",-75],
  PARAMETER["scale_factor",0.9996],
  PARAMETER["false_easting",500000],
  PARAMETER["false_northing",0],
  UNIT["metre",1,AUTHORITY["EPSG","9001"]],
  AXIS["Easting",EAST],AXIS["Northing",NORTH],
  AUTHORITY["EPSG","26918"]]

让我们将一些数据从我们的工作投影转换为地理坐标 - 也称为“经度/纬度”。

要将数据从一个 SRID 转换为另一个 SRID,您必须首先验证您的几何体是否具有有效的 SRID。由于我们已经确认了有效的 SRID,因此接下来我们需要要转换到的投影的 SRID。换句话说,地理坐标的 SRID 是什么?

地理坐标最常用的 SRID 是 4326,对应于“WGS84 椭球体上的经度/纬度”。您可以在此处查看定义

您也可以从 spatial_ref_sys 表中提取定义

SELECT srtext FROM spatial_ref_sys WHERE srid = 4326;
GEOGCS["WGS 84",
  DATUM["WGS_1984",
    SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],
    AUTHORITY["EPSG","6326"]],
  PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
  UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],
  AUTHORITY["EPSG","4326"]]

让我们将“Broad St”地铁站的坐标转换为地理坐标

SELECT ST_AsText(ST_Transform(geom,4326))
FROM nyc_subway_stations
WHERE name = 'Broad St';
POINT(-74.01067146887341 40.70710481558761)

如果您加载数据或创建新的几何图形而没有指定 SRID,则 SRID 值将为 0。回想一下在 Geometries 中,当我们创建 geometries 表时,我们没有指定 SRID。如果我们查询数据库,我们应该期望所有 nyc_ 表都具有 26918 的 SRID,而 geometries 表默认使用 0 的 SRID。

要查看表的 SRID 分配,请查询数据库的 geometry_columns 表。

SELECT f_table_name AS name, srid
FROM geometry_columns;
        name         | srid
---------------------+-------
 nyc_census_blocks   | 26918
 nyc_homicides       | 26918
 nyc_neighborhoods   | 26918
 nyc_streets         | 26918
 nyc_subway_stations | 26918
 geometries          |     0

但是,如果您知道坐标的 SRID 应该是什么,您可以使用几何图形上的 ST_SetSRID 事后设置它。然后您将能够将几何图形转换为其他系统。

SELECT ST_AsText(
    ST_Transform(
      ST_SetSRID(geom,26918),
      4326)
    )
  FROM geometries;

16.3. 函数列表

ST_AsText: 返回几何/地理图形的 Well-Known Text (WKT) 表示,不包含 SRID 元数据。

ST_SetSRID(geometry, srid): 将几何图形上的 SRID 设置为特定整数值。

ST_SRID(geometry): 返回 ST_Geometry 的空间参考标识符,如 spatial_ref_sys 表中定义。

ST_Transform(geometry, srid): 返回一个新的几何图形,其坐标已转换为整数参数引用的 SRID。