Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@ RUN git clone --depth 1 --branch $OSM2PGSQL_BRANCH $OSM2PGSQL_REPO \
RUN wget https://github.com/rustprooflabs/pgdd/releases/download/0.6.1/pgdd_0.6.1_postgis_pg18_amd64.deb \
&& dpkg -i ./pgdd_0.6.1_postgis_pg18_amd64.deb \
&& rm ./pgdd_0.6.1_postgis_pg18_amd64.deb \
&& wget https://github.com/rustprooflabs/convert/releases/download/0.0.5/convert_0.0.5_postgis_pg18_amd64.deb \
&& dpkg -i ./convert_0.0.5_postgis_pg18_amd64.deb \
&& rm ./convert_0.0.5_postgis_pg18_amd64.deb

&& wget https://github.com/rustprooflabs/convert/releases/download/0.1.0/convert_0.1.0_postgis_pg18_amd64.deb \
&& dpkg -i ./convert_0.1.0_postgis_pg18_amd64.deb \
&& rm ./convert_0.1.0_postgis_pg18_amd64.deb


WORKDIR /app
Expand Down
59 changes: 32 additions & 27 deletions db/data/roads-us.sql
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
-- Road lookup details for generic default-
-- Region: United States
INSERT INTO pgosm.road (region, osm_type, route_motor, route_foot, route_cycle, maxspeed)
VALUES ('United States', 'motorway', True, False, False, 104.60736),
('United States', 'motorway_link', True, False, False, 104.60736),
('United States', 'trunk', True, False, True, 96.56064),
('United States', 'trunk_link', True, False, True, 96.56064),
('United States', 'primary', True, False, True, 96.56064),
('United States', 'primary_link', True, False, True, 96.56064),
('United States', 'secondary', True, False, True, 72.42048),
('United States', 'secondary_link', True, False, True, 72.42048),
('United States', 'tertiary', True, False, True, 72.42048),
('United States', 'tertiary_link', True, False, True, 72.42048),
('United States', 'residential', True, True, True, 40.2336),
('United States', 'service', True, True, True, 40.2336),
('United States', 'unclassified', True, True, True, 30),
('United States', 'proposed', False, False, False, -1),
('United States', 'planned', False, False, False, -1),
('United States', 'path', False, True, True, 4),
('United States', 'footway', False, True, False, 4),
('United States', 'track', False, True, True, 2),
('United States', 'pedestrian', False, True, False, 4),
('United States', 'cycleway', False, True, True, 32),
('United States', 'crossing', False, True, True, 2),
('United States', 'platform', False, True, False, 2),
('United States', 'social_path', False, True, False, 3),
('United States', 'steps', False, True, False, 2),
('United States', 'trailhead', False, True, True, 3)
INSERT INTO pgosm.road (
region, osm_type, route_motor, route_foot, route_cycle, maxspeed
, traffic_penalty_normal
)
VALUES ('United States', 'motorway', True, False, False, 104.60736, 0.75),
('United States', 'motorway_link', True, False, False, 104.60736, 0.72),
('United States', 'trunk', True, False, True, 96.56064, 0.75),
('United States', 'trunk_link', True, False, True, 96.56064, 0.72),
('United States', 'primary', True, False, True, 96.56064, 0.6),
('United States', 'primary_link', True, False, True, 96.56064, 0.6),
('United States', 'secondary', True, False, True, 72.42048, 0.6),
('United States', 'secondary_link', True, False, True, 72.42048, 0.6),
('United States', 'tertiary', True, False, True, 72.42048, 0.6),
('United States', 'tertiary_link', True, False, True, 72.42048, 0.6),
('United States', 'residential', True, True, True, 40.2336, 0.95),
('United States', 'service', True, True, True, 40.2336, 0.95),
('United States', 'unclassified', True, True, True, 30, 0.95),
('United States', 'proposed', False, False, False, -1, 1.0),
('United States', 'planned', False, False, False, -1, 1.0),
('United States', 'path', False, True, True, 4, 1.0),
('United States', 'footway', False, True, False, 4, 1.0),
('United States', 'track', False, True, True, 2, 1.0),
('United States', 'pedestrian', False, True, False, 4, 1.0),
('United States', 'cycleway', False, True, True, 32, 0.95),
('United States', 'crossing', False, True, True, 2, 0.3),
('United States', 'platform', False, True, False, 2, 0.3),
('United States', 'social_path', False, True, False, 3, 0.7),
('United States', 'steps', False, True, False, 2, 0.9),
('United States', 'trailhead', False, True, True, 3, 0.9)
-- Doing nothing allows users to safely customize this table
ON CONFLICT DO NOTHING
ON CONFLICT (region, osm_type) DO UPDATE
SET maxspeed = EXCLUDED.maxspeed
, traffic_penalty_normal = EXCLUDED.traffic_penalty_normal
;
8 changes: 6 additions & 2 deletions db/deploy/pgosm_road.sql
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ CREATE TABLE IF NOT EXISTS pgosm.road
CONSTRAINT uq_pgosm_routable_code UNIQUE (region, osm_type)
);

