/src/gdal/ogr/ogrsf_frmts/geojson/ogrtopojsonreader.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implementation of OGRTopoJSONReader class |
5 | | * Author: Even Rouault, even dot rouault at spatialys.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "ogrgeojsonreader.h" |
14 | | #include "ogrgeojsonutils.h" |
15 | | #include "ogrlibjsonutils.h" |
16 | | #include "ogr_geojson.h" |
17 | | #include "ogrgeojsongeometry.h" |
18 | | #include <json.h> // JSON-C |
19 | | #include "ogr_api.h" |
20 | | |
21 | | /************************************************************************/ |
22 | | /* OGRTopoJSONReader() */ |
23 | | /************************************************************************/ |
24 | | |
25 | 0 | OGRTopoJSONReader::OGRTopoJSONReader() : poGJObject_(nullptr) |
26 | 0 | { |
27 | 0 | } |
28 | | |
29 | | /************************************************************************/ |
30 | | /* ~OGRTopoJSONReader() */ |
31 | | /************************************************************************/ |
32 | | |
33 | | OGRTopoJSONReader::~OGRTopoJSONReader() |
34 | 0 | { |
35 | 0 | if (nullptr != poGJObject_) |
36 | 0 | { |
37 | 0 | json_object_put(poGJObject_); |
38 | 0 | } |
39 | |
|
40 | 0 | poGJObject_ = nullptr; |
41 | 0 | } |
42 | | |
43 | | /************************************************************************/ |
44 | | /* Parse() */ |
45 | | /************************************************************************/ |
46 | | |
47 | | OGRErr OGRTopoJSONReader::Parse(const char *pszText, bool bLooseIdentification) |
48 | 0 | { |
49 | 0 | json_object *jsobj = nullptr; |
50 | 0 | if (bLooseIdentification) |
51 | 0 | { |
52 | 0 | CPLPushErrorHandler(CPLQuietErrorHandler); |
53 | 0 | } |
54 | 0 | const bool bOK = nullptr != pszText && OGRJSonParse(pszText, &jsobj, true); |
55 | 0 | if (bLooseIdentification) |
56 | 0 | { |
57 | 0 | CPLPopErrorHandler(); |
58 | 0 | CPLErrorReset(); |
59 | 0 | } |
60 | 0 | if (!bOK) |
61 | 0 | { |
62 | 0 | return OGRERR_CORRUPT_DATA; |
63 | 0 | } |
64 | | |
65 | | // JSON tree is shared for while lifetime of the reader object |
66 | | // and will be released in the destructor. |
67 | 0 | poGJObject_ = jsobj; |
68 | 0 | return OGRERR_NONE; |
69 | 0 | } |
70 | | |
71 | | typedef struct |
72 | | { |
73 | | double dfScale0; |
74 | | double dfScale1; |
75 | | double dfTranslate0; |
76 | | double dfTranslate1; |
77 | | bool bElementExists; |
78 | | } ScalingParams; |
79 | | |
80 | | /************************************************************************/ |
81 | | /* ParsePoint() */ |
82 | | /************************************************************************/ |
83 | | |
84 | | static bool ParsePoint(json_object *poPoint, double *pdfX, double *pdfY) |
85 | 0 | { |
86 | 0 | if (poPoint != nullptr && |
87 | 0 | json_type_array == json_object_get_type(poPoint) && |
88 | 0 | json_object_array_length(poPoint) == 2) |
89 | 0 | { |
90 | 0 | json_object *poX = json_object_array_get_idx(poPoint, 0); |
91 | 0 | json_object *poY = json_object_array_get_idx(poPoint, 1); |
92 | 0 | if (poX != nullptr && |
93 | 0 | (json_type_int == json_object_get_type(poX) || |
94 | 0 | json_type_double == json_object_get_type(poX)) && |
95 | 0 | poY != nullptr && |
96 | 0 | (json_type_int == json_object_get_type(poY) || |
97 | 0 | json_type_double == json_object_get_type(poY))) |
98 | 0 | { |
99 | 0 | *pdfX = json_object_get_double(poX); |
100 | 0 | *pdfY = json_object_get_double(poY); |
101 | 0 | return true; |
102 | 0 | } |
103 | 0 | } |
104 | 0 | return false; |
105 | 0 | } |
106 | | |
107 | | /************************************************************************/ |
108 | | /* ParseArc() */ |
109 | | /************************************************************************/ |
110 | | |
111 | | static void ParseArc(OGRLineString *poLS, json_object *poArcsDB, int nArcID, |
112 | | bool bReverse, ScalingParams *psParams) |
113 | 0 | { |
114 | 0 | json_object *poArcDB = json_object_array_get_idx(poArcsDB, nArcID); |
115 | 0 | if (poArcDB == nullptr || json_type_array != json_object_get_type(poArcDB)) |
116 | 0 | return; |
117 | 0 | auto nPoints = json_object_array_length(poArcDB); |
118 | 0 | double dfAccX = 0.0; |
119 | 0 | double dfAccY = 0.0; |
120 | 0 | int nBaseIndice = poLS->getNumPoints(); |
121 | 0 | for (auto i = decltype(nPoints){0}; i < nPoints; i++) |
122 | 0 | { |
123 | 0 | json_object *poPoint = json_object_array_get_idx(poArcDB, i); |
124 | 0 | double dfX = 0.0; |
125 | 0 | double dfY = 0.0; |
126 | 0 | if (ParsePoint(poPoint, &dfX, &dfY)) |
127 | 0 | { |
128 | 0 | if (psParams->bElementExists) |
129 | 0 | { |
130 | 0 | dfAccX += dfX; |
131 | 0 | dfAccY += dfY; |
132 | 0 | dfX = dfAccX * psParams->dfScale0 + psParams->dfTranslate0; |
133 | 0 | dfY = dfAccY * psParams->dfScale1 + psParams->dfTranslate1; |
134 | 0 | } |
135 | 0 | else |
136 | 0 | { |
137 | 0 | dfX = dfX * psParams->dfScale0 + psParams->dfTranslate0; |
138 | 0 | dfY = dfY * psParams->dfScale1 + psParams->dfTranslate1; |
139 | 0 | } |
140 | 0 | if (i == 0) |
141 | 0 | { |
142 | 0 | if (!bReverse && poLS->getNumPoints() > 0) |
143 | 0 | { |
144 | 0 | poLS->setNumPoints(nBaseIndice + static_cast<int>(nPoints) - |
145 | 0 | 1); |
146 | 0 | nBaseIndice--; |
147 | 0 | continue; |
148 | 0 | } |
149 | 0 | else if (bReverse && poLS->getNumPoints() > 0) |
150 | 0 | { |
151 | 0 | poLS->setNumPoints(nBaseIndice + static_cast<int>(nPoints) - |
152 | 0 | 1); |
153 | 0 | nPoints--; |
154 | 0 | if (nPoints == 0) |
155 | 0 | break; |
156 | 0 | } |
157 | 0 | else |
158 | 0 | poLS->setNumPoints(nBaseIndice + static_cast<int>(nPoints)); |
159 | 0 | } |
160 | | |
161 | 0 | if (!bReverse) |
162 | 0 | poLS->setPoint(nBaseIndice + static_cast<int>(i), dfX, dfY); |
163 | 0 | else |
164 | 0 | poLS->setPoint(nBaseIndice + static_cast<int>(nPoints) - 1 - |
165 | 0 | static_cast<int>(i), |
166 | 0 | dfX, dfY); |
167 | 0 | } |
168 | 0 | } |
169 | 0 | } |
170 | | |
171 | | /************************************************************************/ |
172 | | /* ParseLineString() */ |
173 | | /************************************************************************/ |
174 | | |
175 | | static void ParseLineString(OGRLineString *poLS, json_object *poRing, |
176 | | json_object *poArcsDB, ScalingParams *psParams) |
177 | 0 | { |
178 | 0 | const auto nArcsDB = json_object_array_length(poArcsDB); |
179 | |
|
180 | 0 | const auto nArcsRing = json_object_array_length(poRing); |
181 | 0 | for (auto j = decltype(nArcsRing){0}; j < nArcsRing; j++) |
182 | 0 | { |
183 | 0 | json_object *poArcId = json_object_array_get_idx(poRing, j); |
184 | 0 | if (poArcId != nullptr && |
185 | 0 | json_type_int == json_object_get_type(poArcId)) |
186 | 0 | { |
187 | 0 | int nArcId = json_object_get_int(poArcId); |
188 | 0 | bool bReverse = false; |
189 | 0 | if (nArcId < 0) |
190 | 0 | { |
191 | 0 | nArcId = -(nArcId + 1); |
192 | 0 | bReverse = true; |
193 | 0 | } |
194 | 0 | if (nArcId < static_cast<int>(nArcsDB)) |
195 | 0 | { |
196 | 0 | ParseArc(poLS, poArcsDB, nArcId, bReverse, psParams); |
197 | 0 | } |
198 | 0 | } |
199 | 0 | } |
200 | 0 | } |
201 | | |
202 | | /************************************************************************/ |
203 | | /* ParsePolygon() */ |
204 | | /************************************************************************/ |
205 | | |
206 | | static void ParsePolygon(OGRPolygon *poPoly, json_object *poArcsObj, |
207 | | json_object *poArcsDB, ScalingParams *psParams) |
208 | 0 | { |
209 | 0 | const auto nRings = json_object_array_length(poArcsObj); |
210 | 0 | for (auto i = decltype(nRings){0}; i < nRings; i++) |
211 | 0 | { |
212 | 0 | OGRLinearRing *poLR = new OGRLinearRing(); |
213 | |
|
214 | 0 | json_object *poRing = json_object_array_get_idx(poArcsObj, i); |
215 | 0 | if (poRing != nullptr && |
216 | 0 | json_type_array == json_object_get_type(poRing)) |
217 | 0 | { |
218 | 0 | ParseLineString(poLR, poRing, poArcsDB, psParams); |
219 | 0 | } |
220 | 0 | poLR->closeRings(); |
221 | 0 | if (poLR->getNumPoints() < 4) |
222 | 0 | { |
223 | 0 | CPLDebug("TopoJSON", "Discarding polygon ring made of %d points", |
224 | 0 | poLR->getNumPoints()); |
225 | 0 | delete poLR; |
226 | 0 | } |
227 | 0 | else |
228 | 0 | { |
229 | 0 | poPoly->addRingDirectly(poLR); |
230 | 0 | } |
231 | 0 | } |
232 | 0 | } |
233 | | |
234 | | /************************************************************************/ |
235 | | /* ParseMultiLineString() */ |
236 | | /************************************************************************/ |
237 | | |
238 | | static void ParseMultiLineString(OGRMultiLineString *poMLS, |
239 | | json_object *poArcsObj, json_object *poArcsDB, |
240 | | ScalingParams *psParams) |
241 | 0 | { |
242 | 0 | const auto nRings = json_object_array_length(poArcsObj); |
243 | 0 | for (auto i = decltype(nRings){0}; i < nRings; i++) |
244 | 0 | { |
245 | 0 | OGRLineString *poLS = new OGRLineString(); |
246 | 0 | poMLS->addGeometryDirectly(poLS); |
247 | |
|
248 | 0 | json_object *poRing = json_object_array_get_idx(poArcsObj, i); |
249 | 0 | if (poRing != nullptr && |
250 | 0 | json_type_array == json_object_get_type(poRing)) |
251 | 0 | { |
252 | 0 | ParseLineString(poLS, poRing, poArcsDB, psParams); |
253 | 0 | } |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | | /************************************************************************/ |
258 | | /* ParseMultiPolygon() */ |
259 | | /************************************************************************/ |
260 | | |
261 | | static void ParseMultiPolygon(OGRMultiPolygon *poMultiPoly, |
262 | | json_object *poArcsObj, json_object *poArcsDB, |
263 | | ScalingParams *psParams) |
264 | 0 | { |
265 | 0 | const auto nPolys = json_object_array_length(poArcsObj); |
266 | 0 | for (auto i = decltype(nPolys){0}; i < nPolys; i++) |
267 | 0 | { |
268 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
269 | |
|
270 | 0 | json_object *poPolyArcs = json_object_array_get_idx(poArcsObj, i); |
271 | 0 | if (poPolyArcs != nullptr && |
272 | 0 | json_type_array == json_object_get_type(poPolyArcs)) |
273 | 0 | { |
274 | 0 | ParsePolygon(poPoly, poPolyArcs, poArcsDB, psParams); |
275 | 0 | } |
276 | |
|
277 | 0 | if (poPoly->IsEmpty()) |
278 | 0 | { |
279 | 0 | delete poPoly; |
280 | 0 | } |
281 | 0 | else |
282 | 0 | { |
283 | 0 | poMultiPoly->addGeometryDirectly(poPoly); |
284 | 0 | } |
285 | 0 | } |
286 | 0 | } |
287 | | |
288 | | /************************************************************************/ |
289 | | /* ParseObject() */ |
290 | | /************************************************************************/ |
291 | | |
292 | | static void ParseObject(const char *pszId, json_object *poObj, |
293 | | OGRGeoJSONLayer *poLayer, json_object *poArcsDB, |
294 | | ScalingParams *psParams) |
295 | 0 | { |
296 | 0 | json_object *poType = OGRGeoJSONFindMemberByName(poObj, "type"); |
297 | 0 | if (poType == nullptr || json_object_get_type(poType) != json_type_string) |
298 | 0 | return; |
299 | 0 | const char *pszType = json_object_get_string(poType); |
300 | |
|
301 | 0 | json_object *poArcsObj = OGRGeoJSONFindMemberByName(poObj, "arcs"); |
302 | 0 | json_object *poCoordinatesObj = |
303 | 0 | OGRGeoJSONFindMemberByName(poObj, "coordinates"); |
304 | 0 | if (strcmp(pszType, "Point") == 0 || strcmp(pszType, "MultiPoint") == 0) |
305 | 0 | { |
306 | 0 | if (poCoordinatesObj == nullptr || |
307 | 0 | json_type_array != json_object_get_type(poCoordinatesObj)) |
308 | 0 | return; |
309 | 0 | } |
310 | 0 | else |
311 | 0 | { |
312 | 0 | if (poArcsObj == nullptr || |
313 | 0 | json_type_array != json_object_get_type(poArcsObj)) |
314 | 0 | return; |
315 | 0 | } |
316 | | |
317 | 0 | if (pszId == nullptr) |
318 | 0 | { |
319 | 0 | json_object *poId = OGRGeoJSONFindMemberByName(poObj, "id"); |
320 | 0 | if (poId != nullptr && |
321 | 0 | (json_type_string == json_object_get_type(poId) || |
322 | 0 | json_type_int == json_object_get_type(poId))) |
323 | 0 | { |
324 | 0 | pszId = json_object_get_string(poId); |
325 | 0 | } |
326 | 0 | } |
327 | |
|
328 | 0 | OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); |
329 | 0 | if (pszId != nullptr) |
330 | 0 | poFeature->SetField("id", pszId); |
331 | |
|
332 | 0 | json_object *poProperties = OGRGeoJSONFindMemberByName(poObj, "properties"); |
333 | 0 | if (poProperties != nullptr && |
334 | 0 | json_type_object == json_object_get_type(poProperties)) |
335 | 0 | { |
336 | 0 | json_object_iter it; |
337 | 0 | it.key = nullptr; |
338 | 0 | it.val = nullptr; |
339 | 0 | it.entry = nullptr; |
340 | 0 | json_object_object_foreachC(poProperties, it) |
341 | 0 | { |
342 | 0 | const int nField = poFeature->GetFieldIndex(it.key); |
343 | 0 | OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key, it.val, |
344 | 0 | false, 0); |
345 | 0 | } |
346 | 0 | } |
347 | |
|
348 | 0 | OGRGeometry *poGeom = nullptr; |
349 | 0 | if (strcmp(pszType, "Point") == 0) |
350 | 0 | { |
351 | 0 | double dfX = 0.0; |
352 | 0 | double dfY = 0.0; |
353 | 0 | if (ParsePoint(poCoordinatesObj, &dfX, &dfY)) |
354 | 0 | { |
355 | 0 | dfX = dfX * psParams->dfScale0 + psParams->dfTranslate0; |
356 | 0 | dfY = dfY * psParams->dfScale1 + psParams->dfTranslate1; |
357 | 0 | poGeom = new OGRPoint(dfX, dfY); |
358 | 0 | } |
359 | 0 | else |
360 | 0 | { |
361 | 0 | poGeom = new OGRPoint(); |
362 | 0 | } |
363 | 0 | } |
364 | 0 | else if (strcmp(pszType, "MultiPoint") == 0) |
365 | 0 | { |
366 | 0 | OGRMultiPoint *poMP = new OGRMultiPoint(); |
367 | 0 | poGeom = poMP; |
368 | 0 | const auto nTuples = json_object_array_length(poCoordinatesObj); |
369 | 0 | for (auto i = decltype(nTuples){0}; i < nTuples; i++) |
370 | 0 | { |
371 | 0 | json_object *poPair = |
372 | 0 | json_object_array_get_idx(poCoordinatesObj, i); |
373 | 0 | double dfX = 0.0; |
374 | 0 | double dfY = 0.0; |
375 | 0 | if (ParsePoint(poPair, &dfX, &dfY)) |
376 | 0 | { |
377 | 0 | dfX = dfX * psParams->dfScale0 + psParams->dfTranslate0; |
378 | 0 | dfY = dfY * psParams->dfScale1 + psParams->dfTranslate1; |
379 | 0 | poMP->addGeometryDirectly(new OGRPoint(dfX, dfY)); |
380 | 0 | } |
381 | 0 | } |
382 | 0 | } |
383 | 0 | else if (strcmp(pszType, "LineString") == 0) |
384 | 0 | { |
385 | 0 | OGRLineString *poLS = new OGRLineString(); |
386 | 0 | poGeom = poLS; |
387 | 0 | ParseLineString(poLS, poArcsObj, poArcsDB, psParams); |
388 | 0 | } |
389 | 0 | else if (strcmp(pszType, "MultiLineString") == 0) |
390 | 0 | { |
391 | 0 | OGRMultiLineString *poMLS = new OGRMultiLineString(); |
392 | 0 | poGeom = poMLS; |
393 | 0 | ParseMultiLineString(poMLS, poArcsObj, poArcsDB, psParams); |
394 | 0 | } |
395 | 0 | else if (strcmp(pszType, "Polygon") == 0) |
396 | 0 | { |
397 | 0 | OGRPolygon *poPoly = new OGRPolygon(); |
398 | 0 | poGeom = poPoly; |
399 | 0 | ParsePolygon(poPoly, poArcsObj, poArcsDB, psParams); |
400 | 0 | } |
401 | 0 | else if (strcmp(pszType, "MultiPolygon") == 0) |
402 | 0 | { |
403 | 0 | OGRMultiPolygon *poMultiPoly = new OGRMultiPolygon(); |
404 | 0 | poGeom = poMultiPoly; |
405 | 0 | ParseMultiPolygon(poMultiPoly, poArcsObj, poArcsDB, psParams); |
406 | 0 | } |
407 | |
|
408 | 0 | if (poGeom != nullptr) |
409 | 0 | poFeature->SetGeometryDirectly(poGeom); |
410 | 0 | poLayer->AddFeature(poFeature); |
411 | 0 | delete poFeature; |
412 | 0 | } |
413 | | |
414 | | /************************************************************************/ |
415 | | /* EstablishLayerDefn() */ |
416 | | /************************************************************************/ |
417 | | |
418 | | static void |
419 | | EstablishLayerDefn(int nPrevFieldIdx, std::vector<int> &anCurFieldIndices, |
420 | | std::map<std::string, int> &oMapFieldNameToIdx, |
421 | | std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn, |
422 | | gdal::DirectedAcyclicGraph<int, std::string> &dag, |
423 | | json_object *poObj, |
424 | | std::set<int> &aoSetUndeterminedTypeFields) |
425 | 0 | { |
426 | 0 | json_object *poObjProps = OGRGeoJSONFindMemberByName(poObj, "properties"); |
427 | 0 | if (nullptr != poObjProps && |
428 | 0 | json_object_get_type(poObjProps) == json_type_object) |
429 | 0 | { |
430 | 0 | json_object_iter it; |
431 | 0 | it.key = nullptr; |
432 | 0 | it.val = nullptr; |
433 | 0 | it.entry = nullptr; |
434 | |
|
435 | 0 | json_object_object_foreachC(poObjProps, it) |
436 | 0 | { |
437 | 0 | anCurFieldIndices.clear(); |
438 | 0 | OGRGeoJSONReaderAddOrUpdateField( |
439 | 0 | anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn, it.key, |
440 | 0 | it.val, false, 0, false, false, aoSetUndeterminedTypeFields); |
441 | 0 | for (int idx : anCurFieldIndices) |
442 | 0 | { |
443 | 0 | dag.addNode(idx, apoFieldDefn[idx]->GetNameRef()); |
444 | 0 | if (nPrevFieldIdx != -1) |
445 | 0 | { |
446 | 0 | dag.addEdge(nPrevFieldIdx, idx); |
447 | 0 | } |
448 | 0 | nPrevFieldIdx = idx; |
449 | 0 | } |
450 | 0 | } |
451 | 0 | } |
452 | 0 | } |
453 | | |
454 | | /************************************************************************/ |
455 | | /* ParseObjectMain() */ |
456 | | /************************************************************************/ |
457 | | |
458 | | static bool |
459 | | ParseObjectMain(const char *pszId, json_object *poObj, |
460 | | const OGRSpatialReference *poSRS, OGRGeoJSONDataSource *poDS, |
461 | | OGRGeoJSONLayer **ppoMainLayer, json_object *poArcs, |
462 | | ScalingParams *psParams, std::vector<int> &anCurFieldIndices, |
463 | | std::map<std::string, int> &oMapFieldNameToIdx, |
464 | | std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn, |
465 | | gdal::DirectedAcyclicGraph<int, std::string> &dag, |
466 | | std::set<int> &aoSetUndeterminedTypeFields) |
467 | 0 | { |
468 | 0 | bool bNeedSecondPass = false; |
469 | |
|
470 | 0 | if (poObj != nullptr && json_type_object == json_object_get_type(poObj)) |
471 | 0 | { |
472 | 0 | json_object *poType = OGRGeoJSONFindMemberByName(poObj, "type"); |
473 | 0 | if (poType != nullptr && |
474 | 0 | json_type_string == json_object_get_type(poType)) |
475 | 0 | { |
476 | 0 | const char *pszType = json_object_get_string(poType); |
477 | 0 | if (strcmp(pszType, "GeometryCollection") == 0) |
478 | 0 | { |
479 | 0 | json_object *poGeometries = |
480 | 0 | OGRGeoJSONFindMemberByName(poObj, "geometries"); |
481 | 0 | if (poGeometries != nullptr && |
482 | 0 | json_type_array == json_object_get_type(poGeometries)) |
483 | 0 | { |
484 | 0 | if (pszId == nullptr) |
485 | 0 | { |
486 | 0 | json_object *poId = |
487 | 0 | OGRGeoJSONFindMemberByName(poObj, "id"); |
488 | 0 | if (poId != nullptr && |
489 | 0 | (json_type_string == json_object_get_type(poId) || |
490 | 0 | json_type_int == json_object_get_type(poId))) |
491 | 0 | { |
492 | 0 | pszId = json_object_get_string(poId); |
493 | 0 | } |
494 | 0 | } |
495 | |
|
496 | 0 | OGRGeoJSONLayer *poLayer = |
497 | 0 | new OGRGeoJSONLayer(pszId ? pszId : "TopoJSON", nullptr, |
498 | 0 | wkbUnknown, poDS, nullptr); |
499 | 0 | poLayer->SetSupportsZGeometries(false); |
500 | 0 | OGRFeatureDefn *poDefn = poLayer->GetLayerDefn(); |
501 | |
|
502 | 0 | whileUnsealing(poDefn)->GetGeomFieldDefn(0)->SetSpatialRef( |
503 | 0 | poSRS); |
504 | |
|
505 | 0 | const auto nGeometries = |
506 | 0 | json_object_array_length(poGeometries); |
507 | | // First pass to establish schema. |
508 | |
|
509 | 0 | std::vector<int> anCurFieldIndicesLocal; |
510 | 0 | std::map<std::string, int> oMapFieldNameToIdxLocal; |
511 | 0 | std::vector<std::unique_ptr<OGRFieldDefn>> |
512 | 0 | apoFieldDefnLocal; |
513 | 0 | gdal::DirectedAcyclicGraph<int, std::string> dagLocal; |
514 | 0 | std::set<int> aoSetUndeterminedTypeFieldsLocal; |
515 | |
|
516 | 0 | apoFieldDefnLocal.emplace_back( |
517 | 0 | std::make_unique<OGRFieldDefn>("id", OFTString)); |
518 | 0 | oMapFieldNameToIdxLocal["id"] = 0; |
519 | 0 | dagLocal.addNode(0, "id"); |
520 | 0 | const int nPrevFieldIdx = 0; |
521 | |
|
522 | 0 | for (auto i = decltype(nGeometries){0}; i < nGeometries; |
523 | 0 | i++) |
524 | 0 | { |
525 | 0 | json_object *poGeom = |
526 | 0 | json_object_array_get_idx(poGeometries, i); |
527 | 0 | if (poGeom != nullptr && |
528 | 0 | json_type_object == json_object_get_type(poGeom)) |
529 | 0 | { |
530 | 0 | EstablishLayerDefn( |
531 | 0 | nPrevFieldIdx, anCurFieldIndicesLocal, |
532 | 0 | oMapFieldNameToIdxLocal, apoFieldDefnLocal, |
533 | 0 | dagLocal, poGeom, |
534 | 0 | aoSetUndeterminedTypeFieldsLocal); |
535 | 0 | } |
536 | 0 | } |
537 | |
|
538 | 0 | const auto sortedFields = dagLocal.getTopologicalOrdering(); |
539 | 0 | CPLAssert(sortedFields.size() == apoFieldDefnLocal.size()); |
540 | 0 | { |
541 | 0 | auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer()); |
542 | 0 | for (int idx : sortedFields) |
543 | 0 | { |
544 | 0 | poDefn->AddFieldDefn(apoFieldDefnLocal[idx].get()); |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | // Second pass to build objects. |
549 | 0 | for (auto i = decltype(nGeometries){0}; i < nGeometries; |
550 | 0 | i++) |
551 | 0 | { |
552 | 0 | json_object *poGeom = |
553 | 0 | json_object_array_get_idx(poGeometries, i); |
554 | 0 | if (poGeom != nullptr && |
555 | 0 | json_type_object == json_object_get_type(poGeom)) |
556 | 0 | { |
557 | 0 | ParseObject(nullptr, poGeom, poLayer, poArcs, |
558 | 0 | psParams); |
559 | 0 | } |
560 | 0 | } |
561 | |
|
562 | 0 | poLayer->DetectGeometryType(); |
563 | 0 | poDS->AddLayer(poLayer); |
564 | 0 | } |
565 | 0 | } |
566 | 0 | else if (strcmp(pszType, "Point") == 0 || |
567 | 0 | strcmp(pszType, "MultiPoint") == 0 || |
568 | 0 | strcmp(pszType, "LineString") == 0 || |
569 | 0 | strcmp(pszType, "MultiLineString") == 0 || |
570 | 0 | strcmp(pszType, "Polygon") == 0 || |
571 | 0 | strcmp(pszType, "MultiPolygon") == 0) |
572 | 0 | { |
573 | 0 | if (*ppoMainLayer == nullptr) |
574 | 0 | { |
575 | 0 | *ppoMainLayer = new OGRGeoJSONLayer( |
576 | 0 | "TopoJSON", nullptr, wkbUnknown, poDS, nullptr); |
577 | |
|
578 | 0 | (*ppoMainLayer)->SetSupportsZGeometries(false); |
579 | |
|
580 | 0 | whileUnsealing((*ppoMainLayer)->GetLayerDefn()) |
581 | 0 | ->GetGeomFieldDefn(0) |
582 | 0 | ->SetSpatialRef(poSRS); |
583 | |
|
584 | 0 | apoFieldDefn.emplace_back( |
585 | 0 | std::make_unique<OGRFieldDefn>("id", OFTString)); |
586 | 0 | oMapFieldNameToIdx["id"] = 0; |
587 | 0 | dag.addNode(0, "id"); |
588 | 0 | } |
589 | |
|
590 | 0 | const int nPrevFieldIdx = 0; |
591 | 0 | EstablishLayerDefn(nPrevFieldIdx, anCurFieldIndices, |
592 | 0 | oMapFieldNameToIdx, apoFieldDefn, dag, poObj, |
593 | 0 | aoSetUndeterminedTypeFields); |
594 | |
|
595 | 0 | bNeedSecondPass = true; |
596 | 0 | } |
597 | 0 | } |
598 | 0 | } |
599 | 0 | return bNeedSecondPass; |
600 | 0 | } |
601 | | |
602 | | /************************************************************************/ |
603 | | /* ParseObjectMainSecondPass() */ |
604 | | /************************************************************************/ |
605 | | |
606 | | static void ParseObjectMainSecondPass(const char *pszId, json_object *poObj, |
607 | | OGRGeoJSONLayer **ppoMainLayer, |
608 | | json_object *poArcs, |
609 | | ScalingParams *psParams) |
610 | 0 | { |
611 | 0 | if (poObj != nullptr && json_type_object == json_object_get_type(poObj)) |
612 | 0 | { |
613 | 0 | json_object *poType = OGRGeoJSONFindMemberByName(poObj, "type"); |
614 | 0 | if (poType != nullptr && |
615 | 0 | json_type_string == json_object_get_type(poType)) |
616 | 0 | { |
617 | 0 | const char *pszType = json_object_get_string(poType); |
618 | 0 | if (strcmp(pszType, "Point") == 0 || |
619 | 0 | strcmp(pszType, "MultiPoint") == 0 || |
620 | 0 | strcmp(pszType, "LineString") == 0 || |
621 | 0 | strcmp(pszType, "MultiLineString") == 0 || |
622 | 0 | strcmp(pszType, "Polygon") == 0 || |
623 | 0 | strcmp(pszType, "MultiPolygon") == 0) |
624 | 0 | { |
625 | 0 | ParseObject(pszId, poObj, *ppoMainLayer, poArcs, psParams); |
626 | 0 | } |
627 | 0 | } |
628 | 0 | } |
629 | 0 | } |
630 | | |
631 | | /************************************************************************/ |
632 | | /* ReadLayers() */ |
633 | | /************************************************************************/ |
634 | | |
635 | | void OGRTopoJSONReader::ReadLayers(OGRGeoJSONDataSource *poDS) |
636 | 0 | { |
637 | 0 | if (nullptr == poGJObject_) |
638 | 0 | { |
639 | 0 | CPLDebug("TopoJSON", |
640 | 0 | "Missing parsed TopoJSON data. Forgot to call Parse()?"); |
641 | 0 | return; |
642 | 0 | } |
643 | | |
644 | 0 | poDS->SetSupportsZGeometries(false); |
645 | |
|
646 | 0 | ScalingParams sParams; |
647 | 0 | sParams.dfScale0 = 1.0; |
648 | 0 | sParams.dfScale1 = 1.0; |
649 | 0 | sParams.dfTranslate0 = 0.0; |
650 | 0 | sParams.dfTranslate1 = 0.0; |
651 | 0 | sParams.bElementExists = false; |
652 | 0 | json_object *poObjTransform = |
653 | 0 | OGRGeoJSONFindMemberByName(poGJObject_, "transform"); |
654 | 0 | if (nullptr != poObjTransform && |
655 | 0 | json_type_object == json_object_get_type(poObjTransform)) |
656 | 0 | { |
657 | 0 | json_object *poObjScale = |
658 | 0 | OGRGeoJSONFindMemberByName(poObjTransform, "scale"); |
659 | 0 | if (nullptr != poObjScale && |
660 | 0 | json_type_array == json_object_get_type(poObjScale) && |
661 | 0 | json_object_array_length(poObjScale) == 2) |
662 | 0 | { |
663 | 0 | json_object *poScale0 = json_object_array_get_idx(poObjScale, 0); |
664 | 0 | json_object *poScale1 = json_object_array_get_idx(poObjScale, 1); |
665 | 0 | if (poScale0 != nullptr && |
666 | 0 | (json_object_get_type(poScale0) == json_type_double || |
667 | 0 | json_object_get_type(poScale0) == json_type_int) && |
668 | 0 | poScale1 != nullptr && |
669 | 0 | (json_object_get_type(poScale1) == json_type_double || |
670 | 0 | json_object_get_type(poScale1) == json_type_int)) |
671 | 0 | { |
672 | 0 | sParams.dfScale0 = json_object_get_double(poScale0); |
673 | 0 | sParams.dfScale1 = json_object_get_double(poScale1); |
674 | 0 | sParams.bElementExists = true; |
675 | 0 | } |
676 | 0 | } |
677 | |
|
678 | 0 | json_object *poObjTranslate = |
679 | 0 | OGRGeoJSONFindMemberByName(poObjTransform, "translate"); |
680 | 0 | if (nullptr != poObjTranslate && |
681 | 0 | json_type_array == json_object_get_type(poObjTranslate) && |
682 | 0 | json_object_array_length(poObjTranslate) == 2) |
683 | 0 | { |
684 | 0 | json_object *poTranslate0 = |
685 | 0 | json_object_array_get_idx(poObjTranslate, 0); |
686 | 0 | json_object *poTranslate1 = |
687 | 0 | json_object_array_get_idx(poObjTranslate, 1); |
688 | 0 | if (poTranslate0 != nullptr && |
689 | 0 | (json_object_get_type(poTranslate0) == json_type_double || |
690 | 0 | json_object_get_type(poTranslate0) == json_type_int) && |
691 | 0 | poTranslate1 != nullptr && |
692 | 0 | (json_object_get_type(poTranslate1) == json_type_double || |
693 | 0 | json_object_get_type(poTranslate1) == json_type_int)) |
694 | 0 | { |
695 | 0 | sParams.dfTranslate0 = json_object_get_double(poTranslate0); |
696 | 0 | sParams.dfTranslate1 = json_object_get_double(poTranslate1); |
697 | 0 | sParams.bElementExists = true; |
698 | 0 | } |
699 | 0 | } |
700 | 0 | } |
701 | |
|
702 | 0 | json_object *poArcs = OGRGeoJSONFindMemberByName(poGJObject_, "arcs"); |
703 | 0 | if (poArcs == nullptr || json_type_array != json_object_get_type(poArcs)) |
704 | 0 | return; |
705 | | |
706 | 0 | OGRGeoJSONLayer *poMainLayer = nullptr; |
707 | |
|
708 | 0 | json_object *poObjects = OGRGeoJSONFindMemberByName(poGJObject_, "objects"); |
709 | 0 | if (poObjects == nullptr) |
710 | 0 | return; |
711 | | |
712 | 0 | OGRSpatialReference *poSRS = OGRGeoJSONReadSpatialReference(poGJObject_); |
713 | |
|
714 | 0 | std::vector<int> anCurFieldIndices; |
715 | 0 | std::map<std::string, int> oMapFieldNameToIdx; |
716 | 0 | std::vector<std::unique_ptr<OGRFieldDefn>> apoFieldDefn; |
717 | 0 | gdal::DirectedAcyclicGraph<int, std::string> dag; |
718 | |
|
719 | 0 | std::set<int> aoSetUndeterminedTypeFields; |
720 | 0 | if (json_type_object == json_object_get_type(poObjects)) |
721 | 0 | { |
722 | 0 | json_object_iter it; |
723 | 0 | it.key = nullptr; |
724 | 0 | it.val = nullptr; |
725 | 0 | it.entry = nullptr; |
726 | 0 | bool bNeedSecondPass = false; |
727 | 0 | json_object_object_foreachC(poObjects, it) |
728 | 0 | { |
729 | 0 | json_object *poObj = it.val; |
730 | 0 | bNeedSecondPass |= ParseObjectMain( |
731 | 0 | it.key, poObj, poSRS, poDS, &poMainLayer, poArcs, &sParams, |
732 | 0 | anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn, dag, |
733 | 0 | aoSetUndeterminedTypeFields); |
734 | 0 | } |
735 | 0 | if (bNeedSecondPass) |
736 | 0 | { |
737 | 0 | OGRFeatureDefn *poDefn = poMainLayer->GetLayerDefn(); |
738 | 0 | const auto sortedFields = dag.getTopologicalOrdering(); |
739 | 0 | CPLAssert(sortedFields.size() == apoFieldDefn.size()); |
740 | 0 | auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer()); |
741 | 0 | for (int idx : sortedFields) |
742 | 0 | { |
743 | 0 | poDefn->AddFieldDefn(apoFieldDefn[idx].get()); |
744 | 0 | } |
745 | |
|
746 | 0 | it.key = nullptr; |
747 | 0 | it.val = nullptr; |
748 | 0 | it.entry = nullptr; |
749 | 0 | json_object_object_foreachC(poObjects, it) |
750 | 0 | { |
751 | 0 | json_object *poObj = it.val; |
752 | 0 | ParseObjectMainSecondPass(it.key, poObj, &poMainLayer, poArcs, |
753 | 0 | &sParams); |
754 | 0 | } |
755 | 0 | } |
756 | 0 | } |
757 | 0 | else if (json_type_array == json_object_get_type(poObjects)) |
758 | 0 | { |
759 | 0 | const auto nObjects = json_object_array_length(poObjects); |
760 | 0 | bool bNeedSecondPass = false; |
761 | 0 | for (auto i = decltype(nObjects){0}; i < nObjects; i++) |
762 | 0 | { |
763 | 0 | json_object *poObj = json_object_array_get_idx(poObjects, i); |
764 | 0 | bNeedSecondPass |= ParseObjectMain( |
765 | 0 | nullptr, poObj, poSRS, poDS, &poMainLayer, poArcs, &sParams, |
766 | 0 | anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn, dag, |
767 | 0 | aoSetUndeterminedTypeFields); |
768 | 0 | } |
769 | 0 | if (bNeedSecondPass) |
770 | 0 | { |
771 | 0 | OGRFeatureDefn *poDefn = poMainLayer->GetLayerDefn(); |
772 | 0 | const auto sortedFields = dag.getTopologicalOrdering(); |
773 | 0 | CPLAssert(sortedFields.size() == apoFieldDefn.size()); |
774 | 0 | auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer()); |
775 | 0 | for (int idx : sortedFields) |
776 | 0 | { |
777 | 0 | poDefn->AddFieldDefn(apoFieldDefn[idx].get()); |
778 | 0 | } |
779 | |
|
780 | 0 | for (auto i = decltype(nObjects){0}; i < nObjects; i++) |
781 | 0 | { |
782 | 0 | json_object *poObj = json_object_array_get_idx(poObjects, i); |
783 | 0 | ParseObjectMainSecondPass(nullptr, poObj, &poMainLayer, poArcs, |
784 | 0 | &sParams); |
785 | 0 | } |
786 | 0 | } |
787 | 0 | } |
788 | | |
789 | 0 | if (poMainLayer != nullptr) |
790 | 0 | { |
791 | 0 | poMainLayer->DetectGeometryType(); |
792 | 0 | poDS->AddLayer(poMainLayer); |
793 | 0 | } |
794 | |
|
795 | 0 | if (poSRS) |
796 | 0 | poSRS->Release(); |
797 | 0 | } |