Libosmium  2.2.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-2015 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  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  virtual 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 <class TGeomImpl, class 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 <class... TArgs>
171  m_projection(),
172  m_impl(std::forward<TArgs>(args)...) {
173  }
174 
179  template <class... TArgs>
180  GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
181  m_projection(std::move(projection)),
182  m_impl(std::forward<TArgs>(args)...) {
183  }
184 
185  typedef typename TGeomImpl::point_type point_type;
186  typedef typename TGeomImpl::linestring_type linestring_type;
187  typedef typename TGeomImpl::polygon_type polygon_type;
188  typedef typename TGeomImpl::multipolygon_type multipolygon_type;
189  typedef typename TGeomImpl::ring_type ring_type;
190 
191  int epsg() const {
192  return m_projection.epsg();
193  }
194 
195  std::string proj_string() const {
196  return m_projection.proj_string();
197  }
198 
199  /* Point */
200 
201  point_type create_point(const osmium::Location location) const {
202  return m_impl.make_point(m_projection(location));
203  }
204 
205  point_type create_point(const osmium::Node& node) {
206  try {
207  return create_point(node.location());
208  } catch (osmium::geometry_error& e) {
209  e.set_id("node", node.id());
210  throw;
211  }
212  }
213 
214  point_type create_point(const osmium::NodeRef& node_ref) {
215  try {
216  return create_point(node_ref.location());
217  } catch (osmium::geometry_error& e) {
218  e.set_id("node", node_ref.ref());
219  throw;
220  }
221  }
222 
223  /* LineString */
224 
226  m_impl.linestring_start();
227  }
228 
229  template <class TIter>
230  size_t fill_linestring(TIter it, TIter end) {
231  size_t num_points = 0;
232  for (; it != end; ++it, ++num_points) {
233  m_impl.linestring_add_location(m_projection(it->location()));
234  }
235  return num_points;
236  }
237 
238  template <class TIter>
239  size_t fill_linestring_unique(TIter it, TIter end) {
240  size_t num_points = 0;
241  osmium::Location last_location;
242  for (; it != end; ++it) {
243  if (last_location != it->location()) {
244  last_location = it->location();
245  m_impl.linestring_add_location(m_projection(last_location));
246  ++num_points;
247  }
248  }
249  return num_points;
250  }
251 
252  linestring_type linestring_finish(size_t num_points) {
253  return m_impl.linestring_finish(num_points);
254  }
255 
258  size_t num_points = 0;
259 
260  if (un == use_nodes::unique) {
261  osmium::Location last_location;
262  switch (dir) {
263  case direction::forward:
264  num_points = fill_linestring_unique(wnl.cbegin(), wnl.cend());
265  break;
266  case direction::backward:
267  num_points = fill_linestring_unique(wnl.crbegin(), wnl.crend());
268  break;
269  }
270  } else {
271  switch (dir) {
272  case direction::forward:
273  num_points = fill_linestring(wnl.cbegin(), wnl.cend());
274  break;
275  case direction::backward:
276  num_points = fill_linestring(wnl.crbegin(), wnl.crend());
277  break;
278  }
279  }
280 
281  if (num_points < 2) {
282  throw osmium::geometry_error("need at least two points for linestring");
283  }
284 
285  return linestring_finish(num_points);
286  }
287 
289  try {
290  return create_linestring(way.nodes(), un, dir);
291  } catch (osmium::geometry_error& e) {
292  e.set_id("way", way.id());
293  throw;
294  }
295  }
296 
297  /* Polygon */
298 
299  void polygon_start() {
300  m_impl.polygon_start();
301  }
302 
303  template <class TIter>
304  size_t fill_polygon(TIter it, TIter end) {
305  size_t num_points = 0;
306  for (; it != end; ++it, ++num_points) {
307  m_impl.polygon_add_location(m_projection(it->location()));
308  }
309  return num_points;
310  }
311 
312  template <class TIter>
313  size_t fill_polygon_unique(TIter it, TIter end) {
314  size_t num_points = 0;
315  osmium::Location last_location;
316  for (; it != end; ++it) {
317  if (last_location != it->location()) {
318  last_location = it->location();
319  m_impl.polygon_add_location(m_projection(last_location));
320  ++num_points;
321  }
322  }
323  return num_points;
324  }
325 
326  polygon_type polygon_finish(size_t num_points) {
327  return m_impl.polygon_finish(num_points);
328  }
329 
331  polygon_start();
332  size_t num_points = 0;
333 
334  if (un == use_nodes::unique) {
335  osmium::Location last_location;
336  switch (dir) {
337  case direction::forward:
338  num_points = fill_polygon_unique(wnl.cbegin(), wnl.cend());
339  break;
340  case direction::backward:
341  num_points = fill_polygon_unique(wnl.crbegin(), wnl.crend());
342  break;
343  }
344  } else {
345  switch (dir) {
346  case direction::forward:
347  num_points = fill_polygon(wnl.cbegin(), wnl.cend());
348  break;
349  case direction::backward:
350  num_points = fill_polygon(wnl.crbegin(), wnl.crend());
351  break;
352  }
353  }
354 
355  if (num_points < 4) {
356  throw osmium::geometry_error("need at least four points for polygon");
357  }
358 
359  return polygon_finish(num_points);
360  }
361 
363  try {
364  return create_polygon(way.nodes(), un, dir);
365  } catch (osmium::geometry_error& e) {
366  e.set_id("way", way.id());
367  throw;
368  }
369  }
370 
371  /* MultiPolygon */
372 
373  multipolygon_type create_multipolygon(const osmium::Area& area) {
374  try {
375  size_t num_polygons = 0;
376  size_t num_rings = 0;
377  m_impl.multipolygon_start();
378 
379  for (auto it = area.cbegin(); it != area.cend(); ++it) {
380  const osmium::OuterRing& ring = static_cast<const osmium::OuterRing&>(*it);
381  if (it->type() == osmium::item_type::outer_ring) {
382  if (num_polygons > 0) {
383  m_impl.multipolygon_polygon_finish();
384  }
385  m_impl.multipolygon_polygon_start();
386  m_impl.multipolygon_outer_ring_start();
387  add_points(ring);
388  m_impl.multipolygon_outer_ring_finish();
389  ++num_rings;
390  ++num_polygons;
391  } else if (it->type() == osmium::item_type::inner_ring) {
392  m_impl.multipolygon_inner_ring_start();
393  add_points(ring);
394  m_impl.multipolygon_inner_ring_finish();
395  ++num_rings;
396  }
397  }
398 
399  // if there are no rings, this area is invalid
400  if (num_rings == 0) {
401  throw osmium::geometry_error("area contains no rings");
402  }
403 
404  m_impl.multipolygon_polygon_finish();
405  return m_impl.multipolygon_finish();
406  } catch (osmium::geometry_error& e) {
407  e.set_id("area", area.id());
408  throw;
409  }
410  }
411 
412  }; // class GeometryFactory
413 
414  } // namespace geom
415 
416 } // namespace osmium
417 
418 #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:151
point_type create_point(const osmium::NodeRef &node_ref)
Definition: factory.hpp:214
linestring_type linestring_finish(size_t num_points)
Definition: factory.hpp:252
Definition: factory.hpp:146
const_reverse_iterator crbegin() const noexcept
Returns a reverse_iterator to the beginning.
Definition: node_ref_list.hpp:171
size_t fill_polygon_unique(TIter it, TIter end)
Definition: factory.hpp:313
Linestring has reverse direction.
point_type create_point(const osmium::Location location) const
Definition: factory.hpp:201
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
osmium::object_id_type ref() const noexcept
Definition: node_ref.hpp:62
TGeomImpl::ring_type ring_type
Definition: factory.hpp:189
const_iterator cend() const noexcept
Returns an iterator to the end.
Definition: node_ref_list.hpp:156
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:185
polygon_type create_polygon(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:362
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:55
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:256
TProjection m_projection
Definition: factory.hpp:161
void polygon_start()
Definition: factory.hpp:299
Definition: coordinates.hpp:47
size_t fill_linestring_unique(TIter it, TIter end)
Definition: factory.hpp:239
int epsg() const
Definition: factory.hpp:191
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:225
Definition: area.hpp:56
std::string proj_string() const
Definition: factory.hpp:195
osmium::object_id_type m_id
Definition: factory.hpp:60
TGeomImpl::multipolygon_type multipolygon_type
Definition: factory.hpp:188
Definition: location.hpp:79
osmium::Location & location() noexcept
Definition: node_ref.hpp:73
multipolygon_type create_multipolygon(const osmium::Area &area)
Definition: factory.hpp:373
size_t fill_linestring(TIter it, TIter end)
Definition: factory.hpp:230
polygon_type polygon_finish(size_t num_points)
Definition: factory.hpp:326
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:187
double lon() const
Definition: location.hpp:186
TGeomImpl::linestring_type linestring_type
Definition: factory.hpp:186
size_t fill_polygon(TIter it, TIter end)
Definition: factory.hpp:304
osmium::Location location() const noexcept
Definition: node.hpp:61
osmium::object_id_type id() const noexcept
Definition: factory.hpp:88
virtual const char * what() const noexceptoverride
Definition: factory.hpp:92
Definition: node.hpp:47
point_type create_point(const osmium::Node &node)
Definition: factory.hpp:205
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:176
linestring_type create_linestring(const osmium::Way &way, use_nodes un=use_nodes::unique, direction dir=direction::forward)
Definition: factory.hpp:288
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:330
Definition: factory.hpp:124