ALTER TABLE pgosm.road
ADD COLUMN IF NOT EXISTS traffic_penalty_normal NUMERIC(3,2) NOT NULL DEFAULT 1.0
;


COMMENT ON TABLE pgosm.road IS 'Provides lookup information for road layers, generally related to routing use cases.';
COMMENT ON COLUMN pgosm.road.region IS 'Allows defining different definitions based on region. Can be custom defined.';
COMMENT ON COLUMN pgosm.road.osm_type IS 'Value from highway tags.';
COMMENT ON COLUMN pgosm.road.route_motor IS 'Used to filter for classifications that typically allow motorized traffic.';
COMMENT ON COLUMN pgosm.road.route_foot IS 'Used to filter for classifications that typically allow foot traffic.';
COMMENT ON COLUMN pgosm.road.route_cycle IS 'Used to filter for classifications that typically allow bicycle traffic.';
COMMENT ON COLUMN pgosm.road.maxspeed IS 'Maxspeed in km/hr';
COMMENT ON COLUMN pgosm.road.maxspeed_mph IS 'Maxspeed in mph';
COMMENT ON COLUMN pgosm.road.maxspeed IS 'Max speed in km/hr';
COMMENT ON COLUMN pgosm.road.maxspeed_mph IS 'Max speed in mph. Calculated from max speed in km/hr.';

COMMIT;
162 changes: 119 additions & 43 deletions db/deploy/routing_functions.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
CREATE OR REPLACE PROCEDURE {schema_name}.pgrouting_version_check()
CREATE OR REPLACE PROCEDURE {schema_name}.extension_version_check()
LANGUAGE plpgsql
AS $$
DECLARE pgr_ver TEXT;
DECLARE convert_version TEXT;
BEGIN
-- Ensure pgRouting extension exists with at least pgRouting 4.0
IF NOT EXISTS (
Expand All @@ -21,10 +22,28 @@ BEGIN
pgr_ver;
END IF;

-- Ensure convert extension exists with at least convert 0.1.0
IF NOT EXISTS (
SELECT 1 FROM pg_extension WHERE extname = 'convert'
) THEN
RAISE EXCEPTION
'The convert extension is not installed. Version >= 0.1.0 required.';
END IF;

SELECT extversion INTO convert_version FROM pg_extension WHERE extname = 'convert'
;

-- Enforce minimum version
IF string_to_array(convert_version, '.')::INT[] < ARRAY[0,1,0] THEN
RAISE EXCEPTION
'Convert version % detected. Version >= 0.1.0 required.',
convert_version;
END IF;

END $$;


COMMENT ON PROCEDURE {schema_name}.pgrouting_version_check IS 'Ensures appropriate pgRouting extension is installed with an appropriate version.';
COMMENT ON PROCEDURE {schema_name}.extension_version_check IS 'Ensures pgRouting and convert extensions are installed with appropriate versions.';



Expand Down Expand Up @@ -229,7 +248,7 @@ LANGUAGE plpgsql
AS $$
BEGIN

CALL {schema_name}.pgrouting_version_check();
CALL {schema_name}.extension_version_check();

--Create edges table for input to routing_prepare_edge_network procedure
DROP TABLE IF EXISTS route_edge_input;
Expand Down Expand Up @@ -263,68 +282,75 @@ BEGIN
, tunnel TEXT
, bridge TEXT
, access TEXT
, geom GEOMETRY(LINESTRING)
, cost_length DOUBLE PRECISION
, cost_length_forward DOUBLE PRECISION NULL
, cost_length_reverse DOUBLE PRECISION NULL
, cost_motor_forward_s DOUBLE PRECISION NULL
, cost_motor_reverse_s DOUBLE PRECISION NULL
, geom GEOMETRY(LINESTRING) NOT NULL
--, UNIQUE (osm_id, sub_id) -- Currently not enforceable... dups exist...
);

