Changeset 11894

Show
Ignore:
Timestamp:
08/17/07 15:43:44 (1 year ago)
Author:
rouault
Message:

* (bug 1735 : BNA driver)
* add two methods to OGREnvelope
* make the BNA parser a bit more tolerant again
* complete change in the handling of complex polygons
* add write support
* add HTML documentation

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/gdal/ogr/ogr_core.h

    r11873 r11894  
    8686            MinY = MaxY = dfY; 
    8787        } 
     88    } 
     89 
     90    int Intersects(OGREnvelope& other) 
     91    { 
     92        return MinX <= other.MaxX && MaxX >= other.MinX &&  
     93               MinY <= other.MaxY && MaxY >= other.MinY; 
     94    } 
     95 
     96    int Contains(OGREnvelope& other) 
     97    { 
     98        return MinX <= other.MinX && MinY <= other.MinY && 
     99               MaxX >= other.MaxX && MaxY >= other.MaxY; 
    88100    } 
    89101}; 
  • trunk/gdal/ogr/ogrsf_frmts/bna/GNUmakefile

    r11853 r11894  
    44 
    55OBJ     =       ogrbnadriver.o ogrbnadatasource.o ogrbnalayer.o ogrbnaparser.o 
     6 
     7ifeq ($(HAVE_GEOS),yes) 
     8CPPFLAGS        :=      -DHAVE_GEOS=1 $(GEOS_CFLAGS) $(CPPFLAGS) 
     9endif 
    610 
    711CPPFLAGS        :=      -I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS) 
  • trunk/gdal/ogr/ogrsf_frmts/bna/makefile.vc

    r11857 r11894  
    33                ogrbnaparser.obj 
    44 
    5 EXTRAFLAGS =    -I.. -I..\.. 
     5EXTRAFLAGS =    -I.. -I..\.. $(GEOS_CFLAGS) 
    66 
    77GDAL_ROOT       =       ..\..\.. 
  • trunk/gdal/ogr/ogrsf_frmts/bna/ogr_bna.h

    r11853 r11894  
    4949class OGRBNALayer : public OGRLayer 
    5050{ 
    51     OGRFeatureDefn     *poFeatureDefn; 
     51    OGRFeatureDefn*    poFeatureDefn; 
     52     
     53    OGRBNADataSource*  poDS; 
     54    int                bWriter; 
    5255 
     56    int                nIDs; 
    5357    int                eof; 
    5458    int                failed; 
    5559    int                curLine; 
    5660    int                nNextFID; 
    57     FILE               *fpBNA; 
     61    FILE*              fpBNA; 
    5862    int                nFeatures; 
    5963    int                partialIndexTable; 
     
    6165 
    6266    BNAFeatureType     bnaFeatureType; 
    63      
     67 
    6468    OGRFeature *       BuildFeatureFromBNARecord (BNARecord* record, long fid); 
    6569    void               FastParseUntil ( int interestFID); 
     70    void               WriteFeatureAttributes(FILE* fp, OGRFeature *poFeature); 
     71     
    6672  public: 
    67     OGRBNALayer( const char *pszFilename, 
    68                  const char* layerName, 
    69                  BNAFeatureType bnaFeatureType, 
    70                  OGRwkbGeometryType eLayerGeomType ); 
    71     ~OGRBNALayer(); 
     73                        OGRBNALayer(const char *pszFilename, 
     74                                    const char* layerName, 
     75                                    BNAFeatureType bnaFeatureType, 
     76                                    OGRwkbGeometryType eLayerGeomType, 
     77                                    int bWriter, 
     78                                    OGRBNADataSource* poDS, 
     79                                    int nIDs = NB_MAX_BNA_IDS); 
     80                        ~OGRBNALayer(); 
     81 
     82    void                SetFeatureIndexTable(int nFeatures, 
     83                                             OffsetAndLine* offsetAndLineFeaturesTable, 
     84                                             int partialIndexTable); 
    7285 
    7386    void                ResetReading(); 
    7487    OGRFeature *        GetNextFeature(); 
     88     
     89    OGRErr              CreateFeature( OGRFeature *poFeature ); 
     90    OGRErr              CreateField( OGRFieldDefn *poField, int bApproxOK ); 
    7591 
    7692    OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; } 
    77      
    78     int                 GetFeatureCount( int ); 
    7993     
    8094    OGRFeature *        GetFeature( long nFID ); 
     
    90104class OGRBNADataSource : public OGRDataSource 
    91105{ 
    92     char                *pszName; 
     106    char*               pszName; 
    93107 
    94     OGRBNALayer       **papoLayers; 
     108    OGRBNALayer**       papoLayers; 
    95109    int                 nLayers; 
    96110 
    97111    int                 bUpdate; 
     112     
     113    /*  Export related */ 
     114    FILE                *fpOutput; 
     115    int                 bUseCRLF; 
     116    int                 bMultiLine; 
     117    int                 nbOutID; 
     118    int                 bEllipsesAsEllipses; 
     119    int                 nbPairPerLine; 
     120    int                 coordinatePrecision; 
     121    char*               pszCoordinateSeparator; 
    98122     
    99123  public: 
     
    101125                        ~OGRBNADataSource(); 
    102126 
     127    FILE                *GetOutputFP() { return fpOutput; } 
     128    int                 GetUseCRLF() { return bUseCRLF; } 
     129    int                 GetMultiLine() { return bMultiLine; } 
     130    int                 GetNbOutId() { return nbOutID; } 
     131    int                 GetEllipsesAsEllipses() { return bEllipsesAsEllipses; } 
     132    int                 GetNbPairPerLine() { return nbPairPerLine; } 
     133    int                 GetCoordinatePrecision() { return coordinatePrecision; } 
     134    const char*         GetCoordinateSeparator() { return pszCoordinateSeparator; } 
     135 
    103136    int                 Open( const char * pszFilename, 
    104137                              int bUpdate ); 
    105138     
    106     const char          *GetName() { return pszName; } 
     139    int                 Create( const char *pszFilename,  
     140                              char **papszOptions ); 
     141     
     142    const char*         GetName() { return pszName; } 
    107143 
    108144    int                 GetLayerCount() { return nLayers; } 
    109     OGRLayer            *GetLayer( int ); 
     145    OGRLayer*           GetLayer( int ); 
     146     
     147    OGRLayer *          CreateLayer( const char * pszLayerName, 
     148                                    OGRSpatialReference *poSRS, 
     149                                    OGRwkbGeometryType eType, 
     150                                    char ** papszOptions ); 
    110151 
    111152    int                 TestCapability( const char * ); 
     
    121162                ~OGRBNADriver(); 
    122163 
    123     const char *GetName(); 
    124     OGRDataSource *Open( const char *, int ); 
    125     int         TestCapability( const char * ); 
     164    const char*         GetName(); 
     165    OGRDataSource*      Open( const char *, int ); 
     166    OGRDataSource*      CreateDataSource( const char * pszName, char **papszOptions ); 
     167    int                 DeleteDataSource( const char *pszFilename ); 
     168    int                 TestCapability( const char * ); 
    126169     
    127170}; 
  • trunk/gdal/ogr/ogrsf_frmts/bna/ogrbnadatasource.cpp

    r11853 r11894  
    4343    papoLayers = NULL; 
    4444    nLayers = 0; 
     45     
     46    fpOutput = NULL; 
    4547 
    4648    pszName = NULL; 
     49     
     50    pszCoordinateSeparator = NULL; 
    4751 
    4852    bUpdate = FALSE; 
     
    5660 
    5761{ 
     62    if ( fpOutput != NULL ) 
     63    { 
     64        VSIFClose( fpOutput); 
     65    } 
     66 
    5867    for( int i = 0; i < nLayers; i++ ) 
    5968        delete papoLayers[i]; 
    6069    CPLFree( papoLayers ); 
     70     
     71    CPLFree( pszCoordinateSeparator ); 
    6172 
    6273    CPLFree( pszName ); 
     
    7182{ 
    7283    if( EQUAL(pszCap,ODsCCreateLayer) ) 
    73         return FALSE; 
     84        return TRUE; 
    7485    else if( EQUAL(pszCap,ODsCDeleteLayer) ) 
    7586        return FALSE; 
     
    89100    else 
    90101        return papoLayers[iLayer]; 
     102} 
     103 
     104/************************************************************************/ 
     105/*                            CreateLayer()                             */ 
     106/************************************************************************/ 
     107 
     108OGRLayer * OGRBNADataSource::CreateLayer( const char * pszLayerName, 
     109                                          OGRSpatialReference *poSRS, 
     110                                          OGRwkbGeometryType eType, 
     111                                          char ** papszOptions ) 
     112 
     113{ 
     114    BNAFeatureType bnaFeatureType; 
     115     
     116    switch(eType) 
     117    { 
     118        case wkbPolygon: 
     119        case wkbPolygon25D: 
     120        case wkbMultiPolygon: 
     121        case wkbMultiPolygon25D: 
     122            bnaFeatureType = BNA_POLYGON; 
     123            break; 
     124         
     125        case wkbPoint: 
     126        case wkbPoint25D: 
     127            bnaFeatureType = BNA_POINT; 
     128            break; 
     129             
     130        case wkbLineString: 
     131        case wkbLineString25D: 
     132            bnaFeatureType = BNA_POLYLINE; 
     133            break; 
     134             
     135        default: 
     136            CPLError( CE_Failure, CPLE_NotSupported, 
     137                    "Geometry type of `%s' not supported in BNAs.\n", 
     138                    OGRGeometryTypeToName(eType) ); 
     139            return NULL; 
     140    } 
     141     
     142    nLayers++; 
     143    papoLayers = (OGRBNALayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRBNALayer*)); 
     144    papoLayers[nLayers-1] = new OGRBNALayer( pszName, pszLayerName, bnaFeatureType, eType, TRUE, this ); 
     145     
     146    return papoLayers[nLayers-1]; 
    91147} 
    92148 
     
    116172    if( !EQUAL( CPLGetExtension(pszFilename), "bna" ) ) 
    117173        return FALSE; 
    118  
    119     FILE* f = VSIFOpen(pszFilename, "rb"); 
    120     if (f
     174     
     175    FILE* fp = VSIFOpen(pszFilename, "r"); 
     176    if (fp
    121177    { 
    122178        BNARecord* record; 
    123179        int curLine = 0; 
    124         record = BNA_GetNextRecord(f, &ok, &curLine, 0, BNA_READ_NONE); 
     180        const char* layerRadixName[] = { "points", "polygons", "lines", "ellipses"}; 
     181        OGRwkbGeometryType wkbGeomTypes[] = { wkbPoint, wkbMultiPolygon, wkbLineString, wkbPolygon }; 
     182        int i; 
     183#if defined(BNA_FAST_DS_OPEN) 
     184        record = BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); 
    125185        BNA_FreeRecord(record); 
    126186 
     
    130190 
    131191            papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*)); 
    132             papoLayers[0] = new OGRBNALayer( pszFilename, "points", BNA_POINT, wkbPoint ); 
    133             papoLayers[1] = new OGRBNALayer( pszFilename, "lines", BNA_POLYLINE, wkbLineString ); 
    134             papoLayers[2] = new OGRBNALayer( pszFilename, "polygons", BNA_POLYGON, wkbMultiPolygon ); 
    135             papoLayers[3] = new OGRBNALayer( pszFilename, "ellipses", BNA_ELLIPSE, wkbPolygon ); 
    136         } 
    137  
    138         VSIFClose(f); 
     192            for(i=0;i<4;i++) 
     193                papoLayers[i] = new OGRBNALayer( pszFilename, 
     194                                                 layerRadixName[i], 
     195                                                 (BNAFeatureType)i, wkbGeomTypes[i], FALSE, this ); 
     196        } 
     197#else 
     198        int nFeatures[4] = { 0, 0, 0, 0 }; 
     199        OffsetAndLine* offsetAndLineFeaturesTable[4] = { NULL, NULL, NULL, NULL }; 
     200        int nIDs[4] = {0, 0, 0, 0}; 
     201        int partialIndexTable = TRUE; 
     202 
     203        while(1) 
     204        { 
     205            int offset = VSIFTell(fp); 
     206            int line = curLine; 
     207            record =  BNA_GetNextRecord(fp, &ok, &curLine, FALSE, BNA_READ_NONE); 
     208            if (ok == FALSE) 
     209            { 
     210                BNA_FreeRecord(record); 
     211                if (line != 0) 
     212                    ok = TRUE; 
     213                break; 
     214            } 
     215            if (record == NULL) 
     216            { 
     217                /* end of file */ 
     218                ok = TRUE; 
     219 
     220                /* and we have finally build the whole index table */ 
     221                partialIndexTable = FALSE; 
     222                break; 
     223            } 
     224 
     225            if (record->nIDs > nIDs[record->featureType]) 
     226                nIDs[record->featureType] = record->nIDs; 
     227 
     228            nFeatures[record->featureType]++; 
     229            offsetAndLineFeaturesTable[record->featureType] = 
     230                (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable[record->featureType], 
     231                                           nFeatures[record->featureType] * sizeof(OffsetAndLine)); 
     232            offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].offset = offset; 
     233            offsetAndLineFeaturesTable[record->featureType][nFeatures[record->featureType]-1].line = line; 
     234 
     235            BNA_FreeRecord(record); 
     236        } 
     237 
     238        nLayers = (nFeatures[0] != 0) + (nFeatures[1] != 0) + (nFeatures[2] != 0) + (nFeatures[3] != 0); 
     239        papoLayers = (OGRBNALayer **) CPLMalloc(nLayers * sizeof(OGRBNALayer*)); 
     240        int iLayer = 0; 
     241        for(i=0;i<4;i++) 
     242        { 
     243            if (nFeatures[i]) 
     244            { 
     245                papoLayers[iLayer] = new OGRBNALayer( pszFilename, 
     246                                                      layerRadixName[i], 
     247                                                      (BNAFeatureType)i, 
     248                                                      wkbGeomTypes[i], 
     249                                                      FALSE, 
     250                                                      this, 
     251                                                      nIDs[i]); 
     252                papoLayers[iLayer]->SetFeatureIndexTable(nFeatures[i], 
     253                                                        offsetAndLineFeaturesTable[i], 
     254                                                        partialIndexTable); 
     255                iLayer++; 
     256            } 
     257        } 
     258#endif 
     259        VSIFClose(fp); 
    139260    } 
    140261 
     
    142263} 
    143264 
     265 
     266/************************************************************************/ 
     267/*                               Create()                               */ 
     268/************************************************************************/ 
     269 
     270int OGRBNADataSource::Create( const char *pszFilename,  
     271                              char **papszOptions ) 
     272{ 
     273    if( fpOutput != NULL) 
     274    { 
     275        CPLAssert( FALSE ); 
     276        return FALSE; 
     277    } 
     278 
     279/* -------------------------------------------------------------------- */ 
     280/*     Do not override exiting file.                                    */ 
     281/* -------------------------------------------------------------------- */ 
     282    VSIStatBufL sStatBuf; 
     283 
     284    if( VSIStatL( pszFilename, &sStatBuf ) == 0 ) 
     285        return FALSE; 
     286     
     287/* -------------------------------------------------------------------- */ 
     288/*      Create the output file.                                         */ 
     289/* -------------------------------------------------------------------- */ 
     290    pszName = CPLStrdup( pszFilename ); 
     291 
     292    if( EQUAL(pszFilename,"stdout") ) 
     293        fpOutput = stdout; 
     294    else 
     295        fpOutput = VSIFOpen( pszFilename, "w" ); 
     296    if( fpOutput == NULL ) 
     297    { 
     298        CPLError( CE_Failure, CPLE_OpenFailed,  
     299                  "Failed to create BNA file %s.",  
     300                  pszFilename ); 
     301        return FALSE; 
     302    } 
     303     
     304    /* EOL token */ 
     305    const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT"); 
     306 
     307    if( pszCRLFFormat == NULL ) 
     308    { 
     309#ifdef WIN32 
     310        bUseCRLF = TRUE; 
     311#else 
     312        bUseCRLF = FALSE; 
     313#endif 
     314    } 
     315    else if( EQUAL(pszCRLFFormat,"CRLF") ) 
     316        bUseCRLF = TRUE; 
     317    else if( EQUAL(pszCRLFFormat,"LF") ) 
     318        bUseCRLF = FALSE; 
     319    else 
     320    { 
     321        CPLError( CE_Warning, CPLE_AppDefined,  
     322                  "LINEFORMAT=%s not understood, use one of CRLF or LF.", 
     323                  pszCRLFFormat ); 
     324#ifdef WIN32 
     325        bUseCRLF = TRUE; 
     326#else 
     327        bUseCRLF = FALSE; 
     328#endif 
     329    } 
     330 
     331    /* Multi line or single line format ? */ 
     332    bMultiLine = CSLFetchBoolean( papszOptions, "MULTILINE", TRUE); 
     333     
     334    /* Number of identifiers per record */ 
     335    const char* pszNbOutID = CSLFetchNameValue ( papszOptions, "NB_IDS"); 
     336    if (pszNbOutID == NULL) 
     337    { 
     338        nbOutID = NB_MIN_BNA_IDS; 
     339    } 
     340    else if (EQUAL(pszNbOutID, "NB_SOURCE_FIELDS")) 
     341    { 
     342        nbOutID = -1; 
     343    } 
     344    else 
     345    { 
     346        nbOutID = atoi(pszNbOutID); 
     347        if (nbOutID <= 0) 
     348        { 
     349            CPLError( CE_Warning, CPLE_AppDefined,  
     350                  "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS", 
     351                  pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS ); 
     352            nbOutID = NB_MIN_BNA_IDS; 
     353        } 
     354        if (nbOutID > NB_MAX_BNA_IDS) 
     355        { 
     356            CPLError( CE_Warning, CPLE_AppDefined,  
     357                  "NB_ID=%s not understood. Must be >=%d and <=%d or equal to NB_SOURCE_FIELDS", 
     358                  pszNbOutID, NB_MIN_BNA_IDS, NB_MAX_BNA_IDS ); 
     359            nbOutID = NB_MAX_BNA_IDS; 
     360        } 
     361    } 
     362     
     363    /* Ellipses export as ellipses or polygons ? */ 
     364    bEllipsesAsEllipses = CSLFetchBoolean( papszOptions, "ELLIPSES_AS_ELLIPSES", TRUE); 
     365     
     366    /* Number of coordinate pairs per line */ 
     367    const char* pszNbPairPerLine = CSLFetchNameValue( papszOptions, "NB_PAIRS_PER_LINE"); 
     368    if (pszNbPairPerLine) 
     369    { 
     370        nbPairPerLine = atoi(pszNbPairPerLine); 
     371        if (nbPairPerLine <= 0) 
     372            nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1; 
     373        if (bMultiLine == FALSE) 
     374        { 
     375            CPLError( CE_Warning, CPLE_AppDefined, "NB_PAIR_PER_LINE option is ignored when MULTILINE=NO"); 
     376        } 
     377    } 
     378    else 
     379    { 
     380        nbPairPerLine = (bMultiLine == FALSE) ? 1000000000 : 1; 
     381    } 
     382     
     383    /* Coordinate precision */ 
     384    const char* pszCoordinatePrecision = CSLFetchNameValue( papszOptions, "COORDINATE_PRECISION"); 
     385    if (pszCoordinatePrecision) 
     386    { 
     387        coordinatePrecision = atoi(pszCoordinatePrecision); 
     388        if (coordinatePrecision <= 0) 
     389            coordinatePrecision = 0; 
     390        else if (coordinatePrecision >= 20) 
     391            coordinatePrecision = 20; 
     392    } 
     393    else 
     394    { 
     395        coordinatePrecision = 10; 
     396    } 
     397     
     398    pszCoordinateSeparator = (char*)CSLFetchNameValue( papszOptions, "COORDINATE_SEPARATOR"); 
     399    if (pszCoordinateSeparator == NULL) 
     400        pszCoordinateSeparator = CPLStrdup(","); 
     401    else 
     402        pszCoordinateSeparator = CPLStrdup(pszCoordinateSeparator); 
     403 
     404    return TRUE; 
     405} 
  • trunk/gdal/ogr/ogrsf_frmts/bna/ogrbnadriver.cpp

    r11853 r11894  
    6969 
    7070/************************************************************************/ 
     71/*                          CreateDataSource()                          */ 
     72/************************************************************************/ 
     73 
     74OGRDataSource *OGRBNADriver::CreateDataSource( const char * pszName, 
     75                                                 char **papszOptions ) 
     76 
     77{ 
     78    OGRBNADataSource   *poDS = new OGRBNADataSource(); 
     79 
     80    if( !poDS->Create( pszName, papszOptions ) ) 
     81    { 
     82        delete poDS; 
     83        poDS = NULL; 
     84    } 
     85 
     86    return poDS; 
     87} 
     88 
     89/************************************************************************/ 
     90/*                          DeleteDataSource()                          */ 
     91/************************************************************************/ 
     92 
     93OGRErr OGRBNADriver::DeleteDataSource( const char *pszFilename ) 
     94 
     95{ 
     96    if( VSIUnlink( pszFilename ) == 0 ) 
     97        return OGRERR_NONE; 
     98    else 
     99        return OGRERR_FAILURE; 
     100} 
     101 
     102/************************************************************************/ 
    71103/*                           TestCapability()                           */ 
    72104/************************************************************************/ 
     
    76108{ 
    77109    if( EQUAL(pszCap,ODrCCreateDataSource) ) 
    78         return FALSE; 
     110        return TRUE; 
    79111    else if( EQUAL(pszCap,ODrCDeleteDataSource) ) 
    80         return FALSE; 
     112        return TRUE; 
    81113    else 
    82114        return FALSE; 
  • trunk/gdal/ogr/ogrsf_frmts/bna/ogrbnalayer.cpp

    r11867 r11894  
    11/****************************************************************************** 
    2  * $Id: ogrbnalayer.cpp 10646 2007-01-18 02:38:10Z warmerdam $ 
     2 * $Id: ogrbnalayer.cpp 
    33 * 
    44 * Project:  BNA Translator 
     
    4747                          const char* layerName, 
    4848                          BNAFeatureType bnaFeatureType, 
    49                           OGRwkbGeometryType eLayerGeomType ) 
     49                          OGRwkbGeometryType eLayerGeomType, 
     50                          int bWriter, 
     51                          OGRBNADataSource* poDS, 
     52                          int nIDs) 
    5053 
    5154{ 
     
    5457    curLine = 0; 
    5558    nNextFID = 0; 
     59     
     60    this->bWriter = bWriter; 
     61    this->poDS = poDS; 
     62    this->nIDs = nIDs; 
    5663 
    5764    nFeatures = 0; 
     
    6976    this->bnaFeatureType = bnaFeatureType; 
    7077 
    71     int i; 
    72     for(i=0;i<NB_MAX_BNA_IDS;i++) 
    73     { 
    74         if (i < (int) (sizeof(iKnowHowToCount)/sizeof(iKnowHowToCount[0])) ) 
    75         { 
    76             sprintf(tmp, "%s ID", iKnowHowToCount[i]); 
    77             OGRFieldDefn oFieldID(tmp, OFTString ); 
    78             poFeatureDefn->AddFieldDefn( &oFieldID ); 
    79         } 
    80         else 
    81         { 
    82             sprintf(tmp, "%dth ID", i+1); 
    83             OGRFieldDefn oFieldID(tmp, OFTString ); 
    84             poFeatureDefn->AddFieldDefn( &oFieldID ); 
    85         } 
    86     } 
    87      
    88     if (bnaFeatureType == BNA_ELLIPSE) 
    89     { 
    90         OGRFieldDefn oFieldMajorRadius( "Major radius", OFTReal ); 
    91         poFeatureDefn->AddFieldDefn( &oFieldMajorRadius ); 
    92        
    93         OGRFieldDefn oFieldMinorRadius( "Minor radius", OFTReal ); 
    94         poFeatureDefn->AddFieldDefn( &oFieldMinorRadius ); 
    95     } 
    96  
    97     fpBNA = VSIFOpen( pszFilename, "rb" ); 
    98     if( fpBNA == NULL ) 
    99         return; 
     78    if (! bWriter ) 
     79    { 
     80        int i; 
     81        for(i=0;i<nIDs;i++) 
     82        { 
     83            if (i < (int) (sizeof(iKnowHowToCount)/sizeof(iKnowHowToCount[0])) ) 
     84            { 
     85                sprintf(tmp, "%s ID", iKnowHowToCount[i]); 
     86                OGRFieldDefn oFieldID(tmp, OFTString ); 
     87                poFeatureDefn->AddFieldDefn( &oFieldID ); 
     88            } 
     89            else 
     90            { 
     91                sprintf(tmp, "%dth ID", i+1); 
     92                OGRFieldDefn oFieldID(tmp, OFTString ); 
     93                poFeatureDefn->AddFieldDefn( &oFieldID ); 
     94            } 
     95        } 
     96 
     97        if (bnaFeatureType == BNA_ELLIPSE) 
     98        { 
     99            OGRFieldDefn oFieldMajorRadius( "Major radius", OFTReal ); 
     100            poFeatureDefn->AddFieldDefn( &oFieldMajorRadius ); 
     101 
     102            OGRFieldDefn oFieldMinorRadius( "Minor radius", OFTReal ); 
     103            poFeatureDefn->AddFieldDefn( &oFieldMinorRadius ); 
     104        } 
     105 
     106        fpBNA = VSIFOpen( pszFilename, "r" ); 
     107        if( fpBNA == NULL ) 
     108            return; 
     109    } 
     110    else 
     111    { 
     112        fpBNA = NULL; 
     113    } 
    100114} 
    101115 
     
    113127    if (fpBNA) 
    114128        VSIFClose( fpBNA ); 
     129} 
     130 
     131/************************************************************************/ 
     132/*                         SetFeatureIndexTable()                       */ 
     133/************************************************************************/ 
     134void  OGRBNALayer::SetFeatureIndexTable(int nFeatures, OffsetAndLine* offsetAndLineFeaturesTable, int partialIndexTable) 
     135{ 
     136    this->nFeatures = nFeatures; 
     137    this->offsetAndLineFeaturesTable = offsetAndLineFeaturesTable; 
     138    this->partialIndexTable = partialIndexTable; 
    115139} 
    116140 
     
    155179        if (ok == FALSE) 
    156180        { 
     181            BNA_FreeRecord(record); 
    157182            failed = TRUE; 
    158183            return NULL; 
     
    162187            /* end of file */ 
    163188            eof = TRUE; 
    164          
     189 
    165190            /* and we have finally build the whole index table */ 
    166191            partialIndexTable = FALSE; 
     
    170195        if (record->featureType == bnaFeatureType) 
    171196        { 
     197            if (nNextFID >= nFeatures) 
     198            { 
     199                nFeatures++; 
     200                offsetAndLineFeaturesTable = 
     201                    (OffsetAndLine*)CPLRealloc(offsetAndLineFeaturesTable, nFeatures * sizeof(OffsetAndLine)); 
     202                offsetAndLineFeaturesTable[nFeatures-1].offset = offset; 
     203                offsetAndLineFeaturesTable[nFeatures-1].line = line; 
     204            } 
     205 
     206            poFeature = BuildFeatureFromBNARecord(record, nNextFID++); 
     207 
     208            BNA_FreeRecord(record); 
     209 
     210            if(   (m_poFilterGeom == NULL 
     211                || FilterGeometry( poFeature->GetGeometryRef() ) ) 
     212            && (m_poAttrQuery == NULL 
     213                || m_poAttrQuery->Evaluate( poFeature )) ) 
     214            { 
     215                 return poFeature; 
     216            } 
     217 
     218            delete poFeature; 
     219        } 
     220        else 
     221        { 
     222            BNA_FreeRecord(record); 
     223        } 
     224    } 
     225} 
     226 
     227 
     228void OGRBNALayer::WriteFeatureAttributes(FILE* fp, OGRFeature *poFeature ) 
     229{ 
     230    int i; 
     231    OGRFieldDefn *poField; 
     232    int nbOutID = poDS->GetNbOutId(); 
     233    if (nbOutID < 0) 
     234        nbOutID = poFeatureDefn->GetFieldCount(); 
     235    for(i=0;i<nbOutID;i++) 
     236    {  
     237        if (i < poFeatureDefn->GetFieldCount()) 
     238        { 
     239            poField = poFeatureDefn->GetFieldDefn( i ); 
     240            if( poFeature->IsFieldSet( i ) ) 
     241            { 
     242                const char *pszRaw = poFeature->GetFieldAsString( i ); 
     243                VSIFPrintf( fp, "\"%s\",", pszRaw); 
     244            } 
     245            else 
     246            { 
     247                VSIFPrintf( fp, "\"\","); 
     248            } 
     249        } 
     250        else 
     251        { 
     252            VSIFPrintf( fp, "\"\","); 
     253        } 
     254    } 
     255} 
     256 
     257/************************************************************************/ 
     258/*                           CreateFeature()                            */ 
     259/************************************************************************/ 
     260 
     261OGRErr OGRBNALayer::CreateFeature( OGRFeature *poFeature ) 
     262 
     263{ 
     264    int i,j,k,n; 
     265    OGRGeometry     *poGeom = poFeature->GetGeometryRef(); 
     266    char eol[3]; 
     267    const char* partialEol = (poDS->GetMultiLine()) ? eol : poDS->GetCoordinateSeparator(); 
     268     
     269    if (poDS->GetUseCRLF()) 
     270    { 
     271        eol[0] = 13; 
     272        eol[1] = 10; 
     273        eol[2] = 0; 
     274    } 
     275    else 
     276    { 
     277        eol[0] = 10; 
     278        eol[1] = 0; 
     279    } 
     280     
     281    if ( ! bWriter ) 
     282    { 
     283        return OGRERR_FAILURE; 
     284    } 
     285     
     286    if( poFeature->GetFID() == OGRNullFID ) 
     287        poFeature->SetFID( nFeatures++ ); 
     288     
     289    FILE* fp = poDS->GetOutputFP(); 
     290    int nbPairPerLine = poDS->GetNbPairPerLine(); 
     291    char formatCoordinates[32]; 
     292    sprintf(formatCoordinates, "%%s%%.%df%s%%.%df", 
     293            poDS->GetCoordinatePrecision(), poDS->GetCoordinateSeparator(), poDS->GetCoordinatePrecision()); 
     294 
     295    switch( poGeom->getGeometryType() ) 
     296    { 
     297        case wkbPoint: 
     298        case wkbPoint25D: 
     299        { 
     300            OGRPoint* point = (OGRPoint*)poGeom; 
     301            WriteFeatureAttributes(fp, poFeature); 
     302            VSIFPrintf( fp, "1"); 
     303            VSIFPrintf( fp, formatCoordinates, partialEol, point->getX(), point->getY()); 
     304            VSIFPrintf( fp, "%s", eol); 
    172305            break; 
    173306        } 
     307             
     308        case wkbPolygon: 
     309        case wkbPolygon25D: 
     310        { 
     311            OGRPolygon* polygon = (OGRPolygon*)poGeom; 
     312            OGRLinearRing* ring = polygon->getExteriorRing(); 
     313            double firstX = ring->getX(0); 
     314            double firstY = ring->getY(0); 
     315            int nBNAPoints = ring->getNumPoints(); 
     316            int is_ellipse = FALSE; 
     317             
     318            /* This code tries to detect an ellipse in a polygon geometry */ 
     319            /* This will only work presumably on ellipses already read from a BNA file */ 
     320            /* Mostly a BNA to BNA feature... */ 
     321            if (poDS->GetEllipsesAsEllipses() && 
     322                polygon->getNumInteriorRings() == 0 && 
     323                nBNAPoints == 361) 
     324            { 
     325                double oppositeX = ring->getX(180); 
     326                double oppositeY = ring->getY(180); 
     327                double quarterX = ring->getX(90); 
     328                double quarterY = ring->getY(90); 
     329                double antiquarterX = ring->getX(270); 
     330                double antiquarterY = ring->getY(270); 
     331                double center1X = 0.5*(firstX + oppositeX); 
     332                double center1Y = 0.5*(firstY + oppositeY); 
     333                double center2X = 0.5*(quarterX + antiquarterX); 
     334                double center2Y = 0.5*(quarterY + antiquarterY); 
     335                if (fabs(center1X - center2X) < 1e-5 && fabs(center1Y - center2Y) < 1e-5 && 
     336                    fabs(oppositeY - firstY) < 1e-5 && 
     337                    fabs(quarterX - antiquarterX) < 1e-5) 
     338                { 
     339                    double major_radius = fabs(firstX - center1X); 
     340                    double minor_radius = fabs(quarterY - center1Y); 
     341                    is_ellipse = TRUE; 
     342                    for(i=0;i<360;i++) 
     343                    { 
     344                        if (!(fabs(center1X + major_radius * cos(i * (M_PI / 180)) - ring->getX(i)) < 1e-5 && 
     345                              fabs(center1Y + minor_radius * sin(i * (M_PI / 180)) - ring->getY(i)) < 1e-5)) 
     346                        { 
     347                            is_ellipse = FALSE; 
     348                            break; 
     349                        } 
     350                    } 
     351                    if ( is_ellipse == TRUE ) 
     352                    { 
     353                        WriteFeatureAttributes(fp, poFeature); 
     354                        VSIFPrintf( fp, "2"); 
     355                        VSIFPrintf( fp, formatCoordinates, partialEol, center1X, center1Y); 
     356                        VSIFPrintf( fp, formatCoordinates,  partialEol, major_radius, minor_radius); 
     357                        VSIFPrintf( fp, "%s", eol); 
     358                    } 
     359                } 
     360            } 
     361 
     362            if ( is_ellipse == FALSE) 
     363            { 
     364                int nInteriorRings = polygon->getNumInteriorRings(); 
     365                for(i=0;i<nInteriorRings;i++) 
     366                { 
     367                    nBNAPoints += polygon->getInteriorRing(i)->getNumPoints() + 1; 
     368                } 
     369                if (nBNAPoints <= 3) 
     370                { 
     371                    CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" ); 
     372                    return OGRERR_FAILURE; 
     373                } 
     374                WriteFeatureAttributes(fp, poFeature); 
     375                VSIFPrintf( fp, "%d", nBNAPoints); 
     376                n = ring->getNumPoints(); 
     377                int nbPair = 0; 
     378                for(i=0;i<n;i++) 
     379                { 
     380                    VSIFPrintf( fp, formatCoordinates, 
     381                                ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(i), ring->getY(i)); 
     382                    nbPair++; 
     383                } 
     384                for(i=0;i<nInteriorRings;i++) 
     385                { 
     386                    ring = polygon->getInteriorRing(i); 
     387                    n = ring->getNumPoints(); 
     388                    for(j=0;i<n;i++) 
     389                    { 
     390                        VSIFPrintf( fp, formatCoordinates, 
     391                                    ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", ring->getX(j), ring->getY(j)); 
     392                        nbPair++; 
     393                    } 
     394                    VSIFPrintf( fp, formatCoordinates, 
     395                                ((nbPair % nbPairPerLine) == 0) ? partialEol : " ", firstX, firstY); 
     396                    nbPair++; 
     397                } 
     398                VSIFPrintf( fp, "%s", eol); 
     399            } 
     400            break; 
     401        } 
     402 
     403        case wkbMultiPolygon: 
     404        case wkbMultiPolygon25D: 
     405        { 
     406            OGRMultiPolygon* multipolygon = (OGRMultiPolygon*)poGeom; 
     407            int N = multipolygon->getNumGeometries(); 
     408            int nBNAPoints = 0; 
     409            double firstX = 0, firstY = 0;  
     410            for(i=0;i<N;i++) 
     411            { 
     412                OGRPolygon* polygon = (OGRPolygon*)multipolygon->getGeometryRef(i); 
     413                OGRLinearRing* ring = polygon->getExteriorRing(); 
     414                if (nBNAPoints) 
     415                    nBNAPoints ++; 
     416                else 
     417                { 
     418                    firstX = ring->getX(0); 
     419                    firstY = ring->getY(0); 
     420                } 
     421                nBNAPoints += ring->getNumPoints(); 
     422                int nInteriorRings = polygon->getNumInteriorRings(); 
     423                for(j=0;j<nInteriorRings;j++) 
     424                { 
     425                    nBNAPoints += polygon->getInteriorRing(j)->getNumPoints() + 1; 
     426                } 
     427            } 
     428            if (nBNAPoints <= 3) 
     429            { 
     430                CPLError( CE_Failure, CPLE_AppDefined, "Invalid geometry" ); 
     431