Libosmium  2.20.0
Fast and flexible C++ library for working with OpenStreetMap data
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-2023 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
39#include <osmium/osm/area.hpp>
42#include <osmium/osm/node.hpp>
45#include <osmium/osm/types.hpp>
46#include <osmium/osm/way.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;
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
128
129 public:
130
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>
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
170 m_projection(),
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
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
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
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
263 return m_impl.linestring_finish(num_points);
264 }
265
268 size_t num_points = 0;
269
270 if (un == use_nodes::unique) {
271 switch (dir) {
273 num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
274 break;
276 num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
277 break;
278 }
279 } else {
280 switch (dir) {
282 num_points = fill_linestring(wnl.cbegin(), wnl.cend());
283 break;
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
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
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
341 size_t num_points = 0;
342
343 if (un == use_nodes::unique) {
344 switch (dir) {
346 num_points = fill_polygon_unique(wnl.cbegin(), wnl.cend());
347 break;
349 num_points = fill_polygon_unique(wnl.crbegin(), wnl.crend());
350 break;
351 }
352 } else {
353 switch (dir) {
355 num_points = fill_polygon(wnl.cbegin(), wnl.cend());
356 break;
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
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
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
Definition: area.hpp:125
Definition: area.hpp:80
Definition: location.hpp:271
double lon() const
Definition: location.hpp:400
double lat() const
Definition: location.hpp:419
Definition: node_ref_list.hpp:52
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition: node_ref_list.hpp:209
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: node_ref_list.hpp:214
const_reverse_iterator crend() const noexcept
Returns a reverse_iterator to the end.
Definition: node_ref_list.hpp:234
const_reverse_iterator crbegin() const noexcept
Returns a reverse_iterator to the beginning.
Definition: node_ref_list.hpp:229
Definition: node_ref.hpp:50
constexpr osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:71
osmium::Location & location() noexcept
Definition: node_ref.hpp:85
Definition: node.hpp:48
Definition: area.hpp:60
Definition: way.hpp:55
Definition: way.hpp:72
Definition: factory.hpp:149
multipolygon_type create_multipolygon(const osmium::Area &area)
Definition: factory.hpp:381
typename TGeomImpl::multipolygon_type multipolygon_type
Definition: factory.hpp:198
void linestring_start()
Definition: factory.hpp:235
size_t fill_polygon(TIter it, TIter end)
Definition: factory.hpp:313
typename TGeomImpl::point_type point_type
Definition: factory.hpp:195
point_type create_point(const osmium::Node &node)
Definition: factory.hpp:215
TGeomImpl m_impl
Definition: factory.hpp:165
GeometryFactory()
Definition: factory.hpp:169
size_t fill_linestring(TIter it, TIter end)
Definition: factory.hpp:240
void polygon_start()
Definition: factory.hpp:308
size_t fill_polygon_unique(TIter it, TIter end)
Definition: factory.hpp:322
linestring_type create_linestring(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:297
polygon_type create_polygon(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:339
typename TGeomImpl::polygon_type polygon_type
Definition: factory.hpp:197
int epsg() const noexcept
Definition: factory.hpp:201
point_type create_point(const osmium::NodeRef &node_ref)
Definition: factory.hpp:224
TProjection projection_type
Definition: factory.hpp:193
TProjection m_projection
Definition: factory.hpp:164
GeometryFactory(TArgs &&... args)
Definition: factory.hpp:178
point_type create_point(const osmium::Location &location) const
Definition: factory.hpp:211
GeometryFactory(TProjection &&projection, TArgs &&... args)
Definition: factory.hpp:188
polygon_type create_polygon(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:370
size_t fill_linestring_unique(TIter it, TIter end)
Definition: factory.hpp:249
linestring_type create_linestring(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:266
linestring_type linestring_finish(size_t num_points)
Definition: factory.hpp:262
typename TGeomImpl::linestring_type linestring_type
Definition: factory.hpp:196
std::string proj_string() const
Definition: factory.hpp:205
polygon_type polygon_finish(size_t num_points)
Definition: factory.hpp:335
typename TGeomImpl::ring_type ring_type
Definition: factory.hpp:199
void add_points(const osmium::NodeRefList &nodes)
Definition: factory.hpp:154
Definition: factory.hpp:127
static std::string proj_string() noexcept
Definition: factory.hpp:139
Coordinates operator()(osmium::Location location) const
Definition: factory.hpp:131
static int epsg() noexcept
Definition: factory.hpp:135
Definition: factory.hpp:60
void set_id(const char *object_type, osmium::object_id_type id)
Definition: factory.hpp:80
const char * what() const noexcept override
Definition: factory.hpp:95
osmium::object_id_type id() const noexcept
Definition: factory.hpp:91
std::string m_message
Definition: factory.hpp:62
osmium::object_id_type m_id
Definition: factory.hpp:63
geometry_error(const std::string &message, const char *object_type="", osmium::object_id_type id=0)
Definition: factory.hpp:67
#define OSMIUM_EXPORT
Definition: compatibility.hpp:54
use_nodes
Definition: factory.hpp:109
@ unique
Remove consecutive nodes with same location.
direction
Definition: factory.hpp:118
@ backward
Linestring has reverse direction.
@ forward
Linestring has same direction as way.
InputIterator< Reader > end(Reader &)
Definition: reader_iterator.hpp:47
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
int64_t object_id_type
Type for OSM object (node, way, or relation) IDs.
Definition: types.hpp:45
Definition: location.hpp:555
Definition: coordinates.hpp:48