不使用自带函数求区域的周长_pgRouting教程七:使用SQL存储过程

本文介绍了如何在pgRouting中利用SQL存储过程来满足复杂的应用需求,如规划车辆路径、处理几何信息等。通过创建自定义函数,避免在高级语言中直接调用pgRouting低级接口,提高代码复用性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

57d895cd801e7afe501e90b3d9c64695.png

本文衔接上篇文章:

不睡觉的怪叔叔:pgRouting教程六:高级路径查询​zhuanlan.zhihu.com
3f173cf7a9e1c98dd805f2254718b003.png

pgRouting函数提供低级接口,在为更高级别的应用程序开发时,需要在SQL查询中调用pgRouting函数以满足应用需求。随着这些SQL查询的逻辑变得更加复杂,我们应该将它们存储在PostgreSQL存储过程或函数中,相当于对pgRouting函数再进行一次封装,这样我们在使用高级语言开发应用程序时只要调用我们定义的存储过程即可。

注意:在PostgreSQL中存储过程就是函数。

一、应用程序的需求

将要开发的存储过程具有以下需求:

1、规划车辆路径

  • 不使用人行道(pedestrian)。
  • 一旦数据库视图被创建,它可以被复用。
  • 道路的成本是时间,单位是分钟。

2、规划的结果路径具有道路名信息。

3、规划的结果路径中的几何线段具有正确的方向

  • 在结果中返回路径的几何信息。
  • 返回结果路径的各个路段的大地方位角(单位十进制度)。
  • 几何信息处理需要得到正确的方向。

1.1、练习1 —— 允许被车辆行驶的路径

车辆不允许在行人道路上行驶,因此:

  • 创建包含车辆可以行驶的道路的数据库视图。
  • 道路成本设置为时间(单位分钟)。
  • 验证以上过程减少了多少路段。
CREATE VIEW vehicle_net AS
	SELECT gid, source, target,
		   cost / 1.3 / 60 AS cost,
		   reverse_cost / 1.3 / 60 AS reverse_cost, -- 假设行人每秒走1.3m
		   geom
	FROM shenzhen_roads 
	WHERE fclass NOT IN ('steps', 'cycleway', 'footway', 'track_grade2', 'track');
	
-- 验证
SELECT count(*) FROM shenzhen_roads;
SELECT count(*) FROM vehicle_net;

后面两条SQL语句分别查询出原先的道路具有111185条,新创建的vehicle_net视图中具有道路92971条(没有包含行人道路和铁轨)。

1.2、练习2 —— 将路网限制在一个范围内

7a7d4ae0a9d9220f0e1ea39e8d66e6af.png

将车辆限制在只能在前海湾附近区域(如上图红框)中行驶,该区域的范围是:(12673569, 2573130, 12680410, 2578570)坐标系ESPG:3857。

  • 车辆只能在区域(12673569, 2573130, 12680410, 2578570)中行驶。
  • 创建一个保存该区域路段的数据库视图。
  • 验证缺少的路段数。
CREATE VIEW little_net AS
	SELECT *
	FROM vehicle_net
	WHERE vehicle_net.geom && ST_MakeEnvelope(12673569, 2573130, 12680410, 2578570, 3857);

-- 验证
SELECT COUNT(*) FROM little_net; 

bc5a014fa403e85e8ef61e2c6f8579b4.png

上面的SQL语句使用了一个PostGIS函数ST_MakeEnvelope创建一个矩形多边形用于筛选数据,它的官方API文档:

ST_MakeEnvelope​postgis.net

1.3、练习3 —— 结果包含道路名信息

a99e811550b5fc496bbe817f9753c06c.png

规划车辆从南方医科大学深圳医院到前海金融中心,结果包含道路名信息

  • 车辆从南方医科大学深圳医院出发(id: 15938)。
  • 车辆到前海金融中心(id: 9064)。
  • 结果包含道路名信息
SELECT dijkstra.*, ways.name FROM pgr_dijkstra(
	'SELECT gid AS id, * FROM little_net',
	15938, 9064
) AS dijkstra LEFT JOIN shenzhen_roads AS ways
ON (edge = gid) 
ORDER BY seq;

