Skip to content

Commit 82e2596

Browse files
committed
Allow detecting duplicate nodes in ways when creating geometry
When linestrings or polygons are created from ways, duplicate nodes are removed automatically. Generally this is what you want. But sometimes it makes sense to be able to detect this situation, for instance when creating some debug output. The information is available on the C++ side anyway, this change exposes this information in the Lua code as a second return parameter of the as_linestring and as_polygon functions which can be ignored during normal use.
1 parent 8b7d01a commit 82e2596

4 files changed

Lines changed: 68 additions & 10 deletions

File tree

src/geom-from-osm.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,15 @@ void fill_polygon(polygon_t *polygon, osmium::Area const &area,
8585

8686
} // anonymous namespace
8787

88-
void create_linestring(geometry_t *geom, osmium::Way const &way)
88+
bool create_linestring(geometry_t *geom, osmium::Way const &way)
8989
{
9090
auto &line = geom->set<linestring_t>();
9191

9292
if (!fill_point_list(&line, way.nodes())) {
9393
geom->reset();
9494
}
95+
96+
return way.nodes().size() == line.size();
9597
}
9698

9799
geometry_t create_linestring(osmium::Way const &way)
@@ -101,28 +103,30 @@ geometry_t create_linestring(osmium::Way const &way)
101103
return geom;
102104
}
103105

104-
void create_polygon(geometry_t *geom, osmium::Way const &way,
106+
bool create_polygon(geometry_t *geom, osmium::Way const &way,
105107
osmium::memory::Buffer *area_buffer)
106108
{
107109
auto &polygon = geom->set<polygon_t>();
108110

109111
// A closed way with less than 4 nodes can never be a valid polygon
110112
if (way.nodes().size() < 4U) {
111113
geom->reset();
112-
return;
114+
return false;
113115
}
114116

115117
geom::area_assembler_t assembler{area_buffer};
116118

117119
if (!assembler(way)) {
118120
geom->reset();
119-
return;
121+
return false;
120122
}
121123

122124
auto const &area = assembler.get_area();
123125
auto const &ring = *area.cbegin<osmium::OuterRing>();
124126

125127
fill_point_list(&polygon.outer(), ring);
128+
129+
return assembler.stats().duplicate_nodes == 0;
126130
}
127131

128132
geometry_t create_polygon(osmium::Way const &way,

src/geom-from-osm.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void create_point(geometry_t *geom, osmium::Node const &node);
6363
* \param geom Pointer to an existing geometry which will be used as output.
6464
* \param way The input way.
6565
*/
66-
void create_linestring(geometry_t *geom, osmium::Way const &way);
66+
bool create_linestring(geometry_t *geom, osmium::Way const &way);
6767

6868
/**
6969
* Create a linestring geometry from a way. Nodes without location are ignored.
@@ -87,7 +87,7 @@ void create_linestring(geometry_t *geom, osmium::Way const &way);
8787
* \param way The input way.
8888
* \param area_buffer Temporary buffer used to create area.
8989
*/
90-
void create_polygon(geometry_t *geom, osmium::Way const &way,
90+
bool create_polygon(geometry_t *geom, osmium::Way const &way,
9191
osmium::memory::Buffer *area_buffer);
9292

9393
/**

src/output-flex.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,14 @@ int output_flex_t::app_as_linestring()
504504
m_way_cache.add_nodes(middle());
505505

506506
auto *geom = create_lua_geometry_object(lua_state());
507-
geom::create_linestring(geom, m_way_cache.get());
507+
bool const okay = geom::create_linestring(geom, m_way_cache.get());
508508

509-
return 1;
509+
if (geom->is_null()) {
510+
return 1;
511+
}
512+
513+
lua_pushboolean(lua_state(), okay);
514+
return 2;
510515
}
511516

512517
int output_flex_t::app_as_polygon()
@@ -517,9 +522,15 @@ int output_flex_t::app_as_polygon()
517522
m_way_cache.add_nodes(middle());
518523

519524
auto *geom = create_lua_geometry_object(lua_state());
520-
geom::create_polygon(geom, m_way_cache.get(), &m_area_buffer);
525+
bool const okay =
526+
geom::create_polygon(geom, m_way_cache.get(), &m_area_buffer);
521527

522-
return 1;
528+
if (geom->is_null()) {
529+
return 1;
530+
}
531+
532+
lua_pushboolean(lua_state(), okay);
533+
return 2;
523534
}
524535

525536
int output_flex_t::app_as_multipoint()

tests/bdd/flex/geometry-linestring.feature

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,46 @@ Feature: Creating linestring features from way
6666
Geometry data for geometry column 'geom' has the wrong type (LINESTRING).
6767
"""
6868

69+
Scenario:
70+
Given the grid
71+
| 1 | 2 | |
72+
| | | 3 |
73+
And the OSM data
74+
"""
75+
w20 Thighway=motorway Nn1,n2,n3,n1
76+
w21 Thighway=motorway Nn1,n2,n2,n3,n1
77+
w22 Thighway=motorway Nn1,n2,n3,n1,n1
78+
w23 Thighway=motorway Nn1,n2,n3
79+
w24 Thighway=motorway Nn2,n2
80+
"""
81+
And the lua style
82+
"""
83+
local lines = osm2pgsql.define_way_table('osm2pgsql_test_lines', {
84+
{ column = 'lgeom', type = 'linestring', projection = 4326 },
85+
{ column = 'pgeom', type = 'polygon', projection = 4326 },
86+
{ column = 'lclean', type = 'bool' },
87+
{ column = 'pclean', type = 'bool' },
88+
})
89+
90+
function osm2pgsql.process_way(object)
91+
lgeom, lclean = object:as_linestring()
92+
pgeom, pclean = object:as_polygon()
93+
lines:insert({
94+
lgeom = lgeom,
95+
pgeom = pgeom,
96+
lclean = lclean,
97+
pclean = pclean,
98+
})
99+
end
100+
101+
"""
102+
When running osm2pgsql flex
103+
104+
Then table osm2pgsql_test_lines contains exactly
105+
| way_id | lgeom!geo | lclean | pgeom!geo | pclean |
106+
| 20 | 1, 2, 3, 1 | True | (1, 2, 3, 1) | True |
107+
| 21 | 1, 2, 3, 1 | False | (1, 2, 3, 1) | False |
108+
| 22 | 1, 2, 3, 1 | False | (1, 2, 3, 1) | False |
109+
| 23 | 1, 2, 3 | True | NULL | NULL |
110+
| 24 | NULL | NULL | NULL | NULL |
111+

0 commit comments

Comments
 (0)