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