Correct directional road rendering, and include all roads with null data in obs layer
This commit is contained in:
parent
f2fa806cab
commit
e3ec5ce1f9
|
@ -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
|
|
@ -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)
|
||||
|
|
1047
frontend/src/mapstyles/positron.json
Normal file
1047
frontend/src/mapstyles/positron.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue