Libosmium  2.13.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 (http://osmcode.org/libosmium).
7 
8 Copyright 2013-2017 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 
36 #include <cstddef>
37 #include <stdexcept>
38 #include <string>
39 #include <utility>
40 
43 #include <osmium/memory/item.hpp>
44 #include <osmium/osm/area.hpp>
45 #include <osmium/osm/item_type.hpp>
46 #include <osmium/osm/location.hpp>
47 #include <osmium/osm/node.hpp>
48 #include <osmium/osm/node_ref.hpp>
50 #include <osmium/osm/types.hpp>
51 #include <osmium/osm/way.hpp>
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  int epsg() const noexcept {
135  return 4326;
136  }
137 
138  std::string proj_string() const {
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(),
170  m_impl(m_projection.epsg()) {
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 
265  linestring_type create_linestring(const osmium::WayNodeList& wnl, use_nodes un = use_nodes::unique, direction dir = direction::forward) {
266  linestring_start();
267  size_t num_points = 0;
268 
269  if (un == use_nodes::unique) {
270  osmium::Location last_location;
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  osmium::Location last_location;
345  switch (dir) {
346  case direction::forward:
347  num_points = fill_polygon_unique(wnl.cbegin(), wnl.cend());
348  break;
349  case direction::backward:
350  num_points = fill_polygon_unique(wnl.crbegin(), wnl.crend());
351  break;
352  }
353  } else {
354  switch (dir) {
355  case direction::forward:
356  num_points = fill_polygon(wnl.cbegin(), wnl.cend());
357  break;
358  case direction::backward:
359  num_points = fill_polygon(wnl.crbegin(), wnl.crend());
360  break;
361  }
362  }
363 
364  if (num_points < 4) {
365  throw osmium::geometry_error{"need at least four points for polygon"};
366  }
367 
368  return polygon_finish(num_points);
369  }
370 
371  polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir = direction::forward) {
372  try {
373  return create_polygon(way.nodes(), un, dir);
374  } catch (osmium::geometry_error& e) {
375  e.set_id("way", way.id());
376  throw;
377  }
378  }
379 
380  /* MultiPolygon */
381 
383  try {
384  size_t num_polygons = 0;
385  size_t num_rings = 0;
386  m_impl.multipolygon_start();
387 
388  for (const auto& item : area) {
389  if (item.type() == osmium::item_type::outer_ring) {
390  auto& ring = static_cast<const osmium::OuterRing&>(item);
391  if (num_polygons > 0) {
392  m_impl.multipolygon_polygon_finish();
393  }
394  m_impl.multipolygon_polygon_start();
395  m_impl.multipolygon_outer_ring_start();
396  add_points(ring);
397  m_impl.multipolygon_outer_ring_finish();
398  ++num_rings;
399  ++num_polygons;
400  } else if (item.type() == osmium::item_type::inner_ring) {
401  auto& ring = static_cast<const osmium::InnerRing&>(item);
402  m_impl.multipolygon_inner_ring_start();
403  add_points(ring);
404  m_impl.multipolygon_inner_ring_finish();
405  ++num_rings;
406  }
407  }
408 
409  // if there are no rings, this area is invalid
410  if (num_rings == 0) {
411  throw osmium::geometry_error{"invalid area"};
412  }
413 
414  m_impl.multipolygon_polygon_finish();
415  return m_impl.multipolygon_finish();
416  } catch (osmium::geometry_error& e) {
417  e.set_id("area", area.id());
418  throw;
419  }
420  }
421 
422  }; // class GeometryFactory
423 
424  } // namespace geom
425 
426 } // namespace osmium
427 
428 #endif // OSMIUM_GEOM_FACTORY_HPP
WayNodeList & nodes()
Definition: way.hpp:89
typename TGeomImpl::ring_type ring_type
Definition: factory.hpp:198
const_iterator cbegin() const noexcept
Returns an iterator to the beginning.
Definition: node_ref_list.hpp:206
typename TGeomImpl::multipolygon_type multipolygon_type
Definition: factory.hpp:197
point_type create_point(const osmium::NodeRef &node_ref)
Definition: factory.hpp:223
linestring_type linestring_finish(size_t num_points)
Definition: factory.hpp:261
Definition: factory.hpp:148
double lon() const
Definition: location.hpp:401
const_reverse_iterator crbegin() const noexcept
Returns a reverse_iterator to the beginning.
Definition: node_ref_list.hpp:226
point_type create_point(const osmium::Location &location) const
Definition: factory.hpp:210
std::string proj_string() const
Definition: factory.hpp:204
size_t fill_polygon_unique(TIter it, TIter end)
Definition: factory.hpp:322
Linestring has reverse direction.
const char * what() const noexcept override
Definition: factory.hpp:94
Definition: area.hpp:126
double lat() const
Definition: location.hpp:420
Definition: reader_iterator.hpp:39
Definition: area.hpp:81
int epsg() const noexcept
Definition: factory.hpp:200
Definition: way.hpp:72
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: node_ref_list.hpp:211
int epsg() const noexcept
Definition: factory.hpp:134
Linestring has same direction as way.
Definition: factory.hpp:59
constexpr osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:65
polygon_type create_polygon(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:371
Definition: way.hpp:55
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
TGeomImpl m_impl
Definition: factory.hpp:164
linestring_type create_linestring(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:265
TProjection m_projection
Definition: factory.hpp:163
void polygon_start()
Definition: factory.hpp:308
std::string proj_string() const
Definition: factory.hpp:138
Definition: coordinates.hpp:48
void add_points(const osmium::NodeRefList &nodes)
Definition: factory.hpp:153
size_t fill_linestring_unique(TIter it, TIter end)
Definition: factory.hpp:248
osmium::io::InputIterator< osmium::io::Reader > end(osmium::io::Reader &)
Definition: reader_iterator.hpp:45
int64_t object_id_type
Type for OSM object (node, way, or relation) IDs.
Definition: types.hpp:45
Remove consecutive nodes with same location.
void linestring_start()
Definition: factory.hpp:234
Definition: area.hpp:61
typename TGeomImpl::linestring_type linestring_type
Definition: factory.hpp:195
osmium::object_id_type m_id
Definition: factory.hpp:62
Definition: location.hpp:273
osmium::Location & location() noexcept
Definition: node_ref.hpp:79
multipolygon_type create_multipolygon(const osmium::Area &area)
Definition: factory.hpp:382
size_t fill_linestring(TIter it, TIter end)
Definition: factory.hpp:239
polygon_type polygon_finish(size_t num_points)
Definition: factory.hpp:335
direction
Definition: factory.hpp:117
object_id_type id() const noexcept
Get ID of this object.
Definition: object.hpp:126
Coordinates operator()(osmium::Location location) const
Definition: factory.hpp:130
typename TGeomImpl::polygon_type polygon_type
Definition: factory.hpp:196
size_t fill_polygon(TIter it, TIter end)
Definition: factory.hpp:313
typename TGeomImpl::point_type point_type
Definition: factory.hpp:194
osmium::Location location() const noexcept
Definition: node.hpp:67
osmium::object_id_type id() const noexcept
Definition: factory.hpp:90
Definition: node.hpp:48
point_type create_point(const osmium::Node &node)
Definition: factory.hpp:214
use_nodes
Definition: factory.hpp:108
geometry_error(const std::string &message, const char *object_type="", osmium::object_id_type id=0)
Definition: factory.hpp:66
Definition: node_ref_list.hpp:52
std::string m_message
Definition: factory.hpp:61
Definition: node_ref.hpp:50
const_reverse_iterator crend() const noexcept
Returns a reverse_iterator to the end.
Definition: node_ref_list.hpp:231
linestring_type create_linestring(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:297
void set_id(const char *object_type, osmium::object_id_type id)
Definition: factory.hpp:79
polygon_type create_polygon(const osmium::WayNodeList &wnl, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:339
Definition: factory.hpp:126
TProjection projection_type
Definition: factory.hpp:192