PostGIS 爆管分析更新日志&&BUG修改

随着爆管分析运用场景越来越多,算法的问题也逐渐突显。在此新开一贴,专门记录算法的优化以及bug的更正(根据进程不断更新此贴)

问题一:寻找上游阀门性能优化

参考:https://www.cnblogs.com/giser-s/p/12091219.html

问题二:查找周围所有阀门:遍历死角

遇到这样的情况:爆点所在管段的source和target端都有阀门,但是算法给出的结果是另一个管段上的阀门。
存在问题
经检查发现:原来算法中,以source为起始点开始遍历,寻找与其相接管段(其他source或target等于爆管source的),由此找到了1、2管段
source情况
接着判断1、2管段上是否有阀门,有阀门就返回,没阀门就继续往下...

这里出现了问题,情况是:1、2管段被找出,理应查到a、b、c三个阀门,但是在查找管段上的阀门时,并没有循环所有被查出的阀门,故a被查丢了(其实丢a丢b是随机的)。
分析图
出现这种情况的原因是,我在查找管段上阀门,考虑到广度遍历时每次循环只判断下游节点,只会有一个结果,因此没有对查出的阀门结果再循环。但是恰恰存在爆点所在管段上下都有阀门的情况(即第一次)。
问题代码
所以打了个补丁,第一次的时候判断,如果爆管管段上下都有阀门,则直接返回,不再执行查找。

      tap_count = 0;
      FOR tap_temprow IN
        select t.gid as v_uptap_gid,t.geom as v_uptap_geom from fm t where t.gid in (
          select a.gid from fm a,(select c.* from zy c where c.gid = v_startGid) b where ST_intersects(a.geom,b.geom) 
        ) 
      LOOP
        tap_count=tap_count+1;
        --执行返回结果
        return query
        select tap_temprow.v_uptap_gid as res_uptap_gid,tap_temprow.v_uptap_geom as res_uptap_geom ;
      END LOOP;
      raise notice '%' , tap_count ;
      IF(tap_count >=2) THEN
        return;
      END IF;

附上最新优化后代码:

-- Function: public.enc_getalltaps(character varying, double precision, double precision)

-- DROP FUNCTION public.enc_getalltaps(character varying, double precision, double precision);

CREATE OR REPLACE FUNCTION public.test_getalltaps(
    IN tbl character varying,
    IN startx double precision,
    IN starty double precision)
  RETURNS TABLE(v_gid integer, v_res geometry) AS
$BODY$  

declare  
    v_startGid integer;--管段gid
    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排除
    up_temprow record ;
    tap_temprow record ;
    v_sql character varying;--管段gid
    test integer;
    tap_count integer;
begin 
    --查询离起点最近的线 
    --3857坐标系
    --找起点15米范围内的最近线 
    execute 'select gid, 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_startGid, v_startLine, v_startSource ,v_startTarget, v_statpoint ,v_endpoint; 
                            
    raise notice '%' , st_astext(v_startLine) ||'-'|| v_startSource ||'-'||v_startTarget;
    
    IF(v_startLine is not null) THEN
      tap_count = 0;
      FOR tap_temprow IN
        select t.gid as v_uptap_gid,t.geom as v_uptap_geom from fm t where t.gid in (
          select a.gid from fm a,(select c.* from zy c where c.gid = v_startGid) b where ST_intersects(a.geom,b.geom) 
        ) 
      LOOP
        tap_count=tap_count+1;
        --执行返回结果
        return query
        select tap_temprow.v_uptap_gid as res_uptap_gid,tap_temprow.v_uptap_geom as res_uptap_geom ;
      END LOOP;
      raise notice '%' , tap_count ;
      IF(tap_count >=2) THEN
        return;
      END IF;
      
    --查找上游阀门
    v_up_idx = 0;
    v_up_source = 1;
    test = 0;
      
    SELECT array_append(v_up_where, v_startSource) into v_up_where;  
    --SELECT array_append(v_up_where, v_startTarget) 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) 
      LOOP
        test = test +1; 
        raise notice '%' , up_temprow;
        
        --清空需要查的点
        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;  
        
        --如果没查找到阀门,则继续往下查
        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 '%' , v_uptap_gid ||'---'||cast(test as text);
          --执行返回结果
          return query
          select v_uptap_gid as res_uptap_gid,v_uptap_geom as res_uptap_geom ;
        END IF;
        --return next;
      END LOOP;
    END LOOP;
    END IF;
end;  

$BODY$
  LANGUAGE plpgsql VOLATILE STRICT
  COST 100
  ROWS 1000;
ALTER FUNCTION public.test_getalltaps(character varying, double precision, double precision)
  OWNER TO postgres;

猜你喜欢

转载自www.cnblogs.com/giser-s/p/12367286.html