LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/bna - ogrbnalayer.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 407 329 80.8 %
Date: 2012-12-26 Functions: 16 12 75.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrbnalayer.cpp 21684 2011-02-11 22:14:01Z warmerdam $
       3                 :  *
       4                 :  * Project:  BNA Translator
       5                 :  * Purpose:  Implements OGRBNALayer class.
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2007, Even Rouault
      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                 : 
      30                 : #include "ogr_bna.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : #include "cpl_csv.h"
      34                 : #include "ogr_p.h"
      35                 : 
      36                 : #ifndef M_PI
      37                 : # define M_PI  3.1415926535897932384626433832795
      38                 : #endif
      39                 : 
      40                 : /************************************************************************/
      41                 : /*                            OGRBNALayer()                             */
      42                 : /*                                                                      */
      43                 : /*      Note that the OGRBNALayer assumes ownership of the passed       */
      44                 : /*      file pointer.                                                   */
      45                 : /************************************************************************/
      46                 : 
      47              41 : OGRBNALayer::OGRBNALayer( const char *pszFilename,
      48                 :                           const char* layerName,
      49                 :                           BNAFeatureType bnaFeatureType,
      50                 :                           OGRwkbGeometryType eLayerGeomType,
      51                 :                           int bWriter,
      52                 :                           OGRBNADataSource* poDS,
      53              41 :                           int nIDs)
      54                 : 
      55                 : {
      56              41 :     eof = FALSE;
      57              41 :     failed = FALSE;
      58              41 :     curLine = 0;
      59              41 :     nNextFID = 0;
      60                 :     
      61              41 :     this->bWriter = bWriter;
      62              41 :     this->poDS = poDS;
      63              41 :     this->nIDs = nIDs;
      64                 : 
      65              41 :     nFeatures = 0;
      66              41 :     partialIndexTable = TRUE;
      67              41 :     offsetAndLineFeaturesTable = NULL;
      68                 : 
      69              41 :     const char* iKnowHowToCount[] = { "Primary", "Secondary", "Third", "Fourth", "Fifth" };
      70                 :     char tmp[32];
      71                 : 
      72                 :     poFeatureDefn = new OGRFeatureDefn( CPLSPrintf("%s_%s", 
      73                 :                                                    CPLGetBasename( pszFilename ) , 
      74              41 :                                                    layerName ));
      75              41 :     poFeatureDefn->Reference();
      76              41 :     poFeatureDefn->SetGeomType( eLayerGeomType );
      77              41 :     this->bnaFeatureType = bnaFeatureType;
      78                 : 
      79              41 :     if (! bWriter )
      80                 :     {
      81                 :         int i;
      82              88 :         for(i=0;i<nIDs;i++)
      83                 :         {
      84              59 :             if (i < (int) (sizeof(iKnowHowToCount)/sizeof(iKnowHowToCount[0])) )
      85                 :             {
      86              59 :                 sprintf(tmp, "%s ID", iKnowHowToCount[i]);
      87              59 :                 OGRFieldDefn oFieldID(tmp, OFTString );
      88              59 :                 poFeatureDefn->AddFieldDefn( &oFieldID );
      89                 :             }
      90                 :             else
      91                 :             {
      92               0 :                 sprintf(tmp, "%dth ID", i+1);
      93               0 :                 OGRFieldDefn oFieldID(tmp, OFTString );
      94               0 :                 poFeatureDefn->AddFieldDefn( &oFieldID );
      95                 :             }
      96                 :         }
      97                 : 
      98              29 :         if (bnaFeatureType == BNA_ELLIPSE)
      99                 :         {
     100               7 :             OGRFieldDefn oFieldMajorRadius( "Major radius", OFTReal );
     101               7 :             poFeatureDefn->AddFieldDefn( &oFieldMajorRadius );
     102                 : 
     103               7 :             OGRFieldDefn oFieldMinorRadius( "Minor radius", OFTReal );
     104               7 :             poFeatureDefn->AddFieldDefn( &oFieldMinorRadius );
     105                 :         }
     106                 : 
     107              29 :         fpBNA = VSIFOpenL( pszFilename, "rb" );
     108              29 :         if( fpBNA == NULL )
     109               0 :             return;
     110                 :     }
     111                 :     else
     112                 :     {
     113              12 :         fpBNA = NULL;
     114                 :     }
     115               0 : }
     116                 : 
     117                 : /************************************************************************/
     118                 : /*                            ~OGRBNALayer()                            */
     119                 : /************************************************************************/
     120                 : 
     121              41 : OGRBNALayer::~OGRBNALayer()
     122                 : 
     123                 : {
     124              41 :     poFeatureDefn->Release();
     125                 : 
     126              41 :     CPLFree(offsetAndLineFeaturesTable);
     127                 : 
     128              41 :     if (fpBNA)
     129              29 :         VSIFCloseL( fpBNA );
     130              41 : }
     131                 : 
     132                 : /************************************************************************/
     133                 : /*                         SetFeatureIndexTable()                       */
     134                 : /************************************************************************/
     135              29 : void  OGRBNALayer::SetFeatureIndexTable(int nFeatures, OffsetAndLine* offsetAndLineFeaturesTable, int partialIndexTable)
     136                 : {
     137              29 :     this->nFeatures = nFeatures;
     138              29 :     this->offsetAndLineFeaturesTable = offsetAndLineFeaturesTable;
     139              29 :     this->partialIndexTable = partialIndexTable;
     140              29 : }
     141                 : 
     142                 : /************************************************************************/
     143                 : /*                            ResetReading()                            */
     144                 : /************************************************************************/
     145                 : 
     146              65 : void OGRBNALayer::ResetReading()
     147                 : 
     148                 : {
     149              65 :     eof = FALSE;
     150              65 :     failed = FALSE;
     151              65 :     curLine = 0;
     152              65 :     nNextFID = 0;
     153              65 :     VSIFSeekL( fpBNA, 0, SEEK_SET );
     154              65 : }
     155                 : 
     156                 : 
     157                 : /************************************************************************/
     158                 : /*                           GetNextFeature()                           */
     159                 : /************************************************************************/
     160                 : 
     161             202 : OGRFeature *OGRBNALayer::GetNextFeature()
     162                 : {
     163                 :     OGRFeature  *poFeature;
     164                 :     BNARecord* record;
     165                 :     int offset, line;
     166                 : 
     167             202 :     if (failed || eof) return NULL;
     168                 : 
     169             172 :     while(1)
     170                 :     {
     171             374 :         int ok = FALSE;
     172             374 :         offset = (int) VSIFTellL(fpBNA);
     173             374 :         line = curLine;
     174             374 :         if (nNextFID < nFeatures)
     175                 :         {
     176             137 :             VSIFSeekL( fpBNA, offsetAndLineFeaturesTable[nNextFID].offset, SEEK_SET );
     177             137 :             curLine = offsetAndLineFeaturesTable[nNextFID].line;
     178                 :         }
     179             374 :         record =  BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType);
     180             374 :         if (ok == FALSE)
     181                 :         {
     182               0 :             BNA_FreeRecord(record);
     183               0 :             failed = TRUE;
     184               0 :             return NULL;
     185                 :         }
     186             374 :         if (record == NULL)
     187                 :         {
     188                 :             /* end of file */
     189              65 :             eof = TRUE;
     190                 : 
     191                 :             /* and we have finally build the whole index table */
     192              65 :             partialIndexTable = FALSE;
     193              65 :             return NULL;
     194                 :         }
     195                 : 
     196             309 :         if (record->featureType == bnaFeatureType)
     197                 :         {
     198             137 :             if (nNextFID >= nFeatures)
     199                 :             {
     200               0 :                 nFeatures++;
     201                 :                 offsetAndLineFeaturesTable =
     202               0 :                     (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine));
     203               0 :                 offsetAndLineFeaturesTable[nFeatures-1].offset = offset;
     204               0 :                 offsetAndLineFeaturesTable[nFeatures-1].line = line;
     205                 :             }
     206                 : 
     207             137 :             poFeature = BuildFeatureFromBNARecord(record, nNextFID++);
     208                 : 
     209             137 :             BNA_FreeRecord(record);
     210                 : 
     211             137 :             if(   (m_poFilterGeom == NULL
     212                 :                 || FilterGeometry( poFeature->GetGeometryRef() ) )
     213                 :             && (m_poAttrQuery == NULL
     214                 :                 || m_poAttrQuery->Evaluate( poFeature )) )
     215                 :             {
     216             137 :                  return poFeature;
     217                 :             }
     218                 : 
     219               0 :             delete poFeature;
     220                 :         }
     221                 :         else
     222                 :         {
     223             172 :             BNA_FreeRecord(record);
     224                 :         }
     225                 :     }
     226                 : }
     227                 : 
     228                 : 
     229                 : /************************************************************************/
     230                 : /*                      WriteFeatureAttributes()                        */
     231                 : /************************************************************************/
     232                 : 
     233              24 : void OGRBNALayer::WriteFeatureAttributes(VSILFILE* fp, OGRFeature *poFeature )
     234                 : {
     235                 :     int i;
     236                 :     OGRFieldDefn *poFieldDefn;
     237              24 :     int nbOutID = poDS->GetNbOutId();
     238              24 :     if (nbOutID < 0)
     239               0 :         nbOutID = poFeatureDefn->GetFieldCount();
     240              72 :     for(i=0;i<nbOutID;i++)
     241                 :     { 
     242              48 :         if (i < poFeatureDefn->GetFieldCount())
     243                 :         {
     244              48 :             poFieldDefn = poFeatureDefn->GetFieldDefn( i );
     245              48 :             if( poFeature->IsFieldSet( i ) )
     246                 :             {
     247              48 :                 if (poFieldDefn->GetType() == OFTReal)
     248                 :                 {
     249                 :                     char szBuffer[64];
     250                 :                     OGRFormatDouble(szBuffer, sizeof(szBuffer),
     251               0 :                                     poFeature->GetFieldAsDouble(i), '.');
     252               0 :                     VSIFPrintfL( fp, "\"%s\",", szBuffer);
     253                 :                 }
     254                 :                 else
     255                 :                 {
     256              48 :                     const char *pszRaw = poFeature->GetFieldAsString( i );
     257              48 :                     VSIFPrintfL( fp, "\"%s\",", pszRaw);
     258                 :                 }
     259                 :             }
     260                 :             else
     261                 :             {
     262               0 :                 VSIFPrintfL( fp, "\"\",");
     263                 :             }
     264                 :         }
     265                 :         else
     266                 :         {
     267               0 :             VSIFPrintfL( fp, "\"\",");
     268                 :         }
     269                 :     }
     270              24 : }
     271                 : 
     272                 : /************************************************************************/
     273                 : /*                             WriteCoord()                             */
     274                 : /************************************************************************/
     275                 : 
     276             282 : void OGRBNALayer::WriteCoord(VSILFILE* fp, double dfX, double dfY)
     277                 : {
     278                 :     char szBuffer[64];
     279             282 :     OGRFormatDouble(szBuffer, sizeof(szBuffer), dfX, '.', poDS->GetCoordinatePrecision());
     280             282 :     VSIFPrintfL( fp, "%s", szBuffer);
     281             282 :     VSIFPrintfL( fp, "%s", poDS->GetCoordinateSeparator());
     282             282 :     OGRFormatDouble(szBuffer, sizeof(szBuffer), dfY, '.', poDS->GetCoordinatePrecision());
     283             282 :     VSIFPrintfL( fp, "%s", szBuffer);
     284             282 : }
     285                 : 
     286                 : /************************************************************************/
     287                 : /*                           CreateFeature()                            */
     288                 : /************************************************************************/
     289                 : 
     290              24 : OGRErr OGRBNALayer::CreateFeature( OGRFeature *poFeature )
     291                 : 
     292                 : {
     293                 :     int i,j,k,n;
     294              24 :     OGRGeometry     *poGeom = poFeature->GetGeometryRef();
     295                 :     char eol[3];
     296              24 :     const char* partialEol = (poDS->GetMultiLine()) ? eol : poDS->GetCoordinateSeparator();
     297                 : 
     298              24 :     if (poGeom == NULL || poGeom->IsEmpty() )
     299                 :     {
     300                 :         CPLError(CE_Failure, CPLE_AppDefined,
     301               0 :                  "OGR BNA driver cannot write features with empty geometries.");
     302               0 :         return OGRERR_FAILURE;
     303                 :     }
     304                 : 
     305              24 :     if (poDS->GetUseCRLF())
     306                 :     {
     307               8 :         eol[0] = 13;
     308               8 :         eol[1] = 10;
     309               8 :         eol[2] = 0;
     310                 :     }
     311                 :     else
     312                 :     {
     313              16 :         eol[0] = 10;
     314              16 :         eol[1] = 0;
     315                 :     }
     316                 :     
     317              24 :     if ( ! bWriter )
     318                 :     {
     319               0 :         return OGRERR_FAILURE;
     320                 :     }
     321                 :     
     322              24 :     if( poFeature->GetFID() == OGRNullFID )
     323              24 :         poFeature->SetFID( nFeatures++ );
     324                 :     
     325              24 :     VSILFILE* fp = poDS->GetOutputFP();
     326              24 :     int nbPairPerLine = poDS->GetNbPairPerLine();
     327                 : 
     328              24 :     switch( poGeom->getGeometryType() )
     329                 :     {
     330                 :         case wkbPoint:
     331                 :         case wkbPoint25D:
     332                 :         {
     333               6 :             OGRPoint* point = (OGRPoint*)poGeom;
     334               6 :             WriteFeatureAttributes(fp, poFeature);
     335               6 :             VSIFPrintfL( fp, "1");
     336               6 :             VSIFPrintfL( fp, "%s", partialEol);
     337               6 :             WriteCoord(fp, point->getX(), point->getY());
     338               6 :             VSIFPrintfL( fp, "%s", eol);
     339               6 :             break;
     340                 :         }
     341                 :             
     342                 :         case wkbPolygon:
     343                 :         case wkbPolygon25D:
     344                 :         {
     345               6 :             OGRPolygon* polygon = (OGRPolygon*)poGeom;
     346               6 :             OGRLinearRing* ring = polygon->getExteriorRing();
     347               6 :             if (ring == NULL)
     348                 :             {
     349               0 :                 return OGRERR_FAILURE;
     350                 :             }
     351                 :             
     352               6 :             double firstX = ring->getX(0);
     353               6 :             double firstY = ring->getY(0);
     354               6 :             int nBNAPoints = ring->getNumPoints();
     355               6 :             int is_ellipse = FALSE;
     356                 :             
     357                 :             /* This code tries to detect an ellipse in a polygon geometry */
     358                 :             /* This will only work presumably on ellipses already read from a BNA file */
     359                 :             /* Mostly a BNA to BNA feature... */
     360               6 :             if (poDS->GetEllipsesAsEllipses() &&
     361                 :                 polygon->getNumInteriorRings() == 0 &&
     362                 :                 nBNAPoints == 361)
     363                 :             {
     364               3 :                 double oppositeX = ring->getX(180);
     365               3 :                 double oppositeY = ring->getY(180);
     366               3 :                 double quarterX = ring->getX(90);
     367               3 :                 double quarterY = ring->getY(90);
     368               3 :                 double antiquarterX = ring->getX(270);
     369               3 :                 double antiquarterY = ring->getY(270);
     370               3 :                 double center1X = 0.5*(firstX + oppositeX);
     371               3 :                 double center1Y = 0.5*(firstY + oppositeY);
     372               3 :                 double center2X = 0.5*(quarterX + antiquarterX);
     373               3 :                 double center2Y = 0.5*(quarterY + antiquarterY);
     374               3 :                 if (fabs(center1X - center2X) < 1e-5 && fabs(center1Y - center2Y) < 1e-5 &&
     375                 :                     fabs(oppositeY - firstY) < 1e-5 &&
     376                 :                     fabs(quarterX - antiquarterX) < 1e-5)
     377                 :                 {
     378               3 :                     double major_radius = fabs(firstX - center1X);
     379               3 :                     double minor_radius = fabs(quarterY - center1Y);
     380               3 :                     is_ellipse = TRUE;
     381            1083 :                     for(i=0;i<360;i++)
     382                 :                     {
     383            1080 :                         if (!(fabs(center1X + major_radius * cos(i * (M_PI / 180)) - ring->getX(i)) < 1e-5 &&
     384                 :                               fabs(center1Y + minor_radius * sin(i * (M_PI / 180)) - ring->getY(i)) < 1e-5))
     385                 :                         {
     386               0 :                             is_ellipse = FALSE;
     387               0 :                             break;
     388                 :                         }
     389                 :                     }
     390               3 :                     if ( is_ellipse == TRUE )
     391                 :                     {
     392               3 :                         WriteFeatureAttributes(fp, poFeature);
     393               3 :                         VSIFPrintfL( fp, "2");
     394               3 :                         VSIFPrintfL( fp, "%s", partialEol);
     395               3 :                         WriteCoord(fp, center1X, center1Y);
     396               3 :                         VSIFPrintfL( fp, "%s", partialEol);
     397               3 :                         WriteCoord(fp, major_radius, minor_radius);
     398               3 :                         VSIFPrintfL( fp, "%s", eol);
     399                 :                     }
     400                 :                 }
     401                 :             }
     402                 : 
     403               6 :             if ( is_ellipse == FALSE)
     404                 :             {
     405               3 :                 int nInteriorRings = polygon->getNumInteriorRings();
     406               6 :                 for(i=0;i<nInteriorRings;i++)
     407                 :                 {
     408               3 :                     nBNAPoints += polygon->getInteriorRing(i)->getNumPoints() + 1;
     409                 :                 }
     410               3 :                 if (nBNAPoints <= 3)
     411                 :                 {
     412               0 :                     CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" );
     413               0 :                     return OGRERR_FAILURE;
     414                 :                 }
     415               3 :                 WriteFeatureAttributes(fp, poFeature);
     416               3 :                 VSIFPrintfL( fp, "%d", nBNAPoints);
     417               3 :                 n = ring->getNumPoints();
     418               3 :                 int nbPair = 0;
     419              18 :                 for(i=0;i<n;i++)
     420                 :                 {
     421              15 :                     VSIFPrintfL( fp, "%s", ((nbPair % nbPairPerLine) == 0) ? partialEol : " ");
     422              15 :                     WriteCoord(fp, ring->getX(i), ring->getY(i));
     423              15 :                     nbPair++;
     424                 :                 }
     425               6 :                 for(i=0;i<nInteriorRings;i++)
     426                 :                 {
     427               3 :                     ring = polygon->getInteriorRing(i);
     428               3 :                     n = ring->getNumPoints();
     429              18 :                     for(j=0;j<n;j++)
     430                 :                     {
     431              15 :                         VSIFPrintfL( fp, "%s", ((nbPair % nbPairPerLine) == 0) ? partialEol : " ");
     432              15 :                         WriteCoord(fp, ring->getX(j), ring->getY(j));
     433              15 :                         nbPair++;
     434                 :                     }
     435               3 :                     VSIFPrintfL( fp, "%s", ((nbPair % nbPairPerLine) == 0) ? partialEol : " ");
     436               3 :                     WriteCoord(fp, firstX, firstY);
     437               3 :                     nbPair++;
     438                 :                 }
     439               3 :                 VSIFPrintfL( fp, "%s", eol);
     440                 :             }
     441               6 :             break;
     442                 :         }
     443                 : 
     444                 :         case wkbMultiPolygon:
     445                 :         case wkbMultiPolygon25D:
     446                 :         {
     447               9 :             OGRMultiPolygon* multipolygon = (OGRMultiPolygon*)poGeom;
     448               9 :             int N = multipolygon->getNumGeometries();
     449               9 :             int nBNAPoints = 0;
     450               9 :             double firstX = 0, firstY = 0; 
     451              30 :             for(i=0;i<N;i++)
     452                 :             {
     453              21 :                 OGRPolygon* polygon = (OGRPolygon*)multipolygon->getGeometryRef(i);
     454              21 :                 OGRLinearRing* ring = polygon->getExteriorRing();
     455              21 :                 if (ring == NULL)
     456               0 :                     continue;
     457                 : 
     458              21 :                 if (nBNAPoints)
     459              12 :                     nBNAPoints ++;
     460                 :                 else
     461                 :                 {
     462               9 :                     firstX = ring->getX(0);
     463               9 :                     firstY = ring->getY(0);
     464                 :                 }
     465              21 :                 nBNAPoints += ring->getNumPoints();
     466              21 :                 int nInteriorRings = polygon->getNumInteriorRings();
     467              36 :                 for(j=0;j<nInteriorRings;j++)
     468                 :                 {
     469              15 :                     nBNAPoints += polygon->getInteriorRing(j)->getNumPoints() + 1;
     470                 :                 }
     471                 :             }
     472               9 :             if (nBNAPoints <= 3)
     473                 :             {
     474               0 :                 CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" );
     475               0 :                 return OGRERR_FAILURE;
     476                 :             }
     477               9 :             WriteFeatureAttributes(fp, poFeature);
     478               9 :             VSIFPrintfL( fp, "%d", nBNAPoints);
     479               9 :             int nbPair = 0;
     480              30 :             for(i=0;i<N;i++)
     481                 :             {
     482              21 :                 OGRPolygon* polygon = (OGRPolygon*)multipolygon->getGeometryRef(i);
     483              21 :                 OGRLinearRing* ring = polygon->getExteriorRing();
     484              21 :                 if (ring == NULL)
     485               0 :                     continue;
     486                 : 
     487              21 :                 n = ring->getNumPoints();
     488              21 :                 int nInteriorRings = polygon->getNumInteriorRings();
     489             135 :                 for(j=0;j<n;j++)
     490                 :                 {
     491             114 :                     VSIFPrintfL( fp, "%s", ((nbPair % nbPairPerLine) == 0) ? partialEol : " ");
     492             114 :                     WriteCoord(fp, ring->getX(j), ring->getY(j));
     493             114 :                     nbPair++;
     494                 :                 }
     495              21 :                 if (i != 0)
     496                 :                 {
     497              12 :                     VSIFPrintfL( fp, "%s", ((nbPair % nbPairPerLine) == 0) ? partialEol : " ");
     498              12 :                     WriteCoord(fp, firstX, firstY);
     499              12 :                     nbPair++;
     500                 :                 }
     501              36 :                 for(j=0;j<nInteriorRings;j++)
     502                 :                 {
     503              15 :                     ring = polygon->getInteriorRing(j);
     504              15 :                     n = ring->getNumPoints();
     505             102 :                     for(k=0;k<n;k++)
     506                 :                     {
     507              87 :                         VSIFPrintfL( fp, "%s", ((nbPair % nbPairPerLine) == 0) ? partialEol : " ");
     508              87 :                         WriteCoord(fp, ring->getX(k), ring->getY(k));
     509              87 :                         nbPair++;
     510                 :                     }
     511              15 :                     VSIFPrintfL( fp, "%s", ((nbPair % nbPairPerLine) == 0) ? partialEol : " ");
     512              15 :                     WriteCoord(fp, firstX, firstY);
     513              15 :                     nbPair++;
     514                 :                 }
     515                 :             }
     516               9 :             VSIFPrintfL( fp, "%s", eol);
     517               9 :             break;
     518                 :         }
     519                 : 
     520                 :         case wkbLineString:
     521                 :         case wkbLineString25D:
     522                 :         {
     523               3 :             OGRLineString* line = (OGRLineString*)poGeom;
     524               3 :             int n = line->getNumPoints();
     525                 :             int i;
     526               3 :             if (n < 2)
     527                 :             {
     528               0 :                 CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" );
     529               0 :                 return OGRERR_FAILURE;
     530                 :             }
     531               3 :             WriteFeatureAttributes(fp, poFeature);
     532               3 :             VSIFPrintfL( fp, "-%d", n);
     533               3 :             int nbPair = 0;
     534              12 :             for(i=0;i<n;i++)
     535                 :             {
     536               9 :                 VSIFPrintfL( fp, "%s", partialEol);
     537               9 :                 WriteCoord(fp, line->getX(i), line->getY(i));
     538               9 :                 nbPair++;
     539                 :             }
     540               3 :             VSIFPrintfL( fp, "%s", eol);
     541               3 :             break;
     542                 :         }
     543                 :             
     544                 :         default:
     545                 :         {
     546                 :             CPLError( CE_Failure, CPLE_AppDefined,
     547                 :                       "Unsupported geometry type : %s.",
     548               0 :                       poGeom->getGeometryName() );
     549                 : 
     550               0 :             return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
     551                 :         }
     552                 :     }
     553                 :     
     554              24 :     return OGRERR_NONE;
     555                 : }
     556                 : 
     557                 : 
     558                 : 
     559                 : /************************************************************************/
     560                 : /*                            CreateField()                             */
     561                 : /************************************************************************/
     562                 : 
     563              30 : OGRErr OGRBNALayer::CreateField( OGRFieldDefn *poField, int bApproxOK )
     564                 : 
     565                 : {
     566              30 :     if( !bWriter || nFeatures != 0)
     567               0 :         return OGRERR_FAILURE;
     568                 : 
     569              30 :     poFeatureDefn->AddFieldDefn( poField );
     570                 : 
     571              30 :     return OGRERR_NONE;
     572                 : }
     573                 : 
     574                 : 
     575                 : /************************************************************************/
     576                 : /*                           BuildFeatureFromBNARecord()                */
     577                 : /************************************************************************/
     578             139 : OGRFeature *    OGRBNALayer::BuildFeatureFromBNARecord (BNARecord* record, long fid)
     579                 : {
     580                 :     OGRFeature  *poFeature;
     581                 :     int i;
     582                 : 
     583             139 :     poFeature = new OGRFeature( poFeatureDefn );
     584             419 :     for(i=0;i<nIDs;i++)
     585                 :     {
     586             280 :         poFeature->SetField( i, record->ids[i] ? record->ids[i] : "");
     587                 :     }
     588             139 :     poFeature->SetFID( fid );
     589             139 :     if (bnaFeatureType == BNA_POINT)
     590                 :     {
     591              36 :         poFeature->SetGeometryDirectly( new OGRPoint( record->tabCoords[0][0], record->tabCoords[0][1] ) );
     592                 :     }
     593             103 :     else if (bnaFeatureType == BNA_POLYLINE)
     594                 :     {
     595              17 :         OGRLineString* lineString = new OGRLineString ();
     596              17 :         lineString->setCoordinateDimension(2);
     597              17 :         lineString->setNumPoints(record->nCoords);
     598              68 :         for(i=0;i<record->nCoords;i++)
     599                 :         {
     600              51 :             lineString->setPoint(i, record->tabCoords[i][0], record->tabCoords[i][1] );
     601                 :         }
     602              17 :         poFeature->SetGeometryDirectly(lineString);
     603                 :     }
     604              86 :     else if (bnaFeatureType == BNA_POLYGON)
     605                 :     {
     606              69 :         double firstX = record->tabCoords[0][0];
     607              69 :         double firstY = record->tabCoords[0][1];
     608              69 :         int isFirstPolygon = 1;
     609              69 :         double secondaryFirstX = 0, secondaryFirstY = 0;
     610                 :   
     611              69 :         OGRLinearRing* ring = new OGRLinearRing ();
     612              69 :         ring->setCoordinateDimension(2);
     613              69 :         ring->addPoint(record->tabCoords[0][0], record->tabCoords[0][1] );
     614                 :   
     615                 :         /* record->nCoords is really a safe upper bound */
     616              69 :         int nbPolygons = 0;
     617                 :         OGRPolygon** tabPolygons =
     618              69 :             (OGRPolygon**)CPLMalloc(record->nCoords * sizeof(OGRPolygon*));
     619                 : 
     620            1075 :         for(i=1;i<record->nCoords;i++)
     621                 :         {
     622            1075 :             ring->addPoint(record->tabCoords[i][0], record->tabCoords[i][1] );
     623            1523 :             if (isFirstPolygon == 1 &&
     624             293 :                 record->tabCoords[i][0] == firstX &&
     625             104 :                 record->tabCoords[i][1] == firstY)
     626                 :             {
     627              69 :                 OGRPolygon* polygon = new OGRPolygon ();
     628              69 :                 polygon->addRingDirectly(ring);
     629              69 :                 tabPolygons[nbPolygons] = polygon;
     630              69 :                 nbPolygons++;
     631                 :     
     632              69 :                 if (i == record->nCoords - 1)
     633                 :                 {
     634              18 :                     break;
     635                 :                 }
     636                 :     
     637              51 :                 isFirstPolygon = 0;
     638                 :     
     639              51 :                 i ++;
     640              51 :                 secondaryFirstX = record->tabCoords[i][0];
     641              51 :                 secondaryFirstY = record->tabCoords[i][1];
     642              51 :                 ring = new OGRLinearRing ();
     643              51 :                 ring->setCoordinateDimension(2);
     644              51 :                 ring->addPoint(record->tabCoords[i][0], record->tabCoords[i][1] );
     645                 :             }
     646            1975 :             else if (isFirstPolygon == 0 &&
     647             782 :                     record->tabCoords[i][0] == secondaryFirstX &&
     648             187 :                     record->tabCoords[i][1] == secondaryFirstY)
     649                 :             {
     650                 : 
     651             170 :                 OGRPolygon* polygon = new OGRPolygon ();
     652             170 :                 polygon->addRingDirectly(ring);
     653             170 :                 tabPolygons[nbPolygons] = polygon;
     654             170 :                 nbPolygons++;
     655                 : 
     656             170 :                 if (i < record->nCoords - 1)
     657                 :                 {
     658                 :                     /* After the closing of a subpolygon, the first coordinates of the first polygon */
     659                 :                     /* should be recalled... in theory */
     660             170 :                     if (record->tabCoords[i+1][0] == firstX &&  record->tabCoords[i+1][1] == firstY)
     661                 :                     {
     662             170 :                         if (i + 1 == record->nCoords - 1)
     663              51 :                             break;
     664             119 :                         i ++;
     665                 :                     }
     666                 :                     else
     667                 :                     {
     668                 : #if 0
     669                 :                         CPLError(CE_Warning, CPLE_AppDefined, 
     670                 :                                  "Geometry of polygon of fid %d starting at line %d is not strictly conformant. "
     671                 :                                  "Trying to go on...\n",
     672                 :                                  fid,
     673                 :                                  offsetAndLineFeaturesTable[fid].line + 1);
     674                 : #endif
     675                 :                     }
     676                 : 
     677             119 :                     i ++;
     678             119 :                     secondaryFirstX = record->tabCoords[i][0];
     679             119 :                     secondaryFirstY = record->tabCoords[i][1];
     680             119 :                     ring = new OGRLinearRing ();
     681             119 :                     ring->setCoordinateDimension(2);
     682             119 :                     ring->addPoint(record->tabCoords[i][0], record->tabCoords[i][1] );
     683                 :                 }
     684                 :                 else
     685                 :                 {
     686                 : #if 0
     687                 :                     CPLError(CE_Warning, CPLE_AppDefined, 
     688                 :                         "Geometry of polygon of fid %d starting at line %d is not strictly conformant. Trying to go on...\n",
     689                 :                         fid,
     690                 :                         offsetAndLineFeaturesTable[fid].line + 1);
     691                 : #endif
     692                 :                 }
     693                 :             }
     694                 :         }
     695              69 :         if (i == record->nCoords)
     696                 :         {
     697                 :             /* Let's be a bit tolerant abount non closing polygons */
     698               0 :             if (isFirstPolygon)
     699                 :             {
     700               0 :                 ring->addPoint(record->tabCoords[0][0], record->tabCoords[0][1] );
     701                 : 
     702               0 :                 OGRPolygon* polygon = new OGRPolygon ();
     703               0 :                 polygon->addRingDirectly(ring);
     704               0 :                 tabPolygons[nbPolygons] = polygon;
     705               0 :                 nbPolygons++;
     706                 :             }
     707                 :         }
     708                 :         
     709              69 :         if (nbPolygons == 1)
     710                 :         {
     711                 :             /* Special optimization here : we directly put the polygon into the multipolygon. */
     712                 :             /* This should save quite a few useless copies */
     713              18 :             OGRMultiPolygon* multipolygon = new OGRMultiPolygon();
     714              18 :             multipolygon->addGeometryDirectly(tabPolygons[0]);
     715              18 :             poFeature->SetGeometryDirectly(multipolygon);
     716                 :         }
     717                 :         else
     718                 :         {
     719                 :             int isValidGeometry;
     720                 :             poFeature->SetGeometryDirectly(
     721              51 :                 OGRGeometryFactory::organizePolygons((OGRGeometry**)tabPolygons, nbPolygons, &isValidGeometry, NULL));
     722                 :             
     723              51 :             if (!isValidGeometry)
     724                 :             {
     725                 :                 CPLError(CE_Warning, CPLE_AppDefined, 
     726                 :                         "Geometry of polygon of fid %ld starting at line %d cannot be translated to Simple Geometry. "
     727                 :                         "All polygons will be contained in a multipolygon.\n",
     728                 :                         fid,
     729               0 :                         offsetAndLineFeaturesTable[fid].line + 1);
     730                 :             }
     731                 :         }
     732                 : 
     733              69 :         CPLFree(tabPolygons);
     734                 :     }
     735                 :     else
     736                 :     {
     737                 :         /* Circle or ellipses are not part of the OGR Simple Geometry, so we discretize them
     738                 :            into polygons by 1 degree step */
     739              17 :         OGRPolygon* polygon = new OGRPolygon ();
     740              34 :         OGRLinearRing* ring = new OGRLinearRing ();
     741              17 :         ring->setCoordinateDimension(2);
     742              17 :         double center_x = record->tabCoords[0][0];
     743              17 :         double center_y = record->tabCoords[0][1];
     744              17 :         double major_radius = record->tabCoords[1][0];
     745              17 :         double minor_radius = record->tabCoords[1][1];
     746              17 :         if (minor_radius == 0)
     747              11 :             minor_radius = major_radius;
     748            6137 :         for(i=0;i<360;i++)
     749                 :         {
     750                 :             ring->addPoint(center_x + major_radius * cos(i * (M_PI / 180)),
     751            6120 :                            center_y + minor_radius * sin(i * (M_PI / 180)) );
     752                 :         }
     753              17 :         ring->addPoint(center_x + major_radius, center_y);
     754              17 :         polygon->addRingDirectly  (  ring );
     755              17 :         poFeature->SetGeometryDirectly(polygon);
     756                 : 
     757              17 :         poFeature->SetField( nIDs, major_radius);
     758              17 :         poFeature->SetField( nIDs+1, minor_radius);
     759                 :     }
     760                 :     
     761             139 :     return poFeature;
     762                 : }
     763                 : 
     764                 : 
     765                 : /************************************************************************/
     766                 : /*                           FastParseUntil()                           */
     767                 : /************************************************************************/
     768               2 : void OGRBNALayer::FastParseUntil ( int interestFID)
     769                 : {
     770               2 :     if (partialIndexTable)
     771                 :     {
     772               0 :         ResetReading();
     773                 : 
     774                 :         BNARecord* record;
     775                 : 
     776               0 :         if (nFeatures > 0)
     777                 :         {
     778               0 :             VSIFSeekL( fpBNA, offsetAndLineFeaturesTable[nFeatures-1].offset, SEEK_SET );
     779               0 :             curLine = offsetAndLineFeaturesTable[nFeatures-1].line;
     780                 : 
     781                 :             /* Just skip the last read one */
     782               0 :             int ok = FALSE;
     783               0 :             record =  BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, BNA_READ_NONE);
     784               0 :             BNA_FreeRecord(record);
     785                 :         }
     786                 : 
     787               0 :         while(1)
     788                 :         {
     789               0 :             int ok = FALSE;
     790               0 :             int offset = (int) VSIFTellL(fpBNA);
     791               0 :             int line = curLine;
     792               0 :             record =  BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, BNA_READ_NONE);
     793               0 :             if (ok == FALSE)
     794                 :             {
     795               0 :                 failed = TRUE;
     796               0 :                 return;
     797                 :             }
     798               0 :             if (record == NULL)
     799                 :             {
     800                 :                 /* end of file */
     801               0 :                 eof = TRUE;
     802                 : 
     803                 :                 /* and we have finally build the whole index table */
     804               0 :                 partialIndexTable = FALSE;
     805               0 :                 return;
     806                 :             }
     807                 : 
     808               0 :             if (record->featureType == bnaFeatureType)
     809                 :             {
     810               0 :                 nFeatures++;
     811                 :                 offsetAndLineFeaturesTable =
     812               0 :                     (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine));
     813               0 :                 offsetAndLineFeaturesTable[nFeatures-1].offset = offset;
     814               0 :                 offsetAndLineFeaturesTable[nFeatures-1].line = line;
     815                 : 
     816               0 :                 BNA_FreeRecord(record);
     817                 : 
     818               0 :                 if (nFeatures - 1 == interestFID)
     819               0 :                   return;
     820                 :             }
     821                 :             else
     822                 :             {
     823               0 :                 BNA_FreeRecord(record);
     824                 :             }
     825                 :         }
     826                 :     }
     827                 : }
     828                 : 
     829                 : /************************************************************************/
     830                 : /*                           GetFeature()                               */
     831                 : /************************************************************************/
     832                 : 
     833               2 : OGRFeature *  OGRBNALayer::GetFeature( long nFID )
     834                 : {
     835                 :     OGRFeature  *poFeature;
     836                 :     BNARecord* record;
     837                 :     int ok;
     838                 :     
     839               2 :     if (nFID < 0)
     840               0 :         return NULL;
     841                 : 
     842               2 :     FastParseUntil(nFID);
     843                 : 
     844               2 :     if (nFID >= nFeatures)
     845               0 :         return NULL;
     846                 : 
     847               2 :     VSIFSeekL( fpBNA, offsetAndLineFeaturesTable[nFID].offset, SEEK_SET );
     848               2 :     curLine = offsetAndLineFeaturesTable[nFID].line;
     849               2 :     record =  BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType);
     850                 : 
     851               2 :     poFeature = BuildFeatureFromBNARecord(record, nFID);
     852                 : 
     853               2 :     BNA_FreeRecord(record);
     854                 : 
     855               2 :     return poFeature;
     856                 : }
     857                 : 
     858                 : /************************************************************************/
     859                 : /*                           TestCapability()                           */
     860                 : /************************************************************************/
     861                 : 
     862               0 : int OGRBNALayer::TestCapability( const char * pszCap )
     863                 : 
     864                 : {
     865               0 :     if( EQUAL(pszCap,OLCSequentialWrite) )
     866               0 :         return bWriter;
     867               0 :     else if( EQUAL(pszCap,OLCCreateField) )
     868               0 :         return bWriter && nFeatures == 0;
     869                 :     else
     870               0 :         return FALSE;
     871                 : }
     872                 : 

Generated by: LCOV version 1.7