Correct directional road rendering, and include all roads with null data in obs layer

This commit is contained in:
Paul Bienkowski 2021-10-31 20:50:09 +01:00
parent f2fa806cab
commit e3ec5ce1f9
6 changed files with 1240 additions and 58 deletions

View file

@ -50,8 +50,12 @@ local MOTORWAY_TYPES = {
"motorway_link",
}
local ONEWAY_YES = {"yes", "true", "1"}
local ONEWAY_REVERSE = {"reverse", "-1"}
local roads = osm2pgsql.define_way_table('road', {
{ column = 'zone', type = 'text', sql_type="zone_type" },
{ column = 'directionality', type = 'int' },
{ column = 'name', type = 'text' },
{ column = 'geometry', type = 'linestring' },
{ column = 'tags', type = 'hstore' },
@ -87,10 +91,18 @@ function osm2pgsql.process_way(object)
end
end
local directionality = 0
if contains(ONEWAY_YES, tags["oneway"]) then
directionality = 1
elseif contains(ONEWAY_REVERSE, tags["oneway"]) then
directionality = -1
end
roads:add_row({
geometry = { create = 'linear' },
geom = { create = 'linear' },
name = tags.name,
zone = zone,
directionality = directionality,
tags = tags,
})
end

@ -1 +1 @@
Subproject commit 767b7166105b2446c3b4e0334222052114b0ebae
Subproject commit e67a2a98f7d8d53c687bc44d72774b5429b049c3

View file

@ -1,61 +1,140 @@
import _ from 'lodash'
import bright from './bright.json'
import positron from './positron.json'
function getRoadsStyle(sourceUrl = "http://localhost:3002/data/v3.json") {
return {
"version": 8,
"name": "OBS Roads",
"sources": {
"obs": {"type": "vector", "url": sourceUrl}
function addRoadsStyle(style, sourceUrl = "http://localhost:3002/data/v3.json") {
style.sources.obs = {"type": "vector", "url": sourceUrl}
// insert before "road_oneway" layer
let idx = style.layers.findIndex(l => l.id === 'road_oneway')
if (idx === -1) {
idx = style.layers.length
}
style.layers.splice(idx, 0, {
"id": "obs",
"type": "line",
"source": "obs",
"source-layer": "obs_roads",
"layout": {
"line-cap": "round",
"line-join": "round"
},
"layers": [
{
"id": "obs",
"type": "line",
"source": "obs",
"source-layer": "obs_roads",
"layout": {"line-cap": "round", "line-join": "round"},
"paint": {
"line-width": {"stops": [[14, 2], [17, 8]]},
"line-color": [
"interpolate-hcl",
["linear"],
["get", "distance_overtaker_mean"],
1,
"rgba(255, 0, 0, 1)",
1.3,
"rgba(255, 200, 0, 1)",
1.5,
"rgba(67, 200, 0, 1)",
1.7,
"rgba(67, 150, 0, 1)"
"paint": {
"line-width": [
"interpolate",
["exponential", 1.5],
["zoom"],
12,
1,
17,
[
"case",
[
"!",
[
"to-boolean",
[
"get",
"distance_overtaker_mean"
]
]
],
"line-opacity": 1,
"line-offset": {"stops": [[14, 1], [17, 7]]}
}
}
],
"id": "obs-roads"
}
}
function mergeStyles(baseStyle, ...extensions) {
const style = _.cloneDeep(baseStyle)
for (const extension of extensions) {
for (const key of Object.keys(extension)) {
if (['sources', 'layers', 'id', 'name', 'version'].includes(key)) {
continue
}
throw new Error(`cannot use style ${extension.id ?? extension.name} as extension style, it defines ${key}`)
}
style.sources = {...style.sources, ...extension.sources}
style.layers = [...style.layers, ...extension.layers]
}
2,
6
]
],
"line-color": [
"case",
[
"!",
[
"to-boolean",
[
"get",
"distance_overtaker_mean"
]
]
],
"#ABC",
[
"interpolate-hcl",
["linear"],
[
"get",
"distance_overtaker_mean"
],
1,
"rgba(255, 0, 0, 1)",
1.3,
"rgba(255, 200, 0, 1)",
1.5,
"rgba(67, 200, 0, 1)",
1.7,
"rgba(67, 150, 0, 1)"
]
],
"line-opacity": [
"interpolate",
["linear"],
["zoom"],
12,
0,
13,
[
"case",
[
"!",
[
"to-boolean",
[
"get",
"distance_overtaker_mean"
]
]
],
0,
1
],
14,
[
"case",
[
"!",
[
"to-boolean",
[
"get",
"distance_overtaker_mean"
]
]
],
0,
1
],
15,
1
],
"line-offset": [
"interpolate",
["exponential", 1.5],
["zoom"],
12,
["get", "offset_direction"],
19,
[
"*",
["get", "offset_direction"],
8
]
]
},
"minzoom": 12
})
return style
}
export const basemap = bright
export const obsRoads = (sourceUrl) => mergeStyles(basemap, getRoadsStyle(sourceUrl))
export const obsRoads = (sourceUrl) => addRoadsStyle(_.cloneDeep(positron), sourceUrl)

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,33 @@
CREATE OR REPLACE FUNCTION layer_obs_roads(bbox geometry, zoom_level int)
RETURNS TABLE(way_id bigint, geometry geometry, distance_overtaker_mean float, direction int) AS $$
RETURNS TABLE(
way_id bigint,
geometry geometry,
distance_overtaker_mean float,
distance_overtaker_min float,
distance_overtaker_max float,
distance_overtaker_median float,
distance_overtaker_array float[],
overtaking_event_count int,
direction int,
offset_direction int
) AS $$
SELECT
road.way_id::bigint as way_id,
road.geometry as geometry,
avg(distance_overtaker) as distance_overtaker_mean,
r.dir as direction
min(distance_overtaker) as distance_overtaker_min,
max(distance_overtaker) as distance_overtaker_max,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY distance_overtaker) as distance_overtaker_median,
array_agg(distance_overtaker) as distance_overtaker_array,
count(overtaking_event.id)::int as distance_overtaker_count,
r.dir as direction,
case when road.directionality = 0 then r.dir else 0 end as offset_direction
FROM road
JOIN overtaking_event on road.way_id = overtaking_event.way_id
JOIN (VALUES (1, TRUE), (-1, FALSE)) AS r(dir, rev) ON overtaking_event.direction_reversed = r.rev
FULL OUTER JOIN (VALUES (1, TRUE), (-1, FALSE)) AS r(dir, rev) ON (road.directionality = 0 or road.directionality = r.dir)
FULL OUTER JOIN overtaking_event ON (road.way_id = overtaking_event.way_id and overtaking_event.direction_reversed = r.rev)
-- WHERE road.name = 'Schlierbergstraße'
WHERE road.geometry && bbox
GROUP BY road.way_id, road.geometry, direction;
GROUP BY road.way_id, road.geometry, road.directionality, direction;
$$ LANGUAGE SQL IMMUTABLE;

View file

@ -4,12 +4,24 @@ layer:
Road segment statistics for OBS events
buffer_size: 4
fields:
distance_overtaker_min: |
Overtaker minimum distance in meters.
distance_overtaker_max: |
Overtaker maximum distance in meters.
distance_overtaker_mean: |
Overtaker mean distance in meters.
distance_overtaker_median: |
Overtaker median distance in meters.
distance_overtaker_array: |
All overtaker distance values in meters.
overtaking_event_count: |
Number of overtaking events.
direction: |
Contains -1 for events while going along the way backwards, 1 for
forwards. Each road is emitted twice, if it has data for both directions,
even if it is oneway.
offset_direction: |
Factor for offset to shift the line to the driving side. One of -1, 0, 1.
defaults:
srs: EPSG:3785
datasource:
@ -17,7 +29,21 @@ layer:
geometry_field: geometry
key_field: way_id
key_field_as_attribute: no
query: (SELECT way_id, geometry, distance_overtaker_mean, direction FROM layer_obs_roads(!bbox!, z(!scale_denominator!))) AS t
query: |
(
SELECT
way_id,
geometry,
distance_overtaker_mean,
distance_overtaker_min,
distance_overtaker_max,
distance_overtaker_median,
distance_overtaker_array,
overtaking_event_count,
direction,
offset_direction
FROM layer_obs_roads(!bbox!, z(!scale_denominator!))
) AS t
schema:
- ./layer.sql