1#pragma once
2
3#include <mapbox/geojson.hpp>
4#include <mapbox/geojson/rapidjson.hpp>
5
6#include <rapidjson/document.h>
7#include <rapidjson/writer.h>
8#include <rapidjson/stringbuffer.h>
9#include <rapidjson/error/en.h>
10
11#include <sstream>
12
13namespace mapbox {
14namespace geojson {
15
16using error = std::runtime_error;
17using prop_map = std::unordered_map<std::string, value>;
18
19template <typename T>
20T convert(const rapidjson_value &json);
21
22template <>
23point convert<point>(const rapidjson_value &json) {
24 if (json.Size() < 2)
25 throw error("coordinates array must have at least 2 numbers");
26
27 return point{ json[0].GetDouble(), json[1].GetDouble() };
28}
29
30template <typename Cont>
31Cont convert(const rapidjson_value &json) {
32 Cont points;
33 auto size = json.Size();
34 points.reserve(size);
35
36 for (auto &element : json.GetArray()) {
37 points.push_back(convert<typename Cont::value_type>(element));
38 }
39 return points;
40}
41
42template <>
43geometry convert<geometry>(const rapidjson_value &json) {
44 if (!json.IsObject())
45 throw error("Geometry must be an object");
46
47 const auto &json_end = json.MemberEnd();
48
49 const auto &type_itr = json.FindMember(name: "type");
50 if (type_itr == json_end)
51 throw error("Geometry must have a type property");
52
53 const auto &type = type_itr->value;
54
55 if (type == "GeometryCollection") {
56 const auto &geometries_itr = json.FindMember(name: "geometries");
57 if (geometries_itr == json_end)
58 throw error("GeometryCollection must have a geometries property");
59
60 const auto &json_geometries = geometries_itr->value;
61
62 if (!json_geometries.IsArray())
63 throw error("GeometryCollection geometries property must be an array");
64
65 return geometry{ convert<geometry_collection>(json: json_geometries) };
66 }
67
68 const auto &coords_itr = json.FindMember(name: "coordinates");
69
70 if (coords_itr == json_end)
71 throw error(std::string(type.GetString()) + " geometry must have a coordinates property");
72
73 const auto &json_coords = coords_itr->value;
74 if (!json_coords.IsArray())
75 throw error("coordinates property must be an array");
76
77 if (type == "Point")
78 return geometry{ convert<point>(json: json_coords) };
79 if (type == "MultiPoint")
80 return geometry{ convert<multi_point>(json: json_coords) };
81 if (type == "LineString")
82 return geometry{ convert<line_string>(json: json_coords) };
83 if (type == "MultiLineString")
84 return geometry{ convert<multi_line_string>(json: json_coords) };
85 if (type == "Polygon")
86 return geometry{ convert<polygon>(json: json_coords) };
87 if (type == "MultiPolygon")
88 return geometry{ convert<multi_polygon>(json: json_coords) };
89
90 throw error(std::string(type.GetString()) + " not yet implemented");
91}
92
93template <>
94value convert<value>(const rapidjson_value &json);
95
96template <>
97prop_map convert(const rapidjson_value &json) {
98 if (!json.IsObject())
99 throw error("properties must be an object");
100
101 prop_map result;
102 for (auto &member : json.GetObject()) {
103 result.emplace(args: std::string(member.name.GetString(), member.name.GetStringLength()),
104 args: convert<value>(json: member.value));
105 }
106 return result;
107}
108
109template <>
110value convert<value>(const rapidjson_value &json) {
111 switch (json.GetType()) {
112 case rapidjson::kNullType:
113 return ::mapbox::geometry::null_value_t{};
114 case rapidjson::kFalseType:
115 return false;
116 case rapidjson::kTrueType:
117 return true;
118 case rapidjson::kObjectType:
119 return convert<prop_map>(json);
120 case rapidjson::kArrayType:
121 return convert<std::vector<value>>(json);
122 case rapidjson::kStringType:
123 return std::string(json.GetString(), json.GetStringLength());
124 default:
125 assert(json.GetType() == rapidjson::kNumberType);
126 if (json.IsUint64())
127 return std::uint64_t(json.GetUint64());
128 if (json.IsInt64())
129 return std::int64_t(json.GetInt64());
130 return json.GetDouble();
131 }
132}
133
134template <>
135identifier convert<identifier>(const rapidjson_value &json) {
136 switch (json.GetType()) {
137 case rapidjson::kStringType:
138 return std::string(json.GetString(), json.GetStringLength());
139 case rapidjson::kNumberType:
140 if (json.IsUint64())
141 return std::uint64_t(json.GetUint64());
142 if (json.IsInt64())
143 return std::int64_t(json.GetInt64());
144 return json.GetDouble();
145 default:
146 throw error("Feature id must be a string or number");
147 }
148}
149
150template <>
151feature convert<feature>(const rapidjson_value &json) {
152 if (!json.IsObject())
153 throw error("Feature must be an object");
154
155 auto const &json_end = json.MemberEnd();
156 auto const &type_itr = json.FindMember(name: "type");
157
158 if (type_itr == json_end)
159 throw error("Feature must have a type property");
160 if (type_itr->value != "Feature")
161 throw error("Feature type must be Feature");
162
163 auto const &geom_itr = json.FindMember(name: "geometry");
164
165 if (geom_itr == json_end)
166 throw error("Feature must have a geometry property");
167
168 feature result{ convert<geometry>(json: geom_itr->value) };
169
170 auto const &id_itr = json.FindMember(name: "id");
171 if (id_itr != json_end) {
172 result.id = convert<identifier>(json: id_itr->value);
173 }
174
175 auto const &prop_itr = json.FindMember(name: "properties");
176 if (prop_itr != json_end) {
177 const auto &json_props = prop_itr->value;
178 if (!json_props.IsNull()) {
179 result.properties = convert<prop_map>(json: json_props);
180 }
181 }
182
183 return result;
184}
185
186template <>
187geojson convert<geojson>(const rapidjson_value &json) {
188 if (!json.IsObject())
189 throw error("GeoJSON must be an object");
190
191 const auto &type_itr = json.FindMember(name: "type");
192 const auto &json_end = json.MemberEnd();
193
194 if (type_itr == json_end)
195 throw error("GeoJSON must have a type property");
196
197 const auto &type = type_itr->value;
198
199 if (type == "FeatureCollection") {
200 const auto &features_itr = json.FindMember(name: "features");
201 if (features_itr == json_end)
202 throw error("FeatureCollection must have features property");
203
204 const auto &json_features = features_itr->value;
205
206 if (!json_features.IsArray())
207 throw error("FeatureCollection features property must be an array");
208
209 feature_collection collection;
210
211 const auto &size = json_features.Size();
212 collection.reserve(n: size);
213
214 for (auto &feature_obj : json_features.GetArray()) {
215 collection.push_back(x: convert<feature>(json: feature_obj));
216 }
217
218 return geojson{ collection };
219 }
220
221 if (type == "Feature")
222 return geojson{ convert<feature>(json) };
223
224 return geojson{ convert<geometry>(json) };
225}
226
227template <class T>
228T parse(const std::string &json) {
229 rapidjson_document d;
230 d.Parse(str: json.c_str());
231 if (d.HasParseError()) {
232 std::stringstream message;
233 message << d.GetErrorOffset() << " - " << rapidjson::GetParseError_En(parseErrorCode: d.GetParseError());
234 throw error(message.str());
235 }
236 return convert<T>(d);
237}
238
239template <>
240geometry parse<geometry>(const std::string &);
241template <>
242feature parse<feature>(const std::string &);
243template <>
244feature_collection parse<feature_collection>(const std::string &);
245
246geojson parse(const std::string &json) {
247 return parse<geojson>(json);
248}
249
250geojson convert(const rapidjson_value &json) {
251 return convert<geojson>(json);
252}
253
254template <>
255rapidjson_value convert<geometry>(const geometry&, rapidjson_allocator&);
256
257template <>
258rapidjson_value convert<feature>(const feature&, rapidjson_allocator&);
259
260template <>
261rapidjson_value convert<feature_collection>(const feature_collection&, rapidjson_allocator&);
262
263struct to_type {
264public:
265 const char * operator()(const point&) {
266 return "Point";
267 }
268
269 const char * operator()(const line_string&) {
270 return "LineString";
271 }
272
273 const char * operator()(const polygon&) {
274 return "Polygon";
275 }
276
277 const char * operator()(const multi_point&) {
278 return "MultiPoint";
279 }
280
281 const char * operator()(const multi_line_string&) {
282 return "MultiLineString";
283 }
284
285 const char * operator()(const multi_polygon&) {
286 return "MultiPolygon";
287 }
288
289 const char * operator()(const geometry_collection&) {
290 return "GeometryCollection";
291 }
292};
293
294struct to_coordinates_or_geometries {
295 rapidjson_allocator& allocator;
296
297 // Handles line_string, polygon, multi_point, multi_line_string, multi_polygon, and geometry_collection.
298 template <class E>
299 rapidjson_value operator()(const std::vector<E>& vector) {
300 rapidjson_value result;
301 result.SetArray();
302 for (std::size_t i = 0; i < vector.size(); ++i) {
303 result.PushBack(operator()(vector[i]), allocator);
304 }
305 return result;
306 }
307
308 rapidjson_value operator()(const point& element) {
309 rapidjson_value result;
310 result.SetArray();
311 result.PushBack(value: element.x, allocator);
312 result.PushBack(value: element.y, allocator);
313 return result;
314 }
315
316 rapidjson_value operator()(const geometry& element) {
317 return convert(element, allocator);
318 }
319};
320
321struct to_value {
322 rapidjson_allocator& allocator;
323
324 rapidjson_value operator()(null_value_t) {
325 rapidjson_value result;
326 result.SetNull();
327 return result;
328 }
329
330 rapidjson_value operator()(bool t) {
331 rapidjson_value result;
332 result.SetBool(t);
333 return result;
334 }
335
336 rapidjson_value operator()(int64_t t) {
337 rapidjson_value result;
338 result.SetInt64(t);
339 return result;
340 }
341
342 rapidjson_value operator()(uint64_t t) {
343 rapidjson_value result;
344 result.SetUint64(t);
345 return result;
346 }
347
348 rapidjson_value operator()(double t) {
349 rapidjson_value result;
350 result.SetDouble(t);
351 return result;
352 }
353
354 rapidjson_value operator()(const std::string& t) {
355 rapidjson_value result;
356 result.SetString(s: t.data(), length: rapidjson::SizeType(t.size()), allocator);
357 return result;
358 }
359
360 rapidjson_value operator()(const std::vector<value>& array) {
361 rapidjson_value result;
362 result.SetArray();
363 for (const auto& item : array) {
364 result.PushBack(value: value::visit(v: item, f&: *this), allocator);
365 }
366 return result;
367 }
368
369 rapidjson_value operator()(const std::unordered_map<std::string, value>& map) {
370 rapidjson_value result;
371 result.SetObject();
372 for (const auto& property : map) {
373 result.AddMember(
374 name: rapidjson::GenericStringRef<char> {
375 property.first.data(),
376 rapidjson::SizeType(property.first.size())
377 },
378 value: value::visit(v: property.second, f&: *this),
379 allocator);
380 }
381 return result;
382 }
383};
384
385template <>
386rapidjson_value convert<geometry>(const geometry& element, rapidjson_allocator& allocator) {
387 rapidjson_value result(rapidjson::kObjectType);
388
389 result.AddMember(
390 name: "type",
391 value: rapidjson::GenericStringRef<char> { geometry::visit(v: element, f: to_type()) },
392 allocator);
393
394 result.AddMember(
395 name: rapidjson::GenericStringRef<char> { element.is<geometry_collection>() ? "geometries" : "coordinates" },
396 value: geometry::visit(v: element, f: to_coordinates_or_geometries { .allocator: allocator }),
397 allocator);
398
399 return result;
400}
401
402template <>
403rapidjson_value convert<feature>(const feature& element, rapidjson_allocator& allocator) {
404 rapidjson_value result(rapidjson::kObjectType);
405 result.AddMember(name: "type", value: "Feature", allocator);
406
407 if (element.id) {
408 result.AddMember(name: "id", value: identifier::visit(v: *element.id, f: to_value { .allocator: allocator }), allocator);
409 }
410
411 result.AddMember(name: "geometry", value: convert(element: element.geometry, allocator), allocator);
412 result.AddMember(name: "properties", value: to_value { .allocator: allocator }(element.properties), allocator);
413
414 return result;
415}
416
417template <>
418rapidjson_value convert<feature_collection>(const feature_collection& collection, rapidjson_allocator& allocator) {
419 rapidjson_value result(rapidjson::kObjectType);
420 result.AddMember(name: "type", value: "FeatureCollection", allocator);
421
422 rapidjson_value features(rapidjson::kArrayType);
423 for (const auto& element : collection) {
424 features.PushBack(value: convert(element, allocator), allocator);
425 }
426 result.AddMember(name: "features", value&: features, allocator);
427
428 return result;
429}
430
431rapidjson_value convert(const geojson& element, rapidjson_allocator& allocator) {
432 return geojson::visit(v: element, f: [&] (const auto& alternative) {
433 return convert(alternative, allocator);
434 });
435}
436
437template <class T>
438std::string stringify(const T& t) {
439 rapidjson_allocator allocator;
440 rapidjson::StringBuffer buffer;
441 rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
442 convert(t, allocator).Accept(writer);
443 return buffer.GetString();
444}
445
446std::string stringify(const geojson& element) {
447 return geojson::visit(v: element, f: [] (const auto& alternative) {
448 return stringify(alternative);
449 });
450}
451
452} // namespace geojson
453} // namespace mapbox
454

source code of qtlocation/src/3rdparty/mapbox-gl-native/deps/geojson/0.4.2/include/mapbox/geojson_impl.hpp