Libosmium  2.20.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
6This file is part of Osmium (https://osmcode.org/libosmium).
7
8Copyright 2013-2023 Jochen Topf <jochen@topf.org> and others (see README).
9
10Boost Software License - Version 1.0 - August 17th, 2003
11
12Permission is hereby granted, free of charge, to any person or organization
13obtaining a copy of the software and accompanying documentation covered by
14this license (the "Software") to use, reproduce, display, distribute,
15execute, and transmit the Software, and to prepare derivative works of the
16Software, and to permit third-parties to whom the Software is furnished to
17do so, all subject to the following:
18
19The copyright notices in the Software and this entire statement, including
20the above license grant, this restriction and the following disclaimer,
21must be included in all copies of the Software, in whole or in part, and
22all derivative works of the Software, unless such copies or derivative
23works are solely in the form of machine-executable object code generated by
24a source language processor.
25
26THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32DEALINGS IN THE SOFTWARE.
33
34*/
35
39
40#include <algorithm>
41#include <cstddef>
42#include <cstdint>
43#include <string>
44
45namespace osmium {
46
47 namespace geom {
48
49 enum class wkb_type : bool {
50 wkb = false,
51 ewkb = true
52 }; // enum class wkb_type
53
54 enum class out_type : bool {
55 binary = false,
56 hex = true
57 }; // enum class out_type
58
59 namespace detail {
60
61 template <typename T>
62 inline void str_push(std::string& str, T data) {
63 str.append(reinterpret_cast<const char*>(&data), sizeof(T));
64 }
65
66 inline std::string convert_to_hex(const std::string& str) {
67 static const char* lookup_hex = "0123456789ABCDEF";
68 std::string out;
69 out.reserve(str.size() * 2);
70
71 for (const char c : str) {
72 out += lookup_hex[(static_cast<unsigned int>(c) >> 4U) & 0xfU];
73 out += lookup_hex[ static_cast<unsigned int>(c) & 0xfU];
74 }
75
76 return out;
77 }
78
79 class WKBFactoryImpl {
80
88 enum wkbGeometryType : uint32_t {
89 wkbPoint = 1,
90 wkbLineString = 2,
91 wkbPolygon = 3,
92 wkbMultiPoint = 4,
93 wkbMultiLineString = 5,
94 wkbMultiPolygon = 6,
95 wkbGeometryCollection = 7,
96
97 // SRID-presence flag (EWKB)
98 wkbSRID = 0x20000000
99 }; // enum wkbGeometryType
100
104 enum class wkb_byte_order_type : uint8_t {
105 XDR = 0, // Big Endian
106 NDR = 1 // Little Endian
107 }; // enum class wkb_byte_order_type
108
109 std::string m_data;
110 uint32_t m_points = 0;
111 int m_srid;
112 wkb_type m_wkb_type;
113 out_type m_out_type;
114
115 std::size_t m_linestring_size_offset = 0;
116 std::size_t m_polygons = 0;
117 std::size_t m_rings = 0;
118 std::size_t m_multipolygon_size_offset = 0;
119 std::size_t m_polygon_size_offset = 0;
120 std::size_t m_ring_size_offset = 0;
121
122 std::size_t header(std::string& str, wkbGeometryType type, bool add_length) const {
123#if __BYTE_ORDER == __LITTLE_ENDIAN
124 str_push(str, wkb_byte_order_type::NDR);
125#else
126 str_push(str, wkb_byte_order_type::XDR);
127#endif
128 if (m_wkb_type == wkb_type::ewkb) {
129 str_push(str, type | wkbSRID);
130 str_push(str, m_srid);
131 } else {
132 str_push(str, type);
133 }
134 const std::size_t offset = str.size();
135 if (add_length) {
136 str_push(str, static_cast<uint32_t>(0));
137 }
138 return offset;
139 }
140
141 void set_size(const std::size_t offset, const std::size_t size) {
142 if (size > std::numeric_limits<uint32_t>::max()) {
143 throw geometry_error{"Too many points in geometry"};
144 }
145 const auto s = static_cast<uint32_t>(size);
146 std::copy_n(reinterpret_cast<const char*>(&s), sizeof(uint32_t), &m_data[offset]);
147 }
148
149 public:
150
151 using point_type = std::string;
152 using linestring_type = std::string;
153 using polygon_type = std::string;
154 using multipolygon_type = std::string;
155 using ring_type = std::string;
156
157 explicit WKBFactoryImpl(int srid, wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
158 m_srid(srid),
159 m_wkb_type(wtype),
160 m_out_type(otype) {
161 }
162
163 /* Point */
164
165 point_type make_point(const osmium::geom::Coordinates& xy) const {
166 std::string data;
167 header(data, wkbPoint, false);
168 str_push(data, xy.x);
169 str_push(data, xy.y);
170
171 if (m_out_type == out_type::hex) {
172 return convert_to_hex(data);
173 }
174
175 return data;
176 }
177
178 /* LineString */
179
180 void linestring_start() {
181 m_data.clear();
182 m_linestring_size_offset = header(m_data, wkbLineString, true);
183 }
184
185 void linestring_add_location(const osmium::geom::Coordinates& xy) {
186 str_push(m_data, xy.x);
187 str_push(m_data, xy.y);
188 }
189
190 linestring_type linestring_finish(std::size_t num_points) {
191 set_size(m_linestring_size_offset, num_points);
192 std::string data;
193
194 using std::swap;
195 swap(data, m_data);
196
197 if (m_out_type == out_type::hex) {
198 return convert_to_hex(data);
199 }
200
201 return data;
202 }
203
204 /* Polygon */
205
206 void polygon_start() {
207 m_data.clear();
208 set_size(header(m_data, wkbPolygon, true), 1);
209 m_ring_size_offset = m_data.size();
210 str_push(m_data, static_cast<uint32_t>(0));
211 }
212
213 void polygon_add_location(const osmium::geom::Coordinates& xy) {
214 str_push(m_data, xy.x);
215 str_push(m_data, xy.y);
216 }
217
218 polygon_type polygon_finish(std::size_t num_points) {
219 set_size(m_ring_size_offset, num_points);
220 std::string data;
221
222 using std::swap;
223 swap(data, m_data);
224
225 if (m_out_type == out_type::hex) {
226 return convert_to_hex(data);
227 }
228
229 return data;
230 }
231
232 /* MultiPolygon */
233
234 void multipolygon_start() {
235 m_data.clear();
236 m_polygons = 0;
237 m_multipolygon_size_offset = header(m_data, wkbMultiPolygon, true);
238 }
239
240 void multipolygon_polygon_start() {
241 ++m_polygons;
242 m_rings = 0;
243 m_polygon_size_offset = header(m_data, wkbPolygon, true);
244 }
245
246 void multipolygon_polygon_finish() {
247 set_size(m_polygon_size_offset, m_rings);
248 }
249
250 void multipolygon_outer_ring_start() {
251 ++m_rings;
252 m_points = 0;
253 m_ring_size_offset = m_data.size();
254 str_push(m_data, static_cast<uint32_t>(0));
255 }
256
257 void multipolygon_outer_ring_finish() {
258 set_size(m_ring_size_offset, m_points);
259 }
260
261 void multipolygon_inner_ring_start() {
262 ++m_rings;
263 m_points = 0;
264 m_ring_size_offset = m_data.size();
265 str_push(m_data, static_cast<uint32_t>(0));
266 }
267
268 void multipolygon_inner_ring_finish() {
269 set_size(m_ring_size_offset, m_points);
270 }
271
272 void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
273 str_push(m_data, xy.x);
274 str_push(m_data, xy.y);
275 ++m_points;
276 }
277
278 multipolygon_type multipolygon_finish() {
279 set_size(m_multipolygon_size_offset, m_polygons);
280 std::string data;
281
282 using std::swap;
283 swap(data, m_data);
284
285 if (m_out_type == out_type::hex) {
286 return convert_to_hex(data);
287 }
288
289 return data;
290 }
291
292 }; // class WKBFactoryImpl
293
294 } // namespace detail
295
296 template <typename TProjection = IdentityProjection>
298
299 } // namespace geom
300
301} // namespace osmium
302
303#endif // OSMIUM_GEOM_WKB_HPP
Definition: factory.hpp:149
Definition: attr.hpp:342
wkb_type
Definition: wkb.hpp:49
out_type
Definition: wkb.hpp:54
type
Definition: entity_bits.hpp:63
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
Definition: coordinates.hpp:48
double y
Definition: coordinates.hpp:51
double x
Definition: coordinates.hpp:50