基於postGIS的室內地圖最短路徑演算法四
阿新 • • 發佈:2019-02-19
在上一篇博文基於postGIS的室內地圖最短路徑演算法三,雖然路徑分析的結果,最後返回了起點到終點的完整線路,但是可能產生起點或終點到路網的連線穿越障礙物的情況,這裡就需要用虛線表示。
這樣就需要將路徑分析的結果分三條記錄返回,起點到路網、路網中路徑、路網到終點線,並需要對這三段線進行區別。然後在Goeserver中配置樣式。
執行結果如下圖所示:
資料庫程式碼:
--DROP FUNCTION pgr_floor_test3(character varying, double precision, double precision, double precision, double precision, integer); --tbl路網表名 --startx起點經度 --starty起點緯度 --endx終點經度 --endy終點緯度 --fnumber樓層 CREATE OR REPLACE function pgr_floor_test3(IN tbl varchar,IN startx float,IN starty float,IN endx float,IN endy float,IN fnumber integer,OUT lineType integer,OUT geom geometry) --限制返回型別 returns SETOF record as $body$ declare fmin integer; fmax integer; 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[]; lines myline[];--返回線集 line1 myline; line2 myline; line3 myline; ii integer; begin fmin=fnumber*1000; fmax=fmin+1000; raise notice '%', fmin; raise notice '%', fmax; --查詢離起點最近的線 --4326座標系 --找起點15米範圍內的最近線 execute 'select geom, source, target from ' ||tbl|| ' where ST_DWithin(geom,ST_Geometryfromtext(''point('|| startx ||' ' || starty||')'',4326),15) and source between '||fmin||' and '||fmax||' 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),15) and source between '||fmin||' and '||fmax||' 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 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; -- 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 ; --從開始的終點到結束的起點最短路徑 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 ; --從開始的起點到結束的終點最短路徑 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 ; --從開始的終點到結束的終點最短路徑 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 ; 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_ClosestPoint(v_endLine, ST_GeometryFromText('point('|| endx ||' ' || endy ||')',4326)) into v_endpoint; -- select ST_MakePoint(endx , endy) into startpoint; 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; -- select st_union(end_line,v_shPath1) into v_shPath2; --select st_union(star_line,v_shPath2) into v_shPath; --line1.id=1; --line1.geom=star_line; --line2.id=2; --line2.geom=v_shPath1; --line3.id=3; --line3.geom=end_line; --lines[0]=line1; --lines[1]=line2; --lines[2]=line3; geoARR :=array[end_line,v_shPath1,star_line]; geoType :=array[1,2,1]; --select st_union(geoARR) into v_shPath; --raise notice '%', '返回資料'; --OUT lineType integer,OUT geom geometry FOR ii IN 1..3 Loop lineType:=geoType[ii]; geom:=geoARR[ii]; raise notice '%', '返回資料'; return next; end loop; return; --return geoARR; --return lines; --return v_shPath; end; $body$ LANGUAGE plpgsql VOLATILE STRICT;
樣式程式碼如下:
<?xml version="1.0" encoding="GBK"?><sld:StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:sld="http://www.opengis.net/sld" xmlns:gml="http://www.opengis.net/gml" xmlns:ogc="http://www.opengis.net/ogc" version="1.0.0"> <sld:UserLayer> <sld:LayerFeatureConstraints> <sld:FeatureTypeConstraint/> </sld:LayerFeatureConstraints> <sld:UserStyle> <sld:Name>F34</sld:Name> <sld:FeatureTypeStyle> <sld:Name>group 0</sld:Name> <sld:FeatureTypeName>Feature</sld:FeatureTypeName> <sld:SemanticTypeIdentifier>generic:geometry</sld:SemanticTypeIdentifier> <sld:SemanticTypeIdentifier>simple</sld:SemanticTypeIdentifier> <sld:Rule> <sld:Name>虛線</sld:Name> <ogc:Filter> <ogc:PropertyIsEqualTo> <ogc:PropertyName>linetype</ogc:PropertyName> <ogc:Literal>1</ogc:Literal> </ogc:PropertyIsEqualTo> </ogc:Filter> <sld:LineSymbolizer> <sld:Stroke> <sld:CssParameter name="stroke">#00FF40</sld:CssParameter> <sld:CssParameter name="stroke-width">2.0</sld:CssParameter> <sld:CssParameter name="stroke-dasharray">5.0</sld:CssParameter> </sld:Stroke> </sld:LineSymbolizer> </sld:Rule> <sld:Rule> <sld:Name>實線</sld:Name> <ogc:Filter> <ogc:PropertyIsEqualTo> <ogc:PropertyName>linetype</ogc:PropertyName> <ogc:Literal>2</ogc:Literal> </ogc:PropertyIsEqualTo> </ogc:Filter> <sld:LineSymbolizer> <sld:Stroke> <sld:CssParameter name="stroke">#FF0000</sld:CssParameter> <sld:CssParameter name="stroke-width">2.0</sld:CssParameter> </sld:Stroke> </sld:LineSymbolizer> </sld:Rule> </sld:FeatureTypeStyle> </sld:UserStyle> </sld:UserLayer> </sld:StyledLayerDescriptor>