GIS

PostGIS Geometry是什么

了解PostGIS中Geometry空间数据类型的基本概念、常见几何类型、SRID、坐标、空间计算以及Geometry与PostgreSQL和GIS数据的关系。

阅读约 129 分钟

PostGIS Geometry是什么

PostGIS Geometry是PostGIS提供的一种空间数据类型,用于在PostgreSQL数据库中存储和处理二维、三维以及带测量值的几何对象。

PostGIS是PostgreSQL的空间数据库扩展。

通过Geometry,可以在数据库中直接保存:

  • Point
  • LineString
  • Polygon
  • MultiPoint
  • MultiLineString
  • MultiPolygon
  • GeometryCollection

例如:

POINT (116.397 39.908)

可以作为一个Geometry存储在PostgreSQL表中。

简单来说:

PostGIS Geometry就是PostgreSQL数据库中用于存储和计算GIS空间几何数据的数据类型。

PostGIS是什么

PostGIS是PostgreSQL的空间数据库扩展。

普通PostgreSQL主要处理:

整数
字符串
日期
JSON
数组

安装PostGIS以后,可以增加:

Geometry
Geography
Raster
空间索引
空间函数
空间分析

可以理解为:

PostgreSQL
    ↓
PostGIS
    ↓
空间数据库能力

例如:

SELECT *
FROM roads
WHERE ST_Length(geom) > 1000;

数据库就可以直接进行空间计算。

Geometry的基本结构

PostGIS中的Geometry不仅包含几何类型和坐标,还包含空间参考信息。

可以简单理解为:

Geometry
├── Geometry Type
│   ├── Point
│   ├── LineString
│   └── Polygon
│
├── Coordinates
│   ├── X
│   ├── Y
│   ├── Z
│   └── M
│
└── SRID
    └── Coordinate Reference System

例如:

POINT (116.397 39.908)

对应:

Geometry Type = Point
X = 116.397
Y = 39.908

如果设置:

SRID = 4326

就可以明确这些坐标使用的是EPSG:4326坐标参考系统。

创建Geometry字段

PostGIS中最常见的Geometry字段定义方式:

CREATE TABLE cities (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    geom geometry(Point, 4326)
);

这里:

geom geometry(Point, 4326)

表示:

geom
 ↓
Geometry字段

Point
 ↓
只允许Point类型

4326
 ↓
SRID为EPSG:4326

因此数据库可以对空间数据进行一定程度的类型约束。

插入Point

可以使用WKT创建Geometry:

INSERT INTO cities (name, geom)
VALUES (
    '北京',
    ST_GeomFromText('POINT (116.397 39.908)', 4326)
);

其中:

ST_GeomFromText()

用于将WKT转换为PostGIS Geometry。

结构:

WKT
 ↓
ST_GeomFromText
 ↓
Geometry
 ↓
PostGIS

查询Geometry

例如:

SELECT name, geom
FROM cities;

查询结果中的:

geom

就是PostGIS Geometry对象。

如果希望转换成WKT:

SELECT ST_AsText(geom)
FROM cities;

结果:

POINT(116.397 39.908)

因此:

Geometry
 ↓
ST_AsText()
 ↓
WKT

Geometry常见类型

PostGIS支持常见的OGC空间几何类型。

主要包括:

Point
MultiPoint

LineString
MultiLineString

Polygon
MultiPolygon

GeometryCollection

可以理解为:

Geometry
├── Point
├── MultiPoint
├── LineString
├── MultiLineString
├── Polygon
├── MultiPolygon
└── GeometryCollection

Point

Point表示一个空间位置。

例如:

'POINT (116.397 39.908)'

可以表示:

  • 城市
  • POI
  • 医院
  • 学校
  • 设备
  • 传感器
  • 摄像头

数据库定义:

CREATE TABLE devices (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    geom geometry(Point, 4326)
);

LineString

LineString表示一条有顺序的线。

例如:

LINESTRING (
    116.397 39.908,
    116.405 39.915,
    116.412 39.920
)

