1 #include "qt_geojson.hpp"
2 #include <mapbox/geojson.hpp>
3 #include <mbgl/util/geometry.hpp>
4 #include <mbgl/util/feature.hpp>
5 
6 namespace QMapbox {
7 
asMapboxGLPoint(const QMapbox::Coordinate & coordinate)8 mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate) {
9     return mbgl::Point<double> { coordinate.second, coordinate.first };
10 }
11 
asMapboxGLMultiPoint(const QMapbox::Coordinates & multiPoint)12 mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint) {
13     mbgl::MultiPoint<double> mbglMultiPoint;
14     mbglMultiPoint.reserve(multiPoint.size());
15     for (const auto &point: multiPoint) {
16         mbglMultiPoint.emplace_back(asMapboxGLPoint(point));
17     }
18     return mbglMultiPoint;
19 };
20 
asMapboxGLLineString(const QMapbox::Coordinates & lineString)21 mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString) {
22     mbgl::LineString<double> mbglLineString;
23     mbglLineString.reserve(lineString.size());
24     for (const auto &coordinate : lineString) {
25         mbglLineString.emplace_back(asMapboxGLPoint(coordinate));
26     }
27     return mbglLineString;
28 };
29 
asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection & multiLineString)30 mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString) {
31     mbgl::MultiLineString<double> mbglMultiLineString;
32     mbglMultiLineString.reserve(multiLineString.size());
33     for (const auto &lineString : multiLineString) {
34         mbglMultiLineString.emplace_back(std::forward<mbgl::LineString<double>>(asMapboxGLLineString(lineString)));
35     }
36     return mbglMultiLineString;
37 };
38 
asMapboxGLPolygon(const QMapbox::CoordinatesCollection & polygon)39 mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon) {
40     mbgl::Polygon<double> mbglPolygon;
41     mbglPolygon.reserve(polygon.size());
42     for (const auto &linearRing : polygon) {
43         mbgl::LinearRing<double> mbglLinearRing;
44         mbglLinearRing.reserve(linearRing.size());
45         for (const auto &coordinate: linearRing) {
46             mbglLinearRing.emplace_back(asMapboxGLPoint(coordinate));
47         }
48         mbglPolygon.emplace_back(std::move(mbglLinearRing));
49     }
50     return mbglPolygon;
51 };
52 
asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections & multiPolygon)53 mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon) {
54     mbgl::MultiPolygon<double> mbglMultiPolygon;
55     mbglMultiPolygon.reserve(multiPolygon.size());
56     for (const auto &polygon : multiPolygon) {
57         mbglMultiPolygon.emplace_back(std::forward<mbgl::Polygon<double>>(asMapboxGLPolygon(polygon)));
58     }
59     return mbglMultiPolygon;
60 };
61 
asMapboxGLPropertyValue(const QVariant & value)62 mbgl::Value asMapboxGLPropertyValue(const QVariant &value) {
63     auto valueList = [](const QVariantList &list) {
64         std::vector<mbgl::Value> mbglList;
65         mbglList.reserve(list.size());
66         for (const auto& listValue : list) {
67             mbglList.emplace_back(asMapboxGLPropertyValue(listValue));
68         }
69         return mbglList;
70     };
71 
72     auto valueMap = [](const QVariantMap &map) {
73         std::unordered_map<std::string, mbgl::Value> mbglMap;
74         mbglMap.reserve(map.size());
75         for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
76             mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value())));
77         }
78         return mbglMap;
79     };
80 
81     switch (value.type()) {
82 #if QT_VERSION >= 0x050000
83     case QMetaType::UnknownType:
84 #else
85     case QVariant::Invalid:
86 #endif
87         return mbgl::NullValue {};
88     case QMetaType::Bool:
89         return { value.toBool() };
90     case QMetaType::ULongLong:
91         return { uint64_t(value.toULongLong()) };
92     case QMetaType::LongLong:
93         return { int64_t(value.toLongLong()) };
94     case QMetaType::Double:
95         return { value.toDouble() };
96     case QMetaType::QString:
97         return { value.toString().toStdString() };
98     case QMetaType::QVariantList:
99         return valueList(value.toList());
100     case QMetaType::QVariantMap:
101         return valueMap(value.toMap());
102     default:
103         qWarning() << "Unsupported feature property value:" << value;
104         return {};
105     }
106 }
107 
asMapboxGLFeatureIdentifier(const QVariant & id)108 mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) {
109     switch (id.type()) {
110 #if QT_VERSION >= 0x050000
111     case QMetaType::UnknownType:
112 #else
113     case QVariant::Invalid:
114 #endif
115         return {};
116     case QMetaType::ULongLong:
117         return { uint64_t(id.toULongLong()) };
118     case QMetaType::LongLong:
119         return { int64_t(id.toLongLong()) };
120     case QMetaType::Double:
121         return { id.toDouble() };
122     case QMetaType::QString:
123         return { id.toString().toStdString() };
124     default:
125         qWarning() << "Unsupported feature identifier:" << id;
126         return {};
127     }
128 }
129 
asMapboxGLFeature(const QMapbox::Feature & feature)130 mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature) {
131     mbgl::PropertyMap properties;
132     properties.reserve(feature.properties.size());
133     for (auto it = feature.properties.constBegin(); it != feature.properties.constEnd(); ++it) {
134         properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value())));
135     }
136 
137     mbgl::FeatureIdentifier id = asMapboxGLFeatureIdentifier(feature.id);
138 
139     if (feature.type == QMapbox::Feature::PointType) {
140         const QMapbox::Coordinates &points = feature.geometry.first().first();
141         if (points.size() == 1) {
142             return { asMapboxGLPoint(points.first()), std::move(properties), std::move(id) };
143         } else {
144             return { asMapboxGLMultiPoint(points), std::move(properties), std::move(id) };
145         }
146     } else if (feature.type == QMapbox::Feature::LineStringType) {
147         const QMapbox::CoordinatesCollection &lineStrings = feature.geometry.first();
148         if (lineStrings.size() == 1) {
149             return { asMapboxGLLineString(lineStrings.first()), std::move(properties), std::move(id) };
150         } else {
151             return { asMapboxGLMultiLineString(lineStrings), std::move(properties), std::move(id) };
152         }
153     } else { // PolygonType
154         const QMapbox::CoordinatesCollections &polygons = feature.geometry;
155         if (polygons.size() == 1) {
156             return { asMapboxGLPolygon(polygons.first()), std::move(properties), std::move(id) };
157         } else {
158             return { asMapboxGLMultiPolygon(polygons), std::move(properties), std::move(id) };
159         }
160     }
161 };
162 
163 } // namespace QMapbox
164