PostGIS 爆管分析之找出上游阀门
环境:
Win10
ArcMap10.4(用于数据处理)
postgresql9.4
postgis2.2.3
pgRouting2.3(postgresql插件)
说明:
继上一篇文章做了爆管分析找出周围所有影响阀门后(参见:https://www.cnblogs.com/giser-s/p/11662932.html),发现在业务上使用有局限性,因为通常爆管以后我并不需要关闭所有周围阀门,而是只要关闭上游阀门即可。
下面的方法,是在查找到周围所有阀门的基础上继续的,在周围阀门中找出与他相接的上游阀门
步骤:
1、在PostGIS中,建立方向模型,模拟气体流向。原理就是新增length或者reverse_cost(关键字),与source/target方向一致的,则length为值,reverse_cost为设一个大点的值9999999;如source/target方向不一致,则给reverse_cost赋值,length为设一个大点的值9999999。
这里在查询时,pgr_dijkstraCost会识别关键词cost和reverse_cost
双向查询时不用关注reverse_cost(注意cost字段一定要有,或可以如下例子将length命名cost的别名)
SELECT * FROM pgr_dijkstra( 'SELECT gid AS id, source, target, length as cost FROM zy', 15139, 13670, directed := false);
单向查询时需要加上reverse_cost一起查(注意cost字段一定要有,或可以如下例子将length命名cost的别名)
SELECT * FROM pgr_dijkstra( 'SELECT gid AS id, source, target, length as cost,reverse_cost as reverse_cost FROM zy', 15139, 13670, directed := true);
#正向结果:
#逆向结果:
2、这里查询到爆点周围所有影响阀门后,需要进行记录,这里采用拼接成字符串记录在数组中(这里略复杂,不同于上一博文直接返回输出了)
格式:[{v_uptap_gid||','||cast(v_uptap_geom as text)||','||up_temprow.source]}]
说明:[{阀门gid,转成字符串的geom,管段的头source}]
raise notice '%' , up_temprow.source;
--记录阀门所在管段source
IF (v_cost @> ARRAY[up_temprow.source::integer]) THEN
ELSE
SELECT array_append(v_cost,up_temprow.source) into v_cost;
SELECT array_append(v_cost,up_temprow.target) into v_cost;
END IF;
IF (res_tap_pipe is not null) THEN
select res_tap_pipe || ARRAY[v_uptap_gid||','||cast(v_uptap_geom as text)||','||up_temprow.source] into res_tap_pipe;
ELSE
select ARRAY[v_uptap_gid||','||cast(v_uptap_geom as text)||','||up_temprow.source] into res_tap_pipe;
END IF;
3、v_cost是周围所有阀门,利用pgRouting的pgr_dijkstraCost函数,逆向找出与爆点管段相接的阀门。
--查找上游阀门
FOREACH m_cost IN ARRAY v_cost
LOOP
SELECT count(*) FROM pgr_dijkstraCost('select gid as id, source, target, length as cost, reverse_cost from zy',m_cost, ARRAY[v_startSource,v_startTarget], true) where agg_cost >= 9999999 into m_cost_value;
raise notice '%' , 'm_cost---'||cast(m_cost as text);
----如果没有消耗大于9999999的(阈值),则认为是上游阀门
IF(m_cost_value = 0) THEN
FOREACH m_tap_pipe IN ARRAY res_tap_pipe
LOOP
raise notice '%' , 'm_cost---'||cast(m_cost as text) ;
raise notice '%' , 'm_tap_pipe---'||cast(m_tap_pipe as text) ;
IF (split_part(m_tap_pipe, ',', 3)::integer = m_cost) THEN
--阀门id,阀门图形要素,阀门类型(上游/下游)
return query
select split_part(m_tap_pipe, ',', 1)::integer as res_uptap_gid,split_part(m_tap_pipe, ',', 2)::geometry as res_uptap_geom ,split_part(m_tap_pipe, ',', 3)::integer as res_source;
END IF;
END LOOP;
END IF;
END LOOP;
4、附上全部存储过程
-- Function: test_getpoint8(character varying, double precision, double precision) -- DROP FUNCTION test_getpoint8(character varying, double precision, double precision); CREATE OR REPLACE FUNCTION test_getpoint8(
IN tbl character varying,
IN startx double precision,
IN starty double precision)
RETURNS TABLE(v_gid integer, v_res geometry, v_type integer) AS
$BODY$ declare
v_startLine geometry;--离起点最近的线
v_startTarget integer;--距离起点最近线的终点
v_startSource integer;
v_statpoint geometry;--在v_startLine上距离起点最近的点
v_endpoint geometry;--在v_endLine上距离终点最近的点
v_up_source integer;--游标,记录是否有记录
v_up_idx integer;--记录遍历到多少层级
v_uptap_gid integer;--上游阀门gid
v_uptap_geom geometry;--上游阀门要素
v_all_where integer[];--记录所有查询过的管段
v_up_where integer[];--where条件,将遍历到阀门的管段gid排除
v_down_where integer[];--where条件,将遍历到阀门的管段gid排除
up_temprow record ;
--v_cost record;--记录阀门管段source(用于计算消耗,判断方向)
m_cost integer;
m_cost_value integer;
temprow record;
v_cost integer[];
res_source integer;
res_tap_pipe text[];
m_tap_pipe text;
idx_tap_pipe integer; --遍历结果游标
m_up_cost integer;--上游阀门
v_up_cost integer[];--上游阀门集合
res_main_pipe integer[];--总阀门集合
m_main_pipe integer;--总阀门
begin
--查询离起点最近的线
--3857坐标系
--找起点15米范围内的最近线
execute 'select geom, source, target, ST_StartPoint(geom) as startpoint,ST_EndPoint(geom) as endpoint from ' ||tbl||
' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| startx ||' ' || starty ||')'',3857),15)
order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',3857)) limit 1'
into v_startLine, v_startSource ,v_startTarget, v_statpoint ,v_endpoint;
raise notice '%' , 'v_startSource---'||cast(v_startSource as text);
IF(v_startLine is not null) THEN
--查找上游阀门
v_up_idx = 0;
v_up_source = 1;
--寻找上游阀门
SELECT array_append(v_up_where, v_startSource) into v_up_where;
--如果没有下级节点需要遍历
WHILE array_length(v_up_where,1) > 0
LOOP
--游标归零
v_up_source = 0;
--记录层级
--v_up_idx = v_up_idx + 1;
--获取当前层级节点
FOR up_temprow IN
select zy1.gid,zy1.source,zy1.target from zy zy1 where source = any(v_up_where) or target = any(v_up_where)
--select zy1.gid,zy1.source,zy1.target from zy zy1 where target = any(v_up_where)--找上游
LOOP
--清空需要查的点
IF(v_up_source = 0) THEN
v_up_where = null;
END IF;
--清空初始执行节点
--v_startSource = 0;
--标志执行有数据
v_up_source = 1;
--查询管网上的点
select t.gid,t.geom from fm t where t.gid in (
select a.gid from fm a,(select c.* from zy c where c.gid = up_temprow.gid) b where ST_intersects(a.geom,b.geom)
) into v_uptap_gid, v_uptap_geom;
raise notice '%' , 'UP---'||up_temprow.gid;
--如果没查找到阀门,则继续往下查
IF(v_uptap_gid is null) then
--source去重,判断如果数组中已有,则不添加
IF (v_up_where @> ARRAY[up_temprow.source::integer] OR v_all_where @> ARRAY[up_temprow.source::integer]) THEN
ELSE
SELECT array_append(v_up_where,up_temprow.source) into v_up_where;
SELECT array_append(v_all_where,up_temprow.source) into v_all_where;
END IF;
--target去重,判断如果数组中已有,则不添加
IF (v_up_where @> ARRAY[up_temprow.target::integer] OR v_all_where @> ARRAY[up_temprow.target::integer]) THEN
ELSE
SELECT array_append(v_up_where,up_temprow.target) into v_up_where;
SELECT array_append(v_all_where,up_temprow.target) into v_all_where;
END IF;
ELSE
raise notice '%' , up_temprow.source;
--记录阀门所在管段source
IF (v_cost @> ARRAY[up_temprow.source::integer]) THEN
ELSE
SELECT array_append(v_cost,up_temprow.source) into v_cost;
SELECT array_append(v_cost,up_temprow.target) into v_cost;
END IF;
IF (res_tap_pipe is not null) THEN
select res_tap_pipe || ARRAY[v_uptap_gid||','||cast(v_uptap_geom as text)||','||up_temprow.source] into res_tap_pipe;
ELSE
select ARRAY[v_uptap_gid||','||cast(v_uptap_geom as text)||','||up_temprow.source] into res_tap_pipe;
END IF;
END IF;
END LOOP;
END LOOP;
--raise notice '%' , v_cost;
raise notice '%' , 'res_tap_pipe---'||cast(res_tap_pipe as text);
--return query select * from v_cost;
raise notice '%' , 'v_cost---'||cast(v_cost as text); --查找上游阀门
FOREACH m_cost IN ARRAY v_cost
LOOP
SELECT count(*) FROM pgr_dijkstraCost('select gid as id, source, target, length as cost, reverse_cost from zy',m_cost, ARRAY[v_startSource,v_startTarget], true) where agg_cost >= 9999999 into m_cost_value;
raise notice '%' , 'm_cost---'||cast(m_cost as text);
----如果没有消耗大于9999999的(阈值),则认为是上游阀门
--IF(m_cost_value = 0) THEN
-- --判断上游阀门间是否有上下游关系
-- SELECT array_append(v_up_cost,m_cost) into v_up_cost;
--END IF;
IF(m_cost_value = 0) THEN
FOREACH m_tap_pipe IN ARRAY res_tap_pipe
LOOP
raise notice '%' , 'm_cost---'||cast(m_cost as text) ;
raise notice '%' , 'm_tap_pipe---'||cast(m_tap_pipe as text) ;
IF (split_part(m_tap_pipe, ',', 3)::integer = m_cost) THEN
--阀门id,阀门图形要素,阀门类型(上游/下游)
return query
select split_part(m_tap_pipe, ',', 1)::integer as res_uptap_gid,split_part(m_tap_pipe, ',', 2)::geometry as res_uptap_geom ,split_part(m_tap_pipe, ',', 3)::integer as res_source;
END IF;
END LOOP;
END IF;
END LOOP; raise notice '%' , '上游阀门---'||cast(v_up_cost as text);
END IF;
end; $BODY$
LANGUAGE plpgsql VOLATILE STRICT
COST 100
ROWS 1000;
ALTER FUNCTION test_getpoint8(character varying, double precision, double precision)
OWNER TO postgres;
结尾:
此文算是半成品文章,代码很乱也没有进行优化,很多没有用到的变量没有删掉,这里暂且当作思路的记录。
算法上还有很多需要改进,这里只是在找到所有周边阀门的基础上继续往下写的,其实可以不用分两块,直接上来就开始找上游阀门(算法留待后面继续优化)
-- Function: test_getpoint8(character varying, double precision, double precision)
-- DROP FUNCTION test_getpoint8(character varying, double precision, double precision);
CREATE OR REPLACE FUNCTION test_getpoint8( IN tbl character varying, IN startx double precision, IN starty double precision) RETURNS TABLE(v_gid integer, v_res geometry, v_type integer) AS$BODY$
declare v_startLine geometry;--离起点最近的线 v_startTarget integer;--距离起点最近线的终点 v_startSource integer; v_statpoint geometry;--在v_startLine上距离起点最近的点 v_endpoint geometry;--在v_endLine上距离终点最近的点 v_up_source integer;--游标,记录是否有记录 v_up_idx integer;--记录遍历到多少层级 v_uptap_gid integer;--上游阀门gid v_uptap_geom geometry;--上游阀门要素 v_all_where integer[];--记录所有查询过的管段 v_up_where integer[];--where条件,将遍历到阀门的管段gid排除 v_down_where integer[];--where条件,将遍历到阀门的管段gid排除 up_temprow record ; --v_cost record;--记录阀门管段source(用于计算消耗,判断方向) m_cost integer; m_cost_value integer; temprow record; v_cost integer[]; res_source integer; res_tap_pipe text[]; m_tap_pipe text; idx_tap_pipe integer; --遍历结果游标 m_up_cost integer;--上游阀门 v_up_cost integer[];--上游阀门集合 res_main_pipe integer[];--总阀门集合 m_main_pipe integer;--总阀门begin --查询离起点最近的线 --3857坐标系 --找起点15米范围内的最近线 execute 'select geom, source, target, ST_StartPoint(geom) as startpoint,ST_EndPoint(geom) as endpoint from ' ||tbl|| ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| startx ||' ' || starty ||')'',3857),15) order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',3857)) limit 1' into v_startLine, v_startSource ,v_startTarget, v_statpoint ,v_endpoint; raise notice '%' , 'v_startSource---'||cast(v_startSource as text); IF(v_startLine is not null) THEN --查找上游阀门 v_up_idx = 0; v_up_source = 1; --寻找上游阀门 SELECT array_append(v_up_where, v_startSource) into v_up_where; --如果没有下级节点需要遍历 WHILE array_length(v_up_where,1) > 0 LOOP --游标归零 v_up_source = 0; --记录层级 --v_up_idx = v_up_idx + 1; --获取当前层级节点 FOR up_temprow IN select zy1.gid,zy1.source,zy1.target from zy zy1 where source = any(v_up_where) or target = any(v_up_where) --select zy1.gid,zy1.source,zy1.target from zy zy1 where target = any(v_up_where)--找上游 LOOP --清空需要查的点 IF(v_up_source = 0) THEN v_up_where = null; END IF; --清空初始执行节点 --v_startSource = 0; --标志执行有数据 v_up_source = 1; --查询管网上的点 select t.gid,t.geom from fm t where t.gid in ( select a.gid from fm a,(select c.* from zy c where c.gid = up_temprow.gid) b where ST_intersects(a.geom,b.geom) ) into v_uptap_gid, v_uptap_geom; raise notice '%' , 'UP---'||up_temprow.gid; --如果没查找到阀门,则继续往下查 IF(v_uptap_gid is null) then --source去重,判断如果数组中已有,则不添加 IF (v_up_where @> ARRAY[up_temprow.source::integer] OR v_all_where @> ARRAY[up_temprow.source::integer]) THEN ELSE SELECT array_append(v_up_where,up_temprow.source) into v_up_where; SELECT array_append(v_all_where,up_temprow.source) into v_all_where; END IF; --target去重,判断如果数组中已有,则不添加 IF (v_up_where @> ARRAY[up_temprow.target::integer] OR v_all_where @> ARRAY[up_temprow.target::integer]) THEN ELSE SELECT array_append(v_up_where,up_temprow.target) into v_up_where; SELECT array_append(v_all_where,up_temprow.target) into v_all_where; END IF; ELSE raise notice '%' , up_temprow.source; --记录阀门所在管段source IF (v_cost @> ARRAY[up_temprow.source::integer]) THEN ELSE SELECT array_append(v_cost,up_temprow.source) into v_cost; SELECT array_append(v_cost,up_temprow.target) into v_cost; END IF; IF (res_tap_pipe is not null) THEN select res_tap_pipe || ARRAY[v_uptap_gid||','||cast(v_uptap_geom as text)||','||up_temprow.source] into res_tap_pipe; ELSE select ARRAY[v_uptap_gid||','||cast(v_uptap_geom as text)||','||up_temprow.source] into res_tap_pipe; END IF; END IF; END LOOP; END LOOP; --raise notice '%' , v_cost; raise notice '%' , 'res_tap_pipe---'||cast(res_tap_pipe as text); --return query select * from v_cost; raise notice '%' , 'v_cost---'||cast(v_cost as text);
--查找上游阀门 FOREACH m_cost IN ARRAY v_cost LOOP SELECT count(*) FROM pgr_dijkstraCost('select gid as id, source, target, length as cost, reverse_cost from zy',m_cost, ARRAY[v_startSource,v_startTarget], true) where agg_cost >= 9999999 into m_cost_value; raise notice '%' , 'm_cost---'||cast(m_cost as text); ----如果没有消耗大于9999999的(阈值),则认为是上游阀门 --IF(m_cost_value = 0) THEN -- --判断上游阀门间是否有上下游关系 -- SELECT array_append(v_up_cost,m_cost) into v_up_cost; --END IF; IF(m_cost_value = 0) THEN FOREACH m_tap_pipe IN ARRAY res_tap_pipe LOOP raise notice '%' , 'm_cost---'||cast(m_cost as text) ; raise notice '%' , 'm_tap_pipe---'||cast(m_tap_pipe as text) ; IF (split_part(m_tap_pipe, ',', 3)::integer = m_cost) THEN --阀门id,阀门图形要素,阀门类型(上游/下游) return query select split_part(m_tap_pipe, ',', 1)::integer as res_uptap_gid,split_part(m_tap_pipe, ',', 2)::geometry as res_uptap_geom ,split_part(m_tap_pipe, ',', 3)::integer as res_source; END IF; END LOOP; END IF; END LOOP;
raise notice '%' , '上游阀门---'||cast(v_up_cost as text); END IF;end;
$BODY$ LANGUAGE plpgsql VOLATILE STRICT COST 100 ROWS 1000;ALTER FUNCTION test_getpoint8(character varying, double precision, double precision) OWNER TO postgres;
PostGIS 爆管分析之找出上游阀门的更多相关文章
- PostGIS 爆管分析之找出上游阀门(优化版)
说明 前面描述过利用postgis查找上游阀门的原理,以及代码,其实当初写完就发现又很大的优化空间,但一直没有时间去做. 最近遇到一个情况,处理60w+条管网数据时,效率太慢了,于是腾时间优化了一版. ...
- PostGIS 爆管分析之找出总阀门
这个算法算是被摒弃了,但是很多自己思考过后留下的成果,虽然不用了,留着做记录. 算法目的是为了发生爆管后找到总阀门,这里分了几个步骤: 1.找到爆管点所在管段 2.通过遍历找到爆管点所有影响的阀门 3 ...
- PostGIS 爆管分析之根据爆点找出所有影响阀门
环境: Win10 ArcMap10.4(用于数据处理) postgresql9.4 postgis2.2.3 pgRouting2.3(postgresql插件) 说明: 做爆管分析的第一步,需要先 ...
- Python练习六十:网页分析,找出里面的正文与链接
网页分析,找出里面的正文与链接 代码如下: from urllib import request from bs4 import BeautifulSoup request = request.url ...
- 《BI那点儿事》Microsoft 决策树算法——找出三国武将特性分布,献给广大的三国爱好者们
根据游戏<三国志11>武将数据,利用决策树分析,找出三国武将特性分布.其中变量包括统率.武力.智力.政治.魅力.身分.变量说明:统率:武将带兵出征时的部队防御力.统帅越高受到普通攻击与兵法 ...
- 如何找出你性能最差的SQL Server查询
我经常会被反复问到这样的问题:”我有一个性能很差的SQL Server.我如何找出最差性能的查询?“.因此在今天的文章里会给你一些让你很容易找到问题答案的信息向导. 问SQL Server! SQL ...
- 记录一下通过分析Tomcat内部jar包找出request.getReader()所用的字符编码在哪里设置和起效的完整分析流程
前言: 之前写Java服务端处理POST请求时遇到了请求体转换成字符流所用编码来源的疑惑,在doPost方法里通过request.getReader()获取的BufferedReader对象内部的 R ...
- Bugku-CTF分析篇-weblogic(黑客攻击了Weblogic应用,请分析攻击过程,找出Weblogic的主机名。)
weblogic 黑客攻击了Weblogic应用,请分析攻击过程,找出Weblogic的主机名. flag格式:flag{} Tip:主机名为十六进制.
- c#封装DBHelper类 c# 图片加水印 (摘)C#生成随机数的三种方法 使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象 c# 制作正方形图片 JavaScript 事件循环及异步原理(完全指北)
c#封装DBHelper类 public enum EffentNextType { /// <summary> /// 对其他语句无任何影响 /// </summary> ...
随机推荐
- 解决Anki服务器同步问题:坚果云 & Floder sync (已测试)
读前须知: 更新日期:2019-07-08 1.本教程面向对象为:有一定计算机知识人群 2.配合参考链接中的文章,共同食用. 3.已经过测试,可同步图片,音频,视频 4.尝试有风险,提前导出Anki卡 ...
- WPF_在APP.xaml应用资源样式
先上代码: <Application x:Class="NetAnalysis.App" xmlns="http://schemas.microsoft.com/w ...
- WCF(一):初探WCF
目录: 一.什么是WCF 二.WCF能做什么 三.WCF的模型 四.WCF的基本概念 五.WCF的快速创建 1.WCF是什么? A.WindowsCommunication Foundation(WC ...
- UE4蓝图与C++交互——射击游戏中多武器系统的实现
回顾 学习UE4已有近2周的时间,跟着数天学院"UE4游戏开发"课程的学习,已经完成了UE4蓝图方面比较基础性的学习.通过UE4蓝图的开发,我实现了类似CS的单人版射击游戏,效 ...
- .NET Core 3.1 编写混合 C++ 程序
前言 随着 .NET Core 3.1 的第二个预览版本发布,微软正式将 C++/CLI 移植到 .NET Core 上,从此可以使用 C++ 编写 .NET Core 的程序了. 由于目前仅有 MS ...
- Java迭代Map方法
Map map=new HashMap(); map.put("1", "one"); map.put("2","two" ...
- JavaSE语法
二.JavaSE语法(上) 1.Java 有没有 goto 语句? goto 是 Java 中的保留字,在目前版本的 Java 中没有使用.根据 James Gosling(Java 之父)编写的&l ...
- centos创建kvm虚拟机
1.检查kvm模块是否已经加载 lsmod |grep kvm 上图已经加载 没有加载 2.加载kvm 模块至内核 modprobe kvm modprobe kvm-intel modprobe: ...
- gedit一些小的新发现
写应该还有一些人正在像我一样用gedit呢. 现在vim,gedit,guide三党还是互相瞧不起呢. 我写这一篇是想稍微交流一下gedit的一些乱七八糟的玩意,非gedit党勿喷. 有些人连一些比较 ...
- CSPS模拟 68
令人kuku的一场考试, T1 令人kuku的贪心,反工了好几次,耗费了1h之久. T2 令人kuku的数据结构,到死也没调出来,还是细节问题,要积累. T3 令人kuku的二分答案. 先二分第一个答 ...