基础准备工作

1.PostGIS 的安装

在安装PostGIS前首先必须安装PostgreSQL,然后再安装好的Stack Builder中选择安装PostGIS组件。具体安装步骤可参照 PostGIS的安装与初步使用_不睡觉的怪叔叔的博客-CSDN博客_postgis

2.加载Post GIS扩展

选中指定数据库,执行加载扩展语句

–添加支持
CREATE EXTENSION postgis; --添加postgis扩展
CREATE EXTENSION pgrouting; --添加pgrouting扩展
CREATE EXTENSION postgis_topology;
CREATE EXTENSION fuzzystrmatch;
CREATE EXTENSION postgis_tiger_geocoder;

在做两点间河流轨迹及流经长度计算过程中,需要加载postgis和pgrouting两个扩展

可以通过查看加载扩展的版本验证扩展加载是否成功

–查看postgresql版本
show server_version; –查看postgis版本
SELECT PostGIS_full_version(); –查看pgrouting版本
select pgr_version();

3.河流矢量图层转成单线格式

河流包括各种汇入和汇出,为了实现流经流域的计算,河流水系矢量数据需要一个河流一个ID的方式,可以在河流交汇点处将河流进行打段处理。

4.河流矢量数据导入PostgreSQL数据库

打开位于“开始>所有程序>PostGIS 2.3 bundle for PostgreSQL”之中的PostGIS Shapefile Import/Export Manager

首先单击"View connection details"按钮,打开"PostGIS connection"对话框,输入用户名"postgres"及其对应的密码,设置连接的数据库,如下图所示:

连接数据库之后,单击"Add file"按钮,加入***.shp文件,并将其SRID设置为"4326",如下图所示。这一步绝对不能省略,否则不能正确导入数据。

5.河流数据拓扑处理

在数据分析过程中,使用到了pgrouting扩展中的 pgr_dijkstra 算法

Dijkstra算法(迪杰斯特拉算法),由荷兰计算机科学家Edsger Dijkstra于1956年提出。它是一种图搜索算法,它解决了非负代价边路径图的最短路径问题,即从起始顶点(start_vid)到结束顶点(end_vid)的最短路径。此算法可以与有向图或无向图一起使用。

函数的签名摘要:

在实际使用中,需要先明确所有的顶点,并为所有顶点分配唯一的编号,函数的 start_vid 和 end_vid 都是整型数值,函数使用edges_sql参数(sql脚本)筛选出和顶点相邻的所有边信息(即河流信息)。

所以,在使用pgr_dijkstra方法前,需要

  • 对找到河流的所有顶点信息,并做唯一整型值编号
  • 在数据库中为每条河流设置好起始顶点和结束顶点
--筛选出所有顶点信息,st_dump函数主要是将MultiLineString类型 调整成 LineString类型
select st_astext(st_startpoint((ST_Dump(geom)).geom)) from singleriver
union
select st_astext(st_endpoint((ST_Dump(geom)).geom)) from singleriver

将查询结果在Excel中进行整型值编号,再导入到postgresql中的新建表 distinctpoint 中,然后关联河流数据表,更新河流的开始顶点(source)和结束顶点编号(target)

--更新起始顶点编号
update singleriver q
set source=tt.sourcepoint
from singleriver s,
(select gid,p.id as sourcepoint from
(select gid,st_astext(st_startpoint((ST_Dump(geom)).geom)) as startpoint, st_astext(st_endpoint((ST_Dump(geom)).geom)) as endpoint from singleriver )s
left join distinctpoint p
on s.startpoint=p.point) tt
where q.gid=tt.gid
--插入结束顶点编号
update singleriver q
set target=tt.endpoint
from singleriver s,
(select gid,p.id as endpoint from
(select gid,st_astext(st_startpoint((ST_Dump(geom)).geom)) as startpoint, st_astext(st_endpoint((ST_Dump(geom)).geom)) as endpoint from singleriver )s
left join distinctpoint p
on s.endpoint=p.point) tt
where q.gid=tt.gid

至此,河流拓扑数据处理完成

PG分析处理函数

1.函数编写

