PostGIS 路线规划

❤️通过SQL存储过程,利用PostGIS实现路线规划❤️

pgRouting扩展了PostgreSQL/PostGIS地理空间数据库,以提供地理空间路由功能。

1、环境配置
--添加postgis扩展
CREATE EXTENSION postgis;
--添加 pgrouting扩展
CREATE EXTENSION pgrouting;
--创建拓扑扩展 
CREATE EXTENSION postgis_topology;
--添加fuzzystrmatch扩展	fuzzystrmatch模块提供多个函数来判断字符串之间的相似性和距离。
CREATE EXTENSION fuzzystrmatch;
--创建平面坐标
CREATE EXTENSION address_standard
2、导入shp文件
2.1、打开PostGis Shapefile插件

在这里插入图片描述

2.2、连接数据库

数据库地址可以本地数据库地址也可以是远程数据库地址

在这里插入图片描述

2.3、添加并导入矢量数据

在这里插入图片描述

注意:

  1. 一定要设置数据的坐标系(可以不是该数据原坐标系),否则导入到数据库中数据是无坐标系的。
  2. 数据量数据本地存放的路径名称不能含有中文或特殊符号的,否则导入的时候会报错。
2.4、查看数据
--查询字段类型
select st_srid(geom) from daolu; 
--查询数据
select st_asewkt(geom) from daolu;
3、执行初始化命令
--添加起点
alter table daolu add column source integer;
--添加终点
alter table daolu add column target integer;
--正向道路长度
alter table daolu add column length double precision;
--创建拓扑图表,存放道路所有节点,并给source和target赋值,同时将路网相交点的空间数据放入daolu_vertices_pgr表
select pgr_createtopology('daolu', 0.00001, 'geom', 'gid');
--给source和target添加索引增加查询速度
create index source_idx on daolu("source");
create index targer_idx on daolu("target");
--给每一条道路赋值权重
update daolu set length = st_length(geom);
--反向道路长度
alter table daolu add column reverse_cost double precision;
--将正向道路的权重赋值给反向道路
update daolu set reverse_cost = length;
4、创建存储函数

推荐方法二,距离更远

4.1、方法一:

create function _myShortPath(startx float, starty float,endx float,endy float,costfile varchar)
returns  geometry as
$body$
declare
	--离起点最近的线
	v_startLine geometry;
	--离终点最近的线
	v_endLine geometry;
	--距离起点最近线的终点
	v_startTarget integer;
	--距离终点最近线的起点
	v_endSource integer;
	
	--在v_startLine上距离起点最近的点
	v_statpoint geometry;
	--在v_endLine上距离终点最近的点
	v_endpoint geometry;
	--最短路径分析结果
	v_res geometry;

	--v_statpoint在v_res上的百分比
	v_perStart float;
	--v_endpoint在v_res上的百分比
	v_perEnd float;
	--最终结果
	v_shPath geometry;
begin

	--查询离起点最近的线
	select geom ,target into v_startLine ,v_startTarget from  daolu where
	ST_DWithin(geom,ST_Geometryfromtext('point('|| startx ||' ' || starty ||')', 4326),0.015)
	order by ST_Distance(geom,ST_GeometryFromText('point('|| startx ||' '|| starty ||')', 4326))  limit 1;

	--查询离终点最近的线
	select geom,source into v_endLine,v_endSource from  daolu where
	ST_DWithin(geom,ST_Geometryfromtext('point('|| endx || ' ' || endy ||')', 4326),0.015)
	order by ST_Distance(geom,ST_GeometryFromText('point('|| endx ||' ' || endy ||')', 4326))  limit 1;

	--如果没找到最近的线,就返回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 ||')', 4326)) into v_statpoint;
	select  ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')', 4326)) into v_endpoint;


        --最短路径
	SELECT st_linemerge(st_union(b.geom)) into v_res
	FROM pgr_kdijkstraPath(
	'SELECT gid as id, source, target, ' || costfile ||' as cost FROM daolu',
	v_startTarget, array[v_endSource], true, false
	) a,
	daolu b
	WHERE a.id3=b.gid
	GROUP by id1
	ORDER by id1;

	--如果找不到最短路径,就返回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;

	--截取v_res
	SELECT ST_Line_SubString(v_res,v_perStart, v_perEnd) into v_shPath;

	return v_shPath;
