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