Skip to content

Commit 444bfbd

Browse files
committed
Add admin_boundaries topic to explore theme
1 parent 6001b6a commit 444bfbd

File tree

4 files changed

+242
-0
lines changed

4 files changed

+242
-0
lines changed

Diff for: config/explore_admin_boundaries.lua

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
-- ---------------------------------------------------------------------------
2+
--
3+
-- Example config for exploring OSM data
4+
--
5+
-- Configuration for the osm2pgsql Themepark framework
6+
--
7+
-- ---------------------------------------------------------------------------
8+
9+
local themepark = require('themepark')
10+
11+
-- For debug mode set this or the environment variable THEMEPARK_DEBUG.
12+
themepark.debug = true
13+
14+
-- ---------------------------------------------------------------------------
15+
16+
themepark:set_option('debug', 'debug') -- Add JSONB column `debug` with debug infos in debug mode
17+
themepark:set_option('tags', 'all_tags') -- Add JSONB column `tags` with original OSM tags in debug mode
18+
19+
-- ---------------------------------------------------------------------------
20+
21+
themepark:add_topic('explore/admin_boundaries')
22+
23+
-- ---------------------------------------------------------------------------

Diff for: themes/explore/README.md

+11
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ user=USERNAME
5757
password=PASSWORD
5858
```
5959

60+
## Topic: Admin Boundaries
61+
62+
Everything related to administrative boundaries.
63+
64+
Pre-Filtering:
65+
66+
```
67+
osmium tags-filter -o admin_boundaries.osm.pbf DATA.osm.pbf \
68+
wr/boundary=administrative,disputed
69+
```
70+
6071
## Topic: Coastline
6172

6273
Explore coastline tagging. Everything tagged `natural=coastline`.

Diff for: themes/explore/qgis/admin_boundaries.qgz

35 KB
Binary file not shown.

Diff for: themes/explore/topics/admin_boundaries.lua

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
-- ---------------------------------------------------------------------------
2+
--
3+
-- Theme: explore
4+
-- Topic: admin_boundaries
5+
--
6+
-- ---------------------------------------------------------------------------
7+
8+
local themepark, theme, cfg = ...
9+
10+
themepark:add_table({
11+
name = 'admin_boundaries_ways',
12+
ids_type = 'way',
13+
geom = 'linestring',
14+
columns = themepark:columns({
15+
{ column = 'admin_level', type = 'int' },
16+
{ column = 'min_admin_level', type = 'int' },
17+
{ column = 'border_type', type = 'text' },
18+
{ column = 'maritime', type = 'bool' },
19+
{ column = 'coastline', type = 'bool' },
20+
{ column = 'disputed_on_way', type = 'text' },
21+
{ column = 'disputed', type = 'bool' },
22+
{ column = 'is_rel_member', type = 'bool' },
23+
}),
24+
})
25+
26+
27+
themepark:add_table({
28+
name = 'admin_boundaries_relations',
29+
ids_type = 'relation',
30+
geom = 'multilinestring',
31+
columns = themepark:columns({
32+
{ column = 'admin_level', type = 'int' },
33+
{ column = 'type', type = 'text' },
34+
{ column = 'border_type', type = 'text' },
35+
{ column = 'wikidata', type = 'text' },
36+
{ column = 'maritime', type = 'bool' },
37+
{ column = 'disputed', type = 'bool' },
38+
}),
39+
})
40+
41+
themepark:add_table({
42+
name = 'admin_boundaries_areas',
43+
ids_type = 'relation',
44+
geom = 'multipolygon',
45+
columns = themepark:columns({
46+
{ column = 'admin_level', type = 'int' },
47+
{ column = 'type', type = 'text' },
48+
{ column = 'border_type', type = 'text' },
49+
{ column = 'wikidata', type = 'text' },
50+
{ column = 'maritime', type = 'bool' },
51+
{ column = 'disputed', type = 'bool' },
52+
}),
53+
})
54+
55+
themepark:add_table({
56+
name = 'admin_boundaries_errors',
57+
ids_type = 'any',
58+
geom = 'multilinestring',
59+
columns = {
60+
{ column = 'errormsg', type = 'text', not_null = true },
61+
{ column = 'value', type = 'text' },
62+
},
63+
})
64+
65+
-- ---------------------------------------------------------------------------
66+
-- Storage of information from boundary relations for use by boundary ways
67+
-- (two-stage processing).
68+
69+
-- Minimum admin level of all relations that reference a way id
70+
local min_admin_level = {}
71+
72+
-- Minimum admin level of all relations tagged boundary=disputed that
73+
-- reference a way id
74+
local min_disputed_admin_level = {}
75+
76+
-- ---------------------------------------------------------------------------
77+
78+
-- Get numerical admin level from string
79+
local function get_admin_level(value)
80+
if not value or not string.match(value, '^[1-9][0-9]?$') then
81+
return nil
82+
end
83+
84+
return tonumber(value)
85+
end
86+
87+
local function add_error(msg, value, geom, tags)
88+
themepark:insert('admin_boundaries_errors', {
89+
errormsg = msg,
90+
value = value,
91+
geom = geom,
92+
}, tags)
93+
end
94+
95+
-- ---------------------------------------------------------------------------
96+
97+
themepark:add_proc('way', function(object, data)
98+
local t = object.tags
99+
100+
if osm2pgsql.stage == 1 and not (t.boundary == 'administrative' or t.boundary == 'disputed') then
101+
return
102+
end
103+
104+
local min_admin_level_from_rels = min_admin_level[object.id] or 1
105+
106+
-- Set disputed flag either from disputed or boundary tag on the way...
107+
local disputed = (t.disputed == 'yes' or t.boundary == 'disputed')
108+
109+
-- .. or from a parent relation with boundary=disputed
110+
if osm2pgsql.stage == 2
111+
and min_disputed_admin_level[object.id]
112+
and min_disputed_admin_level[object.id] <= min_admin_level_from_rels then
113+
disputed = true
114+
end
115+
116+
local a = {
117+
admin_level = t.admin_level,
118+
border_type = t.border_type,
119+
maritime = (t.maritime == 'yes'),
120+
coastline = (t.natural == 'coastline'),
121+
disputed_on_way = t.disputed,
122+
disputed = disputed,
123+
min_admin_level = min_admin_level_from_rels,
124+
is_rel_member = (osm2pgsql.stage == 2),
125+
geom = object:as_linestring(),
126+
}
127+
128+
themepark:insert('admin_boundaries_ways', a, t)
129+
end)
130+
131+
themepark:add_proc('select_relation_members', function(relation)
132+
if relation.tags.boundary == 'administrative' then
133+
return { ways = osm2pgsql.way_member_ids(relation) }
134+
end
135+
end)
136+
137+
themepark:add_proc('relation', function(object, data)
138+
local t = object.tags
139+
140+
if t.boundary ~= 'administrative' and t.boundary ~= 'disputed' then
141+
return
142+
end
143+
144+
local admin_level = t.admin_level
145+
local numeric_admin_level = get_admin_level(admin_level)
146+
147+
local geom_multilinestring = object:as_multilinestring()
148+
local geom_multipolygon = object:as_multipolygon()
149+
150+
if t.type ~= 'boundary' and t.type ~= 'multipolygon' then
151+
add_error('missing type tag', nil, geom_multilinestring, t)
152+
end
153+
154+
if t.boundary == 'administrative' and geom_multipolygon:is_null() then
155+
add_error('not a (multi)polygon', nil, geom_multilinestring, t)
156+
end
157+
158+
if numeric_admin_level == nil then
159+
add_error('invalid admin level (not set or not number)', t.admin_level, geom_multilinestring, t)
160+
elseif numeric_admin_level < 2 or numeric_admin_level > 11 then
161+
add_error('admin level not between 2 and 11', t.admin_level, geom_multilinestring, t)
162+
end
163+
164+
if t.maritime and t.maritime ~= 'yes' then
165+
add_error('invalid maritime tag value', t.maritime, geom_multilinestring, t)
166+
end
167+
168+
local a = {
169+
admin_level = numeric_admin_level,
170+
type = t.type,
171+
border_type = t.border_type,
172+
wikidata = t.wikidata,
173+
maritime = (t.maritime == 'yes'),
174+
disputed = (t.boundary == 'disputed'),
175+
}
176+
177+
if geom_multipolygon:is_null() then
178+
a.geom = geom_multilinestring
179+
themepark:insert('admin_boundaries_relations', a, t)
180+
else
181+
a.geom = geom_multipolygon
182+
themepark:insert('admin_boundaries_areas', a, t)
183+
end
184+
185+
if numeric_admin_level == nil then
186+
return
187+
end
188+
189+
if t.boundary == 'administrative' then
190+
for _, id in ipairs(osm2pgsql.way_member_ids(object)) do
191+
if not min_admin_level[id] or min_admin_level[id] > numeric_admin_level then
192+
min_admin_level[id] = numeric_admin_level
193+
end
194+
end
195+
elseif t.boundary == 'disputed' then
196+
-- Ways in relations tagged boundary=disputed are flagged as disputed
197+
-- if either the relation doesn't have an admin_level tag or the
198+
-- admin_level tag is <= the admin level the way got from the
199+
-- boundary=administrative relation(s).
200+
for _, id in ipairs(osm2pgsql.way_member_ids(object)) do
201+
if not min_disputed_admin_level[id] or min_disputed_admin_level[id] > numeric_admin_level then
202+
min_disputed_admin_level[id] = numeric_admin_level
203+
end
204+
end
205+
end
206+
end)
207+
208+
-- ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)