Libosmium  2.16.0
Fast and flexible C++ library for working with OpenStreetMap data
geos.hpp
Go to the documentation of this file.
1 #ifndef OSMIUM_GEOM_GEOS_HPP
2 #define OSMIUM_GEOM_GEOS_HPP
3 
4 /*
5 
6 This file is part of Osmium (https://osmcode.org/libosmium).
7 
8 Copyright 2013-2021 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 <geos/version.h>
37 #if defined(GEOS_VERSION_MAJOR) && defined(GEOS_VERSION_MINOR) && (GEOS_VERSION_MAJOR < 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR <= 5))
38 
39 #define OSMIUM_WITH_GEOS
40 
56 #include <osmium/geom/factory.hpp>
58 
59 #include <geos/geom/Coordinate.h>
60 #include <geos/geom/CoordinateSequence.h>
61 #include <geos/geom/CoordinateSequenceFactory.h>
62 #include <geos/geom/GeometryFactory.h>
63 #include <geos/geom/LinearRing.h>
64 #include <geos/geom/MultiPolygon.h>
65 #include <geos/geom/Point.h>
66 #include <geos/geom/Polygon.h>
67 #include <geos/geom/PrecisionModel.h>
68 #include <geos/util/GEOSException.h>
69 
70 #include <algorithm>
71 #include <cassert>
72 #include <cstddef>
73 #include <iterator>
74 #include <memory>
75 #include <string>
76 #include <utility>
77 #include <vector>
78 
79 // MSVC doesn't support throw_with_nested yet
80 #ifdef _MSC_VER
81 # define THROW throw
82 #else
83 # include <exception>
84 # define THROW std::throw_with_nested
85 #endif
86 
87 namespace osmium {
88 
89  struct geos_geometry_error : public geometry_error {
90 
91  explicit geos_geometry_error(const char* message) :
92  geometry_error(std::string{"geometry creation failed in GEOS library: "} + message) {
93  }
94 
95  }; // struct geos_geometry_error
96 
97  namespace geom {
98 
99  namespace detail {
100 
102  class GEOSFactoryImpl {
103 
104  std::unique_ptr<const geos::geom::PrecisionModel> m_precision_model;
105  std::unique_ptr<geos::geom::GeometryFactory> m_our_geos_factory;
106  geos::geom::GeometryFactory* m_geos_factory;
107 
108  std::unique_ptr<geos::geom::CoordinateSequence> m_coordinate_sequence;
109  std::vector<std::unique_ptr<geos::geom::LinearRing>> m_rings;
110  std::vector<std::unique_ptr<geos::geom::Polygon>> m_polygons;
111 
112  public:
113 
114  using point_type = std::unique_ptr<geos::geom::Point>;
115  using linestring_type = std::unique_ptr<geos::geom::LineString>;
116  using polygon_type = std::unique_ptr<geos::geom::Polygon>;
117  using multipolygon_type = std::unique_ptr<geos::geom::MultiPolygon>;
118  using ring_type = std::unique_ptr<geos::geom::LinearRing>;
119 
120  explicit GEOSFactoryImpl(int /* srid */, geos::geom::GeometryFactory& geos_factory) :
121  m_precision_model(nullptr),
122  m_our_geos_factory(nullptr),
123  m_geos_factory(&geos_factory) {
124  }
125 
130  OSMIUM_DEPRECATED explicit GEOSFactoryImpl(int /* srid */, int srid) :
131  m_precision_model(new geos::geom::PrecisionModel),
132  m_our_geos_factory(new geos::geom::GeometryFactory{m_precision_model.get(), srid}),
133  m_geos_factory(m_our_geos_factory.get()) {
134  }
135 
136  explicit GEOSFactoryImpl(int srid) :
137  m_precision_model(new geos::geom::PrecisionModel),
138  m_our_geos_factory(new geos::geom::GeometryFactory{m_precision_model.get(), srid}),
139  m_geos_factory(m_our_geos_factory.get()) {
140  }
141 
142  /* Point */
143 
144  point_type make_point(const osmium::geom::Coordinates& xy) const {
145  try {
146  return point_type{m_geos_factory->createPoint(geos::geom::Coordinate{xy.x, xy.y})};
147  } catch (const geos::util::GEOSException& e) {
148  THROW(osmium::geos_geometry_error(e.what()));
149  }
150  }
151 
152  /* LineString */
153 
154  void linestring_start() {
155  try {
156  m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
157  } catch (const geos::util::GEOSException& e) {
158  THROW(osmium::geos_geometry_error(e.what()));
159  }
160  }
161 
162  void linestring_add_location(const osmium::geom::Coordinates& xy) {
163  try {
164  m_coordinate_sequence->add(geos::geom::Coordinate{xy.x, xy.y});
165  } catch (const geos::util::GEOSException& e) {
166  THROW(osmium::geos_geometry_error(e.what()));
167  }
168  }
169 
170  linestring_type linestring_finish(std::size_t /* num_points */) {
171  try {
172  return linestring_type{m_geos_factory->createLineString(m_coordinate_sequence.release())};
173  } catch (const geos::util::GEOSException& e) {
174  THROW(osmium::geos_geometry_error(e.what()));
175  }
176  }
177 
178  /* MultiPolygon */
179 
180  void multipolygon_start() {
181  m_polygons.clear();
182  }
183 
184  void multipolygon_polygon_start() {
185  m_rings.clear();
186  }
187 
188  void multipolygon_polygon_finish() {
189  try {
190  assert(!m_rings.empty());
191  auto inner_rings = new std::vector<geos::geom::Geometry*>;
192  std::transform(std::next(m_rings.begin(), 1), m_rings.end(), std::back_inserter(*inner_rings), [](std::unique_ptr<geos::geom::LinearRing>& r) {
193  return r.release();
194  });
195  m_polygons.emplace_back(m_geos_factory->createPolygon(m_rings[0].release(), inner_rings));
196  m_rings.clear();
197  } catch (const geos::util::GEOSException& e) {
198  THROW(osmium::geos_geometry_error(e.what()));
199  }
200  }
201 
202  void multipolygon_outer_ring_start() {
203  try {
204  m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
205  } catch (const geos::util::GEOSException& e) {
206  THROW(osmium::geos_geometry_error(e.what()));
207  }
208  }
209 
210  void multipolygon_outer_ring_finish() {
211  try {
212  m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
213  } catch (const geos::util::GEOSException& e) {
214  THROW(osmium::geos_geometry_error(e.what()));
215  }
216  }
217 
218  void multipolygon_inner_ring_start() {
219  try {
220  m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<std::size_t>(0), 2));
221  } catch (const geos::util::GEOSException& e) {
222  THROW(osmium::geos_geometry_error(e.what()));
223  }
224  }
225 
226  void multipolygon_inner_ring_finish() {
227  try {
228  m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
229  } catch (const geos::util::GEOSException& e) {
230  THROW(osmium::geos_geometry_error(e.what()));
231  }
232  }
233 
234  void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
235  try {
236  m_coordinate_sequence->add(geos::geom::Coordinate{xy.x, xy.y});
237  } catch (const geos::util::GEOSException& e) {
238  THROW(osmium::geos_geometry_error(e.what()));
239  }
240  }
241 
242  multipolygon_type multipolygon_finish() {
243  try {
244  auto polygons = new std::vector<geos::geom::Geometry*>;
245  std::transform(m_polygons.begin(), m_polygons.end(), std::back_inserter(*polygons), [](std::unique_ptr<geos::geom::Polygon>& p) {
246  return p.release();
247  });
248  m_polygons.clear();
249  return multipolygon_type{m_geos_factory->createMultiPolygon(polygons)};
250  } catch (const geos::util::GEOSException& e) {
251  THROW(osmium::geos_geometry_error(e.what()));
252  }
253  }
254 
255  }; // class GEOSFactoryImpl
256 
257  } // namespace detail
258 
260  template <typename TProjection = IdentityProjection>
261  using GEOSFactory = GeometryFactory<osmium::geom::detail::GEOSFactoryImpl, TProjection>;
262 
263  } // namespace geom
264 
265 } // namespace osmium
266 
267 #undef THROW
268 
269 #endif
270 
271 #endif // OSMIUM_GEOM_GEOS_HPP
#define OSMIUM_DEPRECATED
Definition: compatibility.hpp:51
Definition: attr.hpp:342
OSMIUM_DEPRECATED Coordinates transform(const CRS &src, const CRS &dest, Coordinates c)
Definition: projection.hpp:126
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
Definition: location.hpp:551
Definition: coordinates.hpp:48
double y
Definition: coordinates.hpp:51
double x
Definition: coordinates.hpp:50