end;
$body$
LANGUAGE plpgsql VOLATILE STRICT;

例子

--例子:
select st_astext(_myshortpath(117.370023799659, 26.3370107998085,117.385395500302, 26.3350246004051,'length'));
4.2、方法二:
create function pgr_road(tbl character varying, startx double precision, starty double precision, endx double precision, endy double precision, OUT linetype integer, OUT geom geometry) returns SETOF record
    strict
    language plpgsql
as
$$
declare

    v_startLine geometry;--离起点最近的线

    v_endLine geometry;--离终点最近的线

    v_startTarget integer;--距离起点最近线的终点

    v_startSource integer;

    v_endSource integer;--距离终点最近线的起点

    v_endTarget integer;


    v_statpoint geometry;--在v_startLine上距离起点最近的点

    v_endpoint geometry;--在v_endLine上距离终点最近的点

    v_res geometry;--最短路径分析结果

    v_res_a geometry;

    v_res_b geometry;

    v_res_c geometry;

    v_res_d geometry;

    v_perStart float;--v_statpoint在v_res上的百分比

    v_perEnd float;--v_endpoint在v_res上的百分比


    v_shPath_se geometry;--开始到结束

    v_shPath_es geometry;--结束到开始

    v_shPath geometry;--最终结果

    tempnode float;

    startpoint geometry;
    endpoint geometry;

    v_shPath1 geometry;--一次结果
    v_shPath2 geometry;--二次结果
    star_line geometry; --起点到最近点的线
    end_line geometry; --终点到最近点的线
    geoARR geometry[];

    geoType integer[];



    ii integer;

begin

    --查询离起点最近的线
    --4326坐标系
    --找起点15米范围内的最近线

    execute 'select geom, source, target  from ' ||tbl||

                            ' where ST_DWithin(geom,ST_Geometryfromtext(''point('||         startx ||' ' || starty||')'',4326),0.015)
                             order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'',4326))  limit 1'

                            into v_startLine, v_startSource ,v_startTarget;

raise notice '%',  v_startSource;
raise notice '%', v_startTarget;

    --查询离终点最近的线
    --找终点15米范围内的最近线

    execute 'select geom, source, target from ' ||tbl||

                            ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')'',4326),0.015)

                            order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')'',4326))  limit 1'

                            into v_endLine, v_endSource,v_endTarget;
raise notice '%',  v_endSource;
raise notice '%', v_endTarget;


    --如果没找到最近的线,就返回null

raise notice 'v_startLine %', v_startLine;
raise notice 'v_endLine %', v_endLine;
    if (v_startLine is null) or (v_endLine is null) then

        return;

    end if ;

    select  ST_ClosestPoint(v_startLine, ST_Geometryfromtext('point('|| startx ||' ' || starty ||')',4326)) into v_statpoint;

    select  ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')',4326)) into v_endpoint;

raise notice 'v_statpoint %', v_statpoint;
raise notice 'v_endpoint %', v_endpoint;

   -- ST_Distance

    --从开始的起点到结束的起点最短路径

    execute 'SELECT st_linemerge(st_union(b.geom)) FROM pgr_kdijkstraPath(
    ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''','

    ||v_startSource || ', ' ||'array['||v_endSource||'] , false, false
    ) a, '

    || tbl || ' b
    WHERE a.id3=b.gid
    GROUP by id1
    ORDER by id1' into v_res ;

raise notice 'v_res %', v_res;

    --从开始的终点到结束的起点最短路径

    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_b ;

raise notice 'v_res_b %', v_res_b;
    --从开始的起点到结束的终点最短路径

    execute 'SELECT st_linemerge(st_union(b.geom)) ' ||

    'FROM pgr_kdijkstraPath(
    ''SELECT gid as id, source, target, length as cost FROM ' || tbl ||''','

    ||v_startSource || ', ' ||'array['||v_endTarget||'] , false, false
    ) a, '

    || tbl || ' b
    WHERE a.id3=b.gid
    GROUP by id1
    ORDER by id1' into v_res_c ;

