6#include <QtCore/QJsonArray>
7#include <QtCore/QJsonValue>
8#include <QtCore/QCoreApplication>
9#include <QtCore/QVariantMap>
10#include <QtLocation/private/qgeojson_p.h>
11#include <QtPositioning/QGeoCoordinate>
12#include <QtPositioning/QGeoPath>
13#include <QtPositioning/QGeoPolygon>
24 constexpr const char *
_errorPrefix = QT_TRANSLATE_NOOP(
"GeoJsonHelper",
"GeoJson file load failed. %1");
33 if (value.canConvert<QGeoPolygon>() || value.canConvert<QGeoPath>() || value.canConvert<QGeoShape>()) {
34 (void) shapes.append(value);
37 if (value.typeId() == QMetaType::QVariantList) {
38 const QVariantList children = value.toList();
39 for (
const QVariant &child : children) {
42 }
else if (value.typeId() == QMetaType::QVariantMap) {
43 const QVariantMap map = value.toMap();
44 for (
auto it = map.cbegin(); it != map.cend(); ++it) {
53 for (
const QVariant &value : values) {
66 QCoreApplication::translate(
"GeoJson",
"File not found: %1").arg(filePath));
67 return QJsonDocument();
70 if (!file.open(QIODevice::ReadOnly)) {
72 QCoreApplication::translate(
"GeoJson",
"Unable to open file: %1 error: %2")
73 .arg(filePath, file.errorString()));
74 return QJsonDocument();
77 QJsonDocument jsonDoc;
78 const QByteArray bytes = file.readAll();
92 return ShapeType::Error;
95 const QVariantList imported = QGeoJson::importGeoJson(jsonDoc);
97 if (shapes.isEmpty()) {
99 QCoreApplication::translate(
"GeoJson",
"No shapes found in GeoJson file."));
100 return ShapeType::Error;
103 for (
const QVariant &shapeVar : shapes) {
104 if (shapeVar.canConvert<QGeoPolygon>()) {
105 return ShapeType::Polygon;
107 if (shapeVar.canConvert<QGeoPath>()) {
108 return ShapeType::Polyline;
110 if (shapeVar.canConvert<QGeoShape>()) {
111 const QGeoShape shape = shapeVar.value<QGeoShape>();
112 if (shape.type() == QGeoShape::PolygonType) {
113 return ShapeType::Polygon;
115 if (shape.type() == QGeoShape::PathType) {
116 return ShapeType::Polyline;
122 QCoreApplication::translate(
"GeoJson",
"No supported type found in GeoJson file."));
123 return ShapeType::Error;
136 const QVariantList imported = QGeoJson::importGeoJson(jsonDoc);
138 if (shapes.isEmpty()) {
140 QCoreApplication::translate(
"GeoJson",
"No polygon data found in GeoJson file."));
144 for (
const QVariant &shapeVar : shapes) {
145 if (shapeVar.canConvert<QGeoPolygon>()) {
146 const QGeoPolygon poly = shapeVar.value<QGeoPolygon>();
147 vertices = poly.perimeter();
150 if (shapeVar.canConvert<QGeoShape>()) {
151 const QGeoShape shape = shapeVar.value<QGeoShape>();
152 if (shape.type() == QGeoShape::PolygonType) {
153 const QGeoPolygon poly(shape);
154 vertices = poly.perimeter();
155 if (!vertices.isEmpty()) {
163 QCoreApplication::translate(
"GeoJson",
"No polygon found in GeoJson file."));
177 const QVariantList imported = QGeoJson::importGeoJson(jsonDoc);
179 if (shapes.isEmpty()) {
181 QCoreApplication::translate(
"GeoJson",
"No polyline data found in GeoJson file."));
185 for (
const QVariant &shapeVar : shapes) {
186 if (shapeVar.canConvert<QGeoPath>()) {
187 const QGeoPath path = shapeVar.value<QGeoPath>();
188 coords = path.path();
191 if (shapeVar.canConvert<QGeoShape>()) {
192 const QGeoShape shape = shapeVar.value<QGeoShape>();
193 if (shape.type() == QGeoShape::PathType) {
194 const QGeoPath path(shape);
195 coords = path.path();
196 if (!coords.isEmpty()) {
204 QCoreApplication::translate(
"GeoJson",
"No polyline found in GeoJson file."));
210 if (!jsonValue.isArray()) {
211 errorString = QCoreApplication::translate(
"GeoJsonHelper",
"value for coordinate is not array");
215 const QJsonArray coordinateArray = jsonValue.toArray();
216 const int requiredCount = altitudeRequired ? 3 : 2;
217 if (coordinateArray.count() != requiredCount) {
218 errorString = QCoreApplication::translate(
"GeoJsonHelper",
"Coordinate array must contain %1 values").arg(requiredCount);
222 for (
const QJsonValue &coordinateValue : coordinateArray) {
223 if ((coordinateValue.type() != QJsonValue::Double) && (coordinateValue.type() != QJsonValue::Null)) {
225 QCoreApplication::translate(
"GeoJsonHelper",
"Coordinate array may only contain double values, found: %1").arg(coordinateValue.type());
231 coordinate = QGeoCoordinate(coordinateArray[1].toDouble(), coordinateArray[0].toDouble());
232 if (altitudeRequired) {
241 QJsonArray coordinateArray;
242 coordinateArray << coordinate.longitude() << coordinate.latitude();
244 coordinateArray << coordinate.altitude();
246 jsonValue = QJsonValue(coordinateArray);
252 if (!jsonValue.isArray()) {
253 errorString = QCoreApplication::translate(
"GeoJsonHelper",
"value for coordinate is not array");
257 const QJsonArray coordinateArray = jsonValue.toArray();
258 const int requiredCount = altitudeRequired ? 3 : 2;
259 if (coordinateArray.count() != requiredCount) {
260 errorString = QCoreApplication::translate(
"GeoJsonHelper",
"Coordinate array must contain %1 values").arg(requiredCount);
264 for (
const QJsonValue &coordinateValue : coordinateArray) {
265 if ((coordinateValue.type() != QJsonValue::Double) && (coordinateValue.type() != QJsonValue::Null)) {
267 QCoreApplication::translate(
"GeoJsonHelper",
"Coordinate array may only contain double values, found: %1").arg(coordinateValue.type());
272 coordinate = QGeoCoordinate(
276 if (altitudeRequired) {
285 QJsonArray coordinateArray;
286 coordinateArray << coordinate.latitude() << coordinate.longitude();
289 coordinateArray << coordinate.altitude();
292 jsonValue = QJsonValue(coordinateArray);
298 if (!jsonValue.isArray()) {
299 errorString = QCoreApplication::translate(
"GeoJsonHelper",
"value for coordinate array is not array");
303 const QJsonArray rgJsonPoints = jsonValue.toArray();
306 for (
const QJsonValue &point : rgJsonPoints) {
307 QGeoCoordinate coordinate;
311 rgVarPoints.append(QVariant::fromValue(coordinate));
318 QList<QGeoCoordinate> &rgPoints, QString &
errorString)
320 QVariantList rgVarPoints;
327 for (
const QVariant &point : rgVarPoints) {
328 rgPoints.append(point.value<QGeoCoordinate>());
336 QJsonArray rgJsonPoints;
337 for (
const QVariant &point : rgVarPoints) {
338 QJsonValue jsonPoint;
340 rgJsonPoints.append(jsonPoint);
343 jsonValue = rgJsonPoints;
347 QJsonValue &jsonValue)
349 QVariantList rgVarPoints;
350 for (
const QGeoCoordinate &coord : rgPoints) {
351 rgVarPoints.append(QVariant::fromValue(coord));
#define QGC_LOGGING_CATEGORY(name, categoryStr)
bool loadGeoCoordinateArray(const QJsonValue &jsonValue, bool altitudeRequired, QVariantList &rgVarPoints, QString &errorString)
Loads a list of QGeoCoordinates (QGC plan format) from a json array.
void saveGeoCoordinateArray(const QVariantList &rgVarPoints, bool writeAltitude, QJsonValue &jsonValue)
Saves a list of QGeoCoordinates (QGC plan format) to a json array.
QVariantList _extractShapeValues(const QVariantList &values)
constexpr const char * _errorPrefix
bool loadGeoCoordinate(const QJsonValue &jsonValue, bool altitudeRequired, QGeoCoordinate &coordinate, QString &errorString)
ShapeFileHelper::ShapeType determineShapeType(const QString &filePath, QString &errorString)
bool loadPolylineFromFile(const QString &filePath, QList< QGeoCoordinate > &coords, QString &errorString)
bool loadGeoJsonCoordinate(const QJsonValue &jsonValue, bool altitudeRequired, QGeoCoordinate &coordinate, QString &errorString)
returned error string if load failure
void saveGeoJsonCoordinate(const QGeoCoordinate &coordinate, bool writeAltitude, QJsonValue &jsonValue)
json value to save to
void saveGeoCoordinate(const QGeoCoordinate &coordinate, bool writeAltitude, QJsonValue &jsonValue)
Saves a QGeoCoordinate as [lat, lon, alt] array (QGC plan format).
QJsonDocument _loadFile(const QString &filePath, QString &errorString)
bool loadPolygonFromFile(const QString &filePath, QList< QGeoCoordinate > &vertices, QString &errorString)
constexpr int _maxRecursionDepth
void _extractShapeValuesRecursive(const QVariant &value, QVariantList &shapes, int depth=0)
bool isJsonFile(const QByteArray &bytes, QJsonDocument &jsonDoc, QString &errorString)
Determines whether an in-memory byte buffer contains parseable JSON content.
double possibleNaNJsonValue(const QJsonValue &value)
Returns NaN if the value is null, or the value converted to double otherwise.