Libosmium  2.17.0
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-2021 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>
47
48#include <cstddef>
49#include <stdexcept>
50#include <string>
51#include <utility>
52
53namespace osmium {
54
59 class geometry_error : public std::runtime_error {
60
61 std::string m_message;
63
64 public:
65
66 explicit geometry_error(const std::string& message, const char* object_type = "", osmium::object_id_type id = 0) :
67 std::runtime_error(message),
68 m_message(message),
69 m_id(id) {
70 if (m_id != 0) {
71 m_message += " (";
72 m_message += object_type;
73 m_message += "_id=";
74 m_message += std::to_string(m_id);
75 m_message += ")";
76 }
77 }
78
79 void set_id(const char* object_type, osmium::object_id_type id) {
80 if (m_id == 0 && id != 0) {
81 m_message += " (";
82 m_message += object_type;
83 m_message += "_id=";
84 m_message += std::to_string(id);
85 m_message += ")";
86 }
87 m_id = id;
88 }
89
90 osmium::object_id_type id() const noexcept {
91 return m_id;
92 }
93
94 const char* what() const noexcept override {
95 return m_message.c_str();
96 }
97
98 }; // class geometry_error
99
103 namespace geom {
104
108 enum class use_nodes : bool {
109 unique = true,
110 all = false
111 }; // enum class use_nodes
112
117 enum class direction : bool {
118 backward = true,
119 forward = false
120 }; // enum class direction
121
127
128 public:
129
131 return Coordinates{location.lon(), location.lat()};
132 }
133
134 static int epsg() noexcept {
135 return 4326;
136 }
137
138 static std::string proj_string() noexcept {
139 return "+proj=longlat +datum=WGS84 +no_defs";
140 }
141
142 }; // class IdentityProjection
143
147 template <typename TGeomImpl, typename TProjection = IdentityProjection>
149
153 void add_points(const osmium::NodeRefList& nodes) {
154 osmium::Location last_location;
155 for (const osmium::NodeRef& node_ref : nodes) {
156 if (last_location != node_ref.location()) {
157 last_location = node_ref.location();
158 m_impl.multipolygon_add_location(m_projection(last_location));
159 }
160 }
161 }
162
163 TProjection m_projection;
164 TGeomImpl m_impl;
165
166 public:
167
169 m_projection(),
171 }
172
176 template <typename... TArgs>
177 explicit GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
178 m_projection(),
179 m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
180 }
181
186 template <typename... TArgs>
187 explicit GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
188 m_projection(std::move(projection)),
189 m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
190 }
191
192 using projection_type = TProjection;
193
194 using point_type = typename TGeomImpl::point_type;
195 using linestring_type = typename TGeomImpl::linestring_type;
196 using polygon_type = typename TGeomImpl::polygon_type;
197 using multipolygon_type = typename TGeomImpl::multipolygon_type;
198 using ring_type = typename TGeomImpl::ring_type;
199
200 int epsg() const noexcept {
201 return m_projection.epsg();
202 }
203
204 std::string proj_string() const {
205 return m_projection.proj_string();
206 }
207
208 /* Point */
209
210 point_type create_point(const osmium::Location& location) const {
211 return m_impl.make_point(m_projection(location));
212 }
213
215 try {
216 return create_point(node.location());
217 } catch (osmium::geometry_error& e) {
218 e.set_id("node", node.id());
219 throw;
220 }
221 }
222
224 try {
225 return create_point(node_ref.location());
226 } catch (osmium::geometry_error& e) {
227 e.set_id("node", node_ref.ref());
228 throw;
229 }
230 }
231
232 /* LineString */
233
235 m_impl.linestring_start();
236 }
237
238 template <typename TIter>
239 size_t fill_linestring(TIter it, TIter end) {
240 size_t num_points = 0;
241 for (; it != end; ++it, ++num_points) {
242 m_impl.linestring_add_location(m_projection(it->location()));
243 }
244 return num_points;
245 }
246
247 template <typename TIter>
248 size_t fill_linestring_unique(TIter it, TIter end) {
249 size_t num_points = 0;
250 osmium::Location last_location;
251 for (; it != end; ++it) {
252 if (last_location != it->location()) {
253 last_location = it->location();
254 m_impl.linestring_add_location(m_projection(last_location));
255 ++num_points;
256 }
257 }
258 return num_points;
259 }
260
262 return m_impl.linestring_finish(num_points);
263 }
264
267 size_t num_points = 0;
268
269 if (un == use_nodes::unique) {
270 switch (dir) {
272 num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
273 break;
275 num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
276 break;
277 }
278 } else {
279 switch (dir) {
281 num_points = fill_linestring(wnl.cbegin(), wnl.cend());
282 break;
284 num_points = fill_linestring(wnl.crbegin(), wnl.crend());
285 break;
286 }
287 }
288
289 if (num_points < 2) {
290 throw osmium::geometry_error{"need at least two points for linestring"};
291 }
292
293 return linestring_finish(num_points);
294 }
295
297 try {
298 return create_linestring(way.nodes(), un, dir);
299 } catch (osmium::geometry_error& e) {
300 e.set_id("way", way.id());
301 throw;
302 }
303 }
304
305 /* Polygon */
306
308 m_impl.polygon_start();
309 }
310
311 template <typename TIter>
312 size_t fill_polygon(TIter it, TIter end) {
313 size_t num_points = 0;
314 for (; it != end; ++it, ++num_points) {
315 m_impl.polygon_add_location(m_projection(it->location()));
316 }
317 return num_points;
318 }
319
320 template <typename TIter>
321 size_t fill_polygon_unique(TIter it, TIter end) {
322 size_t num_points = 0;
323 osmium::Location last_location;
324 for (; it != end; ++it) {
325 if (last_location != it->location()) {
326 last_location = it->location();
327 m_impl.polygon_add_location(m_projection(last_location));
328 ++num_points;
329 }
330 }
331 return num_points;
332 }
333
334 polygon_type polygon_finish(size_t num_points) {
335 return m_impl.polygon_finish(num_points);
336 }
337
340 size_t num_points = 0;
341
342 if (un == use_nodes::unique) {
343 switch (dir) {
345 num_points = fill_polygon_unique(wnl.cbegin(), wnl.cend());
346 break;
348 num_points = fill_polygon_unique(wnl.crbegin(), wnl.crend());
349 break;
350 }
351 } else {
352 switch (dir) {
354 num_points = fill_polygon(wnl.cbegin(), wnl.cend());
355 break;
357 num_points = fill_polygon(wnl.crbegin(), wnl.crend());
358 break;
359 }
360 }
361
362 if (num_points < 4) {
363 throw osmium::geometry_error{"need at least four points for polygon"};
364 }
365
366 return polygon_finish(num_points);
367 }
368
370 try {
371 return create_polygon(way.nodes(), un, dir);
372 } catch (osmium::geometry_error& e) {
373 e.set_id("way", way.id());
374 throw;
375 }
376 }
377
378 /* MultiPolygon */
379
381 try {
382 size_t num_polygons = 0;
383 size_t num_rings = 0;
384 m_impl.multipolygon_start();
385
386 for (const auto& item : area) {
387 if (item.type() == osmium::item_type::outer_ring) {
388 const auto& ring = static_cast<const osmium::OuterRing&>(item);
389 if (num_polygons > 0) {
390 m_impl.multipolygon_polygon_finish();
391 }
392 m_impl.multipolygon_polygon_start();
393 m_impl.multipolygon_outer_ring_start();
394 add_points(ring);
395 m_impl.multipolygon_outer_ring_finish();
396 ++num_rings;
397 ++num_polygons;
398 } else if (item.type() == osmium::item_type::inner_ring) {
399 const auto& ring = static_cast<const osmium::InnerRing&>(item);
400 m_impl.multipolygon_inner_ring_start();
401 add_points(ring);
402 m_impl.multipolygon_inner_ring_finish();
403 ++num_rings;
404 }
405 }
406
407 // if there are no rings, this area is invalid
408 if (num_rings == 0) {
409 throw osmium::geometry_error{"invalid area"};
410 }
411
412 m_impl.multipolygon_polygon_finish();
413 return m_impl.multipolygon_finish();
414 } catch (osmium::geometry_error& e) {
415 e.set_id("area", area.id());
416 throw;
417 }
418 }
419
420 }; // class GeometryFactory
421
422 } // namespace geom
423
424} // namespace osmium
425
426#endif // OSMIUM_GEOM_FACTORY_HPP
Definition: area.hpp:126
Definition: area.hpp:81
Definition: location.hpp:271
double lon() const
Definition: location.hpp:396
double lat() const
Definition: location.hpp:415
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:61
Definition: way.hpp:55
Definition: way.hpp:72
Definition: factory.hpp:148
multipolygon_type create_multipolygon(const osmium::Area &area)
Definition: factory.hpp:380
typename TGeomImpl::multipolygon_type multipolygon_type
Definition: factory.hpp:197
void linestring_start()
Definition: factory.hpp:234
size_t fill_polygon(TIter it, TIter end)
Definition: factory.hpp:312
typename TGeomImpl::point_type point_type
Definition: factory.hpp:194
point_type create_point(const osmium::Node &node)
Definition: factory.hpp:214
TGeomImpl m_impl
Definition: factory.hpp:164
size_t fill_linestring(TIter it, TIter end)
Definition: factory.hpp:239
void polygon_start()
Definition: factory.hpp:307
size_t fill_polygon_unique(TIter it, TIter end)
Definition: factory.hpp:321
linestring_type create_linestring(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:296
polygon_type create_polygon(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:338
typename TGeomImpl::polygon_type polygon_type
Definition: factory.hpp:196
int epsg() const noexcept
Definition: factory.hpp:200
point_type create_point(const osmium::NodeRef &node_ref)
Definition: factory.hpp:223
TProjection projection_type
Definition: factory.hpp:192
TProjection m_projection
Definition: factory.hpp:163
point_type create_point(const osmium::Location &location) const
Definition: factory.hpp:210
polygon_type create_polygon(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:369
size_t fill_linestring_unique(TIter it, TIter end)
Definition: factory.hpp:248
linestring_type create_linestring(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:265
linestring_type linestring_finish(size_t num_points)
Definition: factory.hpp:261
typename TGeomImpl::linestring_type linestring_type
Definition: factory.hpp:195
std::string proj_string() const
Definition: factory.hpp:204
polygon_type polygon_finish(size_t num_points)
Definition: factory.hpp:334
typename TGeomImpl::ring_type ring_type
Definition: factory.hpp:198
void add_points(const osmium::NodeRefList &nodes)
Definition: factory.hpp:153
Definition: factory.hpp:126
static std::string proj_string() noexcept
Definition: factory.hpp:138
Coordinates operator()(osmium::Location location) const
Definition: factory.hpp:130
static int epsg() noexcept
Definition: factory.hpp:134
Definition: factory.hpp:59
void set_id(const char *object_type, osmium::object_id_type id)
Definition: factory.hpp:79
const char * what() const noexcept override
Definition: factory.hpp:94
osmium::object_id_type id() const noexcept
Definition: factory.hpp:90
std::string m_message
Definition: factory.hpp:61
osmium::object_id_type m_id
Definition: factory.hpp:62
geometry_error(const std::string &message, const char *object_type="", osmium::object_id_type id=0)
Definition: factory.hpp:66
use_nodes
Definition: factory.hpp:108
@ unique
Remove consecutive nodes with same location.
@ all
Use all nodes.
direction
Definition: factory.hpp:117
@ backward
Linestring has reverse direction.
@ forward
Linestring has same direction as way.
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:551
Definition: coordinates.hpp:48