Libosmium  2.17.3
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 
6 This file is part of Osmium (https://osmcode.org/libosmium).
7 
8 Copyright 2013-2022 Jochen Topf <jochen@topf.org> and others (see README).
9 
10 Boost Software License - Version 1.0 - August 17th, 2003
11 
12 Permission is hereby granted, free of charge, to any person or organization
13 obtaining a copy of the software and accompanying documentation covered by
14 this license (the "Software") to use, reproduce, display, distribute,
15 execute, and transmit the Software, and to prepare derivative works of the
16 Software, and to permit third-parties to whom the Software is furnished to
17 do so, all subject to the following:
18 
19 The copyright notices in the Software and this entire statement, including
20 the above license grant, this restriction and the following disclaimer,
21 must be included in all copies of the Software, in whole or in part, and
22 all derivative works of the Software, unless such copies or derivative
23 works are solely in the form of machine-executable object code generated by
24 a source language processor.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 DEALINGS IN THE SOFTWARE.
33 
34 */
35 
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>
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 
54 namespace 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<TGeomImpl, TProjection>(TArgs&&... args) :
179  m_projection(),
180  m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
181  }
182 
187  template <typename... TArgs>
188  explicit GeometryFactory<TGeomImpl, TProjection>(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 
262  linestring_type linestring_finish(size_t num_points) {
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) {
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 
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 
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 
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:126
Definition: area.hpp:81
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
osmium::Location & location() noexcept
Definition: node_ref.hpp:85
constexpr osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:71
Definition: node.hpp:48
Definition: area.hpp:61
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
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
point_type create_point(const osmium::Location &location) const
Definition: factory.hpp:211
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:63
use_nodes
Definition: factory.hpp:109
@ unique
Remove consecutive nodes with same location.
@ all
Use all nodes.
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