Skip to content

Commit 15ecf96

Browse files
authored
Merge pull request #1709 from joto/geom-create-collection
Add function to create geometry collection from OSM data
2 parents 91a5381 + 865758d commit 15ecf96

File tree

5 files changed

+139
-1
lines changed

5 files changed

+139
-1
lines changed

src/geom-from-osm.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,38 @@ geometry_t create_multipolygon(osmium::Relation const &relation,
173173
return geom;
174174
}
175175

176+
void create_collection(geometry_t *geom,
177+
osmium::memory::Buffer const &member_buffer)
178+
{
179+
auto &collection = geom->set<collection_t>();
180+
181+
for (auto const &obj : member_buffer) {
182+
if (obj.type() == osmium::item_type::node) {
183+
auto const &node = static_cast<osmium::Node const &>(obj);
184+
if (node.location().valid()) {
185+
collection.add_geometry(create_point(node));
186+
}
187+
} else if (obj.type() == osmium::item_type::way) {
188+
auto const &way = static_cast<osmium::Way const &>(obj);
189+
geometry_t item;
190+
auto &line = item.set<linestring_t>();
191+
fill_point_list(&line, way.nodes());
192+
if (line.size() >= 2U) {
193+
collection.add_geometry(std::move(item));
194+
}
195+
}
196+
}
197+
198+
if (collection.num_geometries() == 0) {
199+
geom->reset();
200+
}
201+
}
202+
203+
geometry_t create_collection(osmium::memory::Buffer const &member_buffer)
204+
{
205+
geometry_t geom{};
206+
create_collection(&geom, member_buffer);
207+
return geom;
208+
}
209+
176210
} // namespace geom

src/geom-from-osm.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,30 @@ void create_multipolygon(geometry_t *geom, osmium::Relation const &relation,
142142
geometry_t create_multipolygon(osmium::Relation const &relation,
143143
osmium::memory::Buffer const &way_buffer);
144144

145+
/**
146+
* Create a geometry collection from a relation and node/way members.
147+
*
148+
* If the resulting geometry would be empty or invalid, a null geometry is
149+
* returned.
150+
*
151+
* \param geom Pointer to an existing geometry which will be used as output.
152+
* \param relation The input relation.
153+
* \param way_buffer Buffer containing all member nodes and ways.
154+
*/
155+
void create_collection(geometry_t *geom,
156+
osmium::memory::Buffer const &member_buffer);
157+
158+
/**
159+
* Create a geometry collection from a relation and node/way members.
160+
*
161+
* If the resulting geometry would be empty or invalid, a null geometry is
162+
* returned.
163+
*
164+
* \param way_buffer Buffer containing all member nodes and ways.
165+
* \returns The created geometry.
166+
*/
167+
geometry_t create_collection(osmium::memory::Buffer const &member_buffer);
168+
145169
} // namespace geom
146170

147171
#endif // OSM2PGSQL_GEOM_FROM_OSM_HPP

src/geom-functions.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,8 @@ geometry_t centroid(geometry_t const &geom)
554554
geom.visit(overloaded{
555555
[&](geom::nullgeom_t const & /*input*/) { output.reset(); },
556556
[&](geom::collection_t const & /*input*/) {
557-
throw std::runtime_error{"not implemented yet"};
557+
throw std::runtime_error{
558+
"Centroid of geometry collection not implemented yet"};
558559
},
559560
[&](auto const &input) { boost::geometry::centroid(input, center); }});
560561

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ set_test(test-domain-matcher LABELS NoDB)
4444
set_test(test-expire-tiles LABELS NoDB)
4545
set_test(test-geom-box LABELS NoDB)
4646
set_test(test-geom-lines LABELS NoDB)
47+
set_test(test-geom-collections LABELS NoDB)
4748
set_test(test-geom-null LABELS NoDB)
4849
set_test(test-geom-points LABELS NoDB)
4950
set_test(test-geom-polygons LABELS NoDB)

tests/test-geom-collections.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* SPDX-License-Identifier: GPL-2.0-or-later
3+
*
4+
* This file is part of osm2pgsql (https://osm2pgsql.org/).
5+
*
6+
* Copyright (C) 2006-2022 by the osm2pgsql developer community.
7+
* For a full list of authors see the git log.
8+
*/
9+
10+
#include <catch.hpp>
11+
12+
#include "common-buffer.hpp"
13+
14+
#include "geom-from-osm.hpp"
15+
#include "geom-functions.hpp"
16+
#include "geom.hpp"
17+
18+
TEST_CASE("geometry collection with point", "[NoDB]")
19+
{
20+
geom::geometry_t geom{geom::collection_t{}};
21+
auto &c = geom.get<geom::collection_t>();
22+
23+
c.add_geometry(geom::geometry_t{geom::point_t{1, 1}});
24+
25+
REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
26+
REQUIRE(num_geometries(geom) == 1);
27+
REQUIRE(area(geom) == Approx(0.0));
28+
REQUIRE_THROWS(centroid(geom));
29+
}
30+
31+
TEST_CASE("geometry collection with several geometries", "[NoDB]")
32+
{
33+
geom::geometry_t geom{geom::collection_t{}};
34+
auto &c = geom.get<geom::collection_t>();
35+
36+
c.add_geometry(geom::geometry_t{geom::point_t{1, 1}});
37+
c.add_geometry(geom::geometry_t{geom::linestring_t{{1, 1}, {2, 2}}});
38+
c.add_geometry(geom::geometry_t{geom::point_t{2, 2}});
39+
40+
REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
41+
REQUIRE(num_geometries(geom) == 3);
42+
REQUIRE(area(geom) == Approx(0.0));
43+
REQUIRE_THROWS(centroid(geom));
44+
}
45+
46+
TEST_CASE("create_collection from OSM data", "[NoDB]")
47+
{
48+
test_buffer_t buffer;
49+
buffer.add_node("n1 x1 y1");
50+
buffer.add_way("w20 Nn1x1y1,n2x2y1,n3x2y2,n4x1y2,n1x1y1");
51+
buffer.add_way("w21 Nn5x10y10,n6x10y20");
52+
buffer.add_relation("r30 Mw20@");
53+
54+
auto const geom = geom::create_collection(buffer.buffer());
55+
56+
REQUIRE(geometry_type(geom) == "GEOMETRYCOLLECTION");
57+
REQUIRE(num_geometries(geom) == 3);
58+
59+
auto const &c = geom.get<geom::collection_t>();
60+
REQUIRE(c[0] == geom::geometry_t{geom::point_t{1, 1}});
61+
REQUIRE(c[1] == geom::geometry_t{geom::linestring_t{
62+
{1, 1}, {2, 1}, {2, 2}, {1, 2}, {1, 1}}});
63+
REQUIRE(c[2] == geom::geometry_t{geom::linestring_t{{10, 10}, {10, 20}}});
64+
65+
REQUIRE(area(geom) == Approx(0.0));
66+
REQUIRE_THROWS(centroid(geom));
67+
}
68+
69+
TEST_CASE("create_collection from no OSM data returns null geometry", "[NoDB]")
70+
{
71+
test_buffer_t buffer;
72+
buffer.add_relation("r30 Mw20@");
73+
74+
auto const geom = geom::create_collection(buffer.buffer());
75+
76+
REQUIRE(geometry_type(geom) == "NULL");
77+
REQUIRE(num_geometries(geom) == 0);
78+
}

0 commit comments

Comments
 (0)