PostGIS系列课程之Geography

34 篇文章 8 订阅

坐标为“地理”或“纬度/经度”的数据非常常见。

与墨卡托(Mercator),UTM或Stateplane中的坐标不同,地理坐标不是笛卡尔坐标。 地理坐标不代表在平面上绘制的距原点的线性距离。 而是,这些球坐标描述了地球仪上的角坐标。 在球坐标中,一个点由与参考子午线的旋转角度(经度)和与赤道的角度(纬度)指定。

区别

您可以将地理坐标视为近似的笛卡尔坐标,然后继续进行空间计算。
但是,距离,长度和面积的测量是没有意义的。
由于球坐标测量角距离,所以单位为“度”。
此外,索引和真/假测试(如相交和包含)的近似结果可能会变得非常错误。 随着接近极点或国际日期变更线等问题区域,点之间的距离变得更大。

例如,这是洛杉矶和巴黎的坐标。

  • 洛杉矶:POINT(-118.4079 33.9434)
  • 巴黎:POINT(2.3490 48.8533)

下面使用标准PostGIS直角坐标ST_Distance(geometry,geometry)计算洛杉矶和巴黎之间的距离。 请注意,SRID-4326声明了地理空间参考系统。

SELECT ST_Distance(
  ST_GeometryFromText('POINT(-118.4079 33.9434)', 4326), -- Los Angeles (LAX)
  ST_GeometryFromText('POINT(2.5559 49.0083)', 4326)     -- Paris (CDG)
  );

啊哈! 121! 但是,这是什么意思?

空间参考4326的单位是度。 所以我们的答案是121度。 但是(再次),这是什么意思?

在一个球体上,一个“度平方”的大小是非常可变的,随着您远离赤道,尺寸会变小。 想一想地球上的子午线(垂直线)在您接近两极时会越来越靠近。 因此,121度的距离并不代表任何意义。 这是胡扯的数字。

为了计算有意义的距离,我们必须将地理坐标不视为近似的笛卡尔坐标,而应视为真实的球形坐标。 我们必须将点之间的距离测量为球体(大圆环的一部分)上的真实路径。

从1.5版开始,PostGIS通过地理类型提供此功能。

注意

不同的空间数据库具有不同的“处理地理信息”方法

  • 当SRID为地理时,Oracle尝试通过透明地进行地理计算来弥补差异。
  • SQL Server使用两种空间类型,笛卡尔数据使用“ STGeometry”,地理使用“ STGeography”。
  • Informix Spatial是对Informix的纯笛卡尔扩展,而Informix Geodetic是纯地理扩展。
    与SQL Server相似,PostGIS使用两种类型:“几何”和“地理”。

使用地理而不是几何类型,让我们再次尝试测量洛杉矶和巴黎之间的距离。 代替ST_GeometryFromText(text),我们将使用ST_GeographyFromText(text)。

SELECT ST_Distance(
  ST_GeographyFromText('POINT(-118.4079 33.9434)'), -- Los Angeles (LAX)
  ST_GeographyFromText('POINT(2.5559 49.0083)')     -- Paris (CDG)
  );

数量很大! 地理位置计算得出的所有返回值均以米为单位,因此我们的答案是9124公里。

较旧的PostGIS版本使用ST_Distance_Spheroid(点,点,测量)函数支持非常基本的球形计算。 但是,ST_Distance_Spheroid基本上受到限制。 该功能仅适用于点,不支持跨极点或国际日期线的索引。

当提出类似“从洛杉矶到巴黎的航班将到冰岛多远?”之类的问题时,支持非点几何的需求变得非常明显。

示意图

使用笛卡尔坐标系上的地理坐标(紫色线)确实会产生非常错误的答案! 使用大圈路线(红线)会给出正确的答案。
如果我们将LAX-CDG航班转换为线串,并使用地理位置计算到冰岛某个点的距离,我们将获得以米为单位的正确答案(召回率)。

SELECT ST_Distance(
  ST_GeographyFromText('LINESTRING(-118.4079 33.9434, 2.5559 49.0083)'), -- LAX-CDG
  ST_GeographyFromText('POINT(-22.6056 63.9850)')                        -- Iceland (KEF)
);

因此,在LAX-CDG路线上最接近冰岛的航线(从其国际机场测量)为502公里。

对于跨越国际日期变更线的要素,笛卡尔处理地理坐标的方法完全被分解。 从洛杉矶到东京的最短大圆航线穿越太平洋。 最短的笛卡尔路线穿越大西洋和印度洋。

示意图

SELECT ST_Distance(
  ST_GeometryFromText('Point(-118.4079 33.9434)'),  -- LAX
  ST_GeometryFromText('Point(139.733 35.567)'))     -- NRT (Tokyo/Narita)
    AS geometry_distance, 
