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 36 : 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 : auto poFeature = std::make_unique<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.get(), nField, it.key,
344 : it.val, 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(std::move(poFeature));
411 : }
412 :
413 : /************************************************************************/
414 : /* EstablishLayerDefn() */
415 : /************************************************************************/
416 :
417 : static void
418 114 : 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 114 : json_object *poObjProps = OGRGeoJSONFindMemberByName(poObj, "properties");
426 128 : if (nullptr != poObjProps &&
427 14 : json_object_get_type(poObjProps) == json_type_object)
428 : {
429 : json_object_iter it;
430 12 : it.key = nullptr;
431 12 : it.val = nullptr;
432 12 : it.entry = nullptr;
433 :
434 24 : json_object_object_foreachC(poObjProps, it)
435 : {
436 12 : anCurFieldIndices.clear();
437 12 : OGRGeoJSONReaderAddOrUpdateField(
438 12 : anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn, it.key,
439 : it.val, false, 0, false, false, aoSetUndeterminedTypeFields);
440 24 : for (int idx : anCurFieldIndices)
441 : {
442 12 : dag.addNode(idx, apoFieldDefn[idx]->GetNameRef());
443 12 : if (nPrevFieldIdx != -1)
444 : {
445 12 : dag.addEdge(nPrevFieldIdx, idx);
446 : }
447 12 : nPrevFieldIdx = idx;
448 : }
449 : }
450 : }
451 114 : }
452 :
453 : /************************************************************************/
454 : /* ParseObjectMain() */
455 : /************************************************************************/
456 :
457 : static bool
458 128 : ParseObjectMain(const char *pszId, json_object *poObj,
459 : const OGRSpatialReference *poSRS, OGRGeoJSONDataSource *poDS,
460 : OGRGeoJSONLayer **ppoMainLayer, json_object *poArcs,
461 : ScalingParams *psParams, 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 128 : bool bNeedSecondPass = false;
468 :
469 128 : if (poObj != nullptr && json_type_object == json_object_get_type(poObj))
470 : {
471 124 : json_object *poType = OGRGeoJSONFindMemberByName(poObj, "type");
472 246 : if (poType != nullptr &&
473 122 : json_type_string == json_object_get_type(poType))
474 : {
475 120 : const char *pszType = json_object_get_string(poType);
476 120 : if (strcmp(pszType, "GeometryCollection") == 0)
477 : {
478 : json_object *poGeometries =
479 9 : OGRGeoJSONFindMemberByName(poObj, "geometries");
480 14 : if (poGeometries != nullptr &&
481 5 : json_type_array == json_object_get_type(poGeometries))
482 : {
483 5 : 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 5 : wkbUnknown, poDS, nullptr);
498 5 : poLayer->SetSupportsZGeometries(false);
499 5 : OGRFeatureDefn *poDefn = poLayer->GetLayerDefn();
500 :
501 5 : whileUnsealing(poDefn)->GetGeomFieldDefn(0)->SetSpatialRef(
502 : poSRS);
503 :
504 : const auto nGeometries =
505 5 : json_object_array_length(poGeometries);
506 : // First pass to establish schema.
507 :
508 10 : std::vector<int> anCurFieldIndicesLocal;
509 10 : std::map<std::string, int> oMapFieldNameToIdxLocal;
510 : std::vector<std::unique_ptr<OGRFieldDefn>>
511 10 : apoFieldDefnLocal;
512 10 : gdal::DirectedAcyclicGraph<int, std::string> dagLocal;
513 10 : std::set<int> aoSetUndeterminedTypeFieldsLocal;
514 :
515 : apoFieldDefnLocal.emplace_back(
516 5 : std::make_unique<OGRFieldDefn>("id", OFTString));
517 5 : oMapFieldNameToIdxLocal["id"] = 0;
518 5 : dagLocal.addNode(0, "id");
519 5 : const int nPrevFieldIdx = 0;
520 :
521 10 : for (auto i = decltype(nGeometries){0}; i < nGeometries;
522 : i++)
523 : {
524 : json_object *poGeom =
525 5 : json_object_array_get_idx(poGeometries, i);
526 10 : if (poGeom != nullptr &&
527 5 : json_type_object == json_object_get_type(poGeom))
528 : {
529 5 : EstablishLayerDefn(
530 : nPrevFieldIdx, anCurFieldIndicesLocal,
531 : oMapFieldNameToIdxLocal, apoFieldDefnLocal,
532 : dagLocal, poGeom,
533 : aoSetUndeterminedTypeFieldsLocal);
534 : }
535 : }
536 :
537 10 : const auto sortedFields = dagLocal.getTopologicalOrdering();
538 5 : CPLAssert(sortedFields.size() == apoFieldDefnLocal.size());
539 : {
540 10 : auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer());
541 12 : for (int idx : sortedFields)
542 : {
543 7 : poDefn->AddFieldDefn(apoFieldDefnLocal[idx].get());
544 : }
545 : }
546 :
547 : // Second pass to build objects.
548 10 : for (auto i = decltype(nGeometries){0}; i < nGeometries;
549 : i++)
550 : {
551 : json_object *poGeom =
552 5 : json_object_array_get_idx(poGeometries, i);
553 10 : if (poGeom != nullptr &&
554 5 : json_type_object == json_object_get_type(poGeom))
555 : {
556 5 : ParseObject(nullptr, poGeom, poLayer, poArcs,
557 : psParams);
558 : }
559 : }
560 :
561 5 : poLayer->DetectGeometryType();
562 5 : poDS->AddLayer(poLayer);
563 : }
564 : }
565 111 : else if (strcmp(pszType, "Point") == 0 ||
566 97 : strcmp(pszType, "MultiPoint") == 0 ||
567 81 : strcmp(pszType, "LineString") == 0 ||
568 48 : strcmp(pszType, "MultiLineString") == 0 ||
569 32 : strcmp(pszType, "Polygon") == 0 ||
570 16 : strcmp(pszType, "MultiPolygon") == 0)
571 : {
572 109 : if (*ppoMainLayer == nullptr)
573 : {
574 5 : *ppoMainLayer = new OGRGeoJSONLayer(
575 5 : "TopoJSON", nullptr, wkbUnknown, poDS, nullptr);
576 :
577 5 : (*ppoMainLayer)->SetSupportsZGeometries(false);
578 :
579 10 : whileUnsealing((*ppoMainLayer)->GetLayerDefn())
580 5 : ->GetGeomFieldDefn(0)
581 5 : ->SetSpatialRef(poSRS);
582 :
583 : apoFieldDefn.emplace_back(
584 5 : std::make_unique<OGRFieldDefn>("id", OFTString));
585 5 : oMapFieldNameToIdx["id"] = 0;
586 5 : dag.addNode(0, "id");
587 : }
588 :
589 109 : const int nPrevFieldIdx = 0;
590 109 : EstablishLayerDefn(nPrevFieldIdx, anCurFieldIndices,
591 : oMapFieldNameToIdx, apoFieldDefn, dag, poObj,
592 : aoSetUndeterminedTypeFields);
593 :
594 109 : bNeedSecondPass = true;
595 : }
596 : }
597 : }
598 128 : return bNeedSecondPass;
599 : }
600 :
601 : /************************************************************************/
602 : /* ParseObjectMainSecondPass() */
603 : /************************************************************************/
604 :
605 128 : static void ParseObjectMainSecondPass(const char *pszId, json_object *poObj,
606 : OGRGeoJSONLayer **ppoMainLayer,
607 : json_object *poArcs,
608 : ScalingParams *psParams)
609 : {
610 128 : if (poObj != nullptr && json_type_object == json_object_get_type(poObj))
611 : {
612 124 : json_object *poType = OGRGeoJSONFindMemberByName(poObj, "type");
613 246 : if (poType != nullptr &&
614 122 : json_type_string == json_object_get_type(poType))
615 : {
616 120 : const char *pszType = json_object_get_string(poType);
617 120 : if (strcmp(pszType, "Point") == 0 ||
618 106 : strcmp(pszType, "MultiPoint") == 0 ||
619 90 : strcmp(pszType, "LineString") == 0 ||
620 57 : strcmp(pszType, "MultiLineString") == 0 ||
621 41 : strcmp(pszType, "Polygon") == 0 ||
622 25 : strcmp(pszType, "MultiPolygon") == 0)
623 : {
624 109 : ParseObject(pszId, poObj, *ppoMainLayer, poArcs, psParams);
625 : }
626 : }
627 : }
628 128 : }
629 :
630 : /************************************************************************/
631 : /* ReadLayers() */
632 : /************************************************************************/
633 :
634 5 : void OGRTopoJSONReader::ReadLayers(OGRGeoJSONDataSource *poDS)
635 : {
636 5 : if (nullptr == poGJObject_)
637 : {
638 0 : CPLDebug("TopoJSON",
639 : "Missing parsed TopoJSON data. Forgot to call Parse()?");
640 0 : return;
641 : }
642 :
643 5 : poDS->SetSupportsZGeometries(false);
644 :
645 : ScalingParams sParams;
646 5 : sParams.dfScale0 = 1.0;
647 5 : sParams.dfScale1 = 1.0;
648 5 : sParams.dfTranslate0 = 0.0;
649 5 : sParams.dfTranslate1 = 0.0;
650 5 : sParams.bElementExists = false;
651 : json_object *poObjTransform =
652 5 : OGRGeoJSONFindMemberByName(poGJObject_, "transform");
653 9 : if (nullptr != poObjTransform &&
654 4 : json_type_object == json_object_get_type(poObjTransform))
655 : {
656 : json_object *poObjScale =
657 4 : OGRGeoJSONFindMemberByName(poObjTransform, "scale");
658 8 : if (nullptr != poObjScale &&
659 8 : json_type_array == json_object_get_type(poObjScale) &&
660 4 : json_object_array_length(poObjScale) == 2)
661 : {
662 4 : json_object *poScale0 = json_object_array_get_idx(poObjScale, 0);
663 4 : json_object *poScale1 = json_object_array_get_idx(poObjScale, 1);
664 8 : if (poScale0 != nullptr &&
665 4 : (json_object_get_type(poScale0) == json_type_double ||
666 4 : json_object_get_type(poScale0) == json_type_int) &&
667 8 : poScale1 != nullptr &&
668 4 : (json_object_get_type(poScale1) == json_type_double ||
669 2 : json_object_get_type(poScale1) == json_type_int))
670 : {
671 4 : sParams.dfScale0 = json_object_get_double(poScale0);
672 4 : sParams.dfScale1 = json_object_get_double(poScale1);
673 4 : sParams.bElementExists = true;
674 : }
675 : }
676 :
677 : json_object *poObjTranslate =
678 4 : OGRGeoJSONFindMemberByName(poObjTransform, "translate");
679 8 : if (nullptr != poObjTranslate &&
680 8 : json_type_array == json_object_get_type(poObjTranslate) &&
681 4 : json_object_array_length(poObjTranslate) == 2)
682 : {
683 : json_object *poTranslate0 =
684 4 : json_object_array_get_idx(poObjTranslate, 0);
685 : json_object *poTranslate1 =
686 4 : json_object_array_get_idx(poObjTranslate, 1);
687 8 : if (poTranslate0 != nullptr &&
688 4 : (json_object_get_type(poTranslate0) == json_type_double ||
689 4 : json_object_get_type(poTranslate0) == json_type_int) &&
690 8 : poTranslate1 != nullptr &&
691 4 : (json_object_get_type(poTranslate1) == json_type_double ||
692 2 : json_object_get_type(poTranslate1) == json_type_int))
693 : {
694 4 : sParams.dfTranslate0 = json_object_get_double(poTranslate0);
695 4 : sParams.dfTranslate1 = json_object_get_double(poTranslate1);
696 4 : sParams.bElementExists = true;
697 : }
698 : }
699 : }
700 :
701 5 : json_object *poArcs = OGRGeoJSONFindMemberByName(poGJObject_, "arcs");
702 5 : if (poArcs == nullptr || json_type_array != json_object_get_type(poArcs))
703 0 : return;
704 :
705 5 : OGRGeoJSONLayer *poMainLayer = nullptr;
706 :
707 5 : json_object *poObjects = OGRGeoJSONFindMemberByName(poGJObject_, "objects");
708 5 : if (poObjects == nullptr)
709 0 : return;
710 :
711 5 : OGRSpatialReference *poSRS = OGRGeoJSONReadSpatialReference(poGJObject_);
712 :
713 10 : std::vector<int> anCurFieldIndices;
714 10 : std::map<std::string, int> oMapFieldNameToIdx;
715 10 : std::vector<std::unique_ptr<OGRFieldDefn>> apoFieldDefn;
716 10 : gdal::DirectedAcyclicGraph<int, std::string> dag;
717 :
718 10 : std::set<int> aoSetUndeterminedTypeFields;
719 5 : if (json_type_object == json_object_get_type(poObjects))
720 : {
721 : json_object_iter it;
722 3 : it.key = nullptr;
723 3 : it.val = nullptr;
724 3 : it.entry = nullptr;
725 3 : bool bNeedSecondPass = false;
726 9 : json_object_object_foreachC(poObjects, it)
727 : {
728 6 : json_object *poObj = it.val;
729 6 : bNeedSecondPass |= ParseObjectMain(
730 6 : it.key, poObj, poSRS, poDS, &poMainLayer, poArcs, &sParams,
731 : anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn, dag,
732 : aoSetUndeterminedTypeFields);
733 : }
734 3 : if (bNeedSecondPass)
735 : {
736 3 : OGRLayer *poMainLayerAsLayer = poMainLayer;
737 3 : OGRFeatureDefn *poDefn = poMainLayerAsLayer->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 : OGRLayer *poMainLayerAsLayer = poMainLayer;
772 2 : OGRFeatureDefn *poDefn = poMainLayerAsLayer->GetLayerDefn();
773 4 : const auto sortedFields = dag.getTopologicalOrdering();
774 2 : CPLAssert(sortedFields.size() == apoFieldDefn.size());
775 4 : auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer());
776 6 : for (int idx : sortedFields)
777 : {
778 4 : poDefn->AddFieldDefn(apoFieldDefn[idx].get());
779 : }
780 :
781 124 : for (auto i = decltype(nObjects){0}; i < nObjects; i++)
782 : {
783 122 : json_object *poObj = json_object_array_get_idx(poObjects, i);
784 122 : ParseObjectMainSecondPass(nullptr, poObj, &poMainLayer, poArcs,
785 : &sParams);
786 : }
787 : }
788 : }
789 :
790 5 : if (poMainLayer != nullptr)
791 : {
792 5 : poMainLayer->DetectGeometryType();
793 5 : poDS->AddLayer(poMainLayer);
794 : }
795 :
796 5 : if (poSRS)
797 1 : poSRS->Release();
798 : }
|