坐标为"地理(geographics)"形式或者说是" 纬度(latitude)/经度(longitude)"形式的数据非常常见。
与Mercator(墨卡托)、UTM(通用横轴墨卡托)、Stateplane中的坐标不同,地理坐标不是笛卡尔平面坐标(Cartesian coordinates)。地理坐标并不表示平面上与原点的线性距离,相反,这些球坐标描述了地球上的角坐标。在球坐标中,点由该点与参考子午线(经度)的旋转角度和该点与赤道的角度(纬度)指定。
你可以将地理坐标看作近似的笛卡尔平面坐标,并继续进行空间计算,然而,关于距离、长度和面积的测量将会是毫无意义的。由于球坐标测量角度距离,因此单位以"度"表示。此外,索引和真/假测试(如相交和包含)可能会变得非常错误,因为越与极点或国际日期线接近的区域,点与点之间的距离变得越大。
为了计算出真实的距离,我们不能把地理坐标近似的看成笛卡尔平面坐标,而应该把它们看成是球坐标。我们必须把两点之间的距离作为球面上的真实路径来测量——大圆(大圆被定义为过球心的平面和球面的交线)的一部分。
使用geography这种数据类型时,PostGIS的内部计算是基于实际地球球体来计算的;而使用geometry这种数据类型时,PostGIS的内部计算是基于平面来计算的。
早期版本的PostGIS支持使用ST_Distance_Spheroid(point, point, measurement)函数对球体进行非常基本的计算。然而,ST_Distance_Spheroid功能是有限的,该函数仅适用于点,不支持跨极点或国际日期变更线的要素的索引。
一、使用Geography
为了将geometry数据加载到geography表中,首先需要将geometry转换到EPSG:4326(经度-longitude/纬度-latitude),然后再将其转换为geography。ST_Transform(geometry, srid)函数能将坐标转换为地理坐标,Geography(geometry)函数能将基于EPSG:4326的geometry数据类型转换为geography数据类型。
在geography表上构建空间索引与在geometry表上构建空间索引完全相同:
不同之处在于:geography空间索引将正确地处理覆盖极点或国际日期变更线的要素的查询,而geometry空间索引则不会。
对于geography类型,只有相关的少量空间函数:
ST_AsText(geography) returns
textST_GeographyFromText(text) returns
geographyST_AsBinary(geography) returns
byteaST_GeogFromWKB(bytea) returns
geographyST_AsSVG(geography) returns
textST_AsGML(geography) returns
textST_AsKML(geography) returns
textST_AsGeoJson(geography) returns
textST_Distance(geography, geography) returns
doubleST_DWithin(geography, geography, float8) returns
booleanST_Area(geography) returns
doubleST_Length(geography) returns
doubleST_Covers(geography, geography) returns
booleanST_CoveredBy(geography, geography) returns
booleanST_Intersects(geography, geography) returns
booleanST_Buffer(geography, float8) returns
geographyST_Intersection(geography, geography) returns
geography
二、创建一个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的视图中注册的。
三、转换为Geometry
虽然geography类型的空间函数已经可以处理许多问题,但有时你可能需要访问仅由geometry类型支持的其他空间函数。幸运的是,你可以将对象从geography转换为geometry。
PostgreSQL的类型转换语法是将:: typename附加到希望转换的值的末尾。因此,2::text将数字2转换为文本字符串"2";'POINT(0 0)' :: geometry将点的文本表示形式转换为geometry点。
ST_X(point)函数仅支持geometry类型
SELECT code, ST_X(geog::geometry) AS longitude FROM airports;通过将::geometry附加到geography值后面,可以将对象转换为SRID为4326的geometry。现在,我们就可以使用任何的geometry函数了。但是现在的对象是geometry,坐标将被解释为笛卡尔平面坐标,而不是球体坐标。
四、为什么使用Geography
地理坐标是大众普遍接受的坐标——每个人都知道经度/纬度的含义,但很少有人理解UTM坐标的含义。那么为什么不一直用geography类型呢?
首先,如前所述,可直接支持geography类型的函数要少得多。
其次,球体上的计算要比笛卡尔计算计算量大得多。例如,基于笛卡尔平面坐标的计算距离的公式(Pythagoras)涉及一次对sqrt()的调用,基于球体坐标的计算距离的公式包含两次sqrt()调用、一次arctan()调用、四次sin()调用和两次cos()调用,三角函数的计算是非常耗费资源的。
结论:
如果你的数据在地理范围上是紧凑的(包含在州、县或市内),请使用基于笛卡尔坐标的geometry类型,因为范围小,所以可以使你的数据有意义。
如果你需要测量在地理范围上是分散的数据集(覆盖世界大部分地区)的距离,请使用geography类型。通过基于geography类型运行而节省的应用程序级别复杂性将抵消任何硬件性能问题。同时通过将geography类型转换为geometry类型的方法可以消除大多数功能限制问题。
Comments