INSERT INTO {schema_name}.routing_road_edge (
osm_id, sub_id, osm_type, name, ref, maxspeed, oneway, layer, tunnel, bridge, major
, route_foot, route_cycle, route_motor, access
, geom
, cost_length
, geom -- Through geom is in initial query
-- Forward/reverse added next
, cost_length_forward, cost_length_reverse
-- Travel times added last.
, cost_motor_forward_s, cost_motor_reverse_s
)
WITH add_cost AS (
SELECT re.osm_id, re.sub_id
, r.osm_type, r.name, r.ref, r.maxspeed
, r.oneway, re.layer, r.tunnel, r.bridge, r.major
, r.route_foot, r.route_cycle, r.route_motor, r.access
, ST_Length(ST_Transform(re.geom, 4326)::GEOGRAPHY) AS cost_length
, re.geom
FROM route_edges_output re
INNER JOIN {schema_name}.road_line r ON re.osm_id = r.osm_id
ORDER BY re.geom
), add_forward_reverse AS (
SELECT a.*
, CASE WHEN a.oneway IN (0, 1) OR a.oneway IS NULL
THEN a.cost_length
WHEN a.oneway = -1
THEN -1 * a.cost_length
END AS cost_length_forward
, CASE WHEN a.oneway IN (0, -1) OR a.oneway IS NULL
THEN a.cost_length
WHEN a.oneway = 1
THEN -1 * a.cost_length
END AS cost_length_reverse
FROM add_cost a
)
SELECT a.*
, convert.ttt_meters_km_hr_to_seconds(
a.cost_length_forward, COALESCE(a.maxspeed, r.maxspeed) * r.traffic_penalty_normal
) AS cost_motor_forward_s
, convert.ttt_meters_km_hr_to_seconds(
a.cost_length_reverse, COALESCE(a.maxspeed, r.maxspeed) * r.traffic_penalty_normal
) AS cost_motor_reverse_s
FROM add_forward_reverse a
INNER JOIN pgosm.road r ON a.osm_type = r.osm_type
ORDER BY a.geom
;

CREATE INDEX gix_{schema_name}_routing_road_edge
CREATE INDEX gix_{schema_name}_routing_road_edge_geom
ON {schema_name}.routing_road_edge
USING GIST (geom)
;

RAISE NOTICE 'Created table {schema_name}.routing_road_edge';


ALTER TABLE {schema_name}.routing_road_edge
ADD cost_length DOUBLE PRECISION NULL;

UPDATE {schema_name}.routing_road_edge
SET cost_length = ST_Length(ST_Transform(geom, 4326)::GEOGRAPHY)
CREATE INDEX ix_{schema_name}_routing_road_edge_vertex_id_source
ON {schema_name}.routing_road_edge (vertex_id_source)
;
CREATE INDEX ix_{schema_name}_routing_road_edge_vertex_id_target
ON {schema_name}.routing_road_edge (vertex_id_target)
;

COMMENT ON COLUMN {schema_name}.routing_road_edge.cost_length IS 'Length based cost calculated using GEOGRAPHY for accurate length.';


-- Add forward cost column, enforcing oneway restrictions
ALTER TABLE {schema_name}.routing_road_edge
ADD cost_length_forward NUMERIC
GENERATED ALWAYS AS (
CASE WHEN oneway IN (0, 1) OR oneway IS NULL
THEN cost_length
WHEN oneway = -1
THEN -1 * cost_length
END
)
STORED
;
RAISE NOTICE 'Created table {schema_name}.routing_road_edge';

-- Add reverse cost column, enforcing oneway restrictions
ALTER TABLE {schema_name}.routing_road_edge
ADD cost_length_reverse NUMERIC
GENERATED ALWAYS AS (
CASE WHEN oneway IN (0, -1) OR oneway IS NULL
THEN cost_length
WHEN oneway = 1
THEN -1 * cost_length
END
)
STORED
;
COMMENT ON COLUMN {schema_name}.routing_road_edge.cost_length IS 'Length based cost calculated using GEOGRAPHY for accurate length.';

COMMENT ON COLUMN {schema_name}.routing_road_edge.cost_length_forward IS 'Length based cost for forward travel with directed routing. Based on cost_length value.';
COMMENT ON COLUMN {schema_name}.routing_road_edge.cost_length_reverse IS 'Length based cost for reverse travel with directed routing. Based on cost_length value.';
Expand Down Expand Up @@ -392,7 +418,7 @@ LANGUAGE plpgsql
AS $$
BEGIN

CALL {schema_name}.pgrouting_version_check();
CALL {schema_name}.extension_version_check();

--Create edges table for input to routing_prepare_edge_network procedure
DROP TABLE IF EXISTS route_edge_input;
Expand Down Expand Up @@ -520,3 +546,53 @@ END $$;