c673804bff147c40018ea9a840635283.png

ed96c54cc6fdb0a986073e6e0607055c.png

注:因为数据的原因,有的道路没有道路名信息。另外这里的SQL语句性能肯定不佳,这里只是为了体现很多业务场景下SQL语句的逻辑是很复杂的,从而说明存储过程的重要性。

二、玩转几何信息

2.1、练习4 —— 路径的几何信息(WKT格式)

规划车辆从南方医科大学深圳医院到前海金融中心,结果包含如下信息:

  • 路径的道路名
  • 道路的几何信息(WKT格式)
SELECT dijkstra.*, ways.name, ST_AsText(ways.geom) FROM pgr_dijkstra(
	'SELECT gid AS id, * FROM little_net',
	15938, 9064
) AS dijkstra LEFT JOIN shenzhen_roads AS ways
ON (edge = gid) 
ORDER BY seq;

2357fd6e5c89c9a34f94250c425d1154.png

7e1860d827544db9ac3fca28a719ac43.png

2.2、练习5 —— 路径的几何信息(二进制格式)

规划车辆从南方医科大学深圳医院到前海金融中心,结果包含如下信息:

  • 路径的道路名
  • 道路的几何信息(二进制格式)

注意:以下语句使用了WITH操作符,它可以为查询定义一张临时表。

WITH 
dijkstra AS(
	SELECT * FROM pgr_dijkstra(
		'SELECT gid AS id, * FROM little_net',
		15938, 9064
	) 
)
SELECT dijkstra.*, ways.name, ways.geom AS route_geom
FROM dijkstra LEFT JOIN shenzhen_roads AS ways
ON (edge = gid) 
ORDER BY seq;

60b01b80f325396e7fcc33513cfead80.png

70761a124adf52676bffdf5f780d4c4b.png

2.3、练习6 —— 使用几何信息求方位角

规划车辆从南方医科大学深圳医院到前海金融中心,结果包含如下信息:

  • 路径的道路名
  • 路径的几何信息(二进制格式)
  • 路径各个路段的大地方位角(单位十进制度)
WITH 
dijkstra AS(
	SELECT * FROM pgr_dijkstra(
		'SELECT gid AS id, * FROM little_net',
		15938, 9064
	) 
),
get_geom AS (
    SELECT dijkstra.*, ways.name, ways.geom AS route_geom
    FROM dijkstra LEFT JOIN shenzhen_roads AS ways ON (edge = gid)
    ORDER BY seq)
SELECT seq, name, cost,
    -- calculating the azimuth
    degrees(ST_azimuth(ST_StartPoint(route_geom), ST_EndPoint(route_geom))) AS azimuth,
    ST_AsText(route_geom),
    route_geom
FROM get_geom
ORDER BY seq;

26145ae90f8cda911db3a1c351623ef7.png

455d2a7df5e85dc081ac9d72fa0871e1.png

这里使用了一个PostGIS函数ST_Azimuth,简单来说它基于路段起点的正北方向求路段的方位角,结果是弧度制,需要使用PostgreSQL自带的degrees函数将其转换为十进制度。ST_Azimuth函数的官方API文档:

ST_Azimuth​postgis.net
26ad3a0c2b050ad180947d9d837861d5.png

2.4、练习7 —— 几何信息的方向性

当数据库生成一个结果路径时,结果路径的双向路段(oneway字段是'B')可以是正向的,也可以是反向的。那么可以得出如下结论:

  • 结果路径中的双向路段是正向的 —— 路段几何信息的起始点就是source字段指的那个顶点。
  • 结果路径中的双向路段是反向的 —— 路段几何信息的起始点就是target字段指的那个顶点。此时为了满足需求,求方位角需要将路段几何信息逆序排列。

总之我们需要保证计算出来的各路段的方位角能让各个路段沿着整条路径。

