EVOLUTION-MANAGER
Edit File: ogrtopojsonreader.cpp
/****************************************************************************** * $Id: ogrtopojsonreader.cpp 28887 2015-04-12 23:10:28Z rouault $ * * Project: OpenGIS Simple Features Reference Implementation * Purpose: Implementation of OGRTopoJSONReader class * Author: Even Rouault, even dot rouault at mines dash paris dot org * ****************************************************************************** * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "ogrgeojsonreader.h" #include "ogrgeojsonutils.h" #include "ogr_geojson.h" #include <json.h> // JSON-C #include <ogr_api.h> /************************************************************************/ /* OGRTopoJSONReader() */ /************************************************************************/ OGRTopoJSONReader::OGRTopoJSONReader() : poGJObject_( NULL ) { // Take a deep breath and get to work. } /************************************************************************/ /* ~OGRTopoJSONReader() */ /************************************************************************/ OGRTopoJSONReader::~OGRTopoJSONReader() { if( NULL != poGJObject_ ) { json_object_put(poGJObject_); } poGJObject_ = NULL; } /************************************************************************/ /* Parse() */ /************************************************************************/ OGRErr OGRTopoJSONReader::Parse( const char* pszText ) { if( NULL != pszText ) { json_tokener* jstok = NULL; json_object* jsobj = NULL; jstok = json_tokener_new(); jsobj = json_tokener_parse_ex(jstok, pszText, -1); if( jstok->err != json_tokener_success) { CPLError( CE_Failure, CPLE_AppDefined, "TopoJSON parsing error: %s (at offset %d)", json_tokener_error_desc(jstok->err), jstok->char_offset); json_tokener_free(jstok); return OGRERR_CORRUPT_DATA; } json_tokener_free(jstok); /* JSON tree is shared for while lifetime of the reader object * and will be released in the destructor. */ poGJObject_ = jsobj; } return OGRERR_NONE; } typedef struct { double dfScale0, dfScale1; double dfTranslate0, dfTranslate1; } ScalingParams; /************************************************************************/ /* ParsePoint() */ /************************************************************************/ static int ParsePoint(json_object* poPoint, double* pdfX, double* pdfY) { if( poPoint != NULL && json_type_array == json_object_get_type(poPoint) && json_object_array_length(poPoint) == 2 ) { json_object* poX = json_object_array_get_idx(poPoint, 0); json_object* poY = json_object_array_get_idx(poPoint, 1); if( poX != NULL && (json_type_int == json_object_get_type(poX) || json_type_double == json_object_get_type(poX)) && poY != NULL && (json_type_int == json_object_get_type(poY) || json_type_double == json_object_get_type(poY)) ) { *pdfX = json_object_get_double(poX); *pdfY = json_object_get_double(poY); return TRUE; } } return FALSE; } /************************************************************************/ /* ParseArc() */ /************************************************************************/ static void ParseArc(OGRLineString* poLS, json_object* poArcsDB, int nArcID, int bReverse, ScalingParams* psParams) { json_object* poArcDB = json_object_array_get_idx(poArcsDB, nArcID); if( poArcDB == NULL || json_type_array != json_object_get_type(poArcDB) ) return; int nPoints = json_object_array_length(poArcDB); double dfAccX = 0, dfAccY = 0; int nBaseIndice = poLS->getNumPoints(); for(int i=0; i<nPoints; i++) { json_object* poPoint = json_object_array_get_idx(poArcDB, i); double dfX = 0.0, dfY = 0.0; if( ParsePoint( poPoint, &dfX, &dfY ) ) { dfAccX += dfX; dfAccY += dfY; double dfX = dfAccX * psParams->dfScale0 + psParams->dfTranslate0; double dfY = dfAccY * psParams->dfScale1 + psParams->dfTranslate1; if( i == 0 ) { if( !bReverse && poLS->getNumPoints() > 0 ) { poLS->setNumPoints( nBaseIndice + nPoints - 1 ); nBaseIndice --; continue; } else if( bReverse && poLS->getNumPoints() > 0 ) { poLS->setNumPoints( nBaseIndice + nPoints - 1 ); nPoints --; if( nPoints == 0 ) break; } else poLS->setNumPoints( nBaseIndice + nPoints ); } if( !bReverse ) poLS->setPoint(nBaseIndice + i, dfX, dfY); else poLS->setPoint(nBaseIndice + nPoints - 1 - i, dfX, dfY); } } } /************************************************************************/ /* ParseLineString() */ /************************************************************************/ static void ParseLineString(OGRLineString* poLS, json_object* poRing, json_object* poArcsDB, ScalingParams* psParams) { int nArcsDB = json_object_array_length(poArcsDB); int nArcsRing = json_object_array_length(poRing); for(int j=0; j<nArcsRing; j++) { json_object* poArcId = json_object_array_get_idx(poRing, j); if( poArcId != NULL && json_type_int == json_object_get_type(poArcId) ) { int nArcId = json_object_get_int(poArcId); int bReverse = FALSE; if( nArcId < 0 ) { nArcId = - nArcId - 1; bReverse = TRUE; } if( nArcId < nArcsDB ) { ParseArc(poLS, poArcsDB, nArcId, bReverse, psParams); } } } } /************************************************************************/ /* ParsePolygon() */ /************************************************************************/ static void ParsePolygon(OGRPolygon* poPoly, json_object* poArcsObj, json_object* poArcsDB, ScalingParams* psParams) { int nRings = json_object_array_length(poArcsObj); for(int i=0; i<nRings; i++) { OGRLinearRing* poLR = new OGRLinearRing(); poPoly->addRingDirectly(poLR); json_object* poRing = json_object_array_get_idx(poArcsObj, i); if( poRing != NULL && json_type_array == json_object_get_type(poRing) ) { ParseLineString(poLR, poRing, poArcsDB, psParams); } } } /************************************************************************/ /* ParseMultiLineString() */ /************************************************************************/ static void ParseMultiLineString(OGRMultiLineString* poMLS, json_object* poArcsObj, json_object* poArcsDB, ScalingParams* psParams) { int nRings = json_object_array_length(poArcsObj); for(int i=0; i<nRings; i++) { OGRLineString* poLS = new OGRLineString(); poMLS->addGeometryDirectly(poLS); json_object* poRing = json_object_array_get_idx(poArcsObj, i); if( poRing != NULL && json_type_array == json_object_get_type(poRing) ) { ParseLineString(poLS, poRing, poArcsDB, psParams); } } } /************************************************************************/ /* ParseMultiPolygon() */ /************************************************************************/ static void ParseMultiPolygon(OGRMultiPolygon* poMultiPoly, json_object* poArcsObj, json_object* poArcsDB, ScalingParams* psParams) { int nPolys = json_object_array_length(poArcsObj); for(int i=0; i<nPolys; i++) { OGRPolygon* poPoly = new OGRPolygon(); poMultiPoly->addGeometryDirectly(poPoly); json_object* poPolyArcs = json_object_array_get_idx(poArcsObj, i); if( poPolyArcs != NULL && json_type_array == json_object_get_type(poPolyArcs) ) { ParsePolygon(poPoly, poPolyArcs, poArcsDB, psParams); } } } /************************************************************************/ /* ParseObject() */ /************************************************************************/ static void ParseObject(const char* pszId, json_object* poObj, OGRGeoJSONLayer* poLayer, json_object* poArcsDB, ScalingParams* psParams) { json_object* poType = OGRGeoJSONFindMemberByName(poObj, "type"); if( poType == NULL || json_object_get_type(poType) != json_type_string ) return; const char* pszType = json_object_get_string(poType); json_object* poArcsObj = OGRGeoJSONFindMemberByName(poObj, "arcs"); json_object* poCoordinatesObj = OGRGeoJSONFindMemberByName(poObj, "coordinates"); if( strcmp(pszType, "Point") == 0 || strcmp(pszType, "MultiPoint") == 0 ) { if( poCoordinatesObj == NULL || json_type_array != json_object_get_type(poCoordinatesObj) ) return; } else { if( poArcsObj == NULL || json_type_array != json_object_get_type(poArcsObj) ) return; } if( pszId == NULL ) { json_object* poId = OGRGeoJSONFindMemberByName(poObj, "id"); if( poId != NULL && (json_type_string == json_object_get_type(poId) || json_type_int == json_object_get_type(poId)) ) { pszId = json_object_get_string(poId); } } OGRFeature* poFeature = new OGRFeature(poLayer->GetLayerDefn()); if( pszId != NULL ) poFeature->SetField("id", pszId); json_object* poProperties = OGRGeoJSONFindMemberByName(poObj, "properties"); if( poProperties != NULL && json_type_object == json_object_get_type(poProperties) ) { json_object* poName = OGRGeoJSONFindMemberByName(poProperties, "name"); if( poName != NULL && json_type_string == json_object_get_type(poName) ) { const char* pszName = json_object_get_string(poName); poFeature->SetField("name", pszName); } } OGRGeometry* poGeom = NULL; if( strcmp(pszType, "Point") == 0 ) { double dfX = 0.0, dfY = 0.0; if( ParsePoint( poCoordinatesObj, &dfX, &dfY ) ) { dfX = dfX * psParams->dfScale0 + psParams->dfTranslate0; dfY = dfY * psParams->dfScale1 + psParams->dfTranslate1; poGeom = new OGRPoint(dfX, dfY); } else poGeom = new OGRPoint(); } else if( strcmp(pszType, "MultiPoint") == 0 ) { OGRMultiPoint* poMP = new OGRMultiPoint(); poGeom = poMP; int nTuples = json_object_array_length(poCoordinatesObj); for(int i=0; i<nTuples; i++) { json_object* poPair = json_object_array_get_idx(poCoordinatesObj, i); double dfX = 0.0, dfY = 0.0; if( ParsePoint( poPair, &dfX, &dfY ) ) { dfX = dfX * psParams->dfScale0 + psParams->dfTranslate0; dfY = dfY * psParams->dfScale1 + psParams->dfTranslate1; poMP->addGeometryDirectly(new OGRPoint(dfX, dfY)); } } } else if( strcmp(pszType, "LineString") == 0 ) { OGRLineString* poLS = new OGRLineString(); poGeom = poLS; ParseLineString(poLS, poArcsObj, poArcsDB, psParams); } else if( strcmp(pszType, "MultiLineString") == 0 ) { OGRMultiLineString* poMLS = new OGRMultiLineString(); poGeom = poMLS; ParseMultiLineString(poMLS, poArcsObj, poArcsDB, psParams); } else if( strcmp(pszType, "Polygon") == 0 ) { OGRPolygon* poPoly = new OGRPolygon(); poGeom = poPoly; ParsePolygon(poPoly, poArcsObj, poArcsDB, psParams); } else if( strcmp(pszType, "MultiPolygon") == 0 ) { OGRMultiPolygon* poMultiPoly = new OGRMultiPolygon(); poGeom = poMultiPoly; ParseMultiPolygon(poMultiPoly, poArcsObj, poArcsDB, psParams); } if( poGeom != NULL ) poFeature->SetGeometryDirectly(poGeom); poLayer->AddFeature(poFeature); delete poFeature; } /************************************************************************/ /* ParseObjectMain() */ /************************************************************************/ static void ParseObjectMain(const char* pszId, json_object* poObj, OGRGeoJSONDataSource* poDS, OGRGeoJSONLayer **ppoMainLayer, json_object* poArcs, ScalingParams* psParams) { if( poObj != NULL && json_type_object == json_object_get_type( poObj ) ) { json_object* poType = OGRGeoJSONFindMemberByName(poObj, "type"); if( poType != NULL && json_type_string == json_object_get_type( poType ) ) { const char* pszType = json_object_get_string(poType); if( strcmp(pszType, "GeometryCollection") == 0 ) { json_object* poGeometries = OGRGeoJSONFindMemberByName(poObj, "geometries"); if( poGeometries != NULL && json_type_array == json_object_get_type( poGeometries ) ) { if( pszId == NULL ) { json_object* poId = OGRGeoJSONFindMemberByName(poObj, "id"); if( poId != NULL && (json_type_string == json_object_get_type(poId) || json_type_int == json_object_get_type(poId)) ) { pszId = json_object_get_string(poId); } } OGRGeoJSONLayer* poLayer = new OGRGeoJSONLayer( pszId ? pszId : "TopoJSON", NULL, wkbUnknown, poDS ); { OGRFieldDefn fldDefn( "id", OFTString ); poLayer->GetLayerDefn()->AddFieldDefn( &fldDefn ); } { OGRFieldDefn fldDefn( "name", OFTString ); poLayer->GetLayerDefn()->AddFieldDefn( &fldDefn ); } int nGeometries = json_object_array_length(poGeometries); for(int i=0; i<nGeometries; i++) { json_object* poGeom = json_object_array_get_idx(poGeometries, i); if( poGeom != NULL && json_type_object == json_object_get_type( poGeom ) ) { ParseObject(NULL, poGeom, poLayer, poArcs, psParams); } } poDS->AddLayer(poLayer); } } else if( strcmp(pszType, "Point") == 0 || strcmp(pszType, "MultiPoint") == 0 || strcmp(pszType, "LineString") == 0 || strcmp(pszType, "MultiLineString") == 0 || strcmp(pszType, "Polygon") == 0 || strcmp(pszType, "MultiPolygon") == 0 ) { if( *ppoMainLayer == NULL ) { *ppoMainLayer = new OGRGeoJSONLayer( "TopoJSON", NULL, wkbUnknown, poDS ); { OGRFieldDefn fldDefn( "id", OFTString ); (*ppoMainLayer)->GetLayerDefn()->AddFieldDefn( &fldDefn ); } { OGRFieldDefn fldDefn( "name", OFTString ); (*ppoMainLayer)->GetLayerDefn()->AddFieldDefn( &fldDefn ); } } ParseObject(pszId, poObj, *ppoMainLayer, poArcs, psParams); } } } } /************************************************************************/ /* ReadLayers() */ /************************************************************************/ void OGRTopoJSONReader::ReadLayers( OGRGeoJSONDataSource* poDS ) { if( NULL == poGJObject_ ) { CPLDebug( "TopoJSON", "Missing parset TopoJSON data. Forgot to call Parse()?" ); return; } ScalingParams sParams; sParams.dfScale0 = 1.0; sParams.dfScale1 = 1.0; sParams.dfTranslate0 = 0.0; sParams.dfTranslate1 = 0.0; json_object* poObjTransform = OGRGeoJSONFindMemberByName( poGJObject_, "transform" ); if( NULL != poObjTransform && json_type_object == json_object_get_type( poObjTransform ) ) { json_object* poObjScale = OGRGeoJSONFindMemberByName( poObjTransform, "scale" ); if( NULL != poObjScale && json_type_array == json_object_get_type( poObjScale ) && json_object_array_length( poObjScale ) == 2 ) { json_object* poScale0 = json_object_array_get_idx(poObjScale, 0); json_object* poScale1 = json_object_array_get_idx(poObjScale, 1); if( poScale0 != NULL && (json_object_get_type(poScale0) == json_type_double || json_object_get_type(poScale0) == json_type_int) && poScale1 != NULL && (json_object_get_type(poScale1) == json_type_double || json_object_get_type(poScale1) == json_type_int) ) { sParams.dfScale0 = json_object_get_double(poScale0); sParams.dfScale1 = json_object_get_double(poScale1); } } json_object* poObjTranslate = OGRGeoJSONFindMemberByName( poObjTransform, "translate" ); if( NULL != poObjTranslate && json_type_array == json_object_get_type( poObjTranslate ) && json_object_array_length( poObjTranslate ) == 2 ) { json_object* poTranslate0 = json_object_array_get_idx(poObjTranslate, 0); json_object* poTranslate1 = json_object_array_get_idx(poObjTranslate, 1); if( poTranslate0 != NULL && (json_object_get_type(poTranslate0) == json_type_double || json_object_get_type(poTranslate0) == json_type_int) && poTranslate1 != NULL && (json_object_get_type(poTranslate1) == json_type_double || json_object_get_type(poTranslate1) == json_type_int) ) { sParams.dfTranslate0 = json_object_get_double(poTranslate0); sParams.dfTranslate1 = json_object_get_double(poTranslate1); } } } json_object* poArcs = OGRGeoJSONFindMemberByName( poGJObject_, "arcs" ); if( poArcs == NULL || json_type_array != json_object_get_type( poArcs ) ) return; OGRGeoJSONLayer* poMainLayer = NULL; json_object* poObjects = OGRGeoJSONFindMemberByName( poGJObject_, "objects" ); if( poObjects == NULL ) return; if( json_type_object == json_object_get_type( poObjects ) ) { json_object_iter it; it.key = NULL; it.val = NULL; it.entry = NULL; json_object_object_foreachC( poObjects, it ) { json_object* poObj = it.val; ParseObjectMain(it.key, poObj, poDS, &poMainLayer, poArcs, &sParams); } } else if( json_type_array == json_object_get_type( poObjects ) ) { int nObjects = json_object_array_length(poObjects); for(int i=0; i<nObjects; i++) { json_object* poObj = json_object_array_get_idx(poObjects, i); ParseObjectMain(NULL, poObj, poDS, &poMainLayer, poArcs, &sParams); } } if( poMainLayer != NULL ) poDS->AddLayer(poMainLayer); }