常用于:

  • 道路
  • 河流
  • 铁路
  • 管线
  • GPS轨迹

数据库定义:

CREATE TABLE roads (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    geom geometry(LineString, 4326)
);

Polygon

Polygon表示一个封闭区域。

例如:

POLYGON ((
    116.390 39.900,
    116.400 39.900,
    116.400 39.910,
    116.390 39.910,
    116.390 39.900
))

常用于:

  • 行政区
  • 地块
  • 建筑物
  • 公园
  • 土地利用区域

数据库定义:

CREATE TABLE parcels (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    geom geometry(Polygon, 4326)
);

MultiPoint

MultiPoint用于存储多个独立Point。

例如:

MULTIPOINT (
    (116.397 39.908),
    (116.405 39.915),
    (116.412 39.920)
)

适合:

  • 采样点
  • 多个监测点
  • 一组设施
  • 空间事件

MultiLineString

MultiLineString表示多个独立LineString。

例如:

MULTILINESTRING (
    (
        116.397 39.908,
        116.405 39.915
    ),
    (
        116.420 39.920,
        116.430 39.925
    )
)

可以表示:

  • 多段道路
  • 多段河流
  • 多段管线
  • 铁路网络

MultiPolygon

MultiPolygon表示多个Polygon组成的Geometry。

例如:

MULTIPOLYGON (
    (
        (
            116.390 39.900,
            116.400 39.900,
            116.400 39.910,
            116.390 39.910,
            116.390 39.900
        )
    ),
    (
        (
            116.420 39.920,
            116.430 39.920,
            116.430 39.930,
            116.420 39.930,
            116.420 39.920
        )
    )
)

适合:

  • 群岛
  • 多个不连续区域
  • 多块土地
  • 多个行政区域

GeometryCollection

GeometryCollection可以包含不同类型的Geometry。

例如:

GEOMETRYCOLLECTION (
    POINT (116.397 39.908),
    LINESTRING (
        116.397 39.908,
        116.405 39.915
    )
)

其中可以同时包含:

Point
LineString
Polygon

因此:

GeometryCollection
├── Point
├── LineString
└── Polygon

不过实际数据库设计中,通常优先使用明确的Geometry类型。

SRID是什么

SRID用于表示Geometry使用的空间参考系统。

例如:

SRID = 4326

表示:

EPSG:4326

常见:

4326
3857

例如:

geometry(Point, 4326)

表示:

Point
+
EPSG:4326

Geometry和SRID的关系

仅仅看到:

POINT (116.397 39.908)

无法完全确定坐标的空间含义。

还需要知道:

SRID

因此:

Coordinates
+
SRID
=
完整空间参考信息

例如:

POINT (116.397 39.908)
SRID 4326

可以理解为:

X = 116.397
Y = 39.908
CRS = EPSG:4326

设置SRID

可以使用:

ST_SetSRID()

例如:

SELECT ST_SetSRID(
    ST_GeomFromText('POINT (116.397 39.908)'),
    4326
);

这里需要特别注意:

ST_SetSRID主要是给Geometry设置或修改SRID标识,并不会把坐标值从一个坐标系转换到另一个坐标系。

如果需要真正转换坐标,应使用:

ST_Transform()

Geometry坐标转换

例如将EPSG:4326转换为EPSG:3857:

SELECT ST_Transform(
    geom,
    3857
)
FROM cities;

关系:

EPSG:4326
    ↓
ST_Transform
    ↓
EPSG:3857

所以:

ST_SetSRID
 ↓
设置坐标参考标识

ST_Transform
 ↓
真正进行坐标转换

这是PostGIS中非常重要的区别。

Geometry的Z坐标

PostGIS Geometry可以支持三维坐标。

例如:

POINT Z (116.397 39.908 50)

其中:

X = 116.397
Y = 39.908
Z = 50

Z可以表示:

  • 高程
  • 建筑高度
  • 三维空间位置
  • 地形高度

数据库字段可以定义为:

geometry(PointZ, 4326)

Geometry的M值

Geometry还可以支持M值。

例如:

POINT M (116.397 39.908 100)

