Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdeclarativegeojsondata.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 Julian Sherollari <jdotsh@gmail.com>
2// Copyright (C) 2023 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
7
8#include <QtLocation/private/qgeojson_p.h>
9
10QT_BEGIN_NAMESPACE
11
12namespace extractor
13{
14 static bool hasProperties(QQuickItem *item)
15 {
16 QVariant props = item->property("props");
17 return !props.isNull();
18 }
19
20 static QVariant toVariant(QObject *mapItem)
21 {
22 if (QDeclarativeGeoMapItemView *miv = qobject_cast<QDeclarativeGeoMapItemView *>(mapItem)) {
23 return toVariant(miv);
24 } else if (QDeclarativePolylineMapItem *polyline = qobject_cast<QDeclarativePolylineMapItem *>(mapItem)) {
25 return toVariant(polyline);
26 } else if (QDeclarativePolygonMapItem *polygon = qobject_cast<QDeclarativePolygonMapItem *>(mapItem)) {
27 return toVariant(polygon);
28 } else if (QDeclarativeCircleMapItem *circle = qobject_cast<QDeclarativeCircleMapItem *>(mapItem)) {
29 return toVariant(circle); // If GeoJSON Point type is visualized in other ways, handle those types here instead.
30 } else if (QDeclarativeRectangleMapItem *rectangle = qobject_cast<QDeclarativeRectangleMapItem *>(mapItem)) {
31 return toVariant(rectangle); // For the self-drawn rectangles. Will be exported as Polygons
32 }
33 return QVariant();
34 }
35
36 static QVariantMap toVariant(QDeclarativePolygonMapItem *mapPolygon)
37 {
38 QVariantMap ls;
39 ls[QStringLiteral("type")] = QStringLiteral("Polygon");
40 ls[QStringLiteral("data")] = QVariant::fromValue(mapPolygon->geoShape());
41 if (hasProperties(mapPolygon))
42 ls[QStringLiteral("properties")] = mapPolygon->property("props").toMap();
43 return ls;
44 }
45
46 static QVariantMap toVariant(QDeclarativePolylineMapItem *mapPolyline)
47 {
48 QVariantMap ls;
49 ls[QStringLiteral("type")] = QStringLiteral("LineString");
50 ls[QStringLiteral("data")] = QVariant::fromValue(mapPolyline->geoShape());
51 if (hasProperties(mapPolyline))
52 ls[QStringLiteral("properties")] = mapPolyline->property("props").toMap();
53 return ls;
54 }
55
56 static QVariantMap toVariant(QDeclarativeCircleMapItem *mapCircle)
57 {
58 QVariantMap pt;
59 pt[QStringLiteral("type")] = QStringLiteral("Point");
60 pt[QStringLiteral("data")] = QVariant::fromValue(mapCircle->geoShape());
61 QVariantMap propMap = mapCircle->property("props").toMap();
62 propMap[QStringLiteral("radius")] = mapCircle->radius();
63 pt[QStringLiteral("properties")] = propMap;
64 return pt;
65 }
66
67 static QVariantMap toVariant(QDeclarativeRectangleMapItem *mapRectangle)
68 {
69 QVariantMap pt;
70 pt[QStringLiteral("type")] = QStringLiteral("Polygon");
71 QGeoRectangle rectanlge = mapRectangle->geoShape();
72 QGeoPolygon poly;
73 poly.addCoordinate(rectanlge.topLeft());
74 poly.addCoordinate(rectanlge.topRight());
75 poly.addCoordinate(rectanlge.bottomRight());
76 poly.addCoordinate(rectanlge.bottomLeft());
77 pt[QStringLiteral("data")] = QVariant::fromValue(poly);
78 if (hasProperties(mapRectangle))
79 pt[QStringLiteral("properties")] = mapRectangle->property("props").toMap();
80 return pt;
81 }
82};
83
84
85/*!
86 \qmltype GeoJsonData
87 \nativetype QDeclarativeGeoJsonData
88 \inqmlmodule QtLocation
89 \ingroup qml-QtLocation5-maps
90 \since QtLocation 6.7
91
92 \brief A model to represent, load and save GeoJSON documents.
93
94
95 The GeoJsonData type reads and writes GeoJson formatted documents.
96 GeoJsonData has functions to open and save the model at the URL set
97 to the \l sourceUrl property. The loaded model is internally represented by
98 QVariant and binds to the \l model property. Use
99 \l{Models and Views in Qt Quick#View Delegates}{Delegates} to visualize the items
100 in a view.
101
102 For information about GeoJSON, visit the \l{https://geojson.org/}{GeoJSON} website.
103
104 \section1 GeoJSON Object
105
106 The GeoJSON object is a valid JSON object that represents geometry, a feature, or a
107 collection of geometries or features.
108
109 A GeoJSON object must be one of these types:
110 \list
111 \li \c Point
112 \li \c MultiPoint
113 \li \c LineString
114 \li \c MultiLineString
115 \li \c Polygon
116 \li \c MultiPolygon
117 \li \c GeometryCollection
118 \li \c Feature
119 \li \c FeatureCollection
120 \endlist
121
122 To set the type, bind the \c type member to a GeoJSON type. The \c coordinates member can
123 be a type of QGeoShape or a list, depending on the GeoJSON type. The \c Feature type has an additional
124 \c geometry and \c properties member.
125
126 A list of the geometric types and their equivalent QVariant representations:
127
128 \list
129 \li For a \c Point object, \c coordinates pairs with QGeoCircle.
130 For example:
131 \code
132 {
133 "type": "Point",
134 "coordinates": [11, 60]
135 }
136 \endcode
137 This GeoJSON object has a corresponding QVariantMap representation:
138 \code
139 {
140 type: "Point"
141 coordinates: QGeoCircle({11.000, 60.000}, -1)
142 }
143 \endcode
144
145 \li For a \c LineString object, \c coordinates pairs with QGeoPath.
146 For example:
147 \code
148 {
149 "type" : "LineString",
150 "coordinates" : [
151 [13.5, 43],
152 [10.73, 59.92]
153 ]
154 }
155 \endcode
156 This GeoJSON object has a corresponding QVariantMap representation:
157 \code
158 {
159 type : "LineString"
160 data : QGeoPath([{43.000, 13.500}, {59.920, 10.730}])
161 }
162 \endcode
163
164 \li For a \c{Polygon} object, \c coordinates member pairs with QGeoPolygon (holes are possible). The polygon is a
165 \e{linear ring}, whose final coordinate is the same as the first coordinate, thereby opening and closing
166 the ring. The \c bbox member is an optional member and is for setting the area's range, useful for concave boundaries.
167 For more information about the accepted polygon coordinates, read about the
168 \l{https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.6Polygon}{Polygon} type in the GeoJson specification.
169 For example:
170 \code
171 {
172 "type": "Polygon",
173 "coordinates": [
174 [
175 [17.13, 51.11],
176 [30.54, 50.42],
177 [26.70, 58.36],
178 [17.13, 51.11]
179 ]
180 ],
181 "bbox": [50, -50, 10, -10]
182 }
183 \endcode
184 This GeoJSON object has a corresponding QVariantMap representation:
185 \code
186 {
187 type : "Polygon"
188 coordinates : QGeoPolygon([{51.110, 17.130}, {50.420,30.540}, {58.360, 26.700}, {51.110, 17.130}])
189 }
190 \endcode
191
192 \endlist
193
194 For the \c MultiPoint, \c MultiLineString, and \c MultiPolygon types, \c coordinates pairs with a QVariantList.
195 The list element is a QVariantMap containing geometry.
196
197 \list
198 \li For a \c MultiPoint object, \c coordinates pairs with a list of Point coordinates.
199 For example:
200 \code
201 {
202 "type": "MultiPoint",
203 "coordinates": [
204 [11, 60],
205 [5.5, 60.3],
206 [5.7, 58.90]
207 ]
208 }
209 \endcode
210 This GeoJSON object has a corresponding QVariantMap representation:
211 \code
212 {
213 type : "MultiPoint"
214 coordinates : [
215 {
216 type : "Point"
217 coordinates : QGeoCircle({60.000, 11.000}, -1)
218 },
219 {
220 type : "Point"
221 coordinates : QGeoCircle({60.300, 5.500}, -1)
222 },
223 {
224 type : "Point"
225 coordinates : QGeoCircle({58.900, 5.700}, -1)
226 }
227 ]
228 }
229 \endcode
230
231 \li For a \c MultiLineString object, \c coordinates pairs with a list of LineString coordinates.
232 The following GeoJSON object constructs two non-parallel lines:
233 \code
234 {
235 "type" : "MultiLineString",
236 "coordinates" : [
237 [[13.5, 43], [10.73, 59.92]],
238 [[9.15, 45], [-3.15, 58.90]]
239 ]
240 }
241 \endcode
242 This GeoJSON object has a corresponding QVariantMap representation:
243 \code
244 {
245 type : "MultiLineString"
246 coordinates : [
247 {
248 type : "LineString"
249 coordinates : QGeoPath([{45.000, 9.150}, {58.900, -3.150}])
250 },
251 {
252 type : "LineString"
253 coordinates : QGeoPath([{43.000, 13.500}, {59.920, 10.730}])
254 }
255 ]
256 }
257 \endcode
258
259 \li For a \c MultiPolygon type, \c coordinates pairs with a list of Polygon coordinates.
260 The polygon is a \e{linear ring} and the \c Polygon type has more information about accepted formats.
261 The following GeoJSON object contains a list of two triangles:
262 \code
263 {
264 "type" : "MultiPolygon",
265 "coordinates" : [
266 [
267 [[17.13, 51.11],
268 [30.54, 50.42],
269 [26.74, 58.36],
270 [17.13, 51.11]
271 ]],
272 [
273 [[19.84, 41.33],
274 [30.45, 49.26],
275 [17.07, 50.10],
276 [19.84, 41.33]
277 ]]
278 ]
279 }
280 \endcode
281 This GeoJSON object has a corresponding QVariantMap representation:
282 \code
283 {
284 type : "MultiPolygon"
285 coordinates : [
286 {
287 type : "Polygon"
288 coordinates : QGeoPolygon([{51.110, 17.130}, {50.420,30.540}, {58.360, 26.740}])
289 },
290 {
291 type : "Polygon"
292 coordinates : QGeoPolygon([{41.330, 19.840}, {49.260,30.450}, {50.100, 17.070}])
293 }
294 ]
295 }
296 \endcode
297
298 \endlist
299
300 The \c GeometryCollection type is a composition of other geometry types. The value of the
301 \c geometries member is a QVariantList containing QVariantMaps of various types,
302 including other GeometryCollection types.
303
304 For example, the following \c GeometryCollection type contains several other geometries:
305 \code
306 {
307 "type" : "GeometryCollection",
308 "geometries" : [
309 {
310 "type" : "MultiPoint",
311 "coordinates" : [
312 [11,60], [5.5,60.3], [5.7,58.90]
313 ]
314 },
315 {
316 "type" : "MultiLineString",
317 "coordinates": [
318 [[13.5, 43], [10.73, 59.92]],
319 [[9.15, 45], [-3.15, 58.90]]
320 ]
321 },
322 {
323 "type" : "MultiPolygon",
324 "coordinates" : [
325 [
326 [
327 [17.13, 51.11],
328 [30.54, 50.42],
329 [26.74, 58.36],
330 [17.13, 51.11]
331 ]
332 ],
333 [
334 [
335 [19.84, 41.33],
336 [30.45, 49.26],
337 [17.07, 50.10],
338 [19.84, 41.33]
339 ]
340 ]
341 ]
342 }
343 ]
344 }
345 \endcode
346 This GeoJSON object has a corresponding QVariantMap representation:
347 \code
348 {
349 type : "GeometryCollection"
350 coordinates : [
351 {
352 type : "MultiPolygon"
353 coordinates : [
354 {
355 type : "Polygon"
356 coordinates : QGeoPolygon([{41.330, 19.840}, {49.260, 30.450}, {50.100, 17.070}])
357 },
358 {
359 type : "Polygon"
360 coordinates : QGeoPolygon([{51.110, 17.130}, {50.420, 30.540}, {58.360, 26.740}])
361 }
362 ]
363 }
364 {
365 type : "MultiLineString"
366 coordinates : [
367 {
368 type : "LineString"
369 coordinates : QGeoPath([{45.000, 9.150}, {58.900, -3.150}])
370 },
371 {
372 type : "LineString"
373 coordinates : QGeoPath([{43.000, 13.500}, {59.920, 10.730}])
374 }
375 ]
376 }
377 {
378 type : "MultiPoint"
379 coordinates : [
380 {
381 type : Point
382 coordinates : QGeoCircle({58.900, 5.700}, -1)
383 },
384 {
385 type : Point
386 coordinates : QGeoCircle({60.300, 5.500}, -1)
387 },
388 {
389 type : Point
390 coordinates : QGeoCircle({60.000, 11.000}, -1)
391 }
392 ]
393 }
394 ]
395 }
396 \endcode
397
398 The \c Feature type contains an additional \c geometry and \c properties
399 member. The only way to distinguish a Feature object from other geometrical objects
400 is to check for the existence of a \c properties node in the QVariantMap object.
401
402 For example, the following \c Feature has a geometry and properties members:
403 \code
404 {
405 "type": "Feature",
406 "id": "Poly",
407 "properties": {
408 "name": "Poly",
409 "text": "This is a Feature with a Polygon",
410 "color": "limegreen"
411 },
412 "geometry": {
413 "type": "Polygon",
414 "coordinates": [
415 [
416 [17.13, 51.11],
417 [30.54, 50.42],
418 [26.70, 58.36],
419 [17.13, 51.11]
420 ],
421 [
422 [23.46, 54.36],
423 [20.52, 51.91],
424 [28.25, 51.50],
425 [26.80, 54.36],
426 [23.46, 54.36]
427 ]
428 ]
429 }
430 }
431 \endcode
432 This GeoJSON object has a corresponding QVariantMap representation:
433 \code
434 {
435 type : "Polygon"
436 data : QGeoPolygon([{51.110, 17.130}, {50.420,30.540}, {58.360, 26.700}, {51.110, 17.130}])
437 properties : {text : "This is a Feature with a Polygon"}
438 }
439 \endcode
440
441 The \c FeatureCollection is a composition of Feature objects. THe \c features
442 member binds to a QVariantList object containing other Feature objects.
443
444 For example, the following \c FeatureCollection has several Features and geometries:
445 \code
446 {
447 "type" : "FeatureCollection",
448 "properties" : {
449 "color" : "crimson"
450 },
451 "features" : [
452 {
453 "type" : "Feature",
454 "id" : "Poly",
455 "properties" : {
456 "text" : "This is a Feature with a Polygon"
457 },
458 "geometry" : {
459 "type" : "Polygon",
460 "coordinates" : [
461 [
462 [17.13, 51.11],
463 [30.54, 50.42],
464 [26.70, 58.36],
465 [17.13, 51.11]
466 ],
467 [
468 [23.46, 54.36],
469 [20.52, 51.91],
470 [28.25, 51.50],
471 [26.80, 54.36],
472 [23.46, 54.36]
473 ]
474 ]
475 }
476 },
477 {
478 "type" : "Feature",
479 "id" : "MultiLine",
480 "properties" : {
481 "text" : "This is a Feature with a MultiLineString",
482 "color" : "deepskyblue"
483 },
484 "geometry" : {
485 "type" : "MultiLineString",
486 "coordinates" : [
487 [[13.5, 43], [10.73, 59.92]],
488 [[9.15, 45], [-3.15, 58.90]]
489 ]
490 }
491 }
492 ]
493 }
494 \endcode
495 This GeoJSON object has a corresponding QVariantMap representation:
496 \code
497 {
498 type: "FeatureCollection"
499 data: [{
500 type: "MultiLineString"
501 data: [{
502 type: "LineString"
503 data: QGeoPath( [{45.000, 9.150}, {58.900, -3.150}] )
504 } {
505 type: "LineString"
506 data: QGeoPath( [{43.000, 13.500}, {59.920, 10.730}] )
507 }]
508 properties: { text: "This is a Feature with a MultiLineString" }
509 },
510 {
511 type: "Polygon"
512 data: QGeoPolygon( {51.110, 17.130},
513 {50.420, 30.540},
514 {58.360, 26.700},
515 {51.110, 17.130}
516 )
517 properties: { text: "This is a Feature with a Polygon" }
518 }
519 ]
520 }
521 \endcode
522
523 \section1 GeoJson Example
524
525 The \l{GeoJson Viewer (QML)}{GeoJson Viewer} example demonstrates the use of the GeoJsonData QML type to
526 load and visualize coordinates on a map.
527*/
528
529
530QDeclarativeGeoJsonData::QDeclarativeGeoJsonData(QObject *parent)
531 : QObject(parent)
532{
533
534}
535
536QDeclarativeGeoJsonData::~QDeclarativeGeoJsonData()
537{
538
539}
540
541/*!
542 \qmlproperty QVariant QtLocation::GeoJsonData::model
543
544 A QVariant representation of the GeoJSON document. QML
545 delegates can display the contents in views.
546
547 \since 6.7
548*/
549QVariant QDeclarativeGeoJsonData::model() const
550{
551 return m_content;
552}
553
554void QDeclarativeGeoJsonData::setModel(const QVariant &model)
555{
556 m_content = model;
557 emit modelChanged();
558}
559
560
561/*!
562 \qmlproperty url QtLocation::GeoJsonData::sourceUrl
563
564 The URL of a GeoJSON document. Setting this property loads the
565 document and binds the object to the \l model member.
566
567 \since 6.7
568*/
569
570
571QUrl QDeclarativeGeoJsonData::sourceUrl() const
572{
573 return m_url;
574}
575
576/*!
577 \qmlmethod void QtLocation::GeoJsonData::clear()
578
579 Deletes all items bound to the \l model.
580*/
581void QDeclarativeGeoJsonData::clear()
582{
583 m_content = QVariantList();
584 emit modelChanged();
585}
586
587/*!
588 \qmlmethod bool QtLocation::GeoJsonData::addItem(Item item)
589
590 Adds the \a item to the \l model object.
591
592 Returns \c true if adding is successful, \c false otherwise.
593*/
594void QDeclarativeGeoJsonData::addItem(QQuickItem *item)
595{
596 QVariant entry;
597 if (auto *polyline = qobject_cast<QDeclarativePolylineMapItem *>(item))
598 entry = extractor::toVariant(polyline);
599 else if (auto *polygon = qobject_cast<QDeclarativePolygonMapItem *>(item))
600 entry = extractor::toVariant(polygon);
601 else if (auto *circle = qobject_cast<QDeclarativeCircleMapItem *>(item))
602 entry = extractor::toVariant(circle);
603 else if (auto *rectangle = qobject_cast<QDeclarativeRectangleMapItem *>(item))
604 entry = extractor::toVariant(rectangle);
605 else
606 return;
607
608 QVariantList geoJson = m_content.toList();
609 if (!geoJson.isEmpty()){
610 QVariantList geoData = (geoJson[0].toMap()[QStringLiteral("type")] == QStringLiteral("FeatureCollection")) ? geoJson[0].toMap()[QStringLiteral("data")].toList() : geoJson;
611 geoData.append(entry);
612 geoJson[0] = QVariantMap{{QStringLiteral("type"), QStringLiteral("FeatureCollection")}, {QStringLiteral("data"), geoData}};
613 }
614 else {
615 geoJson.append(entry);
616 }
617 m_content = geoJson;
618 emit modelChanged();
619}
620
621/*!
622 \qmlmethod bool QtLocation::GeoJsonData::open()
623
624 Loads the content of the file at \l sourceUrl.
625
626 Returns \c true if opening is successful, \c false otherwise.
627*/
628bool QDeclarativeGeoJsonData::open()
629{
630 return openUrl(m_url);
631}
632
633/*!
634 \qmlmethod bool QtLocation::GeoJsonData::openUrl(Url url)
635
636 Loads the GeoJson document at \a url and binds it to the \l model. The property
637 \l sourceUrl is set to \a url if opening the file is successful.
638
639 Returns \c true if opening is successful, \c false otherwise.
640*/
641bool QDeclarativeGeoJsonData::openUrl(const QUrl &url)
642{
643 // Reading GeoJSON file
644 QFile loadFile(url.toLocalFile());
645 if (!loadFile.open(QIODevice::ReadOnly)) {
646 qWarning() << "Error while opening the file: " << url;
647 qWarning() << loadFile.errorString();
648 return false;
649 }
650
651 // Load the GeoJSON file using Qt's API
652 QJsonParseError err;
653 QJsonDocument loadDoc(QJsonDocument::fromJson(loadFile.readAll(), &err));
654 if (err.error) {
655 qWarning() << "Parsing while importing the JSON document:\n" << err.errorString();
656 return false;
657 }
658
659 // Import geographic data to a QVariantList
660 m_content = QGeoJson::importGeoJson(loadDoc);
661 if (m_url != url) {
662 m_url = url;
663 emit sourceUrlChanged();
664 }
665 emit modelChanged();
666 return true;
667}
668
669/*!
670 \qmlmethod bool QtLocation::GeoJsonData::saveAs(Url url)
671
672 Saves the \l model at \a url.
673 The \l sourceUrl property is set to \a url if successful.
674
675 Returns \c true if saving is successful, \c false otherwise.
676*/
677bool QDeclarativeGeoJsonData::saveAs(const QUrl &url)
678{
679 if (m_url != url){
680 m_url = url;
681 emit sourceUrlChanged();
682 }
683 return save();
684}
685
686/*!
687 \qmlmethod bool QtLocation::GeoJsonData::save()
688
689 Saves the model at \l{sourceUrl}.
690
691 Returns \c true if saving is successful, \c false otherwise.
692*/
693bool QDeclarativeGeoJsonData::save()
694{
695 return dumpGeoJSON(m_content.toList(), m_url);
696}
697
698/*!
699 \qmlmethod void QtLocation::GeoJsonData::setModelToMapContents(MapView mapItemView)
700
701 Adds all map items of \a mapItemView to the \l model of the GeoJsonData
702 object. Deletes previously stored map items from the \l model.
703
704 Returns \c true if setting is successful, \c false otherwise.
705
706 \sa addItem
707*/
708void QDeclarativeGeoJsonData::setModelToMapContents(QDeclarativeGeoMap *map)
709{
710 m_content = toVariant(map);
711 emit modelChanged();
712}
713
714/*! \internal
715 A helper function to convert the children of a map to a \l QVariantList that
716 represents the items and that can be exported to a Json file.
717
718 Returns a \l QVariantList containing all data of the mapItems.
719*/
720QVariantList QDeclarativeGeoJsonData::toVariant(QDeclarativeGeoMap *map)
721{
722 QVariantList res;
723 const QList<QObject*> mapChildren = map->children();
724 for (QObject *child : mapChildren) {
725 QVariant mapItemAsVariant = extractor::toVariant(child);
726 if (mapItemAsVariant.isValid())
727 res.append(mapItemAsVariant);
728 }
729 return res;
730}
731
732/*! \internal
733 A helper function to dump the VariantList \a geoJson into the file at \a url.
734
735 Returns \c true if the file was saved successfully, \c false otherwise.
736*/
737bool QDeclarativeGeoJsonData::dumpGeoJSON(const QVariantList &geoJson, const QUrl &url)
738{
739 QJsonDocument json = QGeoJson::exportGeoJson(geoJson);
740 QFile jsonFile(url.toLocalFile());
741 if (!jsonFile.open(QIODevice::WriteOnly))
742 return false;
743 jsonFile.write(json.toJson());
744 jsonFile.close();
745 return true;
746}
747
748/*! \internal
749 A helper function to write a human interpretable representation of
750 \a geoJson into the file at \a url.
751
752 Returns \c true if the file was saved successfully, \c false otherwise.
753*/
754bool QDeclarativeGeoJsonData::writeDebug(const QVariantList &geoJson, const QUrl &url)
755{
756 QString prettyPrint = QGeoJson::toString(geoJson);
757 QFile debugFile(url.toLocalFile());
758 if (!debugFile.open(QIODevice::WriteOnly))
759 return false;
760 debugFile.write(prettyPrint.toUtf8());
761 debugFile.close();
762 return true;
763}
764
765/*! \internal
766 A helper function to generate a human interpretable representation of
767 \a geoJson.
768
769 Returns a string with the human interpretable representation of \a geoJson.
770*/
771QString QDeclarativeGeoJsonData::toString(const QVariantList &geoJson)
772{
773 return QGeoJson::toString(geoJson);
774}
775
776QT_END_NAMESPACE
static QVariant toVariant(QObject *mapItem)
static bool hasProperties(QQuickItem *item)