Libosmium  2.16.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 
6 This file is part of Osmium (https://osmcode.org/libosmium).
7 
8 Copyright 2013-2021 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>
47 
48 #include <cstddef>
49 #include <stdexcept>
50 #include <string>
51 #include <utility>
52 
53 namespace 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 
261  linestring_type linestring_finish(size_t num_points) {
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) {
271  case direction::forward:
272  num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
273  break;
274  case direction::backward:
275  num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
276  break;
277  }
278  } else {
279  switch (dir) {
280  case direction::forward:
281  num_points = fill_linestring(wnl.cbegin(), wnl.cend());
282  break;
283  case direction::backward:
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 
307  void polygon_start() {
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 
339  polygon_start();
340  size_t num_points = 0;
341 
342  if (un == use_nodes::unique) {
343  switch (dir) {
344  case direction::forward:
345  num_points = fill_polygon_unique(wnl.cbegin(), wnl.cend());
346  break;
347  case direction::backward:
348  num_points = fill_polygon_unique(wnl.crbegin(), wnl.crend());
349  break;
350  }
351  } else {
352  switch (dir) {
353  case direction::forward:
354  num_points = fill_polygon(wnl.cbegin(), wnl.cend());
355  break;
356  case direction::backward:
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
osmium::geom::IdentityProjection
Definition: factory.hpp:126
osmium::geometry_error::set_id
void set_id(const char *object_type, osmium::object_id_type id)
Definition: factory.hpp:79
osmium::osm_entity_bits::node
@ node
Definition: entity_bits.hpp:68
osmium::geom::direction::backward
@ backward
Linestring has reverse direction.
osmium::NodeRefList::crend
const_reverse_iterator crend() const noexcept
Returns a reverse_iterator to the end.
Definition: node_ref_list.hpp:234
osmium::geom::IdentityProjection::proj_string
static std::string proj_string() noexcept
Definition: factory.hpp:138
osmium::geom::GeometryFactory::polygon_start
void polygon_start()
Definition: factory.hpp:307
osmium::NodeRefList::crbegin
const_reverse_iterator crbegin() const noexcept
Returns a reverse_iterator to the beginning.
Definition: node_ref_list.hpp:229
item.hpp
osmium::item_type::outer_ring
@ outer_ring
osmium::geom::use_nodes
use_nodes
Definition: factory.hpp:108
osmium::geom::GeometryFactory::ring_type
typename TGeomImpl::ring_type ring_type
Definition: factory.hpp:198
osmium::geometry_error::what
const char * what() const noexcept override
Definition: factory.hpp:94
node_ref_list.hpp
osmium::NodeRefList::cend
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: node_ref_list.hpp:214
osmium::InnerRing
Definition: area.hpp:81
osmium::geometry_error
Definition: factory.hpp:59
types.hpp
node.hpp
osmium::object_id_type
int64_t object_id_type
Type for OSM object (node, way, or relation) IDs.
Definition: types.hpp:45
osmium::geometry_error::m_id
osmium::object_id_type m_id
Definition: factory.hpp:62
osmium::geom::GeometryFactory::linestring_start
void linestring_start()
Definition: factory.hpp:234
osmium::geom::GeometryFactory::linestring_type
typename TGeomImpl::linestring_type linestring_type
Definition: factory.hpp:195
osmium::Location::lon
double lon() const
Definition: location.hpp:396
osmium::geom::GeometryFactory::fill_linestring_unique
size_t fill_linestring_unique(TIter it, TIter end)
Definition: factory.hpp:248
osmium::geom::GeometryFactory::polygon_type
typename TGeomImpl::polygon_type polygon_type
Definition: factory.hpp:196
osmium::geom::GeometryFactory::proj_string
std::string proj_string() const
Definition: factory.hpp:204
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:296
osmium::Node
Definition: node.hpp:48
osmium::geom::GeometryFactory::fill_polygon
size_t fill_polygon(TIter it, TIter end)
Definition: factory.hpp:312
osmium::geom::use_nodes::unique
@ unique
Remove consecutive nodes with same location.
osmium::geom::GeometryFactory::create_multipolygon
multipolygon_type create_multipolygon(const osmium::Area &area)
Definition: factory.hpp:380
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:338
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:265
osmium::geom::GeometryFactory
Definition: factory.hpp:148
osmium::geom::GeometryFactory::create_point
point_type create_point(const osmium::NodeRef &node_ref)
Definition: factory.hpp:223
way.hpp
osmium::geom::GeometryFactory::add_points
void add_points(const osmium::NodeRefList &nodes)
Definition: factory.hpp:153
osmium::geom::GeometryFactory::m_impl
TGeomImpl m_impl
Definition: factory.hpp:164
osmium::NodeRef::location
osmium::Location & location() noexcept
Definition: node_ref.hpp:85
node_ref.hpp
osmium::geom::direction
direction
Definition: factory.hpp:117
osmium::Location::lat
double lat() const
Definition: location.hpp:415
osmium::NodeRefList
Definition: node_ref_list.hpp:52
osmium
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
osmium::geom::IdentityProjection::epsg
static int epsg() noexcept
Definition: factory.hpp:134
osmium::geometry_error::id
osmium::object_id_type id() const noexcept
Definition: factory.hpp:90
coordinates.hpp
osmium::osm_entity_bits::area
@ area
Definition: entity_bits.hpp:72
osmium::geom::Coordinates
Definition: coordinates.hpp:48
osmium::WayNodeList
Definition: way.hpp:55
osmium::geom::GeometryFactory::create_point
point_type create_point(const osmium::Location &location) const
Definition: factory.hpp:210
osmium::Way
Definition: way.hpp:72
collection.hpp
location.hpp
osmium::NodeRefList::cbegin
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition: node_ref_list.hpp:209
osmium::geom::GeometryFactory::create_point
point_type create_point(const osmium::Node &node)
Definition: factory.hpp:214
osmium::geom::GeometryFactory::fill_polygon_unique
size_t fill_polygon_unique(TIter it, TIter end)
Definition: factory.hpp:321
area.hpp
osmium::Location
Definition: location.hpp:271
osmium::geom::GeometryFactory::projection_type
TProjection projection_type
Definition: factory.hpp:192
std
Definition: location.hpp:551
osmium::Area
Definition: area.hpp:126
osmium::geom::GeometryFactory::point_type
typename TGeomImpl::point_type point_type
Definition: factory.hpp:194
osmium::osm_entity_bits::way
@ way
Definition: entity_bits.hpp:69
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:369
osmium::geom::GeometryFactory::polygon_finish
polygon_type polygon_finish(size_t num_points)
Definition: factory.hpp:334
osmium::geom::GeometryFactory::linestring_finish
linestring_type linestring_finish(size_t num_points)
Definition: factory.hpp:261
osmium::OuterRing
Definition: area.hpp:61
osmium::geom::use_nodes::all
@ all
Use all nodes.
osmium::geom::GeometryFactory::multipolygon_type
typename TGeomImpl::multipolygon_type multipolygon_type
Definition: factory.hpp:197
item_type.hpp
osmium::io::end
InputIterator< Reader > end(Reader &)
Definition: reader_iterator.hpp:47
osmium::NodeRef::ref
constexpr osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:71
osmium::geom::GeometryFactory::fill_linestring
size_t fill_linestring(TIter it, TIter end)
Definition: factory.hpp:239
osmium::geometry_error::geometry_error
geometry_error(const std::string &message, const char *object_type="", osmium::object_id_type id=0)
Definition: factory.hpp:66
osmium::NodeRef
Definition: node_ref.hpp:50
osmium::geom::IdentityProjection::operator()
Coordinates operator()(osmium::Location location) const
Definition: factory.hpp:130
osmium::geom::GeometryFactory::m_projection
TProjection m_projection
Definition: factory.hpp:163
osmium::geom::GeometryFactory::epsg
int epsg() const noexcept
Definition: factory.hpp:200
osmium::item_type::inner_ring
@ inner_ring
osmium::geometry_error::m_message
std::string m_message
Definition: factory.hpp:61