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