Libosmium: include/osmium/geom/factory.hpp Source File

Libosmium Fast and flexible C++ library for working with OpenStreetMap data

Loading...
Searching...
No Matches
factory.hpp
Go to the documentation of this file.
1#ifndef OSMIUM_GEOM_FACTORY_HPP
2#define OSMIUM_GEOM_FACTORY_HPP
3
4/*
5
6This file is part of Osmium (https://osmcode.org/libosmium).
7
8Copyright 2013-2026 Jochen Topf <jochen@topf.org> and others (see README).
9
10Boost Software License - Version 1.0 - August 17th, 2003
11
12Permission is hereby granted, free of charge, to any person or organization
13obtaining a copy of the software and accompanying documentation covered by
14this license (the "Software") to use, reproduce, display, distribute,
15execute, and transmit the Software, and to prepare derivative works of the
16Software, and to permit third-parties to whom the Software is furnished to
17do so, all subject to the following:
18
19The copyright notices in the Software and this entire statement, including
20the above license grant, this restriction and the following disclaimer,
21must be included in all copies of the Software, in whole or in part, and
22all derivative works of the Software, unless such copies or derivative
23works are solely in the form of machine-executable object code generated by
24a source language processor.
25
26THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32DEALINGS IN THE SOFTWARE.
33
34*/
35
36#include <osmium/geom/coordinates.hpp>
37#include <osmium/memory/collection.hpp>
38#include <osmium/memory/item.hpp>
39#include <osmium/osm/area.hpp>
40#include <osmium/osm/item_type.hpp>
41#include <osmium/osm/location.hpp>
42#include <osmium/osm/node.hpp>
43#include <osmium/osm/node_ref.hpp>
44#include <osmium/osm/node_ref_list.hpp>
45#include <osmium/osm/types.hpp>
46#include <osmium/osm/way.hpp>
47#include <osmium/util/compatibility.hpp>
48
49#include <cstddef>
50#include <stdexcept>
51#include <string>
52#include <utility>
53
54namespace osmium {
55
60 class OSMIUM_EXPORT geometry_error : public std::runtime_error {
61
62 std::string m_message;
63 osmium::object_id_type m_id;
64
65 public:
66
67 explicit geometry_error(const std::string& message, const char* object_type = "", osmium::object_id_type id = 0) :
68 std::runtime_error(message),
69 m_message(message),
70 m_id(id) {
71 if (m_id != 0) {
72 m_message += " (";
73 m_message += object_type;
74 m_message += "_id=";
75 m_message += std::to_string(m_id);
76 m_message += ")";
77 }
78 }
79
80 void set_id(const char* object_type, osmium::object_id_type id) {
81 if (m_id == 0 && id != 0) {
82 m_message += " (";
83 m_message += object_type;
84 m_message += "_id=";
85 m_message += std::to_string(id);
86 m_message += ")";
87 }
88 m_id = id;
89 }
90
91 osmium::object_id_type id() const noexcept {
92 return m_id;
93 }
94
95 const char* what() const noexcept override {
96 return m_message.c_str();
97 }
98
99 }; // class geometry_error
100
104 namespace geom {
105
109 enum class use_nodes : bool {
110 unique = true,
111 all = false
112 }; // enum class use_nodes
113
118 enum class direction : bool {
119 backward = true,
120 forward = false
121 }; // enum class direction
122
127 class IdentityProjection {
128
129 public:
130
131 Coordinates operator()(osmium::Location location) const {
132 return Coordinates{location.lon(), location.lat()};
133 }
134
135 static int epsg() noexcept {
136 return 4326;
137 }
138
139 static std::string proj_string() noexcept {
140 return "+proj=longlat +datum=WGS84 +no_defs";
141 }
142
143 }; // class IdentityProjection
144
148 template <typename TGeomImpl, typename TProjection = IdentityProjection>
149 class GeometryFactory {
150
154 void add_points(const osmium::NodeRefList& nodes) {
155 osmium::Location last_location;
156 for (const osmium::NodeRef& node_ref : nodes) {
157 if (last_location != node_ref.location()) {
158 last_location = node_ref.location();
159 m_impl.multipolygon_add_location(m_projection(last_location));
160 }
161 }
162 }
163
164 TProjection m_projection;
165 TGeomImpl m_impl;
166
167 public:
168
169 GeometryFactory() :
170 m_projection(),
171 m_impl(m_projection.epsg()) {
172 }
173
177 template <typename... TArgs>
178 explicit GeometryFactory(TArgs&&... args) :
179 m_projection(),
180 m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
181 }
182
187 template <typename... TArgs>
188 explicit GeometryFactory(TProjection&& projection, TArgs&&... args) :
189 m_projection(std::move(projection)),
190 m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
191 }
192
193 using projection_type = TProjection;
194
195 using point_type = typename TGeomImpl::point_type;
196 using linestring_type = typename TGeomImpl::linestring_type;
197 using polygon_type = typename TGeomImpl::polygon_type;
198 using multipolygon_type = typename TGeomImpl::multipolygon_type;
199 using ring_type = typename TGeomImpl::ring_type;
200
201 int epsg() const noexcept {
202 return m_projection.epsg();
203 }
204
205 std::string proj_string() const {
206 return m_projection.proj_string();
207 }
208
209 /* Point */
210
211 point_type create_point(const osmium::Location& location) const {
212 return m_impl.make_point(m_projection(location));
213 }
214
215 point_type create_point(const osmium::Node& node) {
216 try {
217 return create_point(node.location());
218 } catch (osmium::geometry_error& e) {
219 e.set_id("node", node.id());
220 throw;
221 }
222 }
223
224 point_type create_point(const osmium::NodeRef& node_ref) {
225 try {
226 return create_point(node_ref.location());
227 } catch (osmium::geometry_error& e) {
228 e.set_id("node", node_ref.ref());
229 throw;
230 }
231 }
232
233 /* LineString */
234
235 void linestring_start() {
236 m_impl.linestring_start();
237 }
238
239 template <typename TIter>
240 size_t fill_linestring(TIter it, TIter end) {
241 size_t num_points = 0;
242 for (; it != end; ++it, ++num_points) {
243 m_impl.linestring_add_location(m_projection(it->location()));
244 }
245 return num_points;
246 }
247
248 template <typename TIter>
249 size_t fill_linestring_unique(TIter it, TIter end) {
250 size_t num_points = 0;
251 osmium::Location last_location;
252 for (; it != end; ++it) {
253 if (last_location != it->location()) {
254 last_location = it->location();
255 m_impl.linestring_add_location(m_projection(last_location));
256 ++num_points;
257 }
258 }
259 return num_points;
260 }
261
262 linestring_type linestring_finish(size_t num_points) {
263 return m_impl.linestring_finish(num_points);
264 }
265
266 linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
267 linestring_start();
268 size_t num_points = 0;
269
270 if (un == use_nodes::unique) {
271 switch (dir) {
272 case direction::forward:
273 num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
274 break;
275 case direction::backward:
276 num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
277 break;
278 }
279 } else {
280 switch (dir) {
281 case direction::forward:
282 num_points = fill_linestring(wnl.cbegin(), wnl.cend());
283 break;
284 case direction::backward:
285 num_points = fill_linestring(wnl.crbegin(), wnl.crend());
286 break;
287 }
288 }
289
290 if (num_points < 2) {
291 throw osmium::geometry_error{"need at least two points for linestring"};
292 }
293
294 return linestring_finish(num_points);
295 }
296
297 linestring_type create_linestring(const osmium::Way& way, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
298 try {
299 return create_linestring(way.nodes(), un, dir);
300 } catch (osmium::geometry_error& e) {
301 e.set_id("way", way.id());
302 throw;
303 }
304 }
305
306 /* Polygon */
307
308 void polygon_start() {
309 m_impl.polygon_start();
310 }
311
312 template <typename TIter>
313 size_t fill_polygon(TIter it, TIter end) {
314 size_t num_points = 0;
315 for (; it != end; ++it, ++num_points) {
316 m_impl.polygon_add_location(m_projection(it->location()));
317 }
318 return num_points;
319 }
320
321 template <typename TIter>
322 size_t fill_polygon_unique(TIter it, TIter end) {
323 size_t num_points = 0;
324 osmium::Location last_location;
325 for (; it != end; ++it) {
326 if (last_location != it->location()) {
327 last_location = it->location();
328 m_impl.polygon_add_location(m_projection(last_location));
329 ++num_points;
330 }
331 }
332 return num_points;
333 }
334
335 polygon_type polygon_finish(size_t num_points) {
336 return m_impl.polygon_finish(num_points);
337 }
338
339 polygon_type create_polygon(const osmium::WayNodeList& wnl, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
340 polygon_start();
341 size_t num_points = 0;
342
343 if (un == use_nodes::unique) {
344 switch (dir) {
345 case direction::forward:
346 num_points = fill_polygon_unique(wnl.cbegin(), wnl.cend());
347 break;
348 case direction::backward:
349 num_points = fill_polygon_unique(wnl.crbegin(), wnl.crend());
350 break;
351 }
352 } else {
353 switch (dir) {
354 case direction::forward:
355 num_points = fill_polygon(wnl.cbegin(), wnl.cend());
356 break;
357 case direction::backward:
358 num_points = fill_polygon(wnl.crbegin(), wnl.crend());
359 break;
360 }
361 }
362
363 if (num_points < 4) {
364 throw osmium::geometry_error{"need at least four points for polygon"};
365 }
366
367 return polygon_finish(num_points);
368 }
369
370 polygon_type create_polygon(const osmium::Way& way, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
371 try {
372 return create_polygon(way.nodes(), un, dir);
373 } catch (osmium::geometry_error& e) {
374 e.set_id("way", way.id());
375 throw;
376 }
377 }
378
379 /* MultiPolygon */
380
381 multipolygon_type create_multipolygon(const osmium::Area& area) {
382 try {
383 size_t num_polygons = 0;
384 size_t num_rings = 0;
385 m_impl.multipolygon_start();
386
387 for (const auto& item : area) {
388 if (item.type() == osmium::item_type::outer_ring) {
389 const auto& ring = static_cast<const osmium::OuterRing&>(item);
390 if (num_polygons > 0) {
391 m_impl.multipolygon_polygon_finish();
392 }
393 m_impl.multipolygon_polygon_start();
394 m_impl.multipolygon_outer_ring_start();
395 add_points(ring);
396 m_impl.multipolygon_outer_ring_finish();
397 ++num_rings;
398 ++num_polygons;
399 } else if (item.type() == osmium::item_type::inner_ring) {
400 const auto& ring = static_cast<const osmium::InnerRing&>(item);
401 m_impl.multipolygon_inner_ring_start();
402 add_points(ring);
403 m_impl.multipolygon_inner_ring_finish();
404 ++num_rings;
405 }
406 }
407
408 // if there are no rings, this area is invalid
409 if (num_rings == 0) {
410 throw osmium::geometry_error{"invalid area"};
411 }
412
413 m_impl.multipolygon_polygon_finish();
414 return m_impl.multipolygon_finish();
415 } catch (osmium::geometry_error& e) {
416 e.set_id("area", area.id());
417 throw;
418 }
419 }
420
421 }; // class GeometryFactory
422
423 } // namespace geom
424
425} // namespace osmium
426
427#endif // OSMIUM_GEOM_FACTORY_HPP
area.hpp
osmium::Area
Definition area.hpp:125
osmium::InnerRing
Definition area.hpp:80
osmium::Location
Definition location.hpp:279
osmium::Location::lon
double lon() const
Definition location.hpp:438
osmium::Location::lat
double lat() const
Definition location.hpp:457
osmium::NodeRefList
Definition node_ref_list.hpp:52
osmium::NodeRefList::cbegin
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition node_ref_list.hpp:209
osmium::NodeRefList::cend
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition node_ref_list.hpp:214
osmium::NodeRefList::crend
const_reverse_iterator crend() const noexcept
Returns a reverse_iterator to the end.
Definition node_ref_list.hpp:234
osmium::NodeRefList::crbegin
const_reverse_iterator crbegin() const noexcept
Returns a reverse_iterator to the beginning.
Definition node_ref_list.hpp:229
osmium::NodeRef
Definition node_ref.hpp:50
osmium::NodeRef::ref
constexpr osmium::object_id_type ref() const noexcept
Definition node_ref.hpp:71
osmium::NodeRef::location
osmium::Location & location() noexcept
Definition node_ref.hpp:85
osmium::Node
Definition node.hpp:48
osmium::OuterRing
Definition area.hpp:60
osmium::WayNodeList
Definition way.hpp:55
osmium::Way
Definition way.hpp:72
osmium::geom::GeometryFactory::create_multipolygon
multipolygon_type create_multipolygon(const osmium::Area &area)
Definition factory.hpp:381
osmium::geom::GeometryFactory::multipolygon_type
typename TGeomImpl::multipolygon_type multipolygon_type
Definition factory.hpp:198
osmium::geom::GeometryFactory::linestring_start
void linestring_start()
Definition factory.hpp:235
osmium::geom::GeometryFactory::fill_polygon
size_t fill_polygon(TIter it, TIter end)
Definition factory.hpp:313
osmium::geom::GeometryFactory::point_type
typename TGeomImpl::point_type point_type
Definition factory.hpp:195
osmium::geom::GeometryFactory::create_point
point_type create_point(const osmium::Node &node)
Definition factory.hpp:215
osmium::geom::GeometryFactory< detail::RapidGeoJSONFactoryImpl< TWriter >, TProjection >::m_impl
detail::RapidGeoJSONFactoryImpl< TWriter > m_impl
Definition factory.hpp:165
osmium::geom::GeometryFactory::GeometryFactory
GeometryFactory()
Definition factory.hpp:169
osmium::geom::GeometryFactory::fill_linestring
size_t fill_linestring(TIter it, TIter end)
Definition factory.hpp:240
osmium::geom::GeometryFactory::polygon_start
void polygon_start()
Definition factory.hpp:308
osmium::geom::GeometryFactory::fill_polygon_unique
size_t fill_polygon_unique(TIter it, TIter end)
Definition factory.hpp:322
osmium::geom::GeometryFactory::create_linestring
linestring_type create_linestring(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition factory.hpp:297
osmium::geom::GeometryFactory::create_polygon
polygon_type create_polygon(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition factory.hpp:339
osmium::geom::GeometryFactory::polygon_type
typename TGeomImpl::polygon_type polygon_type
Definition factory.hpp:197
osmium::geom::GeometryFactory< detail::RapidGeoJSONFactoryImpl< TWriter >, TProjection >::epsg
int epsg() const noexcept
Definition factory.hpp:201
osmium::geom::GeometryFactory::create_point
point_type create_point(const osmium::NodeRef &node_ref)
Definition factory.hpp:224
osmium::geom::GeometryFactory::projection_type
TProjection projection_type
Definition factory.hpp:193
osmium::geom::GeometryFactory::m_projection
TProjection m_projection
Definition factory.hpp:164
osmium::geom::GeometryFactory::GeometryFactory
GeometryFactory(TArgs &&... args)
Definition factory.hpp:178
osmium::geom::GeometryFactory::create_point
point_type create_point(const osmium::Location &location) const
Definition factory.hpp:211
osmium::geom::GeometryFactory::GeometryFactory
GeometryFactory(TProjection &&projection, TArgs &&... args)
Definition factory.hpp:188
osmium::geom::GeometryFactory::create_polygon
polygon_type create_polygon(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition factory.hpp:370
osmium::geom::GeometryFactory::fill_linestring_unique
size_t fill_linestring_unique(TIter it, TIter end)
Definition factory.hpp:249
osmium::geom::GeometryFactory::create_linestring
linestring_type create_linestring(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition factory.hpp:266
osmium::geom::GeometryFactory::linestring_finish
linestring_type linestring_finish(size_t num_points)
Definition factory.hpp:262
osmium::geom::GeometryFactory::linestring_type
typename TGeomImpl::linestring_type linestring_type
Definition factory.hpp:196
osmium::geom::GeometryFactory::proj_string
std::string proj_string() const
Definition factory.hpp:205
osmium::geom::GeometryFactory::polygon_finish
polygon_type polygon_finish(size_t num_points)
Definition factory.hpp:335
osmium::geom::GeometryFactory::ring_type
typename TGeomImpl::ring_type ring_type
Definition factory.hpp:199
osmium::geom::GeometryFactory::add_points
void add_points(const osmium::NodeRefList &nodes)
Definition factory.hpp:154
osmium::geom::IdentityProjection
Definition factory.hpp:127
osmium::geom::IdentityProjection::proj_string
static std::string proj_string() noexcept
Definition factory.hpp:139
osmium::geom::IdentityProjection::operator()
Coordinates operator()(osmium::Location location) const
Definition factory.hpp:131
osmium::geom::IdentityProjection::epsg
static int epsg() noexcept
Definition factory.hpp:135
osmium::geometry_error
Definition factory.hpp:60
osmium::geometry_error::set_id
void set_id(const char *object_type, osmium::object_id_type id)
Definition factory.hpp:80
osmium::geometry_error::what
const char * what() const noexcept override
Definition factory.hpp:95
osmium::geometry_error::id
osmium::object_id_type id() const noexcept
Definition factory.hpp:91
osmium::geometry_error::m_message
std::string m_message
Definition factory.hpp:62
osmium::geometry_error::m_id
osmium::object_id_type m_id
Definition factory.hpp:63
osmium::geometry_error::geometry_error
geometry_error(const std::string &message, const char *object_type="", osmium::object_id_type id=0)
Definition factory.hpp:67
collection.hpp
compatibility.hpp
OSMIUM_EXPORT
#define OSMIUM_EXPORT
Definition compatibility.hpp:45
coordinates.hpp
item.hpp
item_type.hpp
location.hpp
osmium::area
Code related to the building of areas (multipolygons) from relations.
Definition assembler.hpp:55
osmium::geom::use_nodes
use_nodes
Definition factory.hpp:109
osmium::geom::use_nodes::unique
@ unique
Remove consecutive nodes with same location.
Definition factory.hpp:110
osmium::geom::use_nodes::all
@ all
Use all nodes.
Definition factory.hpp:111
osmium::geom::direction
direction
Definition factory.hpp:118
osmium::geom::direction::backward
@ backward
Linestring has reverse direction.
Definition factory.hpp:119
osmium::geom::direction::forward
@ forward
Linestring has same direction as way.
Definition factory.hpp:120
osmium
Namespace for everything in the Osmium library.
Definition assembler.hpp:53
osmium::item_type::node
@ node
Definition item_type.hpp:48
osmium::item_type::way
@ way
Definition item_type.hpp:49
osmium::item_type::outer_ring
@ outer_ring
Definition item_type.hpp:57
osmium::item_type::inner_ring
@ inner_ring
Definition item_type.hpp:58
osmium::object_id_type
int64_t object_id_type
Type for OSM object (node, way, or relation) IDs.
Definition types.hpp:45
std
Definition location.hpp:654
node.hpp
node_ref.hpp
node_ref_list.hpp
osmium::geom::Coordinates
Definition coordinates.hpp:48
types.hpp
way.hpp