M通常用于表示:

  • 里程
  • 测量值
  • 时间
  • 路径上的距离

也可以使用:

X Y Z M

表示四维坐标结构。

Geometry与WKT

WKT是Geometry的一种文本表示方式。

例如:

POINT (116.397 39.908)

PostGIS可以通过:

ST_GeomFromText()

将WKT转换为Geometry。

例如:

SELECT ST_GeomFromText(
    'POINT (116.397 39.908)',
    4326
);

反过来:

SELECT ST_AsText(geom)
FROM cities;

得到:

POINT(116.397 39.908)

因此:

WKT
 ↕
Geometry

Geometry与WKB

WKB是Geometry的二进制表示方式。

PostGIS可以使用:

ST_AsBinary()

将Geometry转换为WKB。

例如:

SELECT ST_AsBinary(geom)
FROM cities;

反向可以使用:

ST_GeomFromWKB()

因此:

WKT
 ↓
文本表示

WKB
 ↓
二进制表示

Geometry
 ↓
数据库空间对象

Geometry与GeoJSON

PostGIS可以直接将Geometry转换为GeoJSON。

使用:

ST_AsGeoJSON()

例如:

SELECT ST_AsGeoJSON(geom)
FROM cities;

结果类似:

{
  "type": "Point",
  "coordinates": [116.397, 39.908]
}

反过来,也可以使用:

ST_GeomFromGeoJSON()

将GeoJSON Geometry转换为PostGIS Geometry。

因此:

GeoJSON
 ↓
ST_GeomFromGeoJSON
 ↓
PostGIS Geometry

Geometry与Feature

PostGIS中的Geometry通常只负责空间部分。

例如:

Geometry
    ↓
POINT (116.397 39.908)

属性信息可以单独存储:

name = 北京
type = city
population = ...

数据库表:

cities
├── id
├── name
├── type
└── geom

其中:

geom
 ↓
Geometry

name/type
 ↓
Attributes

因此可以理解为:

Feature
=
Attributes
+
Geometry

Geometry计算长度

对于LineString,可以使用:

ST_Length()

例如:

SELECT ST_Length(geom)
FROM roads;

返回Geometry长度。

需要注意:

长度的单位取决于Geometry所在的坐标参考系统。

如果使用经纬度坐标:

EPSG:4326

Geometry中的数值单位是度,并不适合直接当作米使用。

因此实际距离计算时,需要合理选择投影坐标系,或者根据需求使用Geography。

Geometry计算面积

Polygon可以使用:

ST_Area()

例如:

SELECT ST_Area(geom)
FROM parcels;

返回Polygon面积。

同样需要注意:

面积单位

取决于坐标系单位。

例如投影坐标使用米:

面积 = 平方米

而经纬度坐标直接计算并不能简单理解为平方米。

Geometry计算距离

PostGIS可以使用:

ST_Distance()

计算两个Geometry之间的距离。

例如:

SELECT ST_Distance(
    a.geom,
    b.geom
)
FROM cities a, cities b;

如果Geometry使用适合距离计算的投影坐标系,返回值通常可以直接理解为对应的线性单位。

对于经纬度距离,需要注意坐标系和单位问题。

Geometry缓冲区

PostGIS可以使用:

ST_Buffer()

创建缓冲区。

例如:

SELECT ST_Buffer(
    geom,
    100
)
FROM roads;

可以理解为:

道路
 ↓
100单位缓冲
 ↓
Polygon

常用于:

  • 道路影响范围
  • 服务区分析
  • 查询附近设施
  • 环境影响范围
  • 安全距离分析

Geometry相交

可以使用:

ST_Intersects()

判断两个Geometry是否相交。

例如:

SELECT ST_Intersects(
    a.geom,
    b.geom
)
FROM roads a, parcels b;

返回:

true

或者:

false

这类函数是空间查询的基础。

Geometry包含关系

可以使用:

ST_Contains()

判断一个Geometry是否包含另一个Geometry。

例如:

行政区
   ↓
包含
   ↓
城市

SQL:

