1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Copyright (C) 2018 Julian Sherollari <jdotsh@gmail.com>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qgeojson_p.h"
42#include <qjsonobject.h>
43#include <qjsonvalue.h>
44#include <qjsonarray.h>
45#include <qgeocoordinate.h>
46#include <qgeocircle.h>
47#include <qgeopath.h>
48#include <qgeopolygon.h>
49#include <qtextstream.h>
50
51QT_BEGIN_NAMESPACE
52
53/*! \class QGeoJson
54 \inmodule QtLocation
55 \since 5.13
56
57 QGeoJson class can be used to convert between a GeoJSON document (see the
58 \l {https://en.wikipedia.org/wiki/GeoJSON} {Wikipedia page}, \l
59 {https://tools.ietf.org/html/rfc7946} {RFC}) and a \l
60 {http://doc.qt.io/qt-5/qvariant.html#QVariantList-typedef} {QVariantList}
61 of \l QVariantMap elements ready to be used as Model in a \l MapItemView.
62 WARNING! This private class is part of Qt labs, thus not stable API, it is
63 part of the experimental components of QtLocation. Until it is promoted to
64 public API, it may be subject to source and binary-breaking changes.
65
66 \section2 Importing GeoJSON
67
68 The importGeoJson() method accepts a \l
69 {http://doc.qt.io/qt-5/qjsondocument.html} {QJsonDocument} from which it
70 extracts a single \l {https://tools.ietf.org/html/rfc7159} {JSON} object,
71 since the GeoJSON RFC expects that a valid GeoJSON Document has in its root
72 a single JSON object. This method doesn't perform any validation on the
73 input. The importer returns a QVariantList containing a single QVariantMap.
74 This map has always at least 2 (key, value) pairs. The first one has \c
75 type as key, and the corresponding value is a string identifying the
76 GeoJSON type. This value can be one of the GeoJSON object types: \c Point,
77 \c MultiPoint, \c LineString, \c MultiLineString, \c Polygon, \c
78 MultiPolygon, \c GeometryCollection, \c FeatureCollection. The second pair
79 has \c data as key, and the corresponding value can be either a QGeoShape
80 or a list, depending on the GeoJSON type. The next section provides details
81 about this node. The \c Feature type is converted into the type of the
82 geometry contained within, with an additional (key, value) pair, where the
83 key is \c properties and the value is a \l QVariantMap. Thus, a feature Map
84 is distinguishable from the corresponding geometry, by looking for a \c
85 properties member.
86
87 \section3 Structure of the data node
88
89 For the single type geometry objects (\c Point, \c LineString, and \c
90 Polygon), the value corresponding to the \c data key is a QGeoShape:
91
92 \list
93 \li When the type is \c Point, the data is a QGeoCircle with the point
94 coordinates stored in the center property.
95
96 For example, the following GeoJSON document contains a \c Point
97 geometry:
98
99 \code
100 {
101 "type" : "Point",
102 "data" : [60.0, 11.0]
103 }
104 \endcode
105
106 it is converted to a QVariantMap with the following structure:
107
108 \code
109 {
110 type : Point
111 data : QGeoCircle({60.000, 11.000}, -1)
112 }
113 \endcode
114
115 \li When the type is \c LineString the data ia a QGeoPath.
116
117 For example, the following GeoJSON document contains a \c LineString
118 geometry:
119
120 \code
121 {
122 "type" : "LineString",
123 "coordinates" : [[13.5, 43],[10.73, 59.92]]
124 }
125 \endcode
126
127 it is converted to a QVariantMap with the following structure:
128
129 \code
130 {
131 type : LineString,
132 data : QGeoPath([{43.000, 13.500}, {59.920, 10.730}])
133 }
134 \endcode
135
136 \li When the type is \c Polygon, the data is a QGeoPolygon (holes are
137 supported).
138
139 For example, the following GeoJSON document contains a \c Polygon
140 geometry:
141
142 \code
143 {
144 "type" : "Polygon",
145 "coordinates" : [
146 [[17.13, 51.11],
147 [30.54, 50.42],
148 [26.70, 58.36],
149 [17.13, 51.11]]
150 ],
151 "bbox" : [60, 60, -60, -60]
152
153 }
154 \endcode
155
156 it is converted to a QVariantMap with the following structure:
157
158 \code
159 {
160 type : Polygon
161 data : QGeoPolygon([{51.110, 17.130}, {50.420,30.540}, {58.360, 26.700}, {51.110, 17.130}])
162 }
163 \endcode
164
165 \endlist
166
167 For the homogeneously typed multipart geometry objects (\c MultiPoint, \c
168 MultiLineString, \c MultiPolygon) the value corresponding to the \c data
169 key is a QVariantList. Each element of the list is a QVariantMap of one of
170 the above listed types. The elements in this list will be all of the same
171 GeoJSON type:
172
173 \list
174 \li When the type is \c MultiPoint, the data is a List of Points.
175
176 For example, the following GeoJSON document contains a \c MultiPoint
177 geometry:
178
179 \code
180 {
181 "type" : "MultiPoint",
182 "coordinates" : [
183 [11,60],
184 [5.5,60.3],
185 [5.7,58.90]
186 ]
187 }
188 \endcode
189
190 it is converted to a QVariantMap with the following structure:
191
192 \code
193 {
194 type : MultiPoint
195 data : [
196 {
197 type : Point
198 data : QGeoCircle({60.000, 11.000}, -1)
199 },
200 {
201 type : Point
202 data : QGeoCircle({60.300, 5.500}, -1)
203 },
204 {
205 type : Point
206 data : QGeoCircle({58.900, 5.700}, -1)
207 }
208 ]
209 }
210 \endcode
211
212 \li When the type is \c MultiLineString, the data is a List of LineStrings.
213
214 For example, the following GeoJSON document contains a \c MultiLineString
215 geometry:
216
217 \code
218 {
219 "type" : "MultiLineString",
220 "coordinates" : [
221 [[13.5, 43], [10.73, 59.92]],
222 [[9.15, 45], [-3.15, 58.90]]
223 ]
224 }
225 \endcode
226
227 it is converted to a QVariantMap with the following structure:
228
229 \code
230 {
231 type : MultiLineString
232 data : [
233 {
234 type : LineString
235 data : QGeoPath([{45.000, 9.150}, {58.900, -3.150}])
236 },
237 {
238 type : LineString
239 data : QGeoPath([{43.000, 13.500}, {59.920, 10.730}])
240 }
241 ]
242 }
243 \endcode
244
245 \li When the type is \c MultiPolygon, the data is a List of Polygons.
246
247 For example, the following GeoJSON document contains a \c MultiPolygon
248 geometry:
249
250 \code
251 {
252 "type" : "MultiPoint",
253 "coordinates" : [
254 [11,60],
255 [5.5,60.3],
256 [5.7,58.90]
257 ]
258 }
259 \endcode
260
261 it is converted to a QVariantMap with the following structure:
262
263 \code
264 {
265 type : MultiPoint
266 data : [
267 {
268 type : Point
269 data : QGeoCircle({60.000, 11.000}, -1)
270 },
271 {
272 type : Point
273 data : QGeoCircle({60.300, 5.500}, -1)
274 },
275 {
276 type : Point
277 data : QGeoCircle({58.900, 5.700}, -1)
278 }
279 ]
280 }
281 \endcode
282
283 \endlist
284
285 The \c GeometryCollection is a heterogeneous composition of other geometry
286 types. In the resulting QVariantMap, the value of the \c data member is a
287 QVariantList populated by QVariantMaps of various geometries, including the
288 GeometryCollection itself.
289
290 For example, the following \c GeometryCollection:
291
292 \code
293 {
294 "type" : "GeometryCollection",
295 "geometries" : [
296 {
297 "type" : "MultiPoint",
298 "coordinates" : [
299 [11,60], [5.5,60.3], [5.7,58.90]
300 ]
301 },
302 {
303 "type" : "MultiLineString",
304 "coordinates" : [
305 [[13.5, 43], [10.73, 59.92]],
306 [[9.15, 45], [-3.15, 58.90]]
307 ]
308 },
309 {
310 "type" : "MultiPolygon",
311 "coordinates" : [
312 [
313 [[17.13, 51.11],
314 [30.54, 50.42],
315 [26.74, 58.36],
316 [17.13, 51.11]]
317 ],
318 [
319 [[19.84, 41.33],
320 [30.45, 49.26],
321 [17.07, 50.10],
322 [19.84, 41.33]]
323 ]
324 ]
325 }
326 ]
327 }
328 \endcode
329
330 it is converted to a QVariantMap with the following structure:
331
332 \code
333 {
334 type : GeometryCollection
335 data : [
336 {
337 type : MultiPolygon
338 data : [
339 {
340 type : Polygon
341 data : QGeoPolygon([{41.330, 19.840}, {49.260, 30.450}, {50.100, 17.070}, {41.330, 19.840}])
342 }
343 {
344 type : Polygon
345 data : QGeoPolygon([{51.110, 17.130}, {50.420, 30.540}, {58.360, 26.740}, {51.110, 17.130}])
346 }
347 ]
348 }
349 {
350 type : MultiLineString
351 data : [
352 {
353 type : LineString
354 data : QGeoPath([{45.000, 9.150}, {58.900, -3.150}])
355 }
356 {
357 type : LineString
358 data : QGeoPath([{43.000, 13.500}, {59.920, 10.730}])
359 }
360 ]
361 }
362 {
363 type : MultiPoint
364 data : [
365 {
366 type : Point
367 data : QGeoCircle({58.900, 5.700}, -1)
368 },
369 {
370 type : Point
371 data : QGeoCircle({60.300, 5.500}, -1)
372 },
373 {
374 type : Point
375 data : QGeoCircle({60.000, 11.000}, -1)
376 }
377 ]
378 }
379 ]
380 }
381 \endcode
382
383 The \c Feature object, which consists of one of the previous geometries
384 together with related attributes, is structured like one of the 7 above
385 mentioned geometry types, plus a \c properties member. The value of this
386 member is a QVariantMap. The only way to distinguish a Feature from the
387 included geometry is to check if a \c properties node is present in the
388 QVariantMap.
389
390 For example, the following \c Feature:
391
392 \code
393 {
394 "type" : "Feature",
395 "id" : "Poly",
396 "properties" : {
397 "text" : "This is a Feature with a Polygon"
398 },
399 "geometry" : {
400 "type" : "Polygon",
401 "coordinates" : [
402 [[17.13, 51.11],
403 [30.54, 50.42],
404 [26.70, 58.36],
405 [17.13, 51.11]],
406 [[23.46, 54.36],
407 [20.52, 51.91],
408 [28.25, 51.50],
409 [26.80, 54.36],
410 [23.46, 54.36]]
411 ]
412 }
413 }
414 \endcode
415
416 it is converted to a QVariantMap with the following structure:
417
418 \code
419 {
420 type : Polygon
421 data : QGeoPolygon([{51.110, 17.130}, {50.420,30.540}, {58.360, 26.700}, {51.110, 17.130}])
422 properties : {text : This is a Feature with a Polygon}
423 }
424 \endcode
425
426 The \c FeatureCollection is a composition of Feature objects. The value of
427 the \c data member in a FeatureCollection is a QVariantList populated by
428 Feature type QVariantMaps.
429
430 For example, the following \c FeatureCollection:
431
432 \code
433 {
434 "type" : "FeatureCollection",
435 "features" : [
436 {
437 "type" : "Feature",
438 "id" : "Poly",
439 "properties" : {
440 "text" : "This is a Feature with a Polygon"
441 },
442 "geometry" : {
443 "type" : "Polygon",
444 "coordinates" : [
445 [[17.13, 51.11],
446 [30.54, 50.42],
447 [26.70, 58.36],
448 [17.13, 51.11]],
449 [[23.46, 54.36],
450 [20.52, 51.91],
451 [28.25, 51.50],
452 [26.80, 54.36],
453 [23.46, 54.36]]
454 ]
455 }
456 },
457 {
458 "type" : "Feature",
459 "id" : "MultiLine",
460 "properties" : {
461 "text" : "This is a Feature with a MultiLineString"
462 },
463 "geometry" : {
464 "type" : "MultiLineString",
465 "coordinates" : [
466 [[13.5, 43], [10.73, 59.92]],
467 [[9.15, 45], [-3.15, 58.90]]
468 ]
469 }
470 }
471 ]
472 }
473 \endcode
474
475 it is converted to a QVariantMap with the following structure:
476
477 \code
478 {
479 type : FeatureCollection
480 data : [
481 {
482 type : MultiLineString
483 data : [
484 {
485 type : LineString
486 data : QGeoPath([{45.000, 9.150}, {58.900, -3.150}])
487 }
488 {
489 type : LineString
490 data : QGeoPath([{43.000, 13.500}, {59.920, 10.730}])
491 }
492 ]
493 properties : {text : This is a Feature with a MultiLineString}
494 },
495 {
496 type : Polygon
497 data : QGeoPolygon({51.110, 17.130}, {50.420, 30.540}, {58.360, 26.700}, {51.110, 17.130})
498 properties : {text : This is a Feature with a Polygon}
499 }
500 ]
501 }
502 \endcode
503
504 \section2 Exporting GeoJSON
505
506 The exporter accepts the QVariantList returned by the \l {Importing GeoJSON}
507 {importer}, and returns a JSON document. The exporter is complementary to
508 the importer because it executes the inverse action.
509
510 \section2 The toString function
511
512 The \l toString outputs, for debugging purposes, the content of a
513 QVariantList structured like \l importGeoJson does, to a QString using a
514 prettyfied format.
515*/
516
517static QGeoCoordinate importPosition(const QVariant &position)
518{
519 QGeoCoordinate returnedCoordinates;
520 const QVariantList positionList = position.value<QVariantList>();
521 for (int i = 0; i < positionList.size(); ++i) { // Iterating Point coordinates arrays
522 switch (i) {
523 case 0:
524 returnedCoordinates.setLongitude(positionList.at(i).toDouble());
525 break;
526 case 1:
527 returnedCoordinates.setLatitude(positionList.at(i).toDouble());
528 break;
529 case 2:
530 returnedCoordinates.setAltitude(positionList.at(i).toDouble());
531 break;
532 default:
533 break;
534 }
535 }
536 return returnedCoordinates;
537}
538
539static QList<QGeoCoordinate> importArrayOfPositions(const QVariant &arrayOfPositions)
540{
541 QList <QGeoCoordinate> returnedCoordinates;
542 const QVariantList positionsList = arrayOfPositions.value<QVariantList>();
543 QGeoCoordinate singlePosition;
544 for (int i = 0; i < positionsList.size(); ++i) { // Iterating the LineString coordinates nested arrays
545 singlePosition = importPosition(position: (positionsList.at(i)));
546 returnedCoordinates.append(t: singlePosition); // Populating the QList of coordinates
547 }
548 return returnedCoordinates;
549}
550
551static QList<QList<QGeoCoordinate>> importArrayOfArrayOfPositions(const QVariant &arrayOfArrayofPositions)
552{
553 QList<QList<QGeoCoordinate>> returnedCoordinates;
554 const QVariantList positionsList = arrayOfArrayofPositions.value<QVariantList>();
555 QList<QGeoCoordinate> arrayOfPositions;
556 for (int i = 0; i < positionsList.size(); ++i) { // Iterating the Polygon coordinates nested arrays
557 arrayOfPositions = importArrayOfPositions(arrayOfPositions: (positionsList.at(i)));
558 returnedCoordinates << arrayOfPositions;
559 }
560 return returnedCoordinates;
561}
562
563static QGeoCircle importPoint(const QVariantMap &inputMap)
564{
565 QGeoCircle returnedObject;
566 QGeoCoordinate center;
567 QVariant valueCoords = inputMap.value(QStringLiteral("coordinates"));
568 center = importPosition(position: valueCoords);
569 returnedObject.setCenter(center);
570 return returnedObject;
571}
572
573static QGeoPath importLineString(const QVariantMap &inputMap)
574{
575 QGeoPath returnedObject;
576 QList <QGeoCoordinate> coordinatesList;
577 const QVariant valueCoordinates = inputMap.value(QStringLiteral("coordinates"));
578 coordinatesList = importArrayOfPositions(arrayOfPositions: valueCoordinates);
579 returnedObject.setPath(coordinatesList);
580 return returnedObject;
581}
582
583static QGeoPolygon importPolygon(const QVariantMap &inputMap)
584{
585 QGeoPolygon returnedObject;
586 const QVariant valueCoordinates = inputMap.value(QStringLiteral("coordinates"));
587 QList<QList<QGeoCoordinate>> perimeters = importArrayOfArrayOfPositions(arrayOfArrayofPositions: valueCoordinates);
588 for (int i = 0; i < perimeters.size(); ++i) { // Import an array of QList<QGeocoordinates>
589 if (i == 0)
590 returnedObject.setPath(perimeters.at(i)); // External perimeter
591 else
592 returnedObject.addHole(holePath: perimeters.at(i)); // Inner perimeters
593 }
594 return returnedObject;
595}
596
597static QVariantList importMultiPoint(const QVariantMap &inputMap)
598{
599 QVariantList returnedObject;
600 const QVariantList coordinatesList = inputMap.value(QStringLiteral("coordinates")).value<QVariantList>();
601 QVariantMap singlePointMap;
602 QGeoCircle parsedPoint;
603 for (int i = 0; i < coordinatesList.size(); ++i) { // Iterating MultiPoint coordinates nasted arrays
604 parsedPoint.setCenter(importPosition(position: coordinatesList.at(i)));
605 singlePointMap.insert(QStringLiteral("type"), QStringLiteral("Point"));
606 singlePointMap.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: parsedPoint));
607 returnedObject.append(t: QVariant::fromValue(value: singlePointMap));
608 }
609 return returnedObject;
610}
611
612static QVariantList importMultiLineString(const QVariantMap &inputMap)
613{
614 QVariantList returnedObject;
615 QGeoPath parsedLineString;
616 const QVariant listCoords = inputMap.value(QStringLiteral("coordinates"));
617 const QVariantList list = listCoords.value<QVariantList>();
618 QVariantMap singleLinestringMap;
619 for (int i = 0; i < list.size(); ++i) { // Iterating the MultiLineString coordinates nasted arrays using importArrayOfPositions
620 singleLinestringMap.clear();
621 const QList <QGeoCoordinate> coordinatesList = importArrayOfPositions(arrayOfPositions: list.at(i));
622 singleLinestringMap.insert(QStringLiteral("type"), QStringLiteral("LineString"));
623 parsedLineString.setPath(coordinatesList);
624 singleLinestringMap.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: parsedLineString));
625 returnedObject.append(t: QVariant::fromValue(value: singleLinestringMap));
626 }
627 return returnedObject;
628}
629
630static QVariantList importMultiPolygon(const QVariantMap &inputMap)
631{
632 QVariantList returnedObject;
633 QGeoPolygon singlePoly;
634 QVariantMap singlePolygonMap;
635 const QVariant valueCoordinates = inputMap.value(QStringLiteral("coordinates"));
636 const QVariantList list = valueCoordinates.value<QVariantList>();
637 for (int i = 0; i < list.size(); ++i) { // Iterating the MultiPolygon coordinates nasted arrays
638 singlePolygonMap.clear();
639 const QList<QList<QGeoCoordinate>> coordinatesList = importArrayOfArrayOfPositions(arrayOfArrayofPositions: list.at(i));
640
641 for (int j = 0; j < coordinatesList.size(); ++j) {
642 if (j == 0)
643 singlePoly.setPath(coordinatesList.at(i: j));
644 else
645 singlePoly.addHole(holePath: coordinatesList.at(i: j));
646 }
647 singlePolygonMap.insert(QStringLiteral("type"), QStringLiteral("Polygon"));
648 singlePolygonMap.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: singlePoly));
649 returnedObject.append(t: QVariant::fromValue(value: singlePolygonMap));
650 }
651 return returnedObject;
652}
653
654static QVariantMap importGeometry(const QVariantMap &inputMap); // Function prototype for a tail recursion
655
656static QVariantList importGeometryCollection(const QVariantMap &inputMap)
657{
658 QVariantList returnedObject;
659 const QVariant listGeometries = inputMap.value(QStringLiteral("geometries"));
660 const QVariantList list = listGeometries.value<QVariantList>(); // QVariantList of heterogeneous composition of the other geometry types
661 for (int i = 0; i < list.size(); ++i) {
662 QVariantMap geometryMap = list.at(i).value<QVariantMap>();
663 QVariantMap geoMap = importGeometry(inputMap: geometryMap);
664 returnedObject.append(t: geoMap);
665 }
666 return returnedObject;
667}
668
669static QVariantMap importGeometry(const QVariantMap &inputMap)
670{
671 QVariantMap returnedObject;
672 QString geometryTypes[] = {
673 QStringLiteral("Point"),
674 QStringLiteral("MultiPoint"),
675 QStringLiteral("LineString"),
676 QStringLiteral("MultiLineString"),
677 QStringLiteral("Polygon"),
678 QStringLiteral("MultiPolygon"),
679 QStringLiteral("GeometryCollection")
680 };
681 enum geoTypeSwitch {
682 Point,
683 MultiPoint,
684 LineString,
685 MultiLineString,
686 Polygon,
687 MultiPolygon,
688 GeometryCollection
689 };
690 for (int i = 0; i<7; ++i) {
691 if (inputMap.value(QStringLiteral("type")).value<QString>() == geometryTypes[i]) {
692 switch (i) {
693 case Point: {
694 returnedObject.insert(QStringLiteral("type"), QStringLiteral("Point"));
695 returnedObject.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: importPoint(inputMap)));
696 break;
697 }
698 case MultiPoint: {
699 returnedObject.insert(QStringLiteral("type"), QStringLiteral("MultiPoint"));
700 returnedObject.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: importMultiPoint(inputMap)));
701 break;
702 }
703 case LineString: {
704 returnedObject.insert(QStringLiteral("type"), QStringLiteral("LineString"));
705 returnedObject.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: importLineString(inputMap)));
706 break;
707 }
708 case MultiLineString: {
709 returnedObject.insert(QStringLiteral("type"), QStringLiteral("MultiLineString"));
710 returnedObject.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: importMultiLineString(inputMap)));
711 break;
712 }
713 case Polygon: {
714 returnedObject.insert(QStringLiteral("type"), QStringLiteral("Polygon"));
715 returnedObject.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: importPolygon(inputMap)));
716 break;
717 }
718 case MultiPolygon: {
719 returnedObject.insert(QStringLiteral("type"), QStringLiteral("MultiPolygon"));
720 returnedObject.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: importMultiPolygon(inputMap)));
721 break;
722 }
723 case GeometryCollection: {
724 returnedObject.insert(QStringLiteral("type"), QStringLiteral("GeometryCollection"));
725 returnedObject.insert(QStringLiteral("data"), avalue: QVariant::fromValue(value: importGeometryCollection(inputMap)));
726 break;
727 }
728 default:
729 break;
730 }
731 }
732 }
733 return returnedObject;
734}
735
736static QVariantList importFeatureCollection(const QVariantMap &inputMap)
737{
738 QVariantList returnedObject;
739 const QVariantList featuresList = inputMap.value(QStringLiteral("features")).value<QVariantList>();
740 for (int i = 0; i < featuresList.size(); ++i) {
741 QVariantMap inputFeatureMap = featuresList.at(i).value<QVariantMap>();
742 QVariantMap singleFeatureMap = importGeometry(inputMap: inputFeatureMap.value(QStringLiteral("geometry")).value<QVariantMap>());
743 const QVariantMap importedProperties = inputFeatureMap.value(QStringLiteral("properties")).value<QVariantMap>();
744 singleFeatureMap.insert(QStringLiteral("properties"), avalue: importedProperties);
745 if (inputFeatureMap.contains(QStringLiteral("id"))) {
746 QVariant importedId = inputFeatureMap.value(QStringLiteral("id")).value<QVariant>();
747 singleFeatureMap.insert(QStringLiteral("id"), avalue: importedId);
748 }
749 returnedObject.append(t: singleFeatureMap);
750 }
751 return returnedObject;
752}
753
754static QJsonValue exportPosition(const QGeoCoordinate &obtainedCoordinates)
755{
756 QJsonValue geoLat = obtainedCoordinates.latitude();
757 QJsonValue geoLong = obtainedCoordinates.longitude();
758 QJsonArray array = {geoLong, geoLat};
759 QJsonValue geoAlt;
760 if (!qIsNaN(d: obtainedCoordinates.altitude())) {
761 geoAlt = obtainedCoordinates.altitude();
762 array.append(value: geoAlt);
763 }
764 QJsonValue geoArray = array;
765 return geoArray;
766}
767
768static QJsonValue exportArrayOfPositions(const QList<QGeoCoordinate> &obtainedCoordinatesList)
769{
770 QJsonValue lineCoordinates;
771 QJsonValue multiPosition;
772 QJsonArray arrayPosition;
773 for (int i = 0; i < obtainedCoordinatesList.size(); ++i) {
774 multiPosition = exportPosition(obtainedCoordinates: obtainedCoordinatesList.at(i));
775 arrayPosition.append(value: multiPosition);
776 }
777 lineCoordinates = arrayPosition;
778 return lineCoordinates;
779}
780
781static QJsonValue exportArrayOfArrayOfPositions(const QList<QList<QGeoCoordinate>> &obtainedCoordinates)
782{
783 QJsonValue lineCoordinates;
784 QJsonValue polyCoordinates;
785 QJsonArray arrayPath;
786 for (int i = 0; i < obtainedCoordinates.size(); ++i) {
787 lineCoordinates = exportArrayOfPositions(obtainedCoordinatesList: obtainedCoordinates.at(i));
788 arrayPath.append(value: lineCoordinates);
789 }
790 polyCoordinates = arrayPath;
791 return polyCoordinates;
792}
793
794static QJsonObject exportPoint(const QVariantMap &pointMap)
795{
796 QJsonObject parsedPoint;
797 QGeoCircle circle = pointMap.value(QStringLiteral("data")).value<QGeoCircle>();
798 parsedPoint.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("Point")));
799 parsedPoint.insert(QStringLiteral("coordinates"), value: exportPosition(obtainedCoordinates: circle.center()));
800 return parsedPoint;
801}
802
803static QJsonObject exportLineString(const QVariantMap &lineStringMap)
804{
805 QJsonObject parsedLineString;
806 QList <QGeoCoordinate> linestringPath = lineStringMap.value(QStringLiteral("data")).value<QGeoPath>().path();
807 parsedLineString.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("LineString")));
808 parsedLineString.insert(QStringLiteral("coordinates"), value: exportArrayOfPositions(obtainedCoordinatesList: linestringPath));
809 return parsedLineString;
810}
811
812static QJsonObject exportPolygon(const QVariantMap &polygonMap)
813{
814 QVariant polygonVariant = polygonMap.value(QStringLiteral("data"));
815 QJsonObject parsedPolygon;
816 QJsonValue polyCoordinates;
817 QList<QList<QGeoCoordinate>> obtainedCoordinatesPoly;
818 QGeoPolygon parsedPoly = polygonVariant.value<QGeoPolygon>();
819 obtainedCoordinatesPoly << parsedPoly.path();
820 if (parsedPoly.holesCount()!=0)
821 for (int i = 0; i < parsedPoly.holesCount(); ++i) {
822 obtainedCoordinatesPoly << parsedPoly.holePath(index: i);
823 }
824 polyCoordinates = exportArrayOfArrayOfPositions(obtainedCoordinates: obtainedCoordinatesPoly);
825 parsedPolygon.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("Polygon")));
826 parsedPolygon.insert(QStringLiteral("coordinates"), value: polyCoordinates);
827 return parsedPolygon;
828}
829
830static QJsonObject exportMultiPoint(const QVariantMap &multiPointMap)
831{
832 QJsonObject parsedMultiPoint;
833 QList <QGeoCoordinate> obtainedCoordinatesMP;
834 QVariantList multiCircleVariantList = multiPointMap.value(QStringLiteral("data")).value<QVariantList>();
835 for (const QVariant &exCircleVariantMap: multiCircleVariantList) {
836 obtainedCoordinatesMP << exCircleVariantMap.value<QVariantMap>().value(QStringLiteral("data")).value<QGeoCircle>().center();
837 }
838 QJsonValue multiPosition = exportArrayOfPositions(obtainedCoordinatesList: obtainedCoordinatesMP);
839 parsedMultiPoint.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("MultiPoint")));
840 parsedMultiPoint.insert(QStringLiteral("coordinates"), value: multiPosition);
841 return parsedMultiPoint;
842}
843
844static QJsonObject exportMultiLineString(const QVariantMap &multiLineStringMap)
845{
846 QJsonObject parsedMultiLineString;
847 QList<QList<QGeoCoordinate>> extractedCoordinatesValue;
848 QVariant multiPathVariant = multiLineStringMap.value(QStringLiteral("data"));
849 QVariantList multiPathList = multiPathVariant.value<QVariantList>();
850 for (int i = 0; i < multiPathList.size(); ++i) {
851 extractedCoordinatesValue << multiPathList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPath>().path();
852 }
853 QJsonValue exportedCoordinatesValue = exportArrayOfArrayOfPositions(obtainedCoordinates: extractedCoordinatesValue);
854 parsedMultiLineString.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("MultiLineString")));
855 parsedMultiLineString.insert(QStringLiteral("coordinates"), value: exportedCoordinatesValue);
856 return parsedMultiLineString;
857}
858
859static QJsonObject exportMultiPolygon(const QVariantMap &multiPolygonMap)
860{
861 QJsonObject parsedMultiPolygon;
862 QJsonValue polyCoordinates;
863 QJsonArray parsedArrayPolygon;
864 QList<QList<QGeoCoordinate>> extractedCoordinatesValue;
865 QVariant multiPolygonVariant = multiPolygonMap.value(QStringLiteral("data"));
866 QVariantList multiPolygonList = multiPolygonVariant.value<QVariantList>();
867 int polyHoles = 0;
868 int currentHole;
869 for (int i = 0; i < multiPolygonList.size(); ++i) { // Start parsing Polygon list
870 extractedCoordinatesValue << multiPolygonList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPolygon>().path(); // Extract external polygon path
871 polyHoles = multiPolygonList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPolygon>().holesCount();
872 if (polyHoles) // Check if the polygon has holes
873 for (currentHole = 0 ; currentHole < polyHoles; currentHole++)
874 extractedCoordinatesValue << multiPolygonList.at(i).value<QVariantMap>().value(QStringLiteral("data")).value<QGeoPolygon>().holePath(index: currentHole);
875 polyCoordinates = exportArrayOfArrayOfPositions(obtainedCoordinates: extractedCoordinatesValue); // Generates QJsonDocument compatible value
876 parsedArrayPolygon.append(value: polyCoordinates); // Adds one level of nesting in coordinates
877 extractedCoordinatesValue.clear(); // Clears the temporary polygon linear ring storage
878 }
879 QJsonValue exportedCoordinatesNodeValue = parsedArrayPolygon;
880 parsedMultiPolygon.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("MultiPolygon")));
881 parsedMultiPolygon.insert(QStringLiteral("coordinates"), value: exportedCoordinatesNodeValue);
882 return parsedMultiPolygon;
883}
884
885static QJsonObject exportGeometry(const QVariantMap &geometryMap); // Function prototype
886
887static QJsonObject exportGeometryCollection(const QVariantMap &geometryCollection)
888{
889 QJsonObject parsed;
890 QJsonObject parsedGeometry;
891 QJsonValue valueGeometries;
892 QJsonArray parsedGeometries;
893 QVariantList geometriesList = geometryCollection.value(QStringLiteral("data")).value<QVariantList>();
894 for (int i = 0; i < geometriesList.size(); ++i) {
895 parsedGeometry = exportGeometry(geometryMap: geometriesList.at(i).value<QVariantMap>());
896 valueGeometries = parsedGeometry;
897 parsedGeometries.append(value: valueGeometries);
898 }
899 QJsonValue exportedGeometriesValue = parsedGeometries;
900 parsed.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("GeometryCollection")));
901 parsed.insert(QStringLiteral("geometries"), value: exportedGeometriesValue);
902 return parsed;
903}
904
905static QJsonObject exportGeometry(const QVariantMap &geometryMap)
906{
907 QJsonObject exportedGeometry;
908 if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("Point"))
909 exportedGeometry = exportPoint(pointMap: geometryMap);
910 if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("MultiPoint"))
911 exportedGeometry = exportMultiPoint(multiPointMap: geometryMap);
912 if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("LineString"))
913 exportedGeometry = exportLineString(lineStringMap: geometryMap);
914 if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("MultiLineString"))
915 exportedGeometry = exportMultiLineString(multiLineStringMap: geometryMap);
916 if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("Polygon"))
917 exportedGeometry = exportPolygon(polygonMap: geometryMap);
918 if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("MultiPolygon"))
919 exportedGeometry = exportMultiPolygon(multiPolygonMap: geometryMap);
920 if (geometryMap.value(QStringLiteral("type")) == QStringLiteral("GeometryCollection"))
921 exportedGeometry = exportGeometryCollection(geometryCollection: geometryMap);
922 return exportedGeometry;
923}
924
925static QJsonObject exportFeature(const QVariantMap &featureMap)
926{
927 QJsonObject exportedFeature;
928 QJsonValue geometryNodeValue = QJsonValue(exportGeometry(geometryMap: featureMap));
929 QJsonValue propertiesNodeValue = featureMap.value(QStringLiteral("properties")).value<QVariant>().toJsonValue();
930 QJsonValue idNodeValue = featureMap.value(QStringLiteral("id")).value<QVariant>().toJsonValue();
931 exportedFeature.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("Feature")));
932 exportedFeature.insert(QStringLiteral("geometry"), value: geometryNodeValue);
933 exportedFeature.insert(QStringLiteral("properties"), value: propertiesNodeValue);
934 exportedFeature.insert(QStringLiteral("id"), value: idNodeValue);
935 return exportedFeature;
936}
937
938static QJsonObject exportFeatureCollection(const QVariantMap &featureCollection)
939{
940 QJsonObject exportedFeatureCollection;
941 QJsonArray featureArray;
942 QVariantList featureList = featureCollection.value(QStringLiteral("data")).value<QVariantList>();
943 for (int i = 0; i < featureList.size(); ++i) {
944 featureArray.append(value: QJsonValue(exportFeature(featureMap: featureList.at(i).value<QVariantMap>())));
945 }
946 exportedFeatureCollection.insert(QStringLiteral("type"), value: QJsonValue(QStringLiteral("FeatureCollection")));
947 exportedFeatureCollection.insert(QStringLiteral("features"), value: QJsonValue(featureArray) );
948 return exportedFeatureCollection;
949}
950
951/*!
952This method imports the \a geoJson document, expected to contain valid GeoJSON
953data, into a QVariantList structured like described in the section \l
954{Importing GeoJSON}.
955
956\note This method performs no validation on the input.
957
958\sa exportGeoJson
959*/
960QVariantList QGeoJson::importGeoJson(const QJsonDocument &geoJson)
961{
962 QVariantList returnedList;
963 QJsonObject object = geoJson.object(); // Read json object from imported doc
964 QVariantMap rootGeoJsonObject = object.toVariantMap(); // Extraced map using Qt's API
965 QString geoType[] = {
966 QStringLiteral("Point"),
967 QStringLiteral("MultiPoint"),
968 QStringLiteral("LineString"),
969 QStringLiteral("MultiLineString"),
970 QStringLiteral("Polygon"),
971 QStringLiteral("MultiPolygon"),
972 QStringLiteral("GeometryCollection"),
973 QStringLiteral("Feature"),
974 QStringLiteral("FeatureCollection")
975 };
976 enum geoTypeSwitch {
977 Point,
978 MultiPoint,
979 LineString,
980 MultiLineString,
981 Polygon,
982 MultiPolygon,
983 GeometryCollection,
984 Feature,
985 FeatureCollection
986 };
987 QVariantMap parsedGeoJsonMap;
988
989 // Checking whether the JSON object has a "type" member
990 const QVariant keyVariant = rootGeoJsonObject.value(QStringLiteral("type"));
991 if (keyVariant == QVariant::Invalid) {
992 // Type check failed
993 }
994 QString valueType = keyVariant.value<QString>();
995
996 // Checking whether the "type" member has a GeoJSON admitted value
997 for (int i = 0; i < 9; ++i) {
998 if (valueType == geoType[i]) {
999 switch (i) {
1000 case Point: {
1001 QGeoCircle circle = importPoint(inputMap: rootGeoJsonObject);
1002 QVariant dataNodeValue = QVariant::fromValue(value: circle);
1003 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("Point"));
1004 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1005 break;
1006 }
1007 case MultiPoint: {
1008 QVariantList multiCircle = importMultiPoint(inputMap: rootGeoJsonObject);
1009 QVariant dataNodeValue = QVariant::fromValue(value: multiCircle);
1010 QList <QGeoCircle> testlist;
1011 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("MultiPoint"));
1012 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1013 break;
1014 }
1015 case LineString: {
1016 QGeoPath lineString = importLineString(inputMap: rootGeoJsonObject);
1017 QVariant dataNodeValue = QVariant::fromValue(value: lineString);
1018 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("LineString"));
1019 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1020 break;
1021 }
1022 case MultiLineString: {
1023 QVariantList multiLineString = importMultiLineString(inputMap: rootGeoJsonObject);
1024 QVariant dataNodeValue = QVariant::fromValue(value: multiLineString);
1025 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("MultiLineString"));
1026 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1027 break;
1028 }
1029 case Polygon: {
1030 QGeoPolygon poly = importPolygon(inputMap: rootGeoJsonObject);
1031 QVariant dataNodeValue = QVariant::fromValue(value: poly);
1032 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("Polygon"));
1033 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1034 break;
1035 }
1036 case MultiPolygon: {
1037 QVariantList multiPoly = importMultiPolygon(inputMap: rootGeoJsonObject);
1038 QVariant dataNodeValue = QVariant::fromValue(value: multiPoly);
1039 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("MultiPolygon"));
1040 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1041 break;
1042 }
1043 // List of GeoJson geometry objects
1044 case GeometryCollection: {
1045 QVariantList multiGeo = importGeometryCollection(inputMap: rootGeoJsonObject);
1046 QVariant dataNodeValue = QVariant::fromValue(value: multiGeo);
1047 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("GeometryCollection"));
1048 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1049 break;
1050 }
1051 // Single GeoJson geometry object with properties
1052 case Feature: {
1053 parsedGeoJsonMap = importGeometry(inputMap: rootGeoJsonObject.value(QStringLiteral("geometry")).value<QVariantMap>());
1054 QVariantMap importedProperties = rootGeoJsonObject.value(QStringLiteral("properties")).value<QVariantMap>();
1055 parsedGeoJsonMap.insert(QStringLiteral("properties"), avalue: importedProperties);
1056 if (rootGeoJsonObject.contains(QStringLiteral("id"))){
1057 QVariant importedId = rootGeoJsonObject.value(QStringLiteral("id")).value<QVariant>();
1058 parsedGeoJsonMap.insert(QStringLiteral("id"), avalue: importedId);
1059 }
1060 break;
1061 }
1062 // Heterogeneous list of GeoJSON geometries with properties
1063 case FeatureCollection: {
1064 QVariantList featCollection = importFeatureCollection(inputMap: rootGeoJsonObject);
1065 QVariant dataNodeValue = QVariant::fromValue(value: featCollection);
1066 parsedGeoJsonMap.insert(QStringLiteral("type"), QStringLiteral("FeatureCollection"));
1067 parsedGeoJsonMap.insert(QStringLiteral("data"), avalue: dataNodeValue);
1068 break;
1069 }
1070 default:
1071 break;
1072 }
1073 QVariant bboxNodeValue = rootGeoJsonObject.value(QStringLiteral("bbox"));
1074 if (bboxNodeValue != QVariant::Invalid) {
1075 parsedGeoJsonMap.insert(QStringLiteral("bbox"), avalue: bboxNodeValue);
1076 }
1077 returnedList.append(t: parsedGeoJsonMap);
1078 } else if (i >= 9) {
1079 // Error
1080 break;
1081 }
1082 }
1083 return returnedList;
1084}
1085
1086/*!
1087This method exports the QVariantList \a geoData, expected to be structured like
1088described in the section \l {Importing GeoJSON}, to a QJsonDocument containing
1089the data converted to GeoJSON.
1090
1091\note This method performs no validation on the input.
1092
1093\sa importGeoJson
1094*/
1095QJsonDocument QGeoJson::exportGeoJson(const QVariantList &geoData)
1096{
1097 QVariantMap exportMap = geoData.at(i: 0).value<QVariantMap>(); // Extracting the QVMap
1098 QJsonObject newObject;
1099 QJsonDocument newDocument;
1100 if (exportMap.contains(QStringLiteral("properties"))) {
1101 newObject = exportFeature(featureMap: exportMap);
1102 } else {
1103 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("Point")) // Check the value corresponding to the key "Point"
1104 newObject = exportPoint(pointMap: exportMap);
1105 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("MultiPoint"))
1106 newObject = exportMultiPoint(multiPointMap: exportMap);
1107 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("LineString"))
1108 newObject = exportLineString(lineStringMap: exportMap);
1109 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("MultiLineString"))
1110 newObject = exportMultiLineString(multiLineStringMap: exportMap);
1111 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("Polygon"))
1112 newObject = exportPolygon(polygonMap: exportMap);
1113 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("MultiPolygon"))
1114 newObject = exportMultiPolygon(multiPolygonMap: exportMap);
1115 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("GeometryCollection"))
1116 newObject = exportGeometryCollection(geometryCollection: exportMap);
1117 if (exportMap.value(QStringLiteral("type")) == QStringLiteral("FeatureCollection"))
1118 newObject = exportFeatureCollection(featureCollection: exportMap);
1119 }
1120 if (exportMap.contains(akey: (QStringLiteral("bbox")))) {
1121 QJsonArray bboxArray;
1122 QVariantList bboxList = exportMap.value(QStringLiteral("bbox")).value<QVariantList>();
1123 for (int i = 0; i < bboxList.size(); ++i) {
1124 bboxArray.append(value: QJsonValue(bboxList.at(i).value<double>()));
1125 }
1126 newObject.insert(QStringLiteral("bbox"), value: QJsonValue(bboxArray));
1127 }
1128 newDocument.setObject(newObject);
1129 return newDocument;
1130}
1131
1132// Functions for toString
1133QTextStream &operator << (QTextStream &stream, const QGeoCoordinate &crd)
1134{
1135 stream << "{ " << QString::number(crd.latitude(), f: 'f', prec: 3) << ", "
1136 << QString::number(crd.longitude(), f: 'f', prec: 3) << ", "
1137 << QString::number(crd.altitude(), f: 'f', prec: 3) << " }";
1138 return stream;
1139}
1140
1141QTextStream &operator << (QTextStream &stream, const QGeoShape &shape)
1142{
1143 switch (shape.type()) {
1144 case QGeoShape::CircleType: {
1145 QGeoCircle circle(shape);
1146 stream << "QGeoCircle(" <<circle.center() << ", "<< QString::number(circle.radius()) << ")";
1147 break;
1148 }
1149 case QGeoShape::PathType: {
1150 QGeoPath path(shape);
1151 stream << "QGeoPath(";
1152 for (auto c: path.path())
1153 stream << c << ", ";
1154 stream << ")";
1155 break;
1156 }
1157 case QGeoShape::PolygonType: {
1158 QGeoPolygon poly(shape);
1159 stream << "QGeoPolygon(";
1160 for (auto c: poly.path())
1161 stream << c << ", ";
1162 stream << ")";
1163 break;
1164 }
1165 default:
1166 stream << "QGeoShape(Unknown)";
1167 break;
1168 }
1169 return stream;
1170}
1171
1172static const QString sTab = QStringLiteral(" ");
1173
1174QString printQvariant(const QVariant v, int tabs = 0) {
1175 QString sTabs;
1176 QString res;
1177 QTextStream stream(&res);
1178 for (int i = 0; i< tabs; i++) {
1179 sTabs += sTab;
1180 }
1181 if (v.type() == QVariant::List) {
1182 stream << sTabs << "[\n";
1183 const QVariantList &l = v.toList();
1184 for (int i = 0; i < l.size(); ++i)
1185 stream << printQvariant(v: l.at(i), tabs: tabs + 1);
1186 stream << sTabs << "]\n";
1187 } else if (v.type() == QVariant::Map) {
1188 stream << sTabs << "{\n";
1189 const QVariantList &l = v.toList();
1190 const QVariantMap &map = v.toMap();
1191
1192 // Either one or the other are valid
1193 if (!map.keys().isEmpty()) {
1194 // Handle type first, to easy reading
1195 if (map.contains(QStringLiteral("type"))) {
1196 stream << sTabs << sTab << QStringLiteral("type") << " : "
1197 << printQvariant(v: map[QStringLiteral("type")], tabs: tabs + 1).remove(rx: QRegExp(QStringLiteral("^[ ]*")));;
1198 }
1199 for (QVariantMap::const_iterator iter = map.begin(); iter != map.end(); ++iter) {
1200 if (iter.key() == QStringLiteral("type"))
1201 continue;
1202 stream << sTabs << sTab << iter.key() << " : " << printQvariant(v: iter.value(), tabs: tabs + 1).remove(rx: QRegExp(QStringLiteral("^[ ]*")));;
1203 }
1204 }
1205 for (int i = 0; i < l.size(); ++i)
1206 stream << printQvariant(v: l.at(i), tabs: tabs + 1);
1207 stream << sTabs << "}\n";
1208 } else {
1209 stream << sTabs;
1210 QGeoShape workigGeometry;
1211 if ( v.canConvert<QGeoShape>()) {
1212 workigGeometry = v.value<QGeoShape>();
1213 if (workigGeometry.type() == QGeoShape::CircleType) {
1214 QGeoCircle circle = v.value<QGeoCircle>();
1215 stream << circle<< "\n";
1216 } else if (workigGeometry.type() == QGeoShape::PathType) {
1217 QGeoPath path = v.value<QGeoPath>();
1218 stream << path<< "\n";
1219 } else if (workigGeometry.type() == QGeoShape::PolygonType) {
1220 QGeoPolygon polygon = v.value<QGeoPolygon>();
1221 stream << polygon<< "\n";
1222 }
1223 } else {
1224 if (v.isNull())
1225 stream << "null\n";
1226 else
1227 stream << v.toString() << "\n";
1228 }
1229 }
1230 return res;
1231}
1232
1233/*!
1234 This method accepts the QVariantList \a geoData, structured as described in
1235 \l {Importing GeoJSON}, and returns a string containing the same data in a
1236 readable form.
1237*/
1238QString QGeoJson::toString(const QVariantList &geoData) {
1239 return printQvariant(v: geoData.first(), tabs: 0);
1240}
1241
1242QT_END_NAMESPACE
1243

source code of qtlocation/src/location/labs/qgeojson.cpp