LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/geojson - ogrgeojsonlayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 147 127 86.4 %
Date: 2011-12-18 Functions: 19 14 73.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgeojsonlayer.cpp 23367 2011-11-12 22:46:13Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implementation of OGRGeoJSONLayer class (OGR GeoJSON Driver).
       6                 :  * Author:   Mateusz Loskot, mateusz@loskot.net
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2007, Mateusz Loskot
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : #include "ogr_geojson.h"
      30                 : #include "ogrgeojsonwriter.h"
      31                 : #include <jsonc/json.h> // JSON-C
      32                 : #include <algorithm> // for_each, find_if
      33                 : 
      34                 : /* Remove annoying warnings Microsoft Visual C++ */
      35                 : #if defined(_MSC_VER)
      36                 : #  pragma warning(disable:4512)
      37                 : #endif
      38                 : 
      39                 : /************************************************************************/
      40                 : /*                       STATIC MEMBERS DEFINITION                      */
      41                 : /************************************************************************/
      42                 : 
      43                 : const char* const OGRGeoJSONLayer::DefaultName = "OGRGeoJSON";
      44                 : const char* const OGRGeoJSONLayer::DefaultFIDColumn = "id";
      45                 : const OGRwkbGeometryType OGRGeoJSONLayer::DefaultGeometryType = wkbUnknown;
      46                 : 
      47                 : /************************************************************************/
      48                 : /*                           OGRGeoJSONLayer                            */
      49                 : /************************************************************************/
      50                 : 
      51              57 : OGRGeoJSONLayer::OGRGeoJSONLayer( const char* pszName,
      52                 :                                   OGRSpatialReference* poSRSIn,
      53                 :                                   OGRwkbGeometryType eGType,
      54                 :                                   char** papszOptions,
      55                 :                                   OGRGeoJSONDataSource* poDS )
      56              57 :     : iterCurrent_( seqFeatures_.end() ), poDS_( poDS ), poFeatureDefn_(new OGRFeatureDefn( pszName ) ), poSRS_( NULL ), nOutCounter_( 0 )
      57                 : {
      58              57 :     bWriteBBOX = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"));
      59              57 :     bBBOX3D = FALSE;
      60                 : 
      61              57 :     CPLAssert( NULL != poDS_ );
      62              57 :     CPLAssert( NULL != poFeatureDefn_ );
      63                 :     
      64              57 :     poFeatureDefn_->Reference();
      65              57 :     poFeatureDefn_->SetGeomType( eGType );
      66                 : 
      67              57 :     if( NULL != poSRSIn )
      68                 :     {
      69               0 :         SetSpatialRef( poSRSIn );
      70                 :     }
      71                 : 
      72              57 :     nCoordPrecision = atoi(CSLFetchNameValueDef(papszOptions, "COORDINATE_PRECISION", "-1"));
      73              57 : }
      74                 : 
      75                 : /************************************************************************/
      76                 : /*                          ~OGRGeoJSONLayer                            */
      77                 : /************************************************************************/
      78                 : 
      79              57 : OGRGeoJSONLayer::~OGRGeoJSONLayer()
      80                 : {
      81              57 :     VSILFILE* fp = poDS_->GetOutputFile();
      82              57 :     if( NULL != fp )
      83                 :     {
      84              15 :         VSIFPrintfL( fp, "\n]" );
      85                 : 
      86              15 :         if( bWriteBBOX && sEnvelopeLayer.IsInit() )
      87                 :         {
      88               1 :             json_object* poObjBBOX = json_object_new_array();
      89                 :             json_object_array_add(poObjBBOX,
      90               1 :                             json_object_new_double_with_precision(sEnvelopeLayer.MinX, nCoordPrecision));
      91                 :             json_object_array_add(poObjBBOX,
      92               1 :                             json_object_new_double_with_precision(sEnvelopeLayer.MinY, nCoordPrecision));
      93               1 :             if( bBBOX3D )
      94                 :                 json_object_array_add(poObjBBOX,
      95               0 :                             json_object_new_double_with_precision(sEnvelopeLayer.MinZ, nCoordPrecision));
      96                 :             json_object_array_add(poObjBBOX,
      97               1 :                             json_object_new_double_with_precision(sEnvelopeLayer.MaxX, nCoordPrecision));
      98                 :             json_object_array_add(poObjBBOX,
      99               1 :                             json_object_new_double_with_precision(sEnvelopeLayer.MaxY, nCoordPrecision));
     100               1 :             if( bBBOX3D )
     101                 :                 json_object_array_add(poObjBBOX,
     102               0 :                             json_object_new_double_with_precision(sEnvelopeLayer.MaxZ, nCoordPrecision));
     103                 : 
     104               1 :             const char* pszBBOX = json_object_to_json_string( poObjBBOX );
     105               1 :             if( poDS_->GetFpOutputIsSeekable() )
     106                 :             {
     107               1 :                 VSIFSeekL(fp, poDS_->GetBBOXInsertLocation(), SEEK_SET);
     108               1 :                 if (strlen(pszBBOX) + 9 < SPACE_FOR_BBOX)
     109               1 :                     VSIFPrintfL( fp, "\"bbox\": %s,", pszBBOX );
     110               1 :                 VSIFSeekL(fp, 0, SEEK_END);
     111                 :             }
     112                 :             else
     113                 :             {
     114               0 :                 VSIFPrintfL( fp, ",\n\"bbox\": %s", pszBBOX );
     115                 :             }
     116                 : 
     117               1 :             json_object_put( poObjBBOX );
     118                 :         }
     119                 : 
     120              15 :         VSIFPrintfL( fp, "\n}\n" );
     121                 :     }
     122                 : 
     123                 :     std::for_each(seqFeatures_.begin(), seqFeatures_.end(),
     124              57 :                   OGRFeature::DestroyFeature);
     125                 : 
     126              57 :     if( NULL != poFeatureDefn_ )
     127                 :     {
     128              57 :         poFeatureDefn_->Release();
     129                 :     }
     130                 : 
     131              57 :     if( NULL != poSRS_ )
     132                 :     {
     133              38 :         poSRS_->Release();   
     134                 :     }
     135              57 : }
     136                 : 
     137                 : /************************************************************************/
     138                 : /*                           GetLayerDefn                               */
     139                 : /************************************************************************/
     140                 : 
     141             454 : OGRFeatureDefn* OGRGeoJSONLayer::GetLayerDefn()
     142                 : {
     143             454 :     return poFeatureDefn_;
     144                 : }
     145                 : 
     146                 : /************************************************************************/
     147                 : /*                           GetSpatialRef                              */
     148                 : /************************************************************************/
     149                 : 
     150               4 : OGRSpatialReference* OGRGeoJSONLayer::GetSpatialRef()
     151                 : {
     152               4 :     return poSRS_;
     153                 : }
     154                 : 
     155              38 : void OGRGeoJSONLayer::SetSpatialRef( OGRSpatialReference* poSRSIn )
     156                 : {
     157              38 :     if( NULL == poSRSIn )
     158                 :     {
     159               0 :         poSRS_ = NULL;
     160                 :         // poSRS_ = new OGRSpatialReference();
     161                 :         // if( OGRERR_NONE != poSRS_->importFromEPSG( 4326 ) )
     162                 :         // {
     163                 :         //     delete poSRS_;
     164                 :         //     poSRS_ = NULL;
     165                 :         // }
     166                 :     }
     167                 :     else
     168                 :     {
     169              38 :         poSRS_ = poSRSIn->Clone(); 
     170                 :     }
     171              38 : }
     172                 : 
     173                 : /************************************************************************/
     174                 : /*                           GetFeatureCount                            */
     175                 : /************************************************************************/
     176                 : 
     177              13 : int OGRGeoJSONLayer::GetFeatureCount( int bForce )
     178                 : {
     179              13 :     if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
     180              13 :         return static_cast<int>( seqFeatures_.size() );
     181                 :     else
     182               0 :         return OGRLayer::GetFeatureCount(bForce);
     183                 : }
     184                 : 
     185                 : /************************************************************************/
     186                 : /*                           ResetReading                               */
     187                 : /************************************************************************/
     188                 : 
     189              94 : void OGRGeoJSONLayer::ResetReading()
     190                 : {
     191              94 :     iterCurrent_ = seqFeatures_.begin();
     192              94 : }
     193                 : 
     194                 : /************************************************************************/
     195                 : /*                           GetNextFeature                             */
     196                 : /************************************************************************/
     197                 : 
     198             124 : OGRFeature* OGRGeoJSONLayer::GetNextFeature()
     199                 : {
     200             248 :     while ( iterCurrent_ != seqFeatures_.end() )
     201                 :     {
     202              85 :         OGRFeature* poFeature = (*iterCurrent_);
     203              85 :         CPLAssert( NULL != poFeature );
     204              85 :         ++iterCurrent_;
     205                 :         
     206              85 :         if((m_poFilterGeom == NULL
     207                 :             || FilterGeometry( poFeature->GetGeometryRef() ) )
     208                 :         && (m_poAttrQuery == NULL
     209                 :             || m_poAttrQuery->Evaluate( poFeature )) )
     210                 :         {
     211              85 :             OGRFeature* poFeatureCopy = poFeature->Clone();
     212              85 :             CPLAssert( NULL != poFeatureCopy );
     213                 : 
     214              85 :             if (poFeatureCopy->GetGeometryRef() != NULL && poSRS_ != NULL)
     215                 :             {
     216              67 :                 poFeatureCopy->GetGeometryRef()->assignSpatialReference( poSRS_ );
     217                 :             }
     218                 : 
     219              85 :             return poFeatureCopy;
     220                 :         }
     221                 :     }
     222                 : 
     223              39 :     return NULL;
     224                 : }
     225                 : 
     226                 : /************************************************************************/
     227                 : /*                           GetFeature                             */
     228                 : /************************************************************************/
     229                 : 
     230               0 : OGRFeature* OGRGeoJSONLayer::GetFeature( long nFID )
     231                 : {
     232               0 :   OGRFeature* poFeature = NULL;
     233               0 :   poFeature = OGRLayer::GetFeature( nFID );
     234                 : 
     235               0 :   return poFeature;
     236                 : }
     237                 : 
     238                 : /************************************************************************/
     239                 : /*                           CreateFeature                              */
     240                 : /************************************************************************/
     241                 : 
     242              27 : OGRErr OGRGeoJSONLayer::CreateFeature( OGRFeature* poFeature )
     243                 : {
     244              27 :     VSILFILE* fp = poDS_->GetOutputFile();
     245              27 :     if( NULL == fp )
     246                 :     {
     247               0 :         CPLDebug( "GeoJSON", "Target datasource file is invalid." );
     248               0 :         return CE_Failure;
     249                 :     }
     250                 : 
     251              27 :     if( NULL == poFeature )
     252                 :     {
     253               0 :         CPLDebug( "GeoJSON", "Feature is null" );
     254               0 :         return OGRERR_INVALID_HANDLE;
     255                 :     }
     256                 : 
     257              27 :     json_object* poObj = OGRGeoJSONWriteFeature( poFeature, bWriteBBOX, nCoordPrecision );
     258              27 :     CPLAssert( NULL != poObj );
     259                 : 
     260              27 :     if( nOutCounter_ > 0 )
     261                 :     {
     262                 :         /* Separate "Feature" entries in "FeatureCollection" object. */
     263              12 :         VSIFPrintfL( fp, ",\n" );
     264                 :     }
     265              27 :     VSIFPrintfL( fp, "%s\n", json_object_to_json_string( poObj ) );
     266                 : 
     267              27 :     json_object_put( poObj );
     268                 : 
     269              27 :     ++nOutCounter_;
     270                 : 
     271              27 :     OGRGeometry* poGeometry = poFeature->GetGeometryRef();
     272              27 :     if ( bWriteBBOX && !poGeometry->IsEmpty() )
     273                 :     {
     274               2 :         OGREnvelope3D sEnvelope;
     275               2 :         poGeometry->getEnvelope(&sEnvelope);
     276                 : 
     277               2 :         if( poGeometry->getCoordinateDimension() == 3 )
     278               0 :             bBBOX3D = TRUE;
     279                 : 
     280               2 :         sEnvelopeLayer.Merge(sEnvelope);
     281                 :     }
     282                 : 
     283              27 :     return OGRERR_NONE;
     284                 : }
     285                 : 
     286              26 : OGRErr OGRGeoJSONLayer::CreateField(OGRFieldDefn* poField, int bApproxOK)
     287                 : {
     288                 :     UNREFERENCED_PARAM(bApproxOK);
     289                 : 
     290              39 :     for( int i = 0; i < poFeatureDefn_->GetFieldCount(); ++i )
     291                 :     {
     292              13 :         OGRFieldDefn* poDefn = poFeatureDefn_->GetFieldDefn(i);
     293              13 :         CPLAssert( NULL != poDefn );
     294                 : 
     295              13 :         if( EQUAL( poDefn->GetNameRef(), poField->GetNameRef() ) )
     296                 :         {
     297                 :             CPLDebug( "GeoJSON", "Field '%s' already present in schema",
     298               0 :                       poField->GetNameRef() );
     299                 :             
     300                 :             // TODO - mloskot: Is this return code correct?
     301               0 :             return OGRERR_NONE;
     302                 :         }
     303                 :     }
     304                 : 
     305              26 :     poFeatureDefn_->AddFieldDefn( poField );
     306                 : 
     307              26 :     return OGRERR_NONE;
     308                 : }
     309                 : 
     310                 : /************************************************************************/
     311                 : /*                           TestCapability                             */
     312                 : /************************************************************************/
     313                 : 
     314               0 : int OGRGeoJSONLayer::TestCapability( const char* pszCap )
     315                 : {
     316                 :     UNREFERENCED_PARAM(pszCap);
     317                 : 
     318               0 :     return FALSE;
     319                 : }
     320                 : 
     321                 : /************************************************************************/
     322                 : /*                           GetFIDColumn                               */
     323                 : /************************************************************************/
     324                 :   
     325              28 : const char* OGRGeoJSONLayer::GetFIDColumn()
     326                 : {
     327              28 :   return sFIDColumn_.c_str();
     328                 : }
     329                 : 
     330                 : /************************************************************************/
     331                 : /*                           SetFIDColumn                               */
     332                 : /************************************************************************/
     333                 : 
     334               4 : void OGRGeoJSONLayer::SetFIDColumn( const char* pszFIDColumn )
     335                 : {
     336               4 :   sFIDColumn_ = pszFIDColumn;
     337               4 : }
     338                 : 
     339                 : /************************************************************************/
     340                 : /*                           AddFeature                                 */
     341                 : /************************************************************************/
     342                 : 
     343             102 : void OGRGeoJSONLayer::AddFeature( OGRFeature* poFeature )
     344                 : {
     345             102 :     CPLAssert( NULL != poFeature );
     346                 : 
     347                 :     // NOTE - mloskot:
     348                 :     // Features may not be sorted according to FID values.
     349                 : 
     350                 :     // TODO: Should we check if feature already exists?
     351                 :     // TODO: Think about sync operation, upload, etc.
     352                 : 
     353             102 :     OGRFeature* poNewFeature = NULL;
     354             102 :     poNewFeature = poFeature->Clone();
     355                 : 
     356                 : 
     357             102 :     if( -1 == poNewFeature->GetFID() )
     358                 :     {
     359              98 :         int nFID = static_cast<int>(seqFeatures_.size());
     360              98 :         poNewFeature->SetFID( nFID );
     361                 : 
     362                 :         // TODO - mlokot: We need to redesign creation of FID column
     363              98 :         int nField = poNewFeature->GetFieldIndex( DefaultFIDColumn );
     364              98 :         if( -1 != nField )
     365                 :         {
     366               0 :             poNewFeature->SetField( nField, nFID );
     367                 :         }
     368                 :     }
     369                 : 
     370             102 :     seqFeatures_.push_back( poNewFeature );
     371             102 : }
     372                 : 
     373                 : /************************************************************************/
     374                 : /*                           DetectGeometryType                         */
     375                 : /************************************************************************/
     376                 : 
     377              42 : void OGRGeoJSONLayer::DetectGeometryType()
     378                 : {
     379              42 :     if (poFeatureDefn_->GetGeomType() != wkbUnknown)
     380               8 :         return;
     381                 : 
     382              34 :     OGRwkbGeometryType featType = wkbUnknown;
     383              34 :     OGRGeometry* poGeometry = NULL;
     384              34 :     FeaturesSeq::const_iterator it = seqFeatures_.begin();
     385              34 :     FeaturesSeq::const_iterator end = seqFeatures_.end();
     386                 :     
     387              34 :     if( it != end )
     388                 :     {
     389              34 :         poGeometry = (*it)->GetGeometryRef();
     390              34 :         if( NULL != poGeometry )
     391                 :         {
     392              32 :             featType = poGeometry->getGeometryType();
     393              32 :             if( featType != poFeatureDefn_->GetGeomType() )
     394                 :             {
     395              32 :                 poFeatureDefn_->SetGeomType( featType );
     396                 :             }
     397                 :         }
     398              34 :         ++it;
     399                 :     }
     400                 : 
     401              94 :     while( it != end )
     402                 :     {
     403              28 :         poGeometry = (*it)->GetGeometryRef();
     404              28 :         if( NULL != poGeometry )
     405                 :         {
     406              12 :             featType = poGeometry->getGeometryType();
     407              12 :             if( featType != poFeatureDefn_->GetGeomType() )
     408                 :             {
     409                 :                 CPLDebug( "GeoJSON",
     410               2 :                     "Detected layer of mixed-geometry type features." );
     411               2 :                 poFeatureDefn_->SetGeomType( DefaultGeometryType );
     412               2 :                 break;
     413                 :             }
     414                 :         }
     415              26 :         ++it;
     416                 :     }
     417                 : }

Generated by: LCOV version 1.7