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