File indexing completed on 2024-05-12 04:42:47

0001 /*
0002     SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "geojson_p.h"
0008 
0009 #include <QJsonArray>
0010 #include <QJsonObject>
0011 #include <QPointF>
0012 #include <QPolygonF>
0013 
0014 using namespace KPublicTransport;
0015 
0016 static QPointF readPointCoordinates(const QJsonArray &coords)
0017 {
0018     if (coords.size() != 2) {
0019         return {};
0020     }
0021 
0022     return {coords.at(0).toDouble(), coords.at(1).toDouble()};
0023 }
0024 
0025 QPointF GeoJson::readPoint(const QJsonObject &obj)
0026 {
0027     const auto type = obj.value(QLatin1String("type")).toString();
0028     if (type != QLatin1String("Point")) {
0029         return {};
0030     }
0031 
0032     const auto coordinates = obj.value(QLatin1String("coordinates")).toArray();
0033     return readPointCoordinates(coordinates);
0034 }
0035 
0036 static QPolygonF readPolygonCoordinates(const QJsonArray &coords)
0037 {
0038     QPolygonF poly;
0039     poly.reserve(coords.size());
0040     for (const auto &pointV : coords) {
0041         const auto point = pointV.toArray();
0042         poly.push_back(readPointCoordinates(point));
0043     }
0044     return poly;
0045 }
0046 
0047 static QPolygonF readOuterPolygonCoordinates(const QJsonArray &coordinates)
0048 {
0049     if (coordinates.empty()) {
0050         return {};
0051     }
0052     return readPolygonCoordinates(coordinates.at(0).toArray());
0053 }
0054 
0055 QPolygonF GeoJson::readLineString(const QJsonObject &obj)
0056 {
0057     const auto type = obj.value(QLatin1String("type")).toString();
0058     if (type != QLatin1String("LineString")) {
0059         return {};
0060     }
0061 
0062     const auto coordinates = obj.value(QLatin1String("coordinates")).toArray();
0063     return readPolygonCoordinates(coordinates);
0064 }
0065 
0066 QPolygonF GeoJson::readOuterPolygon(const QJsonObject &obj)
0067 {
0068     const auto type = obj.value(QLatin1String("type")).toString();
0069     if (type == QLatin1String("Polygon")) {
0070         return readOuterPolygonCoordinates(obj.value(QLatin1String("coordinates")).toArray());
0071     } else if (type == QLatin1String("MultiPolygon")) {
0072         const auto coordinates = obj.value(QLatin1String("coordinates")).toArray();
0073         QPolygonF poly;
0074         for (const auto &polyV : coordinates) {
0075             auto subPoly = readOuterPolygonCoordinates(polyV.toArray());
0076             poly = poly.empty() ? std::move(subPoly) : poly.united(subPoly);
0077         }
0078         return poly;
0079     }
0080 
0081     return {};
0082 }
0083 
0084 std::vector<QPolygonF> GeoJson::readOuterPolygons(const QJsonObject &obj)
0085 {
0086     const auto type = obj.value(QLatin1String("type")).toString();
0087     if (type == QLatin1String("Polygon")) {
0088         return {readOuterPolygonCoordinates(obj.value(QLatin1String("coordinates")).toArray())};
0089     } else if (type == QLatin1String("MultiPolygon")) {
0090         const auto coordinates = obj.value(QLatin1String("coordinates")).toArray();
0091         std::vector<QPolygonF> polys;
0092         polys.reserve(coordinates.size());
0093         for (const auto &polyV : coordinates) {
0094             polys.push_back(readOuterPolygonCoordinates(polyV.toArray()));
0095         }
0096         return polys;
0097     }
0098 
0099     return {};
0100 }
0101 
0102 static QJsonArray writePoint(const QPointF &p)
0103 {
0104     return QJsonArray({ p.x(), p.y() });
0105 }
0106 
0107 QJsonObject GeoJson::writeLineString(const QPolygonF &lineString)
0108 {
0109     QJsonObject obj;
0110     obj.insert(QLatin1String("type"), QLatin1String("LineString"));
0111 
0112     QJsonArray coords;
0113     for (const auto &p : lineString) {
0114         coords.push_back(writePoint(p));
0115     }
0116     obj.insert(QLatin1String("coordinates"), coords);
0117     return obj;
0118 }
0119 
0120 QJsonObject GeoJson::writePolygon(const QPolygonF &polygon)
0121 {
0122     QJsonObject obj;
0123     obj.insert(QLatin1String("type"), QLatin1String("Polygon"));
0124 
0125     QJsonArray coords;
0126     for (const auto &p : polygon) {
0127         coords.push_back(writePoint(p));
0128     }
0129     QJsonArray polyArray;
0130     polyArray.push_back(coords);
0131     obj.insert(QLatin1String("coordinates"), polyArray);
0132     return obj;
0133 }
0134 
0135 QJsonObject GeoJson::writePolygons(const std::vector<QPolygonF> &polygons)
0136 {
0137     if (polygons.empty()) {
0138         return {};
0139     }
0140     if (polygons.size() == 1) {
0141         return writePolygon(polygons[0]);
0142     }
0143 
0144     QJsonObject obj;
0145     obj.insert(QLatin1String("type"), QLatin1String("MultiPolygon"));
0146 
0147     QJsonArray multiPolys;
0148     for (const auto &polygon : polygons) {
0149         QJsonArray coords;
0150         for (const auto &p : polygon) {
0151             coords.push_back(writePoint(p));
0152         }
0153         QJsonArray polyArray;
0154         polyArray.push_back(coords);
0155         multiPolys.push_back(polyArray);
0156     }
0157     obj.insert(QLatin1String("coordinates"), multiPolys);
0158     return obj;
0159 }