CREATE OR REPLACE FUNCTION "public"."pgr_shortest_river"(IN "startx" float8, IN "starty" float8, IN "endx" float8, IN "endy" float8, OUT "river_name" varchar, OUT "v_shpath" varchar, OUT "cost" float8)
RETURNS SETOF "pg_catalog"."record" AS $BODY$
declare
v_startLine geometry;--离起点最近的线
v_endLine geometry;--离终点最近的线
v_startTarget integer;--距离起点最近线的终点
v_endSource integer;--距离终点最近线的起点
v_statpoint geometry;--在v_startLine上距离起点最近的点
v_endpoint geometry;--在v_endLine上距离终点最近的点
v_res geometry;--最短路径分析结果
v_perStart float;--v_statpoint在v_res上的百分比
v_perEnd float;--v_endpoint在v_res上的百分比
v_rec record;
first_name varchar;
end_name varchar;
first_cost double precision;
end_cost double precision;
begin
--查询离起点最近的线
execute 'select (st_dump(geom)).geom as geom,target as target,name from singleriver where
ST_DWithin(geom,ST_Geometryfromtext(''point('|| startx ||' ' || starty||')''),0.01)
order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'')) limit 1'
into v_startLine ,v_startTarget,first_name;
raise notice '起点线段%',v_startLine;
raise notice '起点位置%',v_startTarget;
raise notice '河流名称%',first_name;
--查询离终点最近的线
execute 'select (st_dump(geom)).geom as geom,"source" as source,name from singleriver
where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')''),0.01)
order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')'')) limit 1'
into v_endLine,v_endSource,end_name;
--如果没找到最近的线,就返回null
if (v_startLine is null) or (v_endLine is null) then
return;
end if ;
select ST_ClosestPoint(v_startLine, ST_Geometryfromtext('point('|| startx ||' ' || starty ||')')) into v_statpoint;
select ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')')) into v_endpoint; --计算距离起点最近线上的点在该线中的位置
select st_linelocatepoint(st_linemerge(v_startLine), v_statpoint) into v_perStart; select st_linelocatepoint(st_linemerge(v_endLine), v_endpoint) into v_perEnd; select st_distancesphere(v_statpoint,ST_PointN(ST_GeometryN(v_startLine,1), ST_NumPoints(ST_GeometryN(v_startLine,1)))) into first_cost; select st_distancesphere(ST_PointN(ST_GeometryN(v_endLine,1),1),v_endpoint) into end_cost; if (ST_Intersects(st_geomfromtext('point('|| startx ||' '|| starty ||') '), v_startLine) and ST_Intersects(st_geomfromtext('point('|| endx ||' '|| endy ||') '), v_startLine)) then
select st_distancesphere(v_statpoint, v_endpoint) into first_cost; select st_linelocatepoint(st_linemerge(v_startLine), v_endpoint) into v_perEnd;
for v_rec in
select st_linesubstring(st_linemerge(v_startLine), v_perStart,v_perEnd) as point,COALESCE(end_name,'无名河流') as name,end_cost as cost loop
v_shPath:= ST_AsGeoJSON(v_rec.point);
cost:= v_rec.cost;
river_name:= v_rec.name;
return next;
end loop;
return;
end if;
--最短路径
for v_rec in
(select st_linesubstring(st_linemerge(v_startLine),v_perStart,1) as point,COALESCE(first_name,'无名河流') as name,first_cost as cost
union all
SELECT st_linemerge(b.geom) as point,COALESCE(b.name,'无名河流') as name,st_length(geom, false) as cost
FROM pgr_dijkstra(
'SELECT gid as id, source, target, st_length(geom, false) as cost FROM singleriver
where st_intersects(geom,st_buffer(st_linefromtext(''linestring('||startx||' ' || starty ||','|| endx ||' ' || endy ||')''),0.05))',
v_startTarget, v_endSource , false
) a, singleriver b
WHERE a.edge = b.gid
union all
select st_linesubstring(st_linemerge(v_endLine),0,v_perEnd) as point,COALESCE(end_name,'无名河流') as name,end_cost as cost)
loop
v_shPath:= ST_AsGeoJSON(v_rec.point);
cost:= v_rec.cost;
river_name:= v_rec.name;
return next;
end loop;
end;
$BODY$
LANGUAGE plpgsql VOLATILE STRICT
COST 100
ROWS 1000

2.参数说明

输入参数:开始点和结束点的经纬度坐标

输出结果:river_name:河流名称;v_shppath:流经的河流路径; cost:河流流经长度

3.内部调用函数说明

函数调用过程,根据postgis不同版本,函数名称可能会有偏差,有版本展示形式为  st_linesubstring ,有版本展示形式为 st_line_substring

4.输出结果验证

为了验证河流输出结果是否正确,流经河流路径是否连通,可以通过在线geojson地图(geojson.io)呈现出来验证。

