Libosmium  2.14.0
Fast and flexible C++ library for working with OpenStreetMap data
wkb.hpp
Go to the documentation of this file.
1 #ifndef OSMIUM_GEOM_WKB_HPP
2 #define OSMIUM_GEOM_WKB_HPP
3 
4 /*
5 
6 This file is part of Osmium (http://osmcode.org/libosmium).
7 
8 Copyright 2013-2018 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 
37 #include <osmium/geom/factory.hpp>
38 #include <osmium/util/cast.hpp>
39 #include <osmium/util/endian.hpp>
40 
41 #include <algorithm>
42 #include <cstddef>
43 #include <cstdint>
44 #include <string>
45 
46 namespace osmium {
47 
48  namespace geom {
49 
50  enum class wkb_type : bool {
51  wkb = false,
52  ewkb = true
53  }; // enum class wkb_type
54 
55  enum class out_type : bool {
56  binary = false,
57  hex = true
58  }; // enum class out_type
59 
60  namespace detail {
61 
62  template <typename T>
63  inline void str_push(std::string& str, T data) {
64  str.append(reinterpret_cast<const char*>(&data), sizeof(T));
65  }
66 
67  inline std::string convert_to_hex(const std::string& str) {
68  static const char* lookup_hex = "0123456789ABCDEF";
69  std::string out;
70  out.reserve(str.size() * 2);
71 
72  for (char c : str) {
73  out += lookup_hex[(static_cast<unsigned int>(c) >> 4u) & 0xfu];
74  out += lookup_hex[ static_cast<unsigned int>(c) & 0xfu];
75  }
76 
77  return out;
78  }
79 
80  class WKBFactoryImpl {
81 
89  enum wkbGeometryType : uint32_t {
90  wkbPoint = 1,
91  wkbLineString = 2,
92  wkbPolygon = 3,
93  wkbMultiPoint = 4,
94  wkbMultiLineString = 5,
95  wkbMultiPolygon = 6,
96  wkbGeometryCollection = 7,
97 
98  // SRID-presence flag (EWKB)
99  wkbSRID = 0x20000000
100  }; // enum wkbGeometryType
101 
105  enum class wkb_byte_order_type : uint8_t {
106  XDR = 0, // Big Endian
107  NDR = 1 // Little Endian
108  }; // enum class wkb_byte_order_type
109 
110  std::string m_data;
111  uint32_t m_points = 0;
112  int m_srid;
113  wkb_type m_wkb_type;
114  out_type m_out_type;
115 
116  std::size_t m_linestring_size_offset = 0;
117  std::size_t m_polygons = 0;
118  std::size_t m_rings = 0;
119  std::size_t m_multipolygon_size_offset = 0;
120  std::size_t m_polygon_size_offset = 0;
121  std::size_t m_ring_size_offset = 0;
122 
123  std::size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
124 #if __BYTE_ORDER == __LITTLE_ENDIAN
125  str_push(str, wkb_byte_order_type::NDR);
126 #else
127  str_push(str, wkb_byte_order_type::XDR);
128 #endif
129  if (m_wkb_type == wkb_type::ewkb) {
130  str_push(str, type | wkbSRID);
131  str_push(str, m_srid);
132  } else {
133  str_push(str, type);
134  }
135  const std::size_t offset = str.size();
136  if (add_length) {
137  str_push(str, static_cast<uint32_t>(0));
138  }
139  return offset;
140  }
141 
142  void set_size(const std::size_t offset, const std::size_t size) {
143  if (size > std::numeric_limits<uint32_t>::max()) {
144  throw geometry_error{"Too many points in geometry"};
145  }
146  const auto s = static_cast<uint32_t>(size);
147  std::copy_n(reinterpret_cast<const char*>(&s), sizeof(uint32_t), &m_data[offset]);
148  }
149 
150  public:
151 
152  using point_type = std::string;
153  using linestring_type = std::string;
154  using polygon_type = std::string;
155  using multipolygon_type = std::string;
156  using ring_type = std::string;
157 
158  explicit WKBFactoryImpl(int srid, wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
159  m_srid(srid),
160  m_wkb_type(wtype),
161  m_out_type(otype) {
162  }
163 
164  /* Point */
165 
166  point_type make_point(const osmium::geom::Coordinates& xy) const {
167  std::string data;
168  header(data, wkbPoint, false);
169  str_push(data, xy.x);
170  str_push(data, xy.y);
171 
172  if (m_out_type == out_type::hex) {
173  return convert_to_hex(data);
174  }
175 
176  return data;
177  }
178 
179  /* LineString */
180 
181  void linestring_start() {
182  m_data.clear();
183  m_linestring_size_offset = header(m_data, wkbLineString, true);
184  }
185 
186  void linestring_add_location(const osmium::geom::Coordinates& xy) {
187  str_push(m_data, xy.x);
188  str_push(m_data, xy.y);
189  }
190 
191  linestring_type linestring_finish(std::size_t num_points) {
192  set_size(m_linestring_size_offset, num_points);
193  std::string data;
194 
195  using std::swap;
196  swap(data, m_data);
197 
198  if (m_out_type == out_type::hex) {
199  return convert_to_hex(data);
200  }
201 
202  return data;
203  }
204 
205  /* MultiPolygon */
206 
207  void multipolygon_start() {
208  m_data.clear();
209  m_polygons = 0;
210  m_multipolygon_size_offset = header(m_data, wkbMultiPolygon, true);
211  }
212 
213  void multipolygon_polygon_start() {
214  ++m_polygons;
215  m_rings = 0;
216  m_polygon_size_offset = header(m_data, wkbPolygon, true);
217  }
218 
219  void multipolygon_polygon_finish() {
220  set_size(m_polygon_size_offset, m_rings);
221  }
222 
223  void multipolygon_outer_ring_start() {
224  ++m_rings;
225  m_points = 0;
226  m_ring_size_offset = m_data.size();
227  str_push(m_data, static_cast<uint32_t>(0));
228  }
229 
230  void multipolygon_outer_ring_finish() {
231  set_size(m_ring_size_offset, m_points);
232  }
233 
234  void multipolygon_inner_ring_start() {
235  ++m_rings;
236  m_points = 0;
237  m_ring_size_offset = m_data.size();
238  str_push(m_data, static_cast<uint32_t>(0));
239  }
240 
241  void multipolygon_inner_ring_finish() {
242  set_size(m_ring_size_offset, m_points);
243  }
244 
245  void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
246  str_push(m_data, xy.x);
247  str_push(m_data, xy.y);
248  ++m_points;
249  }
250 
251  multipolygon_type multipolygon_finish() {
252  set_size(m_multipolygon_size_offset, m_polygons);
253  std::string data;
254 
255  using std::swap;
256  swap(data, m_data);
257 
258  if (m_out_type == out_type::hex) {
259  return convert_to_hex(data);
260  }
261 
262  return data;
263  }
264 
265  }; // class WKBFactoryImpl
266 
267  } // namespace detail
268 
269  template <typename TProjection = IdentityProjection>
271 
272  } // namespace geom
273 
274 } // namespace osmium
275 
276 #endif // OSMIUM_GEOM_WKB_HPP
double y
Definition: coordinates.hpp:51
Definition: factory.hpp:148
type
Definition: entity_bits.hpp:63
void swap(Buffer &lhs, Buffer &rhs)
Definition: buffer.hpp:755
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
Definition: attr.hpp:333
Definition: coordinates.hpp:48
wkb_type
Definition: wkb.hpp:50
out_type
Definition: wkb.hpp:55
double x
Definition: coordinates.hpp:50