SELECT ST_Contains(
    district.geom,
    city.geom
)
FROM districts district, cities city;

Geometry空间关系

PostGIS提供大量空间关系判断函数。

例如:

ST_Intersects
ST_Contains
ST_Within
ST_Covers
ST_Touches
ST_Overlaps
ST_Crosses
ST_Disjoint

可以用于判断:

相交
包含
位于内部
覆盖
接触
重叠
穿过
分离

因此:

Geometry
 ↓
Spatial Relationship
 ↓
空间分析

Geometry空间集合运算

PostGIS还可以对Geometry进行空间集合运算。

常见函数:

ST_Intersection
ST_Union
ST_Difference
ST_SymDifference

例如:

Polygon A
     +
Polygon B
     ↓
Intersection
     ↓
交集区域

使用:

SELECT ST_Intersection(a.geom, b.geom)
FROM a, b;

Geometry空间索引

PostGIS最重要的能力之一就是空间索引。

常见索引:

CREATE INDEX idx_cities_geom
ON cities
USING GIST (geom);

这里使用:

GiST

索引支持空间数据的高效查询。

例如:

SELECT *
FROM cities
WHERE ST_DWithin(
    geom,
    ST_SetSRID(
        ST_Point(116.397, 39.908),
        4326
    ),
    1000
);

在正确的索引和查询条件下,可以大幅减少需要检查的空间对象数量。

为什么需要空间索引

假设数据库中有:

100万个Point

如果查询:

找距离某位置最近的对象。

没有空间索引时可能需要:

100万
 ↓
逐个计算

有空间索引后:

100万
 ↓
空间索引筛选
 ↓
少量候选对象
 ↓
精确计算

因此:

Geometry
+
GiST空间索引
=
高效空间查询

Geometry字段约束

可以限制Geometry类型:

geometry(Point, 4326)

也可以使用更宽泛的:

geometry(Geometry, 4326)

例如:

geometry(Point, 4326)

表示:

只允许Point
SRID必须为4326

而:

geometry(Geometry, 4326)

表示:

允许不同Geometry类型
SRID为4326

在数据库设计中,应根据实际业务选择合适的约束。

Geometry有效性

PostGIS可以检查Geometry是否有效。

例如:

SELECT ST_IsValid(geom)
FROM parcels;

结果:

true

或者:

false

常见无效Geometry包括:

Polygon自相交
环结构错误
重复节点
异常坐标

对于Polygon等复杂Geometry,有效性非常重要。

修复无效Geometry

PostGIS提供:

ST_MakeValid()

可以尝试修复无效Geometry。

例如:

SELECT ST_MakeValid(geom)
FROM parcels
WHERE NOT ST_IsValid(geom);

处理空间数据导入时,经常需要:

导入
 ↓
检查有效性
 ↓
修复
 ↓
空间分析

Geometry与Geography

PostGIS中除了Geometry,还有:

Geography

两者都可以存储空间数据,但使用场景不同。

简单理解:

Geometry
 ↓
平面坐标模型

而:

Geography
 ↓
地球椭球体上的地理坐标模型

例如:

geometry(Point, 4326)

与:

geography(Point, 4326)

虽然都可以表示经纬度Point,但空间计算的模型不同。

Geometry与Geography区别

特性GeometryGeography
模型平面地球曲面/椭球体
常用坐标投影坐标或经纬度经纬度
空间计算平面计算地理测量计算
性能通常较快某些计算更复杂
适合GIS空间分析地球范围距离、面积

因此不能简单认为:

Geometry一定比Geography好。

应该根据业务需求选择。

Geometry常见SQL

创建空间字段:

CREATE TABLE places (
    id SERIAL PRIMARY KEY,
    name TEXT,
    geom geometry(Point, 4326)
);

创建Point:

ST_SetSRID(
    ST_Point(116.397, 39.908),
    4326
)

WKT转Geometry:

ST_GeomFromText(
    'POINT (116.397 39.908)',
    4326
)

Geometry转WKT:

ST_AsText(geom)

Geometry转GeoJSON:

ST_AsGeoJSON(geom)

