Skip to content

Commit 65d0d27

Browse files
authored
Merge pull request #1743 from joto/geom-more-details
Some more work in the geometries
2 parents 384739d + 3eaf81b commit 65d0d27

File tree

9 files changed

+188
-29
lines changed

9 files changed

+188
-29
lines changed

src/flex-lua-geom.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,20 @@ static int geom_is_null(lua_State *lua_state)
119119
return 1;
120120
}
121121

122+
static int geom_line_merge(lua_State *lua_state)
123+
{
124+
auto const *const input_geometry = unpack_geometry(lua_state);
125+
126+
try {
127+
auto *geom = create_lua_geometry_object(lua_state);
128+
geom::line_merge(geom, *input_geometry);
129+
} catch (...) {
130+
return luaL_error(lua_state, "Unknown error in 'line_merge()'.\n");
131+
}
132+
133+
return 1;
134+
}
135+
122136
static int geom_num_geometries(lua_State *lua_state)
123137
{
124138
auto const *const input_geometry = unpack_geometry(lua_state);
@@ -215,6 +229,7 @@ void init_geometry_class(lua_State *lua_state)
215229
luaX_add_table_func(lua_state, "geometry_n", geom_geometry_n);
216230
luaX_add_table_func(lua_state, "geometry_type", geom_geometry_type);
217231
luaX_add_table_func(lua_state, "is_null", geom_is_null);
232+
luaX_add_table_func(lua_state, "line_merge", geom_line_merge);
218233
luaX_add_table_func(lua_state, "num_geometries", geom_num_geometries);
219234
luaX_add_table_func(lua_state, "segmentize", geom_segmentize);
220235
luaX_add_table_func(lua_state, "simplify", geom_simplify);

src/geom-from-osm.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,27 +96,37 @@ geometry_t create_polygon(osmium::Way const &way)
9696
}
9797