ST_Distance(
  ST_GeographyFromText('Point(-118.4079 33.9434)'), -- LAX
  ST_GeographyFromText('Point(139.733 35.567)'))    -- NRT (Tokyo/Narita) 
    AS geography_distance;
使用Geography

为了将几何数据加载到地理表中,首先需要将几何投影到EPSG:4326(经度/纬度)中,然后再将其更改为地理。
ST_Transform(geometry,srid)函数将坐标转换为地理,而Geography(geometry)函数则将其从几何“投射”到地理。

CREATE TABLE nyc_subway_stations_geog AS
SELECT 
  Geography(ST_Transform(geom,4326)) AS geog, 
  name, 
  routes
FROM nyc_subway_stations;

在地理表上建立空间索引与几何图形完全相同:

CREATE INDEX nyc_subway_stations_geog_gix 
ON nyc_subway_stations_geog USING GIST (geog);

两者之间的区别在于:地理索引将正确处理涵盖极点或国际日期变更线的查询,而几何索引则不会。

地理类型只有很少的本机函数:

ST_AsText(geography)返回文本
ST_GeographyFromText(text)返回地理
ST_AsBinary(geography)返回bytea
ST_GeogFromWKB(bytea)返回地理位置
ST_AsSVG(geography)返回文本
ST_AsGML(geography)返回文本
ST_AsKML(geography)返回文本
ST_AsGeoJson(geography)返回文本
ST_Distance(geography,geography)返回双精度
ST_DWithin(geography,geography,float8)返回布尔值
ST_Area(geography)返回double
ST_Length(geography)返回double
ST_Covers(geography,geography)返回布尔值
ST_CoveredBy(geography,geography)返回布尔值
ST_Intersects(geography,geography)返回布尔值
ST_Buffer(geography,float8)返回地理位置[^ 1]
ST_Intersection(geography,geography)返回地理信息[^ 2]
创建Geography表

用于创建带有geography列的新表的SQL与创建几何表的SQL非常相似。 但是,地理区域具有在创建表时直接指定对象类型的功能。 例如:

CREATE TABLE airports (
  code VARCHAR(3),
  geog GEOGRAPHY(Point)
);

INSERT INTO airports VALUES ('LAX', 'POINT(-118.4079 33.9434)');
INSERT INTO airports VALUES ('CDG', 'POINT(2.5559 49.0083)');
INSERT INTO airports VALUES ('KEF', 'POINT(-22.6056 63.9850)');

在表定义中,GEOGRAPHY(Point)将我们的机场数据类型指定为点。 新的地理位置字段不会在geometry_columns视图中注册。 而是将它们注册在名为geography_columns的视图中。

SELECT * FROM geography_columns;
转换为Geometry对象

虽然地理类型的基本功能可以处理许多用例,但有时您可能需要访问仅几何类型支持的其他功能。
幸运的是,您可以将对象从地理区域来回转换为几何。

强制转换的PostgreSQL语法约定是将:: typename附加到要转换的值的末尾。 因此,2 :: text将数字2转换为文本字符串’2’。 而’POINT(0 0)':: geometry会将点的文本表示形式转换为几何点。

ST_X(point)函数仅支持几何类型。 我们如何从地理区域读取X坐标?

SELECT code, ST_X(geog::geometry) AS longitude FROM airports;

通过将:: geometry附加到我们的geoge值,我们将对象转换为SRID为4326的几何。从那里我们可以使用与想象中一样多的几何函数。 但是,请记住-现在我们的对象是几何,坐标将被解释为笛卡尔坐标,而不是球形坐标。

为什么不使用Geography

地理是公认的坐标-每个人都了解纬度/经度的含义,但是很少有人了解UTM坐标的含义。为什么不一直使用地理?

首先,如前所述,直接支持地理类型的可用功能(现在)少得多。您可能会花费大量时间来解决地理类型限制。
其次,球面上的计算比笛卡尔计算要昂贵得多。例如,距离的笛卡尔公式(Pythagoras)涉及对sqrt()的一次调用。距离(Haversine)的球形公式涉及两个sqrt()调用,一个arctan()调用,四个sin()调用和两个cos()调用。三角函数非常昂贵,球面计算涉及很多函数。

结论

如果您的数据在地理上是紧凑的(包含在一个州,县或市内),则将几何类型与对您的数据有意义的笛卡尔投影一起使用。请访问http://epsg.io网站,并输入您所在地区的名称,以选择可能的参考系统。

如果需要使用地理位置分散(覆盖世界大部分地区)的数据集来测量距离,请使用地理类型。通过在地理环境中工作而节省的应用程序复杂性将抵消任何性能问题。并且转换为Geometry可以抵消大多数功能限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丷丩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值