基于pgrouting的任意两点间的最短路径查询函数二

简介:

    在前面的博文中写过一篇查询任意两点间最短路径的函数,当时对pgrouting不熟悉,功能很low。现在对该函数进行扩展,支持用户自己输入查询的数据库表,这一点看似简单,其实意义很大,在做室内导航的时候当用户所在的楼层变化的时候最短路径函数查询的数据表名称也会发生变化,不可能一栋大楼里的道路都是一样的吧,另外进行跨楼层的最短路径规划时,需要查询从A到楼梯口的最短路径和楼梯口到B的最短路径,这些都需要进行最短路径规划的时候能够自己选择数据表。

    先解释一下最短路径规划的处理步骤,首先要确定用户的出发点和目的地所在的道路,再在相应的道路上确定道路的节点,查找这两个节点之间的最短路径,最后再处理出发点和目的地到道路节点之间的路段。具体过程为:

    (1)查找距离用户出发点最近的道路和该道路的终点T。

    (2)查找距离用户目的地最近的道路和该道路的起点S。

    (3)计算前两步找出的两点之间的最短路径。

    (4)处理出发点和道路终点T以及目的去和道路起点S之间的路段。


DROP FUNCTION pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float);
CREATE OR REPLACE function pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float)   
returns  geometry 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_shPath geometry;--最终结果
    tempnode float;	
begin     
          
    --查询离起点最近的线  
    execute 'select geom ,target  from ' ||tbl||
			' where 
			ST_DWithin(geom,ST_Geometryfromtext(''point('||	startx ||' ' || starty||')''),15) 
			order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')''))  limit 1' 
			into v_startLine ,v_startTarget;  
      
    --查询离终点最近的线  
    execute 'select geom,source  from ' ||tbl||
			' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')''),15) 
			order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')''))  limit 1' 
			into v_endLine,v_endSource;  
  
    --如果没找到最近的线,就返回null  
    if (v_startLine is null) or (v_endLine is null) then  
        return null;  
    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;  
  
      
    --最短路径  
    execute 'SELECT st_linemerge(st_union(b.geom)) ' || 
    'FROM pgr_kdijkstraPath(  
    ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''','  
    ||v_startTarget || ', ' ||'array['||v_endSource||'] , false, false  
    ) a, '  
    || tbl || ' b  
    WHERE a.id3=b.gid  
    GROUP by id1  
    ORDER by id1' into v_res;  
  
    --如果找不到最短路径,就返回null  
    if(v_res is null) then  
        return null;  
    end if;  
      
    --将v_res,v_startLine,v_endLine进行拼接  
    select  st_linemerge(ST_Union(array[v_res,v_startLine,v_endLine])) into v_res;  
      
    select  ST_Line_Locate_Point(v_res, v_statpoint) into v_perStart;  
    select  ST_Line_Locate_Point(v_res, v_endpoint) into v_perEnd;  
	
	if(v_perStart > v_perEnd) then  
        tempnode =  v_perStart;
		v_perStart = v_perEnd;
		v_perEnd = tempnode;
    end if;
	
    --截取v_res  
    SELECT ST_Line_SubString(v_res,v_perStart, v_perEnd) into v_shPath;  
       
    return v_shPath;  
  
      
      
end;  
$body$  
LANGUAGE plpgsql VOLATILE STRICT  


使用这个最短路径规划函数进行路径规划一般不会出现问题,但是有的时候会出现这样的问题,因为函数的查找思路是查找距离起点最近的线和改线的终点,查找离目的地最近的线和该线的起点,这样有可能会出现这样的情况,就是起点和终点对应的线段是相连接的,这时查找的距离起点最近线的终点和距离目的地最近线上的起点就是同一个点,这样的话这两点直接就没有最短距离。


所以需要对上述代码第59到61行进行修改,修改后的代码如下:

DROP FUNCTION pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float);
CREATE OR REPLACE function pgr_fromAtoB(tbl varchar,startx float, starty float,endx float,endy float)   
returns  geometry 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_shPath geometry;--最终结果
    tempnode float;	
begin     
          
    --查询离起点最近的线  
    execute 'select geom ,target  from ' ||tbl||
			' where 
			ST_DWithin(geom,ST_Geometryfromtext(''point('||	startx ||' ' || starty||')''),15) 
			order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')''))  limit 1' 
			into v_startLine ,v_startTarget;  
      
    --查询离终点最近的线  
    execute 'select geom,source  from ' ||tbl||
			' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')''),15) 
			order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')''))  limit 1' 
			into v_endLine,v_endSource;  
  
    --如果没找到最近的线,就返回null  
    if (v_startLine is null) or (v_endLine is null) then  
        return null;  
    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;  
  
      
    --最短路径  
    execute 'SELECT st_linemerge(st_union(b.geom)) ' || 
    'FROM pgr_kdijkstraPath(  
    ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''','  
    ||v_startTarget || ', ' ||'array['||v_endSource||'] , false, false  
    ) a, '  
    || tbl || ' b  
    WHERE a.id3=b.gid  
    GROUP by id1  
    ORDER by id1' into v_res ;  
  
    --如果找不到最短路径,就返回null  
    --if(v_res is null) then  
    --    return null;  
    --end if;  
      
    --将v_res,v_startLine,v_endLine进行拼接  
    select  st_linemerge(ST_Union(array[v_res,v_startLine,v_endLine])) into v_res;  
      
    select  ST_Line_Locate_Point(v_res, v_statpoint) into v_perStart;  
    select  ST_Line_Locate_Point(v_res, v_endpoint) into v_perEnd;  
	
	if(v_perStart > v_perEnd) then  
        tempnode =  v_perStart;
		v_perStart = v_perEnd;
		v_perEnd = tempnode;
    end if;
	
    --截取v_res  
    SELECT ST_Line_SubString(v_res,v_perStart, v_perEnd) into v_shPath;  
       
    return v_shPath;  
  
      
      
