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",
|
"motorway_link",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local ONEWAY_YES = {"yes", "true", "1"}
|
||||||
|
local ONEWAY_REVERSE = {"reverse", "-1"}
|
||||||
|
|
||||||
local roads = osm2pgsql.define_way_table('road', {
|
local roads = osm2pgsql.define_way_table('road', {
|
||||||
{ column = 'zone', type = 'text', sql_type="zone_type" },
|
{ column = 'zone', type = 'text', sql_type="zone_type" },
|
||||||
|
{ column = 'directionality', type = 'int' },
|
||||||
{ column = 'name', type = 'text' },
|
{ column = 'name', type = 'text' },
|
||||||
{ column = 'geometry', type = 'linestring' },
|
{ column = 'geometry', type = 'linestring' },
|
||||||
{ column = 'tags', type = 'hstore' },
|
{ column = 'tags', type = 'hstore' },
|
||||||
|
@ -87,10 +91,18 @@ function osm2pgsql.process_way(object)
|
||||||
end
|
end
|
||||||
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({
|
roads:add_row({
|
||||||
geometry = { create = 'linear' },
|
geom = { create = 'linear' },
|
||||||
name = tags.name,
|
name = tags.name,
|
||||||
zone = zone,
|
zone = zone,
|
||||||
|
directionality = directionality,
|
||||||
tags = tags,
|
tags = tags,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 767b7166105b2446c3b4e0334222052114b0ebae
|
Subproject commit e67a2a98f7d8d53c687bc44d72774b5429b049c3
|
|
@ -1,61 +1,140 @@
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
import bright from './bright.json'
|
import bright from './bright.json'
|
||||||
|
import positron from './positron.json'
|
||||||
|
|
||||||
function getRoadsStyle(sourceUrl = "http://localhost:3002/data/v3.json") {
|
function addRoadsStyle(style, sourceUrl = "http://localhost:3002/data/v3.json") {
|
||||||
return {
|
style.sources.obs = {"type": "vector", "url": sourceUrl}
|
||||||
"version": 8,
|
|
||||||
"name": "OBS Roads",
|
// insert before "road_oneway" layer
|
||||||
"sources": {
|
let idx = style.layers.findIndex(l => l.id === 'road_oneway')
|
||||||
"obs": {"type": "vector", "url": sourceUrl}
|
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": [
|
"paint": {
|
||||||
{
|
"line-width": [
|
||||||
"id": "obs",
|
"interpolate",
|
||||||
"type": "line",
|
["exponential", 1.5],
|
||||||
"source": "obs",
|
["zoom"],
|
||||||
"source-layer": "obs_roads",
|
12,
|
||||||
"layout": {"line-cap": "round", "line-join": "round"},
|
1,
|
||||||
"paint": {
|
17,
|
||||||
"line-width": {"stops": [[14, 2], [17, 8]]},
|
[
|
||||||
"line-color": [
|
"case",
|
||||||
"interpolate-hcl",
|
[
|
||||||
["linear"],
|
"!",
|
||||||
["get", "distance_overtaker_mean"],
|
[
|
||||||
1,
|
"to-boolean",
|
||||||
"rgba(255, 0, 0, 1)",
|
[
|
||||||
1.3,
|
"get",
|
||||||
"rgba(255, 200, 0, 1)",
|
"distance_overtaker_mean"
|
||||||
1.5,
|
]
|
||||||
"rgba(67, 200, 0, 1)",
|
]
|
||||||
1.7,
|
|
||||||
"rgba(67, 150, 0, 1)"
|
|
||||||
],
|
],
|
||||||
"line-opacity": 1,
|
2,
|
||||||
"line-offset": {"stops": [[14, 1], [17, 7]]}
|
6
|
||||||
}
|
]
|
||||||
}
|
],
|
||||||
],
|
"line-color": [
|
||||||
"id": "obs-roads"
|
"case",
|
||||||
}
|
[
|
||||||
}
|
"!",
|
||||||
|
[
|
||||||
function mergeStyles(baseStyle, ...extensions) {
|
"to-boolean",
|
||||||
const style = _.cloneDeep(baseStyle)
|
[
|
||||||
for (const extension of extensions) {
|
"get",
|
||||||
for (const key of Object.keys(extension)) {
|
"distance_overtaker_mean"
|
||||||
if (['sources', 'layers', 'id', 'name', 'version'].includes(key)) {
|
]
|
||||||
continue
|
]
|
||||||
}
|
],
|
||||||
|
"#ABC",
|
||||||
throw new Error(`cannot use style ${extension.id ?? extension.name} as extension style, it defines ${key}`)
|
[
|
||||||
}
|
"interpolate-hcl",
|
||||||
style.sources = {...style.sources, ...extension.sources}
|
["linear"],
|
||||||
style.layers = [...style.layers, ...extension.layers]
|
[
|
||||||
}
|
"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
|
return style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const basemap = bright
|
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)
|
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
|
SELECT
|
||||||
road.way_id::bigint as way_id,
|
road.way_id::bigint as way_id,
|
||||||
road.geometry as geometry,
|
road.geometry as geometry,
|
||||||
avg(distance_overtaker) as distance_overtaker_mean,
|
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
|
FROM road
|
||||||
JOIN overtaking_event on road.way_id = overtaking_event.way_id
|
FULL OUTER JOIN (VALUES (1, TRUE), (-1, FALSE)) AS r(dir, rev) ON (road.directionality = 0 or road.directionality = r.dir)
|
||||||
JOIN (VALUES (1, TRUE), (-1, FALSE)) AS r(dir, rev) ON overtaking_event.direction_reversed = r.rev
|
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
|
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;
|
$$ LANGUAGE SQL IMMUTABLE;
|
||||||
|
|
|
@ -4,12 +4,24 @@ layer:
|
||||||
Road segment statistics for OBS events
|
Road segment statistics for OBS events
|
||||||
buffer_size: 4
|
buffer_size: 4
|
||||||
fields:
|
fields:
|
||||||
|
distance_overtaker_min: |
|
||||||
|
Overtaker minimum distance in meters.
|
||||||
|
distance_overtaker_max: |
|
||||||
|
Overtaker maximum distance in meters.
|
||||||
distance_overtaker_mean: |
|
distance_overtaker_mean: |
|
||||||
Overtaker mean distance in meters.
|
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: |
|
direction: |
|
||||||
Contains -1 for events while going along the way backwards, 1 for
|
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,
|
forwards. Each road is emitted twice, if it has data for both directions,
|
||||||
even if it is oneway.
|
even if it is oneway.
|
||||||
|
offset_direction: |
|
||||||
|
Factor for offset to shift the line to the driving side. One of -1, 0, 1.
|
||||||
defaults:
|
defaults:
|
||||||
srs: EPSG:3785
|
srs: EPSG:3785
|
||||||
datasource:
|
datasource:
|
||||||
|
@ -17,7 +29,21 @@ layer:
|
||||||
geometry_field: geometry
|
geometry_field: geometry
|
||||||
key_field: way_id
|
key_field: way_id
|
||||||
key_field_as_attribute: no
|
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:
|
schema:
|
||||||
- ./layer.sql
|
- ./layer.sql
|
||||||
|
|
Loading…
Reference in a new issue