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