end;  
$body$  
LANGUAGE plpgsql VOLATILE STRICT  



相关文章
|
14天前
|
算法 测试技术 C#
【解析几何】 【多源路径】 【贪心】1520 最多的不重叠子字符串
【解析几何】 【多源路径】 【贪心】1520 最多的不重叠子字符串
|
3月前
leetcode-6110:网格图中递增路径的数目
leetcode-6110:网格图中递增路径的数目
22 1
|
8月前
|
算法 索引
算法训练Day36|435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间
算法训练Day36|435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间
|
8月前
|
算法
算法训练Day27|39. 组合总和● 40.组合总和II● 131.分割回文串
算法训练Day27|39. 组合总和● 40.组合总和II● 131.分割回文串
|
8月前
|
算法 安全 机器人
算法提高:计算几何基础 | 判断包含关系
计算几何是计算机科学的一个重要分支,主要研究几何形体的数学描述和计算机描述,在现代工程和数学领域,以及计算机辅助设计、地理信息系统、图形学、机器人技术、超大规模集成电路设计和统计等诸多领域都有重要的用途。在 ACM 竞赛中,出题相对独立,曾出现过与图论、动态规划相结合的题,大多数计算几何问题用程序实现都比较复杂。常用算法包括经典的凸包求解、离散化及扫描线算法、旋转卡壳、半平面交等。本文介绍计算几何常用算法——包含关系。
106 0
【集合论】序关系 ( 偏序集元素之间的关系 | 可比 | 严格小于 | 覆盖 | 哈斯图 )
【集合论】序关系 ( 偏序集元素之间的关系 | 可比 | 严格小于 | 覆盖 | 哈斯图 )
326 0
【集合论】序关系 ( 偏序集元素之间的关系 | 可比 | 严格小于 | 覆盖 | 哈斯图 )
|
存储 算法 容器
Leetcode 76最小覆盖子串&77组合&78子集
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
90 0
Leetcode 76最小覆盖子串&77组合&78子集
|
算法 Serverless 索引
二叉树的路径解析(任意两点/自顶向下)
二叉树的路径解析(任意两点/自顶向下)
二叉树的路径解析(任意两点/自顶向下)
|
机器学习/深度学习 移动开发
【组合数学】排列组合 ( 集合组合、一一对应模型分析示例 )
【组合数学】排列组合 ( 集合组合、一一对应模型分析示例 )
151 0