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