规划车辆从南方医科大学深圳医院到前海金融中心,结果包含如下信息:

  • 路段几何信息的终止点坐标必须与下一条路段的起始点坐标一致。
  • 路径的几何信息(二进制格式)
  • 路径各个路段的大地方位角(单位十进制度)
WITH 
dijkstra AS(
	SELECT * FROM pgr_dijkstra(
		'SELECT gid AS id, * FROM little_net',
		15938, 9064
	) 
),
get_geom AS (
    SELECT dijkstra.*, ways.name, 
	-- 将反向路段的几何信息逆序排列
    CASE
        WHEN dijkstra.node = ways.source THEN ways.geom
        ELSE ST_Reverse(ways.geom)
	END AS route_geom
    FROM dijkstra LEFT JOIN shenzhen_roads AS ways ON (edge = gid)
    ORDER BY seq)
SELECT seq, name, cost,
    -- 计算方位角
    degrees(ST_azimuth(ST_StartPoint(route_geom), ST_EndPoint(route_geom))) AS azimuth,
    ST_AsText(route_geom),
    route_geom
FROM get_geom
ORDER BY seq;

b2a4b1afc05547d509cc414d61782bba.png

015a1471c5399fc4226ff762220b3064.png

以上SQL语句使用了PostGIS函数ST_Reverse,它的功能是将几何信息的坐标点信息逆序排列,它的官方API文档:

ST_Reverse​postgis.net

三、创建函数(存储过程)

我们创建自定义函数要注意以下命名规则:

  • 避免使用PostGIS和pgRouting已经使用的函数名。
  • 避免使用"pgr_"和"ST_"作为函数名的开头。

3.1、练习8 —— 创建一个函数

我们创建的函数具有如下特点:

  • 可以在车辆道路的全部区域进行搜索。
  • 将数据库视图作为参数。
  • 结果包含道路名、路径的几何信息(二进制格式)、路径各个路段的大地方位角(单位十进制度)等等。
CREATE OR REPLACE FUNCTION wrk_dijkstra(
    IN edges_subset regclass,	-- 视图作为参数
    IN source BIGINT,
    IN target BIGINT,
    OUT seq INTEGER,
    OUT gid BIGINT,
    OUT name TEXT,
    OUT cost FLOAT,
    OUT azimuth FLOAT,
    OUT route_readable TEXT,
    OUT route_geom geometry
) RETURNS SETOF record AS 
$BODY$
    WITH
    dijkstra AS (
        SELECT * FROM pgr_dijkstra(
            -- 使用参数化的视图
            'SELECT gid AS id, * FROM ' || $1,
            $2, $3)
    ),
    get_geom AS (
        SELECT dijkstra.*, ways.name,
            CASE
                WHEN dijkstra.node = ways.source THEN geom
                ELSE ST_Reverse(geom)
            END AS route_geom
        FROM dijkstra JOIN shenzhen_roads AS ways ON (edge = gid)
        ORDER BY seq)
    SELECT
        seq,
        edge,
        name,
        cost,
        degrees(ST_azimuth(ST_StartPoint(route_geom), ST_EndPoint(route_geom))) AS azimuth,
        ST_AsText(route_geom),
        route_geom
    FROM get_geom
    ORDER BY seq;
$BODY$
LANGUAGE 'sql';

3.2、练习9 —— 使用函数

现在要规划车辆从南方医科大学深圳医院到前海金融中心,可以直接使用wrk_dijkstra函数。

  • 车辆从南方医科大学深圳医院出发(id: 15938)。
  • 车辆到前海金融中心(id: 9064)
SELECT * FROM wrk_dijkstra('vehicle_net', 15938, 9064);

3.3、练习10 —— 保存函数

可以将函数保存起来到一个SQL文件:E:/wrk_dijkstra.sql。

这个SQL文件可以用于在其他数据库安装wrk_dijkstra函数,比如在pgsql命令行中执行以下命令:

psql -U postgres -d city_routing -f E:/wrk_dijkstra.sql

或者在GUI工具中点击如下按钮打开wrk_dijkstra.sql文件并执行。

9ed7642367f3393f0a617b6ab4a6c190.png

或者直接复制、粘贴。。。本文完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值