raise notice 'v_res_c %', v_res_c;

    --从开始的终点到结束的终点最短路径

    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_endTarget||'] , false, false
    ) a, '

    || tbl || ' b
    WHERE a.id3=b.gid
    GROUP by id1
    ORDER by id1' into v_res_d ;

raise notice 'v_res_d %', v_res_d;

    if(ST_Length(v_res) > ST_Length(v_res_b)) then

       v_res = v_res_b;

    end if;

    if(ST_Length(v_res) > ST_Length(v_res_c)) then

       v_res = v_res_c;

    end if;

    if(ST_Length(v_res) > ST_Length(v_res_d)) then

       v_res = v_res_d;

    end if;

    --如果找不到最短路径,就返回null

    if(v_res is null) then

        return;

    end if;



    --将v_res,v_startLine,v_endLine进行拼接

    select  st_linemerge(ST_Union(array[v_res,v_startLine,v_endLine])) into v_res;

    --return v_res;

    select  ST_LineLocatePoint(v_res, v_statpoint) into v_perStart;

    select  ST_LineLocatePoint(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_shPath1;

    --接下来进行
    --找线的端点

    select ST_SetSRID( ST_MakePoint(startx , starty),4326 )into startpoint;
    select ST_SetSRID( ST_MakePoint(endx , endy),4326 )into endpoint;
    select ST_MakeLine( v_statpoint,startpoint) into star_line;
    select ST_MakeLine( v_endpoint,endpoint) into end_line;

    geoARR :=array[end_line,v_shPath1,star_line];
    geoType :=array[1,2,1];

    FOR ii IN 1..3 Loop

    lineType:=geoType[ii];
    geom:=geoARR[ii];
    raise notice '%', '返回数据';
    return next;
    end loop;
 return;

end;

$$;

alter function pgr_road(varchar, double precision, double precision, double precision, double precision, out integer, out geometry) owner to postgres;

例子

--例子:
select pgr_road('daolu',117.129149399825, 26.3420375002305,117.209062000311, 26.356417999691);
4.3、方法三:
--DROP FUNCTION public.pgr_fromatob(tbl varchar,startx float,starty float,endx float,endy float);
 
CREATE OR REPLACE FUNCTION "public"."pgr_fromatob"(tbl varchar, startx float8, starty float8, endx float8, endy float8)
    RETURNS "public"."geometry" AS $BODY$ 
declare
    v_startLine geometry;--离起点最近的线 
    v_endLine geometry;--离终点最近的线 
 
    v_startTarget integer;--距离起点最近线的终点
    v_startSource integer;
    v_endSource integer;--距离终点最近线的起点
    v_endTarget integer;
    v_statpoint geometry;--在v_startLine上距离起点最近的点 
    v_endpoint geometry;--在v_endLine上距离终点最近的点 
 
    v_res geometry;--最短路径分析结果
    v_res_a geometry;
    v_res_b geometry;
    v_res_c geometry;
    v_res_d geometry; 
 
    v_perStart float;--v_statpoint在v_res上的百分比 
    v_perEnd float;--v_endpoint在v_res上的百分比 
 
    v_shPath_se geometry;--开始到结束
    v_shPath_es geometry;--结束到开始
    v_shPath geometry;--最终结果
    tempnode float; 
begin
    --查询离起点最近的线 
    execute 'select geom, source, target  from ' ||tbl||
                          ' where ST_DWithin(geom,ST_Geomfromtext(''POINT('|| startx ||' ' || starty||')'',4326),15)
                            order by ST_Distance(geom,ST_GeomFromText(''POINT('|| startx ||' '|| starty ||')'',4326))  limit 1'
                            into v_startLine, v_startSource ,v_startTarget; 
 
    --查询离终点最近的线  
    execute 'select geom, source, target from ' ||tbl||
                           ' where ST_DWithin(geom,ST_Geomfromtext(''point('|| endx || ' ' || endy ||')'',4326),15)
                            order by ST_Distance(geom,ST_GeomFromText(''point('|| endx ||' ' || endy ||')'',4326))  limit 1'
                            into v_endLine, v_endSource,v_endTarget; 
    --如果没找到,返回null
    if (v_startLine is null) or (v_endLine is null) then 
        return null; 
    end if ; 
 
    -- 查询起点和起点最近的先的点
    select  ST_ClosestPoint(v_startLine, ST_Geomfromtext('point('|| startx ||' ' || starty ||')',4326)) into v_statpoint; 
    raise notice 'v_statpoint %',  v_statpoint;
 
    -- 查询终点和终点最近的先的点
    select  ST_ClosestPoint(v_endLine, ST_GeomFromText('point('|| endx ||' ' || endy ||')',4326)) into v_endpoint; 
    raise notice 'v_endpoint %',  v_endpoint;
 
    -- ST_Distance 
    --从开始的起点到结束的起点最短路径 
    execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    'FROM pgr_kdijkstraPath ( 
    ''SELECT gid as id, source::integer, target::integer, length::double precision as cost FROM ' || tbl ||''',' 
    ||v_startSource || ', '||'array['|| v_endSource||'] , false, false 
    ) a, ' 
    || tbl || ' b 
    WHERE a.id3=b.gid   
    GROUP by id1   
    ORDER by id1' into v_res ;
 
    --从开始的终点到结束的起点最短路径
    execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    'FROM pgr_kdijkstraPath( 
    ''SELECT gid as id, source::integer, target::integer, length::double precision 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_b ;
 
    --从开始的起点到结束的终点最短路径
    execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    'FROM pgr_kdijkstraPath( 
    ''SELECT gid as id, source::integer, target::integer, length::double precision as cost FROM ' || tbl ||''',' 
    ||v_startSource || ', ' ||'array['|| v_endTarget||'] , false, false 
    ) a, ' 
    || tbl || ' b 
    WHERE a.id3=b.gid   
    GROUP by id1   
    ORDER by id1' into v_res_c ;
 
    --从开始的终点到结束的终点最短路径
    execute 'SELECT st_linemerge(st_union(b.geom)) ' ||
    'FROM pgr_kdijkstraPath( 
    ''SELECT gid as id, source::integer, target::integer, length::double precision as cost FROM ' || tbl ||''',' 
    ||v_startTarget || ', ' ||'array['|| v_endTarget||'], false, false 
     ) a, ' 
    || tbl || ' b 
    WHERE a.id3=b.gid   
    GROUP by id1  
    ORDER by id1' into v_res_d ;
 
    if(ST_Length(v_res) > ST_Length(v_res_b)) then
        v_res = v_res_b;
    end if;
 
    if(ST_Length(v_res) > ST_Length(v_res_c)) then
        v_res = v_res_c;
    end if;
 
    if(ST_Length(v_res) > ST_Length(v_res_d)) then
        v_res = v_res_d;
    end if;
 
    raise notice 'v_res %',  v_res;
    raise notice 'v_startLine %',  v_startLine;
    raise notice 'v_endLine %', v_endLine;
    
    --如果没找到,返回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_LineLocatePoint(v_res, v_statpoint) into v_perStart; 
   select  ST_LineLocatePoint(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  COST 100
;
 
ALTER FUNCTION "public"."pgr_fromatob"(tbl varchar, startx float8, starty float8, endx float8, endy float8) OWNER TO "postgres";

--参考地址:https://www.jianshu.com/p/eaea02568815

例子

--例子:
select pgr_fromatob('daolu',117.129149399825, 26.3420375002305,117.209062000311, 26.356417999691);
select pgr_fromatob('daolu',117.229149399825, 26.3420375002305,117.209062000311, 26.356417999691);
5、查询最优路线
select _myshortpath(117.165833333, 26.3536111111,108.916666667, 34.2166666667,'length');

-- select st_srid(geom) from daolu;  查询字段类型

其他

--EPSG:4326 (WGS84)转EPSG:3857 (Pseudo-Mercator)
--参考网址:https://blog.csdn.net/October_zhang/article/details/103529797
select  st_astext(st_transform(geom)) from daolu;

select st_astext(geom) ,target from daolu where ST_DWithin(geom,ST_Geometryfromtext('point(13068466.05 3040575.7748)',3857),15)
order by ST_Distance(geom,ST_GeometryFromText('point(13067264.4537 3040464.6936)',3857)) limit 1;
6、计算距离
-- 计算两点之间的距离,结果是米
select
ST_Distance(
    ST_SetSRID(ST_MakePoint(117.129149399825, 26.3420375002305),4326)::geography,
    ST_SetSRID(ST_MakePoint(117.209062000311, 26.356417999691),4326)::geography
);

-- 计算线的长度,结果是米
select ST_Length(Geography(ST_GeomFromText('LINESTRING(117.229149399825 26.3420375002305,117.209062000311 26.356417999691)')));


-- 判断点是否与面面相交
select ST_Contains(St_Astext(ST_Buffer(geography(st_geomfromtext('MULTILINESTRING((117.048605999567 26.4415170003094,117.049979999977 26.441910999593,117.051406000087 26.44157400024,117.052468999645 26.4402419999684,117.053297000057 26.4385019997675,117.054616999775 26.4384199995833,117.056773000274 26.4380529997462,117.057517000409 26.4378880002311,117.057711100187 26.43778440013,117.058206400005 26.4375315998035,117.058470100115 26.4374001000347,117.058664100068 26.4372974999797,117.058860199938 26.4371856000355))')),1000.00)),
    st_astext(geography(st_geomfromtext('POINT(117.048605999567 26.4415170003094)')))) as result

https://blog.csdn.net/October_zhang/article/details/103529797

❤️❤️参考地址 ❤️❤️
❤️❤️ PostGIS中的常用函数❤️❤️
❤️ ❤️postgis常用操作❤️ ❤️
❤️ ❤️PostGIS官方教程汇总目录❤️ ❤️
❤️ ❤️六大路径规划算法❤️ ❤️

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
PostGIS是一个用于地理空间数据存储和分析的开源软件扩展,它在PostgreSQL数据库中添加了对地理空间数据类型和地理空间函数的支持。路径规划PostGIS的一个功能,可以用于计算两个地理位置之间的最短路径。在你提供的引用中,安装了PostgreSQL数据库和PostGIS扩展,并创建了拓扑网络以进行路径规划。 要进行路径规划,首先需要在数据库中创建一个包含道路网络的表。这个表包含道路的几何信息和其他属性。然后,使用pgr_createTopology函数来构建拓扑网络,这将填充源和目标列,以便后续的路径规划操作。 例如,使用以下命令创建一个包含道路网络的表: CREATE TABLE edge_table (id serial primary key, geom geometry, length double precision); 然后,将道路数据插入到表中: INSERT INTO edge_table (geom, length) VALUES (ST_GeomFromText('LINESTRING(0 0, 1 1)'), 1.0); 接下来,使用pgr_createTopology函数构建拓扑网络: SELECT pgr_createTopology('edge_table', 0.001); 完成拓扑构建后,你可以使用PostGIS提供的路径规划函数来计算最短路径。例如,使用pgr_dijkstra函数可以计算两个地理位置之间的最短路径: SELECT * FROM pgr_dijkstra('SELECT id, source, target, length FROM edge_table', source_id, target_id); 在这个例子中,source_id和target_id是你要计算最短路径的起点和终点的ID。 总结起来,通过安装PostgreSQL数据库和PostGIS扩展,并创建拓扑网络,你可以使用PostGIS的路径规划功能来计算两个地理位置之间的最短路径。 #### 引用[.reference_title] - *1* [Springboot集成PostGIS完成路径规划](https://blog.csdn.net/2202_75618418/article/details/128163823)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [postgresql路径规划pgrouting使用](https://blog.csdn.net/GliangJu/article/details/118416634)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值