在右侧json-features-geometry 中填充函数输出的v_shppath参数内容(按照行单独输入,可以输入多个,注意需要增加json属性)

使用PostGIS完成两点间的河流轨迹及流经长度的计算的更多相关文章

  1. 经纬度计算两点间的距离,根据距离排序SQL

    #java的Utilspublic class DistanceUtil { // 地球平均半径 private static final double EARTH_RADIUS = 6378137; ...

  2. 利用百度API(JavaScript 版)实现在地图上绘制任一多边形,并判断给定经纬度是否在多边形范围内。以及两点间的测距功能

    权声明:本文为博主原创文章,未经博主允许不得转载. 利用百度API(JavaScript 版)实现在地图上绘制任一多边形,并判断给定经纬度是否在多边形范围内.以及两点间的测距功能. 绘制多边形(蓝色) ...

  3. 用 Excel 测试“绘制两点间连线”的算法

    最近在研究和制作数字示波器,其中涉及一个小算法:需要将 ADC 采样的数值在 TFT LCD 屏幕上面显示并且用“线”连接起来. ADC 按照时序对输入电压采样后,记录的是一个个的数值,如果显示的时候 ...

  4. 图算法之Floyd-Warshall 算法-- 任意两点间最小距离

    1.Floyd-Warshall 算法 给定一张图,在o(n3)时间内求出任意两点间的最小距离,并可以在求解过程中保存路径 2.Floyd-Warshall 算法概念 这是一个动态规划的算法. 将顶点 ...

  5. HDOJ2001计算两点间的距离

    计算两点间的距离 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  6. J - 计算两点间的距离

      Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u   Description 输入两 ...

  7. boost dijkstra获得两点间的最短路

    需求是只需要得到两点间的最短路,不需要求得单源对于全图的最短路,使用boost中的dijsktra_shortest_path,当得到目标点的最短路时直接throw exception. #inclu ...

  8. 计算两点间的距离-hdu2001

    Problem Description 输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离.   Input 输入数据有多组,每组占一行,由4个实数组成,分别表示x1,y1,x2,y2 ...

  9. 计算两点间的距离,hdu-2001

    计算两点间的距离 Problem Description 输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离.   Input 输入数据有多组,每组占一行,由4个实数组成,分别表示x1 ...

随机推荐

  1. Windows通过计划任务定时执行bat文件

    第一步 第二步 第三步 第四步 第五步 第六步

  2. .net 6 (.net core) 发布到linux docker中

    第一步:VMware 安装 虚拟机Linux系统,本文以 CentOS 为例 .

  3. 记一次 .NET 某市附属医院 Web程序 偶发性CPU爆高分析

    一:背景 1. 讲故事 这个月初,一位朋友加微信求助他的程序出现了 CPU 偶发性爆高,希望能有偿解决一下. 从描述看,这个问题应该困扰了很久,还是医院的朋友给力,开门就是 100块 红包 ,那既然是 ...

  4. ViewModel的创建

    ViewModel的创建 ViewModel本身只是ViewModel这个类的子类: class MainViewModel: ViewModel() { } 在屏幕旋转UI重建的时候, 它是如何拥有 ...

  5. Mybatis一对一、一对多级联查询使用

    在A对象的xml配置文件中 一对一<association property="shop" column="shop_id" select="c ...

  6. JAVAWEB进行PC支付宝支付、查询订单支付状态

    官方文档:https://opendocs.alipay.com/open/270/105899 本地开发环境支付回调调试方法可以参考:https://www.cnblogs.com/pxblog/p ...

  7. VS2015 up3激活key

    密钥 专业版:HMGNV-WCYXV-X7G9W-YCX63-B98R2 企业版:HM6NR-QXX7C-DFW2Y-8B82K-WTYJV

  8. LeetCode解题报告汇总! All in One!

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 把自己刷过的所有题目做一个整理,并且用简洁的语言概括了一下思路,汇总成了一个表格. 题目 ...

  9. 【LeetCode】216. Combination Sum III 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述: 题目大意 解题方法 方法一:DFS 方法二:回溯法 日期 题目地址:h ...

  10. 【JAVA今法修真】 第七章 洞天风云起,索引混乱平

    您好,我是南橘,万法仙门的掌门,刚刚从九州世界穿越到地球,因为时空乱流的影响导致我的法力全失,现在不得不通过这个平台向广大修真天才们借去力量.你们的每一个点赞,每一个关注都是让我回到九州世界的助力,兄 ...