Postgresql构建经纬度查询两点之间的最短路径

前言

前段时间遇到了实际的需求,在特定的路网中查询最短路径。同时配合 Cesium 进行动态显示。

需求

  • 动态查询两点之间的最短路径(起点固定);
  • 查询的路径高亮显示;
  • Cesium 对生成的路径进行小车移动展示。

技术实现路线

  1. 动态查询两点之间的最短路径 -> Postgresql 中的 PgRouting 实现;
  2. 查询的路径高亮显示 -> Cesium 中 PolylineGlowMaterialProperty 进行高亮显示;
  3. 路径进行小车移动展示 ->CZML 进行动态展示

实现效果

实现效果

Postgresql 最短路径实现

起初是参考 PgRouting 官网 的做法。但是这种做法是对数据进行拓扑,生成有向图(或者无向图)采用 dijkstra 算法进行最短路径的生成。这种方法最大的问题就是判断鼠标点击的点位于有向图的位置。相对来说比较麻烦。

官网说明

实现流程:

  • 首先将数据导入 Postgresql 数据库
  • 对数据进行路网拓扑数据计算处理,执行成功后,执行成功后会生产一个 vertices_pgr 的表,里面包含路网相交点的空间数据
alter table road add column source int;
alter table road add column target int;

create index road_source_idx on road("source");
create index road_target_idx on road("target");

ALTER TABLE road  ADD COLUMN length double precision;  

SELECT pgr_createTopology('road',0.00001, 'geom', 'gid');  

update road set length =st_length(geom);

  • 查询最短路径 sql 语句前端传入的是有向图中的某两个端点。
SELECT seq, id1 AS node, id2 AS edge, cost,geom  FROM pgr_dijkstra('  
SELECT gid AS id,              
source::integer,                 
target::integer,                
length::double precision AS cost  
FROM xmpark_road',  
1, 10, false, false) as di  
join xmpark_road pt  
on di.id2 = pt.gid


最方便的还是直接传入起始点的坐标进行路径的查询

感谢 itas109 提供的经纬度查询的最短路径的方法。这是 Github 地址 https://github.com/itas109/postgis_navigation

思路是将创建新的函数,将鼠标点击的两点经纬度传入获得最短路径的返回值。

CREATE OR REPLACE FUNCTION "public"."pgr_fromatob"(IN "tbl" varchar, IN "x1" float8, IN "y1" float8, IN "x2" float8, IN "y2" float8, OUT "seq" int4, OUT "gid" int4, OUT "name" text, OUT "heading" float8, OUT "cost" float8, OUT "geom" "public"."geometry")
  RETURNS SETOF "pg_catalog"."record" AS $BODY$  
DECLARE  
        sql     text;  
        rec     record;  
        source  integer;  
        target  integer;  
        point   integer;  

BEGIN  
    -- 查询距离出发点最近的道路节点  
    EXECUTE 'SELECT id::integer FROM road_vertices_pgr   
            ORDER BY the_geom <-> ST_GeometryFromText(''POINT('   
            || x1 || ' ' || y1 || ')'',900913) LIMIT 1' INTO rec;  
    source := rec.id;  

    -- 查询距离目的地最近的道路节点  
    EXECUTE 'SELECT id::integer FROM road_vertices_pgr   
            ORDER BY the_geom <-> ST_GeometryFromText(''POINT('   
            || x2 || ' ' || y2 || ')'',900913) LIMIT 1' INTO rec;  
    target := rec.id;  

    -- 最短路径查询   
        seq := 0;  
        sql := 'SELECT gid, geom, cost, source, target,   
                ST_Reverse(geom) AS flip_geom FROM ' ||  
                        'pgr_bdAstar(''SELECT gid as id, source::int, target::int, '  
                                        || 'length::float AS cost,x1,y1,x2,y2 FROM '  
                                        || quote_ident(tbl) || ''', '  
                                        || source || ', ' || target   
                                        || ' ,false, false), '  
                                || quote_ident(tbl) || ' WHERE id2 = gid ORDER BY seq';  

    -- Remember start point  
        point := source;  

        FOR rec IN EXECUTE sql  
        LOOP  
        -- Flip geometry (if required)  
        IF ( point != rec.source ) THEN  
            rec.geom := rec.flip_geom;  
            point := rec.source;  
        ELSE  
            point := rec.target;  
        END IF;  

        -- Calculate heading (simplified)  
        EXECUTE 'SELECT degrees( ST_Azimuth(   
                ST_StartPoint(''' || rec.geom::text || '''),  
                ST_EndPoint(''' || rec.geom::text || ''') ) )'   
            INTO heading;  

        -- Return record  
                seq     := seq + 1;  
                gid     := rec.gid;   
                cost    := rec.cost;  
                geom    := rec.geom;  
                RETURN NEXT;  
        END LOOP;  
        RETURN;  
END;  
$BODY$
  LANGUAGE plpgsql VOLATILE STRICT
  COST 100
  ROWS 1000

使用新函数之前要对数据进行处理。路网数据必须在节点处打断,同时在 ArcMap 中进行拓扑纠错。数据导入后进行如下处理:

ALTER TABLE road ADD COLUMN source integer;     --添加起点id字段
ALTER TABLE road ADD COLUMN target integer;     --添加终点id字段
ALTER TABLE road ADD COLUMN length double precision;    --添加道路权重字段

SELECT pgr_createTopology('road',0.00001, 'geom', 'gid');   --为source和target赋值,并创建拓扑点表road_vertices_pgr

update road set length =st_length(geom);            --为length赋值

CREATE INDEX source_idx ON road("source");      --为source字段创建索引
CREATE INDEX target_idx ON road("target");          --为target字段创建索引

ALTER TABLE road ADD COLUMN x1 double precision;        --创建起点经度x1
ALTER TABLE road ADD COLUMN y1 double precision;        --创建起点纬度y1
ALTER TABLE road ADD COLUMN x2 double precision;        --创建起点经度x2
ALTER TABLE road ADD COLUMN y2 double precision;        --创建起点经度y2

UPDATE road SET x1 =ST_x(ST_PointN(geom, 1));
UPDATE road SET y1 =ST_y(ST_PointN(geom, 1));
UPDATE road SET x2 =ST_x(ST_PointN(geom, ST_NumPoints(geom)));
UPDATE road SET y2 =ST_y(ST_PointN(geom, ST_NumPoints(geom)));

然后执行查询语句:

SELECT  st_asgeojson(st_makeline(route.geom)) FROM (SELECT geom FROM pgr_fromAtoB('road', 118.574693042441, 31.0002595461945,118.575197797, 31.0068716390001)ORDER BY seq) AS route

查询结果:

查询结果

接下来就是对查询的 GeoJSON 数据转换为 CZML 数据在三维场景中进行展示了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342