1. 程式人生 > >postgresql+pgrouting 最短路線sql (4)

postgresql+pgrouting 最短路線sql (4)

CREATE EXTENSION postgis;  --新增postgis功能
CREATE EXTENSION pgrouting;	--新增pgRouting函式
CREATE EXTENSION postgis_topology;
CREATE EXTENSION fuzzystrmatch;
CREATE EXTENSION postgis_tiger_geocoder;
CREATE EXTENSION address_standardizer;


--新增起點id
ALTER TABLE public.route5 ADD COLUMN source integer;
--新增終點id
ALTER TABLE public.route5 ADD COLUMN target integer;
--新增道路權重值
ALTER TABLE public.route5 ADD COLUMN length double precision;


--為sampledata表建立拓撲佈局,即為source和target欄位賦值
SELECT pgr_createTopology('public.route5',0.00001, 'geom', 'gid');


--為source和target欄位建立索引
CREATE INDEX source_idx ON route5("source");
CREATE INDEX target_idx ON route5("target");

--為length賦值
update route5 set length =st_length(geom);


--為beijingmodified表新增reverse_cost欄位並用length的值賦值
ALTER TABLE route5 ADD COLUMN reverse_cost double precision;
UPDATE route5 SET reverse_cost =length;

--使用pgr_dijkstra演算法查詢
SELECT seq, id1 AS node, id2 AS edge, cost FROM pgr_dijkstra('
SELECT gid AS id,                   
source::integer,                       
target::integer,                      
length::double precision AS cost
FROM route5',
1, 6, false, false);



--為表格beijingmodified新增x1,y1,x2,y2欄位
ALTER TABLE route5 ADD COLUMN x1 double precision;
ALTER TABLE route5 ADD COLUMN y1 double precision;
ALTER TABLE route5 ADD COLUMN x2 double precision;
ALTER TABLE route5 ADD COLUMN y2 double precision;
--為新新增的屬性欄位賦值
UPDATE route5 SET x1 =ST_x(ST_PointN(geom, 1));
UPDATE route5 SET y1 =ST_y(ST_PointN(geom, 1));
UPDATE route5 SET x2 =ST_x(ST_PointN(geom, ST_NumPoints(geom)));
UPDATE route5 SET y2 =ST_y(ST_PointN(geom, ST_NumPoints(geom)));


SELECT seq, id1 AS node, id2 AS edge, cost FROM pgr_astar('              
SELECT gid AS id,                       
source::integer,                       
target::integer,                       
length::double precision AS cost,                       
x1, y1, x2, y2                      
FROM route5',1, 6, false,false);



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||')'', 4326),15)
			order by ST_Distance(geom,ST_GeometryFromText(''point('|| startx ||' '|| starty ||')'', 4326))  limit 1'
			into v_startLine ,v_startTarget;
    --查詢離終點最近的線
    execute 'select geom,source  from ' ||tbl||
			' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| endx || ' ' || endy ||')'', 4326),15)
			order by ST_Distance(geom,ST_GeometryFromText(''point('|| endx ||' ' || endy ||')'', 4326))  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 ||')', 4326)) into v_statpoint;
    select  ST_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')', 4326)) 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