坐标转换:

ST_Transform(geom, 3857)

判断相交:

ST_Intersects(a.geom, b.geom)

计算距离:

ST_Distance(a.geom, b.geom)

创建缓冲:

ST_Buffer(geom, 100)

检查有效性:

ST_IsValid(geom)

一个完整示例

创建城市表:

CREATE TABLE cities (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    geom geometry(Point, 4326)
);

插入数据:

INSERT INTO cities (name, geom)
VALUES (
    '北京',
    ST_SetSRID(
        ST_Point(116.397, 39.908),
        4326
    )
);

查询:

SELECT
    id,
    name,
    ST_AsText(geom) AS wkt
FROM cities;

结果:

id | name | wkt
---+------+----------------------
1  | 北京 | POINT(116.397 39.908)

转换坐标:

SELECT
    ST_AsText(
        ST_Transform(geom, 3857)
    )
FROM cities;

转换为GeoJSON:

SELECT ST_AsGeoJSON(geom)
FROM cities;

这样就形成了一个完整的:

创建
 ↓
存储
 ↓
查询
 ↓
转换
 ↓
输出

Geometry数据流程

一个典型PostGIS数据处理流程:

Shapefile
GeoJSON
WKT
CSV
    ↓
导入PostGIS
    ↓
Geometry
    ↓
设置SRID
    ↓
建立空间索引
    ↓
空间查询
    ↓
空间分析
    ↓
GeoJSON / WKT / WKB
    ↓
WebGIS

例如WebGIS应用:

PostGIS
    ↓
空间查询
    ↓
GeoJSON
    ↓
OpenLayers / Leaflet
    ↓
地图

Geometry与WebGIS

PostGIS经常作为WebGIS后端数据库。

典型架构:

                    WebGIS
                       ↓
              OpenLayers / Leaflet
                       ↓
                    API
                       ↓
                  后端服务
                       ↓
                   PostGIS
                       ↓
                   Geometry

数据库负责:

数据存储
空间查询
空间分析
空间索引

前端负责:

地图显示
交互
样式
编辑

Geometry知识结构

可以这样理解PostGIS Geometry:

PostGIS
    ↓
Geometry
├── Type
│   ├── Point
│   ├── LineString
│   ├── Polygon
│   ├── MultiPoint
│   ├── MultiLineString
│   ├── MultiPolygon
│   └── GeometryCollection
│
├── Coordinates
│   ├── X
│   ├── Y
│   ├── Z
│   └── M
│
├── SRID
│   └── CRS
│
├── Input / Output
│   ├── WKT
│   ├── WKB
│   └── GeoJSON
│
├── Spatial Functions
│   ├── Distance
│   ├── Buffer
│   ├── Intersection
│   └── Spatial Relations
│
└── Spatial Index
    └── GiST

Geometry、WKT、WKB、GeoJSON的关系

可以简单理解为:

                 Geometry
                    │
        ┌───────────┼───────────┐
        ↓           ↓           ↓
       WKT         WKB       GeoJSON
      文本表示     二进制表示    JSON表示

例如同一个Point:

WKT:

POINT (116.397 39.908)

GeoJSON:

{
  "type": "Point",
  "coordinates": [116.397, 39.908]
}

它们表达的是同一个空间对象,只是表示形式不同。

总结

PostGIS Geometry是PostgreSQL空间数据库中最核心的数据类型之一。

它用于存储:

Point
LineString
Polygon
MultiPoint
MultiLineString
MultiPolygon
GeometryCollection

Geometry不仅包含:

Coordinates

还可以关联:

SRID
Z
M

并且PostGIS可以直接对Geometry进行:

距离计算
长度计算
面积计算
缓冲区分析
相交判断
包含判断
空间集合运算
有效性检查
坐标转换

同时可以通过GiST等空间索引提高空间查询效率。

可以记住:

PostGIS Geometry = PostgreSQL中的空间几何数据 + SRID + 空间计算能力 + 空间索引。

🧰

相关工具

使用 IYATools 在线工具快速处理 GIS 数据