/src/gdal/ogr/ogrsf_frmts/mvt/mvtutils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: MVT Translator |
4 | | * Purpose: Mapbox Vector Tile decoder |
5 | | * Author: Even Rouault, Even Rouault <even dot rouault at spatialys dot com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "mvtutils.h" |
14 | | #include "ogr_api.h" |
15 | | |
16 | | /************************************************************************/ |
17 | | /* OGRMVTInitFields() */ |
18 | | /************************************************************************/ |
19 | | |
20 | | void OGRMVTInitFields(OGRFeatureDefn *poFeatureDefn, |
21 | | const CPLJSONObject &oFields, |
22 | | const CPLJSONArray &oAttributesFromTileStats) |
23 | 305k | { |
24 | 305k | { |
25 | 305k | OGRFieldDefn oFieldDefnId("mvt_id", OFTInteger64); |
26 | 305k | poFeatureDefn->AddFieldDefn(&oFieldDefnId); |
27 | 305k | } |
28 | | |
29 | 305k | if (oFields.IsValid()) |
30 | 110k | { |
31 | 110k | for (const auto &oField : oFields.GetChildren()) |
32 | 50.3k | { |
33 | 50.3k | if (oField.GetType() == CPLJSONObject::Type::String) |
34 | 22.4k | { |
35 | 22.4k | if (oField.ToString() == "Number") |
36 | 0 | { |
37 | 0 | OGRFieldDefn oFieldDefn(oField.GetName().c_str(), OFTReal); |
38 | |
|
39 | 0 | for (int i = 0; i < oAttributesFromTileStats.Size(); ++i) |
40 | 0 | { |
41 | 0 | if (oAttributesFromTileStats[i].GetString( |
42 | 0 | "attribute") == oField.GetName() && |
43 | 0 | oAttributesFromTileStats[i].GetString("type") == |
44 | 0 | "number") |
45 | 0 | { |
46 | 0 | const auto eMinType = oAttributesFromTileStats[i] |
47 | 0 | .GetObj("min") |
48 | 0 | .GetType(); |
49 | 0 | const auto eMaxType = oAttributesFromTileStats[i] |
50 | 0 | .GetObj("max") |
51 | 0 | .GetType(); |
52 | 0 | if (eMinType == CPLJSONObject::Type::Integer && |
53 | 0 | eMaxType == CPLJSONObject::Type::Integer) |
54 | 0 | { |
55 | 0 | oFieldDefn.SetType(OFTInteger); |
56 | 0 | } |
57 | 0 | else if ((eMinType == |
58 | 0 | CPLJSONObject::Type::Integer || |
59 | 0 | eMinType == CPLJSONObject::Type::Long) && |
60 | 0 | eMaxType == CPLJSONObject::Type::Long) |
61 | 0 | { |
62 | 0 | oFieldDefn.SetType(OFTInteger64); |
63 | 0 | } |
64 | 0 | break; |
65 | 0 | } |
66 | 0 | } |
67 | |
|
68 | 0 | poFeatureDefn->AddFieldDefn(&oFieldDefn); |
69 | 0 | } |
70 | 22.4k | else if (oField.ToString() == "Integer") // GDAL extension |
71 | 0 | { |
72 | 0 | OGRFieldDefn oFieldDefn(oField.GetName().c_str(), |
73 | 0 | OFTInteger); |
74 | 0 | poFeatureDefn->AddFieldDefn(&oFieldDefn); |
75 | 0 | } |
76 | 22.4k | else if (oField.ToString() == "Boolean") |
77 | 0 | { |
78 | 0 | OGRFieldDefn oFieldDefn(oField.GetName().c_str(), |
79 | 0 | OFTInteger); |
80 | 0 | oFieldDefn.SetSubType(OFSTBoolean); |
81 | 0 | poFeatureDefn->AddFieldDefn(&oFieldDefn); |
82 | 0 | } |
83 | 22.4k | else |
84 | 22.4k | { |
85 | 22.4k | OGRFieldDefn oFieldDefn(oField.GetName().c_str(), |
86 | 22.4k | OFTString); |
87 | 22.4k | poFeatureDefn->AddFieldDefn(&oFieldDefn); |
88 | 22.4k | } |
89 | 22.4k | } |
90 | 50.3k | } |
91 | 110k | } |
92 | 305k | } |
93 | | |
94 | | /************************************************************************/ |
95 | | /* OGRMVTFindGeomTypeFromTileStat() */ |
96 | | /************************************************************************/ |
97 | | |
98 | | OGRwkbGeometryType |
99 | | OGRMVTFindGeomTypeFromTileStat(const CPLJSONArray &oTileStatLayers, |
100 | | const char *pszLayerName) |
101 | 20.8k | { |
102 | 20.8k | OGRwkbGeometryType eGeomType = wkbUnknown; |
103 | 43.7k | for (int i = 0; i < oTileStatLayers.Size(); i++) |
104 | 32.3k | { |
105 | 32.3k | CPLJSONObject oId = oTileStatLayers[i].GetObj("layer"); |
106 | 32.3k | if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String) |
107 | 24.0k | { |
108 | 24.0k | if (oId.ToString() == pszLayerName) |
109 | 9.49k | { |
110 | 9.49k | CPLJSONObject oGeom = oTileStatLayers[i].GetObj("geometry"); |
111 | 9.49k | if (oGeom.IsValid() && |
112 | 9.49k | oGeom.GetType() == CPLJSONObject::Type::String) |
113 | 6.98k | { |
114 | 6.98k | const std::string oGeomType(oGeom.ToString()); |
115 | | // Note: this information is not |
116 | | // reliable in case |
117 | | // of mix of geometry types |
118 | 6.98k | if (oGeomType == "Point") |
119 | 5.87k | { |
120 | 5.87k | eGeomType = wkbMultiPoint; |
121 | 5.87k | } |
122 | 1.10k | else if (oGeomType == "LineString") |
123 | 0 | { |
124 | 0 | eGeomType = wkbMultiLineString; |
125 | 0 | } |
126 | 1.10k | else if (oGeomType == "Polygon") |
127 | 8 | { |
128 | 8 | eGeomType = wkbMultiPolygon; |
129 | 8 | } |
130 | 6.98k | } |
131 | 9.49k | break; |
132 | 9.49k | } |
133 | 24.0k | } |
134 | 32.3k | } |
135 | 20.8k | return eGeomType; |
136 | 20.8k | } |
137 | | |
138 | | /************************************************************************/ |
139 | | /* OGRMVTFindAttributesFromTileStat() */ |
140 | | /************************************************************************/ |
141 | | |
142 | | CPLJSONArray |
143 | | OGRMVTFindAttributesFromTileStat(const CPLJSONArray &oTileStatLayers, |
144 | | const char *pszLayerName) |
145 | 458k | { |
146 | 481k | for (int i = 0; i < oTileStatLayers.Size(); i++) |
147 | 32.3k | { |
148 | 32.3k | CPLJSONObject oId = oTileStatLayers[i].GetObj("layer"); |
149 | 32.3k | if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String) |
150 | 24.0k | { |
151 | 24.0k | if (oId.ToString() == pszLayerName) |
152 | 9.49k | { |
153 | 9.49k | CPLJSONObject oAttributes = |
154 | 9.49k | oTileStatLayers[i].GetObj("attributes"); |
155 | 9.49k | if (oAttributes.IsValid() && |
156 | 9.49k | oAttributes.GetType() == CPLJSONObject::Type::Array) |
157 | 3.20k | { |
158 | 3.20k | return oAttributes.ToArray(); |
159 | 3.20k | } |
160 | 6.28k | break; |
161 | 9.49k | } |
162 | 24.0k | } |
163 | 32.3k | } |
164 | 455k | CPLJSONArray oAttributes; |
165 | 455k | oAttributes.Deinit(); |
166 | 455k | return oAttributes; |
167 | 458k | } |
168 | | |
169 | | /************************************************************************/ |
170 | | /* OGRMVTCreateFeatureFrom() */ |
171 | | /************************************************************************/ |
172 | | |
173 | | OGRFeature *OGRMVTCreateFeatureFrom(OGRFeature *poSrcFeature, |
174 | | OGRFeatureDefn *poTargetFeatureDefn, |
175 | | bool bJsonField, OGRSpatialReference *poSRS) |
176 | 50.7k | { |
177 | 50.7k | OGRFeature *poFeature = new OGRFeature(poTargetFeatureDefn); |
178 | 50.7k | if (bJsonField) |
179 | 7.57k | { |
180 | 7.57k | CPLJSONObject oProperties; |
181 | 7.57k | bool bEmpty = true; |
182 | 14.2k | for (int i = 1; i < poSrcFeature->GetFieldCount(); i++) |
183 | 6.64k | { |
184 | 6.64k | if (poSrcFeature->IsFieldSet(i)) |
185 | 6.64k | { |
186 | 6.64k | bEmpty = false; |
187 | 6.64k | OGRFieldDefn *poFDefn = poSrcFeature->GetFieldDefnRef(i); |
188 | 6.64k | if (poSrcFeature->IsFieldNull(i)) |
189 | 0 | { |
190 | 0 | oProperties.AddNull(poFDefn->GetNameRef()); |
191 | 0 | } |
192 | 6.64k | else if (poFDefn->GetType() == OFTInteger || |
193 | 6.64k | poFDefn->GetType() == OFTInteger64) |
194 | 0 | { |
195 | 0 | if (poFDefn->GetSubType() == OFSTBoolean) |
196 | 0 | { |
197 | 0 | oProperties.Add(poFDefn->GetNameRef(), |
198 | 0 | poSrcFeature->GetFieldAsInteger(i) == |
199 | 0 | 1); |
200 | 0 | } |
201 | 0 | else |
202 | 0 | { |
203 | 0 | oProperties.Add(poFDefn->GetNameRef(), |
204 | 0 | poSrcFeature->GetFieldAsInteger64(i)); |
205 | 0 | } |
206 | 0 | } |
207 | 6.64k | else if (poFDefn->GetType() == OFTReal) |
208 | 0 | { |
209 | 0 | oProperties.Add(poFDefn->GetNameRef(), |
210 | 0 | poSrcFeature->GetFieldAsDouble(i)); |
211 | 0 | } |
212 | 6.64k | else |
213 | 6.64k | { |
214 | 6.64k | oProperties.Add(poFDefn->GetNameRef(), |
215 | 6.64k | poSrcFeature->GetFieldAsString(i)); |
216 | 6.64k | } |
217 | 6.64k | } |
218 | 6.64k | } |
219 | 7.57k | if (!bEmpty) |
220 | 6.64k | { |
221 | 6.64k | poFeature->SetField( |
222 | 6.64k | "json", oProperties.Format(CPLJSONObject::PrettyFormat::Pretty) |
223 | 6.64k | .c_str()); |
224 | 6.64k | } |
225 | | |
226 | 7.57k | OGRGeometry *poSrcGeom = poSrcFeature->GetGeometryRef(); |
227 | 7.57k | if (poSrcGeom) |
228 | 3.54k | { |
229 | 3.54k | poFeature->SetGeometry(poSrcGeom); |
230 | 3.54k | } |
231 | | #ifdef nodef |
232 | | CPLJSONObject oObj; |
233 | | oObj.Add("type", "Feature"); |
234 | | if (poSrcFeature->IsFieldSet(0)) |
235 | | oObj.Add("id", poSrcFeature->GetFieldAsInteger64("mvt_id")); |
236 | | oObj.Add("properties", oProperties); |
237 | | if (poSrcGeom) |
238 | | { |
239 | | char *pszGeomJson = |
240 | | OGR_G_ExportToJson(OGRGeometry::ToHandle(poSrcGeom)); |
241 | | CPLJSONDocument oJSonDoc; |
242 | | oJSonDoc.LoadMemory(reinterpret_cast<const GByte *>(pszGeomJson)); |
243 | | CPLFree(pszGeomJson); |
244 | | oObj.Add("geometry", oJSonDoc.GetRoot()); |
245 | | } |
246 | | poFeature->SetNativeData( |
247 | | oObj.Format(CPLJSONObject::PrettyFormat::Pretty).c_str()); |
248 | | poFeature->SetNativeMediaType("application/vnd.geo+json"); |
249 | | #endif |
250 | 7.57k | } |
251 | 43.1k | else |
252 | 43.1k | { |
253 | 43.1k | poFeature->SetFrom(poSrcFeature); |
254 | 43.1k | } |
255 | 50.7k | OGRGeometry *poGeom = poFeature->GetGeometryRef(); |
256 | 50.7k | if (poGeom) |
257 | 18.2k | poGeom->assignSpatialReference(poSRS); |
258 | 50.7k | return poFeature; |
259 | 50.7k | } |