Skip to content

Commit 031c547

Browse files
committed
Flex: Allow creating point geometry from way
Ways can have a single node (or multiple nodes at the same location) in which case we can't build a proper linestring. This doesn't happen very often and is always an error in the data. This adds the functionality to flex Lua code to run as_point() on a way geometry which creates a point geometry from the first node. This is mostly intended for the use case where we want to create a point from invalid ways to help fix them. It can also be used if you just need any point in that linestring for a rough position or so.
1 parent 83a1af0 commit 031c547

File tree

6 files changed

+98
-10
lines changed

6 files changed

+98
-10
lines changed

src/geom-from-osm.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,18 @@
1919

2020
namespace geom {
2121

22+
void create_point(geometry_t *geom, osmium::Location const &location)
23+
{
24+
if (location.valid()) {
25+
auto &point = geom->set<point_t>();
26+
point.set_x(location.lon());
27+
point.set_y(location.lat());
28+
}
29+
}
30+
2231
void create_point(geometry_t *geom, osmium::Node const &node)
2332
{
24-
auto &point = geom->set<point_t>();
25-
point.set_x(node.location().lon());
26-
point.set_y(node.location().lat());
33+
create_point(geom, node.location());
2734
}
2835

2936
geometry_t create_point(osmium::Node const &node)

src/geom-from-osm.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@
2727

2828
namespace geom {
2929

30+
/**
31+
* Create a point geometry from a location. If the location is not valid,
32+
* the output will not be changed.
33+
*
34+
* \param geom Pointer to an existing geometry which will be used as output.
35+
* \param location The input location.
36+
*/
37+
void create_point(geometry_t *geom, osmium::Location const &location);
38+
3039
/**
3140
* Create a point geometry from a node.
3241
*

src/output-flex.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,12 +454,24 @@ int output_flex_t::app_get_bbox()
454454

455455
int output_flex_t::app_as_point()
456456
{
457-
check_context_and_state("as_point", "node",
458-
m_calling_context != calling_context::process_node);
457+
check_context_and_state(
458+
"as_point", "node/way",
459+
m_calling_context != calling_context::process_node &&
460+
m_calling_context != calling_context::process_way);
459461

460462
auto *geom = create_lua_geometry_object(lua_state());
461-
geom::create_point(geom, *m_context_node);
462463

464+
if (m_calling_context == calling_context::process_node) {
465+
geom::create_point(geom, *m_context_node);
466+
return 1;
467+
}
468+
469+
m_way_cache.add_nodes(middle());
470+
471+
auto const &nodes = m_way_cache.get().nodes();
472+
if (!nodes.empty()) {
473+
geom::create_point(geom, nodes[0].location());
474+
}
463475
return 1;
464476
}
465477

tests/bdd/flex/geometry-linestring.feature

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@ Feature: Creating linestring features from way
1616
{ column = 'sgeom', type = 'linestring', projection = 4326 },
1717
{ column = 'mgeom', type = 'multilinestring', projection = 4326 },
1818
{ column = 'xgeom', type = 'multilinestring', projection = 4326 },
19+
{ column = 'pgeom', type = 'point', projection = 4326 },
1920
})
2021
2122
function osm2pgsql.process_way(object)
2223
if object.tags.highway == 'motorway' then
2324
lines:insert({
2425
sgeom = object:as_linestring(),
2526
mgeom = object:as_multilinestring(),
26-
xgeom = object:as_linestring()
27+
xgeom = object:as_linestring(),
28+
pgeom = object:as_point(),
2729
})
2830
end
2931
end
@@ -32,9 +34,9 @@ Feature: Creating linestring features from way
3234
When running osm2pgsql flex
3335

3436
Then table osm2pgsql_test_lines contains exactly
35-
| way_id | ST_AsText(sgeom) | ST_AsText(mgeom) | ST_AsText(xgeom) |
36-
| 20 | 1, 2, 3 | [ 1, 2, 3 ] | [ 1, 2, 3 ] |
37-
| 21 | 4, 5 | [ 4, 5 ] | [ 4, 5 ] |
37+
| way_id | ST_AsText(sgeom) | ST_AsText(mgeom) | ST_AsText(xgeom) | ST_AsText(pgeom) |
38+
| 20 | 1, 2, 3 | [ 1, 2, 3 ] | [ 1, 2, 3 ] | 1 |
39+
| 21 | 4, 5 | [ 4, 5 ] | [ 4, 5 ] | 4 |
3840

3941
Scenario:
4042
Given the grid

tests/test-geom-linestrings.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,50 @@ TEST_CASE("create_linestring from invalid OSM data", "[NoDB]")
115115
REQUIRE(geom.is_null());
116116
}
117117

118+
TEST_CASE("create_point from OSM way data", "[NoDB]")
119+
{
120+
test_buffer_t buffer;
121+
buffer.add_way("w20 Nn1x1y1,n2x2y2");
122+
123+
auto const &nodes = buffer.buffer().get<osmium::Way>(0).nodes();
124+
geom::geometry_t geom;
125+
geom::create_point(&geom, nodes[0].location());
126+
127+
REQUIRE(geom.is_point());
128+
REQUIRE(geometry_type(geom) == "POINT");
129+
REQUIRE(dimension(geom) == 0);
130+
REQUIRE(num_geometries(geom) == 1);
131+
REQUIRE(geom.get<geom::point_t>() == geom::point_t{1, 1});
132+
}
133+
134+
TEST_CASE("create_point from OSM data without locations", "[NoDB]")
135+
{
136+
test_buffer_t buffer;
137+
buffer.add_way("w20 Nn1,n2");
138+
139+
auto const &nodes = buffer.buffer().get<osmium::Way>(0).nodes();
140+
geom::geometry_t geom;
141+
geom::create_point(&geom, nodes[0].location());
142+
143+
REQUIRE(geom.is_null());
144+
}
145+
146+
TEST_CASE("create_point from way with single node", "[NoDB]")
147+
{
148+
test_buffer_t buffer;
149+
buffer.add_way("w20 Nn1x1y1");
150+
151+
auto const &nodes = buffer.buffer().get<osmium::Way>(0).nodes();
152+
geom::geometry_t geom;
153+
geom::create_point(&geom, nodes[0].location());
154+
155+
REQUIRE(geom.is_point());
156+
REQUIRE(geometry_type(geom) == "POINT");
157+
REQUIRE(dimension(geom) == 0);
158+
REQUIRE(num_geometries(geom) == 1);
159+
REQUIRE(geom.get<geom::point_t>() == geom::point_t{1, 1});
160+
}
161+
118162
TEST_CASE("geom::segmentize w/o split", "[NoDB]")
119163
{
120164
geom::linestring_t const expected{{0, 0}, {1, 2}, {2, 2}};

tests/test-geom-points.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ TEST_CASE("geom::point_t from location", "[NoDB]")
4242
REQUIRE(p == geom::point_t{3.141, 2.718});
4343
}
4444

45+
TEST_CASE("geom::point_t from location with create_point", "[NoDB]")
46+
{
47+
osmium::Location const location{1.1, 2.2};
48+
49+
geom::geometry_t geom;
50+
geom::create_point(&geom, location);
51+
REQUIRE(geom.is_point());
52+
53+
auto const &p = geom.get<geom::point_t>();
54+
REQUIRE(p.x() == Approx(1.1));
55+
REQUIRE(p.y() == Approx(2.2));
56+
REQUIRE(p == geom::point_t{1.1, 2.2});
57+
}
58+
4559
TEST_CASE("create_point from OSM data", "[NoDB]")
4660
{
4761
test_buffer_t buffer;

0 commit comments

Comments
 (0)