COMMENT ON PROCEDURE {schema_name}.routing_prepare_water_network IS 'Creates the {schema_name}.routing_water_edge and {schema_name}.routing_water_vertex from the {schema_name}.water_line input data';




CREATE OR REPLACE FUNCTION {schema_name}.route_motor_travel_time(
route_vertex_id_start BIGINT, route_vertex_id_end BIGINT
)
RETURNS TABLE (segments BIGINT, vertex_ids BIGINT[], edge_ids BIGINT[]
, total_cost_seconds DOUBLE PRECISION, geom GEOMETRY
)
LANGUAGE plpgsql
ROWS 5
AS $function$

BEGIN

RETURN QUERY
WITH route_steps AS (
SELECT d.node AS vertex_id
, d.edge AS edge_id
, d.cost
, n.geom AS node_geom, e.geom AS edge_geom
FROM pgr_dijkstra(
'SELECT e.edge_id AS id
, e.vertex_id_source AS source
, e.vertex_id_target AS target
, e.cost_motor_forward_s AS cost
, e.cost_motor_reverse_s AS reverse_cost
, e.geom
FROM {schema_name}.routing_road_edge e
WHERE e.route_motor
',
route_vertex_id_start, route_vertex_id_end, directed := True
) d
INNER JOIN {schema_name}.routing_road_vertex n ON d.node = n.id
LEFT JOIN {schema_name}.routing_road_edge e ON d.edge = e.edge_id
)
SELECT COUNT(*) AS segments
, ARRAY_AGG(vertex_id) AS vertex_ids
, ARRAY_AGG(edge_id) AS edge_ids
, SUM(cost) AS total_cost_seconds
, ST_Collect(edge_geom) AS geom
FROM route_steps
;
END
$function$
;

COMMENT ON FUNCTION {schema_name}.route_motor_travel_time IS 'Computes best route using ideal travel time costs. Does not account for traffic.';

7 changes: 5 additions & 2 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
- [Data Files](./data-files.md)
- [Query examples](./query.md)
- [Routing](./routing.md)
- [pgRouting 3](./routing-3.md)
- [pgRouting 4](./routing-4.md)
- [Routing Roads](./routing-road.md)
- [Routing Water](./routing-water.md)
- [Routing Process](./routing-process.md)
- [Routing Roads: Legacy (pgRouting 3)](./routing-3.md)

- [Processing Time](./performance.md)

# Production Use
Expand Down
14 changes: 5 additions & 9 deletions docs/src/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,16 @@ passed along to osm2pgsql, with post-processing steps creating indexes,
constraints and comments.


## Versions Supported
## Minimum Versions Supported

Minimum versions supported:

* Postgres 12
* PostGIS 3.0

This project will attempt, but not guarantee, to support PostgreSQL 12 until it
reaches it EOL support.
This project will attempt, but not guarantee, to support each major PostgreSQL version
until it reaches it EOL support.

The Docker image is pinned to osm2pgsql's `master` branch. Users of the Docker image
naturally use the latest version of osm2pgsql at the time the Docker image was created.

This project runs entirely in Docker, optionally connecting to an external Postgres instance.
This project runs entirely in Docker, optionally connecting to an external
Postgres instance at runtime.
It should work on any typical OS able to run Docker.


Expand Down
22 changes: 14 additions & 8 deletions docs/src/routing-3.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
# Routing with pgRouting 3
# Routing Roads: Legacy (pgRouting 3)

If you are using a pgRouting 4.0 or later see [Routing with pgRouting 4](./routing-4.md).
## Plan your Upgrade!

New development in PgOSM Flex will focus support on pgRouting 4.0 support
per the Versions Supported section [in the About page](./readme.md).
[PgOSM Flex 1.1.2](https://github.com/rustprooflabs/pgosm-flex/releases/tag/1.1.2)
simplified and improved performance in the routing data preparation.
This page is a legacy documentation page for versions of pgRouting
older than 4.0. This process requires more manual effort to setup and
results in lower-quality routing networks compared to the
[latest procedures](./routing-road.md).

It is recommended to use pgRouting 4.0 or later, see [the latest Routing Roads](./routing-road.md)
documentation.

> ⚠️ This page will remain in the PgOSM documentation through at least 2026 to ensure
> ⚠️ This page is no longer maintained.
>
> This page will remain in the PgOSM documentation for the foreseeable future to ensure
> continuity for a transition to pgRouting 4.0.
> There will not be improvements made to these legacy instructions.


## Getting Started

Create the `pgRouting` extension.

Expand Down
Loading
Loading