以后估计会长期从事gis
相关的工作,postgis
作为一款功能比较强大的gis
数据库还是需要好好学习一下的。虽然几何数据存储用任何一种类型的数据库都可以自行实现,但也仅仅只是存储,后续的坐标转换、空间分析等功能如果都要一一自己实现,那势必非常麻烦,postgis
已经集成了这些功能,在此记录一下学习过程,便于以后回顾。
postgis
是postgresql
数据库的一个扩展,所以安装postgis
前必须先安装postgresql
(点此下载),可根据自己的系统下载对应的安装包,具体安装过程就不说明了,网上有很多教程。
如果你的电脑装有docker
,则推荐使用postgis
的docker
镜像,可以省去安装的麻烦,部署迁移管理也都更加方便。
docker pull postgis/postgis
运行postgis容器,设置容器名称your_container_name
和postgres的访问密码your_postgres_passwd
docker run -d --name your_container_name -P -p 5432:5432 -e POSTGRES_PASSWORD=your_postgres_passwd postgis/postgis
以后想要使用postgis
数据库,只要启动此容器就行了。
postgres
数据库test
,用于学习create database test
test
数据库,并增加postgis
扩展create extension postgis
postgis
版本,如果由版本号显示则说明postgis
数据库创建成功select postgis_full_version()
选择WGS84
坐标系下的1个点(120, 40, 500)
,使用EPSG网站进行坐标转换得到另外两个坐标系下的坐标,后面就用这两个坐标进行读写测试。
EPSG:3857 WGS 84 / Pseudo-Mercator
坐标系下的坐标为(13358338.90, 4865942.28, 500)
,EPSG:4586 New Beijing / Gauss-Kruger CM 117E
坐标系下的坐标为(756206.42, 4433921.00, 500)
postgis
数据库支持OGC
标准的空间几何数据类型,其格式分WKT
(Well-Known Text
)和WKB
(Well-Known Binary
)两种,前者是文本格式,后者是二进制格式,WKT
格式的几何类型数据如下所示(举例,未列全),同一点坐标用空格
分隔,不同点坐标用逗号
分隔:
POINT(0 0)
二维点
POINTZ(0 0 0)
三维点
POINTZM(0 0 0 0)
三维带属性值的点
LINESTRING(0 0, 1 1, 1 2)
二维线
POLYGON((0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1))
二维多边形
postgis
对OGC
的格式进行了扩展,分为EWKT
和EWKB
两种,这两种类型主要在数据的表示上进行了简化,如WKT
表示有POINT
、POINTZ
、POINTM
、POINTZM
四种形式,EWKT
则只有POINT
和POINTM
两种形式,EWKT
的POINT
可以表示二维或三维,取决于填写的坐标数量,而WKT
的二维和三维是根据类型名是否含Z
来区分的,其基本对比如下
类型 | WKT | EWKT |
---|---|---|
二维点 | POINT(0 0) | POINT(0 0) |
三维点 | POINTZ(0 0 0) | POINT(0 0 0) |
二维带属性点 | POINTM(0 0 0) | POINTM(0 0 0) |
三维带属性点 | POINTZM(0 0 0 0) | POINTM(0 0 0 0) |
postgis
数据库可以创建带有几何类型字段的数据表,其关键字为geometry
,此字段可以存储点线面等几何类型数据以及坐标系参数srid
(实际上是EPSG
的编号)。在创建表时,该字段可以不带参数,此时字段可以存储不同类型的几何数据和坐标系参数;也可以带上参数,格式为(geomType, srid)
,geomType
表示几何数据类型,srid
表示投影参数,如定义一个坐标系为WGS84墨卡托投影
的三维点类型字段对应的描述为(pointz,3857)
(建表时的类型得用OGC
的格式)。
如果表里存储的数据都是相同坐标系和几何类型的,可以在建表时指定,这样在后续的数据插入时就不需要再设置坐标系了。注意:设置了坐标系和类型的表在插入其他类型的坐标系和几何类型时会报错
。
表名为test
,id
为自增字段,name
为几何数据名称,geom
为几何数据
create table test (id serial PRIMARY KEY, name VARCHAR(50), geom geometry(pointz, 3857))
st_geomfromtext
表示把字符串转化为WKT
格式
insert into test (name, geom) values('point1', st_geomfromtext('pointz(13358338.90 4865942.28 500)'))
st_geomfromewkt
表示把字符串转化为EWKT
格式,可以看出相同的数据在WKT
和EWKT
两种不同的解析格式导入之后还是一致的。
insert into test (name, geom) values('point1', st_geomfromewkt('point(13358338.90 4865942.28 500)'))
st_astext
表示把几何数据转化为WKT
格式,可以看到结果里带着POINTZ
,坐标与原来一致
select name, st_astext(geom) from test
st_asewkt
表示把几何数据转化为EWKT
格式,可以看到结果里带着SRID
和POINT
,坐标与原来一致
select name, st_asewkt(geom) from test
st_asgeojson
表示把几何数据转化为JSON
格式,可以看到结果为键值对格式,相比较前两种取值会更方便些
select name, st_asgeojson(geom) from test
st_transform
表示将几何数据转到目标坐标系,参数格式为(几何数据,目标坐标系)
,可以看到输出的坐标与转换前的WGS84
坐标一致(小数8位后有误差)
select name, st_astext(st_transform(geom, 4326)) from test
select name, st_asewkt(st_transform(geom, 4326)) from test
综合类看,基于st_transform
和st_asgeojson
可以方便地得到WGS84
坐标系下的经纬度坐标,便于后续可视化绘制。
select name, st_asgeojson(st_transform(geom, 4326)) from test
如果数据表存储的数据类型或坐标系不固定,则可以在建表时不指定,在插入数据时指定。
geometry
参数不用设置
create table test2 (id serial PRIMARY KEY, name VARCHAR(50), geom geometry)
使用坐标系为3857
的坐标插入一个点
insert into test2 (name, geom) values ('point1', st_geomfromewkt('srid=3857;point(13358338.90 4865942.28 500)'))
使用坐标系为4586
的坐标插入一条线,线的点xy
相同,z
不同,可以看出不同几何类型和坐标系可以成功导入
insert into test2 (name, geom) values ('linestring1', st_geomfromewkt('srid=4586;linestring(756206.42 4433921.00 500, 756206.42 4433921.00 600)'))
select name, st_astext(geom) from test2
select name, st_asewkt(geom) from test2
select name, st_asgeojson(geom) from test2
select name, st_astext(st_transform(geom, 4326)) from test2
select name, st_asewkt(st_transform(geom, 4326)) from test2
select name, st_asgeojson(st_transform(geom, 4326)) from test2
待更新