Skip to content

Commit 6642d04

Browse files
committed
Add geometry functions in Lua / new insert syntax
This is the future of geometry processing in Lua. Geometries are not something happening magically behind the scenes as before, but they are (mostly) normal objects that can be manipulated in Lua. There are several functions to create those geometry objects from the OSM objects: * as_point() (for nodes) * as_linestring() (for ways) * as_polygon() (for ways) * as_multilinestring() (for relations) * as_multipolygon() (for relations) * as_geometrycollection() (for relations) Geometries can be manipulated with the following functions (all based on their equivalents in PostGIS): * area() (for polygons) * centroid() (for polygons) * geometries() for iterating over (multi)geometries * geometry_n() return the nth geometry from a (multi)geometry. * geometry_type() returns type as string ('POINT', 'LINESTRING', ...) * is_null() returns true if this is a null geometry * num_geometries() returns the number of geometries (0 for null geom, 1 for point/linestring/polygon, n for multi* and geometrycollection geoms). This can also be accessed as #geom (the usual Lua length operator) * segmentize(max_segment_length) (for linestrings) * simplify(tolerance) (for linestrings) * srid() * transform(target_srid) Some of these functions are using boost::geometry for their implementation. More functions can be implemented in the future as needed. There is a new syntax for inserting rows into a table. Instead of "add_row" the "insert" function is used. "add_row" is still available and it works as before. But the new geometry types only work with the "insert" command. The "insert" function also allows multiple geometry columns which wasn't possible with "add_row". See the file flex-config/new-insert-syntax.lua for an example that shows how to use the new capabilities.
1 parent f9cdadd commit 6642d04

19 files changed

+1248
-14
lines changed