9898
void create_multilinestring(geometry_t *geom,
99-
osmium::memory::Buffer const &ways)
99+
osmium::memory::Buffer const &ways_buffer,
100+
bool force_multi)
100101
{
101-
auto &mls = geom->set<multilinestring_t>();
102-
103-
for (auto const &way : ways.select<osmium::Way>()) {
104-
linestring_t line;
102+
auto ways = ways_buffer.select<osmium::Way>();
103+
if (ways.size() == 1 && !force_multi) {
104+
auto &line = geom->set<linestring_t>();
105+
auto &way = *ways.begin();
105106
fill_point_list(&line, way.nodes());
106-
if (line.size() >= 2U) {
107-
mls.add_geometry(std::move(line));
107+
if (line.size() < 2U) {
108+
geom->reset();
109+
}
110+
} else {
111+
auto &multiline = geom->set<multilinestring_t>();
112+
for (auto const &way : ways) {
113+
linestring_t line;
114+
fill_point_list(&line, way.nodes());
115+
if (line.size() >= 2U) {
116+
multiline.add_geometry(std::move(line));
117+
}
118+
}
119+
if (multiline.num_geometries() == 0) {
120+
geom->reset();
108121
}
109-
}
110-
111-
if (mls.num_geometries() == 0) {
112-
geom->reset();
113122
}
114123
}
115124

116-
geometry_t create_multilinestring(osmium::memory::Buffer const &ways)
125+
geometry_t create_multilinestring(osmium::memory::Buffer const &ways,
126+
bool force_multi)
117127
{
118128
geometry_t geom{};
119-
create_multilinestring(&geom, ways);
129+
create_multilinestring(&geom, ways, force_multi);
120130
return geom;
121131
}
122132

src/geom-from-osm.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ void create_polygon(geometry_t *geom, osmium::Way const &way);
101101
* \param ways Buffer containing all the input ways.
102102
*/
103103
void create_multilinestring(geometry_t *geom,
104-
osmium::memory::Buffer const &ways);
104+
osmium::memory::Buffer const &ways,
105+
bool force_multi = true);
105106

106107
/**
107108
* Create a multilinestring geometry from a bunch of ways (usually this
@@ -115,7 +116,8 @@ void create_multilinestring(geometry_t *geom,
115116
* \returns The created geometry.
116117
*/
117118
[[nodiscard]] geometry_t
118-
create_multilinestring(osmium::memory::Buffer const &ways);
119+
create_multilinestring(osmium::memory::Buffer const &ways,
120+
bool force_multi = true);
119121

120122
/**
121123
* Create a (multi)polygon geometry from a relation and member ways.

src/geom-functions.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,11 @@ static void add_nodes_to_linestring(linestring_t *linestring, ITERATOR it,
448448

449449
void line_merge(geometry_t *output, geometry_t const &input)
450450
{
451+
if (input.is_linestring()) {
452+
*output = input;
453+
return;
454+
}
455+
451456
if (!input.is_multilinestring()) {
452457
output->reset();
453458
return;

src/geom-functions.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,19 +159,23 @@ double area(geometry_t const &geom);
159159
std::vector<geometry_t> split_multi(geometry_t &&geom, bool split_multi = true);
160160

161161
/**
162-
* Merge lines in a multilinestring end-to-end as far as possible. Always
163-
* returns a multilinestring unless there is an error or the input geometry
164-
* is a nullgeom_t, in which case nullgeom_t is returned.
162+
* Merge lines in a multilinestring end-to-end as far as possible.
163+
*
164+
* * Returns a multilinestring if the input is a multilinestring.
165+
* * Returns a copy of the input if it is a linestring.
166+
* * Returns nullgeom_t otherwise.
165167
*
166168
* \param output Pointer to output geometry.
167169
* \param input Input geometry.
168170
*/
169171
void line_merge(geometry_t *output, geometry_t const &input);
170172

171173
/**
172-
* Merge lines in a multilinestring end-to-end as far as possible. Always
173-
* returns a multilinestring unless there is an error or the input geometry
174-
* is a nullgeom_t, in which case nullgeom_t is returned.
174+
* Merge lines in a multilinestring end-to-end as far as possible.
175+
*
176+
* * Returns a multilinestring if the input is a multilinestring.
177+
* * Returns a copy of the input if it is a linestring.
178+
* * Returns nullgeom_t otherwise.
175179
*
176180
* \param input Input geometry.
177181
* \returns Result multilinestring.

src/output-flex.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -885,23 +885,43 @@ int output_flex_t::app_as_polygon()
885885

886886
int output_flex_t::app_as_multilinestring()
887887
{
888-
check_context_and_state("as_multilinestring", "process_relation() function",
889-
m_calling_context !=
890-
calling_context::process_relation);
888+
check_context_and_state(
889+
"as_multilinestring", "process_way/relation() functions",
890+
m_calling_context != calling_context::process_way &&
891+
m_calling_context != calling_context::process_relation);
892+
893+
if (m_calling_context == calling_context::process_way) {
894+
m_way_cache.add_nodes(middle());
895+
896+
auto *geom = create_lua_geometry_object(lua_state());
897+
geom::create_linestring(geom, m_way_cache.get());
898+
return 1;
899+
}
891900

892901
m_relation_cache.add_members(middle());
893902

894903
auto *geom = create_lua_geometry_object(lua_state());
895-
geom::create_multilinestring(geom, m_relation_cache.members_buffer());
904+
geom::create_multilinestring(geom, m_relation_cache.members_buffer(),
905+
false);
896906

897907
return 1;
898908
}
899909

900910
int output_flex_t::app_as_multipolygon()
901911
{
902-
check_context_and_state("as_multipolygon", "process_relation() function",
903-
m_calling_context !=
904-
calling_context::process_relation);
912+
check_context_and_state(
913+
"as_multipolygon", "process_way/relation() functions",
914+
m_calling_context != calling_context::process_way &&
915+
m_calling_context != calling_context::process_relation);
916+
917+
if (m_calling_context == calling_context::process_way) {
918+
m_way_cache.add_nodes(middle());
919+
920+
auto *geom = create_lua_geometry_object(lua_state());
921+
geom::create_polygon(geom, m_way_cache.get());
922+
923+
return 1;
924+
}
905925

906926
m_relation_cache.add_members(middle());
907927

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
Feature: Creating (multi)linestring features from way and relations
2+
3+
Scenario:
4+
Given the grid
5+
| 1 | 2 | |
6+
| 4 | | 3 |
7+
| | 5 | 6 |
8+
And the OSM data
9+
"""
10+
w20 Thighway=motorway Nn1,n2,n3
11+
w21 Thighway=motorway Nn4,n5,n6
12+
r30 Ttype=route,route=road Mw20@
13+
r31 Ttype=route,route=road Mw20@,w21@
14+
"""
15+
And the lua style
16+
"""
17+
local lines = osm2pgsql.define_table({
18+
name = 'osm2pgsql_test_lines',
19+
ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
20+
columns = {
21+
{ column = 'geom', type = 'geometry', projection = 4326 },
22+
}
23+
})
24+
25+
function osm2pgsql.process_way(object)
26+
if object.tags.highway == 'motorway' then
27+
lines:insert({
28+
geom = object:as_multilinestring()
29+
})
30+
end
31+
end
32+
33+
function osm2pgsql.process_relation(object)
34+
if object.tags.type == 'route' then
35+
lines:insert({
36+
geom = object:as_multilinestring()
37+
})
38+
end
39+
end
40+
"""
41+
When running osm2pgsql flex
42+
43+
Then table osm2pgsql_test_lines contains exactly
44+
| osm_type | osm_id | ST_GeometryType(geom) | ST_AsText(ST_GeometryN(geom, 1)) | ST_AsText(ST_GeometryN(geom, 2)) |
45+
| W | 20 | ST_LineString | 1, 2, 3 | NULL |
46+
| W | 21 | ST_LineString | 4, 5, 6 | NULL |
47+
| R | 30 | ST_LineString | 1, 2, 3 | NULL |
48+
| R | 31 | ST_MultiLineString | 1, 2, 3 | 4, 5, 6 |
49+
50+
Scenario:
51+
Given the grid
52+
| 1 | 2 | | |
53+
| | | 3 | 4 |
54+
And the OSM data
55+
"""
56+
w20 Thighway=motorway Nn1,n2
57+
w21 Thighway=motorway Nn2,n3
58+
w22 Thighway=motorway Nn3,n4
59+
r30 Ttype=route,route=road Mw20@,w21@
60+
r31 Ttype=route,route=road Mw20@,w22@
61+
"""
62+
And the lua style
63+
"""
64+
local roads = osm2pgsql.define_relation_table('osm2pgsql_test_roads', {
65+
{ column = 'geom', type = 'geometry', projection = 4326 },
66+
{ column = 'merged', type = 'geometry', projection = 4326 }
67+
})
68+
69+
function osm2pgsql.process_relation(object)
70+
local g = object:as_multilinestring()
71+
roads:insert({
72+
geom = g,
73+
merged = g:line_merge()
74+
})
75+
end
76+
"""
77+
When running osm2pgsql flex
78+
79+
Then table osm2pgsql_test_roads contains exactly
80+
| relation_id | ST_GeometryType(geom) | ST_GeometryType(merged) | ST_AsText(ST_GeometryN(merged, 1)) | ST_AsText(ST_GeometryN(merged, 2)) |
81+
| 30 | ST_MultiLineString | ST_MultiLineString | 1, 2, 3 | NULL |
82+
| 31 | ST_MultiLineString | ST_MultiLineString | 1, 2 | 3, 4 |
83+

tests/bdd/flex/geometry-processing.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Feature: Tests for Lua geometry processing functions
7474
geomsimple = object:as_linestring():simplify(0.1)
7575
})
7676
77-
local g = object:as_polygon()
77+
local g = object:as_multipolygon()
7878
tables.polygons:insert({
7979
name = object.tags.name,
8080
geom = g,

tests/test-geom-multilinestrings.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ TEST_CASE("create_multilinestring with single line", "[NoDB]")
3636
REQUIRE(ml[0] == expected);
3737
}
3838

39+
TEST_CASE("create_multilinestring with single line and no force_multi",
40+
"[NoDB]")
41+
{
42+
geom::linestring_t const expected{{1, 1}, {2, 1}};
43+
44+
test_buffer_t buffer;
45+
buffer.add_way("w20 Nn10x1y1,n11x2y1");
46+
47+
auto const geom =
48+
geom::line_merge(geom::create_multilinestring(buffer.buffer(), false));
49+
50+
REQUIRE(geom.is_linestring());
51+
REQUIRE(geometry_type(geom) == "LINESTRING");
52+
REQUIRE(num_geometries(geom) == 1);
53+
REQUIRE(area(geom) == Approx(0.0));
54+
auto const &l = geom.get<geom::linestring_t>();
55+
REQUIRE(l.num_geometries() == 1);
56+
REQUIRE(l == expected);
57+
}
58+
3959
TEST_CASE("create_multilinestring with single line forming a ring", "[NoDB]")
4060
{
4161
geom::linestring_t const expected{{1, 1}, {2, 1}, {2, 2}, {1, 1}};

0 commit comments

Comments
 (0)