PostGIS教程十三:地理

    目录

一、使用Geography

二、创建一个Geography表

三、转换为Geometry

四、为什么使用Geography


    坐标为”地理(geographics)”或”纬度(latitude)/经度(longitude)”的数据非常常见。

    与Mercator(墨卡托)、UTM(通用横轴墨卡托)、Stateplane中的坐标不同,地理坐标不是笛卡尔平面坐标(Cartesian coordinates)。地理坐标并不表示平面上与原点的线性距离,相反,这些球坐标描述了地球上的角坐标。在球坐标中,点由该点与参考子午线(经度)的旋转角度和该点与赤道的角度(纬度)指定。

    _images/cartesian_spherical.jpg

    你可以将地理坐标看作近似的笛卡尔平面坐标,并继续进行空间计算,然而,距离、长度和面积的测量将是毫无意义的。由于球坐标测量角度距离,因此单位以”“表示。此外,索引和真/假测试(如相交包含)可能会变得非常错误。越与极点或国际日期线接近的区域,点与点之间的距离变得更大。

    例如,这里是洛杉矶Los Angeles)和巴黎Paris)的坐标:

  • Los Angeles: POINT(-118.4079 33.9434)
  • Paris: 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度。但是,这意味着什么呢?

    在地球球体上,1度对应的地球实际距离的大小是变化的。当远离赤道时,它会变得更小,当越接近两极时,地球上的经线相互之间越来越接近。因此,121度的距离并不意味着什么,这是一个没有意义的数字。

    为了计算出真实的距离,我们不能把地理坐标近似的看成笛卡尔坐标,而应该把它们看成是球坐标。我们必须把点之间的距离作为球面上的真实路径来测量——大圆的一部分

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

    注意:不同的空间数据库有不同的”处理地理”的方法:

  • 当SRID是地理坐标系统时,Oracle试图通过透明地进行地理计算来掩盖差异
  • SQL Server使用两种空间类型,一种是针对笛卡尔平面坐标数据的”STGeometry”,另一种是针对地理坐标系统数据的”StGeography”
  • Informix Spatial是Infomix的纯笛卡尔扩展,而Informix Geodetic是纯地理扩展
  • 与SQL Server类似,PostGIS使用两种类型:”geometry”和”geography”

    使用geography而不是geometry类型,让我们再次尝试测量洛杉矶巴黎之间的距离,我们将使用ST_GeographyFromText(text),而不是ST_GeometryFromText(text)

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

    一个大数字!所有地理计算的返回值都以为单位,所以我们的答案是9124km

    早期版本的PostGIS支持使用ST_Distance_Spheroid(point, point, measurement)函数对球体进行非常基本的计算。然而,ST_Distance_Spheroid功能是有限的,该函数仅适用于点,不支持跨极点或国际日期变更线的索引。

    当提出这样一个问题时,支持非点的几何图形的需求变得非常明显:”从洛杉矶到巴黎的航班路线距离冰岛有多远?

_images/lax_cdg.jpg

    在笛卡尔平面坐标系统上使用地理坐标(紫色线)确实产生了一个非常错误的答案!使用大圆路线(红线)得出了正确的答案。如果我们将LAX-CDG航班转换成一条线串,并利用geography计算到冰岛某个点的距离,我们将得到正确的答案(以为单位)。

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路线上,距离冰岛最近的路线(从冰岛的国际机场测量)是一个相对较小的502km。

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

_images/lax_nrt.png

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

    为了将geometry数据加载到geography表中,首先需要将geometry投影到EPSG:4326(经度-longitude/纬度-latitude),然后需要将其转换为geographyST_Transform(geometry, srid)函数将坐标转换为地理坐标,Geography(geometry)函数将坐标从geometry转换为geography

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

    在geography表上构建空间索引与geometry索引完全相同:

CREATE INDEX nyc_subway_stations_geog_gix
ON nyc_subway_stations_geog USING GIST (geog);

    不同之处在于:geography索引将正确地处理覆盖极点或国际日期变更线的查询,而geometry索引则不会。

    对于geography类型,只有少量的本地函数:

  • ST_AsText(geography) returns text
  • ST_GeographyFromText(text) returns geography
  • ST_AsBinary(geography) returns bytea
  • ST_GeogFromWKB(bytea) returns geography
  • ST_AsSVG(geography) returns text
  • ST_AsGML(geography) returns text
  • ST_AsKML(geography) returns text
  • ST_AsGeoJson(geography) returns text
  • ST_Distance(geography, geography) returns double
  • ST_DWithin(geography, geography, float8) returns boolean
  • ST_Area(geography) returns double
  • ST_Length(geography) returns double
  • ST_Covers(geography, geography) returns boolean
  • ST_CoveredBy(geography, geography) returns boolean
  • ST_Intersects(geography, geography) returns boolean
  • ST_Buffer(geography, float8) returns geography [1]
  • ST_Intersection(geography, geography) returns geography [1]

    

二、创建一个Geography表

    用于创建含有geography列的新表的SQL与用于创建geography表的SQL非常相似。但是,geography包含在表创建时直接指定对象类型的功能。例如:

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)airport数据类型指定为点。新的geography字段不会在geometry_columns视图中注册,相反,它们是在名为geography_columns视图中注册的。

SELECT * FROM geography_columns;

   

三、转换为Geometry

    虽然geography类型的基本函数可以处理许多用例,但有时你可能需要访问仅由geometry类型支持的其他函数。幸运的是,你可以将对象从geography来回转换为geometry

    PostgreSQL的类型转换语法是将::typename附加到希望转换的值的末尾。因此,2::text将数字2转换为文本字符串”2“;‘POINT(0 0)’ :: geometry将点的文本表示形式转换为geometry点。

    ST_X(point)函数仅支持geometry类型,那我们怎样才能从我们的geography中读取X坐标呢?

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

    通过将::geometry附加到geography值后面,可以将对象转换为SRID4326geometry。现在,我们就可以使用任何的geometry函数了。但是,请记住-现在我们的对象是geometry,坐标将被解释为笛卡尔平面坐标,而不是球体坐标

 

四、为什么使用Geography

    地理坐标是大众普遍接受的坐标——每个人都知道经度/纬度的含义,但很少有人理解UTM坐标的含义。为什么不一直用geography呢?

  • 首先,如前所述,可直接支持geography类型的函数要少得多,你可能会花费大量时间在geography类型的限制上。
  • 其次,球体上的计算要比笛卡尔计算计算量大得多。例如,距离的笛卡尔公式(Pythagoras)涉及一次对sqrt()的调用,距离的球体公式包含两次sqrt()调用、一次arctan()调用、四次sin()调用和两次cos()调用,三角函数的计算是非常耗费资源的,球面计算涉及到很多问题。

    结论是什么呢?

    如果你的数据在地理层面上是紧凑的(包含在州、县或市内),请使用基于笛卡尔坐标的geometry类型,这样使你的数据有意义。有关可能的参考系统的选择,请参见http://spatialreference.org站点并输入您所在区域的名称。

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

 

转载自:https://blog.csdn.net/qq_35732147/article/details/86489918

You may also like...