flex-config/new-insert-syntax.lua

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
-- This config example file is released into the Public Domain.
2+
3+
-- This is Lua config showing the handling of custom geometries.
4+
--
5+
-- This is "work in progress", changes are possible.
6+
--
7+
-- Note that the insert() function is used instead of the old add_row()!
8+
9+
-- The following magic can be used to wrap the internal "insert" function
10+
local orig_insert = osm2pgsql.Table.insert
11+
local function my_insert(table, data)
12+
local json = require 'json'
13+
inserted, message, column, object = orig_insert(table, data)
14+
if not inserted then
15+
for key, value in pairs(data) do
16+
if type(value) == 'userdata' then
17+
data[key] = tostring(value)
18+
end
19+
end
20+
print("insert() failed: " .. message .. " column='" .. column .. "' object='" .. json.encode(object) .. "' data='" .. json.encode(data) .. "'")
21+
end
22+
end
23+
osm2pgsql.Table.insert = my_insert
24+
25+
26+
local tables = {}
27+
28+
-- This table will get all nodes and areas with an "addr:street" tag, for
29+
-- areas we'll calculate the centroid.
30+
tables.addr = osm2pgsql.define_table({
31+
name = 'addr',
32+
ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
33+
columns = {
34+
{ column = 'tags', type = 'jsonb' },
35+
{ column = 'geom', type = 'point', projection = 4326 },
36+
}
37+
})
38+
39+
tables.ways = osm2pgsql.define_way_table('ways', {
40+
{ column = 'tags', type = 'jsonb' },
41+
{ column = 'geom', type = 'linestring', projection = 4326 },
42+
{ column = 'poly', type = 'polygon', projection = 4326 },
43+
{ column = 'geom3857', type = 'linestring', projection = 3857 },
44+
{ column = 'geomautoproj', type = 'linestring', projection = 3857 },
45+
})
46+
47+
tables.major_roads = osm2pgsql.define_way_table('major_roads', {
48+
{ column = 'tags', type = 'jsonb' },
49+
{ column = 'geom', type = 'linestring' },
50+
{ column = 'sgeom', type = 'linestring' }
51+
})
52+
53+
tables.polygons = osm2pgsql.define_area_table('polygons', {
54+
{ column = 'tags', type = 'jsonb' },
55+
{ column = 'geom', type = 'geometry', not_null = true },
56+
{ column = 'area4326', type = 'real' },
57+
{ column = 'area3857', type = 'real' }
58+
})
59+
60+
tables.routes = osm2pgsql.define_relation_table('routes', {
61+
{ column = 'tags', type = 'jsonb' },
62+
{ column = 'geom', type = 'multilinestring', projection = 4326 },
63+
})
64+
65+
tables.route_parts = osm2pgsql.define_relation_table('route_parts', {
66+
{ column = 'tags', type = 'jsonb' },
67+
{ column = 'geom', type = 'linestring', projection = 4326 },
68+
})
69+
70+
-- Helper function to remove some of the tags we usually are not interested in.
71+
-- Returns true if there are no tags left.
72+
function clean_tags(tags)
73+
tags.odbl = nil
74+
tags.created_by = nil
75+
tags.source = nil
76+
tags['source:ref'] = nil
77+
78+
return next(tags) == nil
79+
end
80+
81+
-- Helper function that looks at the tags and decides if this is possibly
82+
-- an area.
83+
function has_area_tags(tags)
84+
if tags.area == 'yes' then
85+
return true
86+
end
87+
if tags.area == 'no' then
88+
return false
89+
end
90+
91+
return tags.aeroway
92+
or tags.amenity
93+
or tags.building
94+
or tags.harbour
95+
or tags.historic
96+
or tags.landuse
97+
or tags.leisure
98+
or tags.man_made
99+
or tags.military
100+
or tags.natural
101+
or tags.office
102+
or tags.place
103+
or tags.power
104+
or tags.public_transport
105+
or tags.shop
106+
or tags.sport
107+
or tags.tourism
108+
or tags.water
109+
or tags.waterway
110+
or tags.wetland
111+
or tags['abandoned:aeroway']
112+
or tags['abandoned:amenity']
113+
or tags['abandoned:building']
114+
or tags['abandoned:landuse']
115+
or tags['abandoned:power']
116+
or tags['area:highway']
117+
end
118+
119+
function osm2pgsql.process_node(object)
120+
if clean_tags(object.tags) then
121+
return
122+
end
123+
124+
if object.tags['addr:street'] then
125+
tables.addr:insert({
126+
tags = object.tags,
127+
geom = object:as_point()
128+
})
129+
end
130+
end
131+
132+
function osm2pgsql.process_way(object)
133+
if clean_tags(object.tags) then
134+
return
135+
end
136+
137+
if object.is_closed and object.tags['addr:street'] then
138+
tables.addr:insert({
139+
tags = object.tags,
140+
geom = object:as_polygon():centroid()
141+
})
142+
end
143+
144+
if object.tags.highway == 'motorway' or
145+
object.tags.highway == 'trunk' or
146+
object.tags.highway == 'primary' then
147+
tables.major_roads:insert({
148+
tags = object.tags,
149+
geom = object:as_linestring(),
150+
sgeom = object:as_linestring():simplify(100),
151+
})
152+
end
153+
154+
-- A closed way that also has the right tags for an area is a polygon.
155+
if object.is_closed and has_area_tags(object.tags) then
156+
local g = object:as_polygon()
157+
local a = g:area()
158+
if a < 0.0000001 then
159+
tables.polygons:insert({
160+
tags = object.tags,
161+
geom = g,
162+
area4326 = a,
163+
area3857 = g:transform(3857):area()
164+
})
165+
end
166+
else
167+
tables.ways:insert({
168+
tags = object.tags,
169+
geom = object:as_linestring(),
170+
poly = object:as_polygon(),
171+
geom3857 = object:as_linestring():transform(3857), -- project geometry into target srid 3857
172+
geomautoproj = object:as_linestring() -- automatically projected into projection of target column
173+
})
174+
end
175+
end
176+
177+
function osm2pgsql.process_relation(object)
178+
if clean_tags(object.tags) then
179+
return
180+
end
181+
182+
local relation_type = object:grab_tag('type')
183+
184+
if relation_type == 'multipolygon' then
185+
local g = object:as_multipolygon()
186+
local a = g:area()
187+
if a < 0.0000001 then
188+
tables.polygons:insert({
189+
tags = object.tags,
190+
geom = g,
191+
area4326 = a,
192+
area3857 = g:transform(3857):area()
193+
})
194+
end
195+
return
196+
end
197+
198+
if relation_type == 'route' then
199+
local route_geom = object:as_multilinestring()
200+
if not route_geom:is_null() then
201+
tables.routes:insert({
202+
tags = object.tags,
203+
geom = route_geom
204+
})
205+
for line in route_geom:geometries() do
206+
tables.route_parts:insert({
207+
tags = object.tags,
208+
geom = line
209+
})
210+
end
211+
end
212+
end
213+
end
214+

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ if (WITH_LUA)
4848
target_sources(osm2pgsql_lib PRIVATE
4949
flex-table.cpp
5050
flex-table-column.cpp
51+
flex-lua-geom.cpp
5152
geom-transform.cpp
5253
lua-utils.cpp
5354
output-flex.cpp

0 commit comments

Comments
 (0)