LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/gpx - ogrgpxdatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 198 163 82.3 %
Date: 2010-01-09 Functions: 13 12 92.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgpxdatasource.cpp 17848 2009-10-17 12:59:16Z rouault $
       3                 :  *
       4                 :  * Project:  GPX Translator
       5                 :  * Purpose:  Implements OGRGPXDataSource 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_gpx.h"
      31                 : #include "cpl_conv.h"
      32                 : #include "cpl_string.h"
      33                 : #include "cpl_csv.h"
      34                 : 
      35                 : CPL_CVSID("$Id: ogrgpxdatasource.cpp 17848 2009-10-17 12:59:16Z rouault $");
      36                 : 
      37                 : #define SPACE_FOR_METADATA 160
      38                 : 
      39                 : /************************************************************************/
      40                 : /*                          OGRGPXDataSource()                          */
      41                 : /************************************************************************/
      42                 : 
      43              66 : OGRGPXDataSource::OGRGPXDataSource()
      44                 : 
      45                 : {
      46              66 :     lastGPXGeomTypeWritten = GPX_NONE;
      47              66 :     bUseExtensions = FALSE;
      48              66 :     pszExtensionsNS = NULL;
      49                 : 
      50              66 :     papoLayers = NULL;
      51              66 :     nLayers = 0;
      52                 :     
      53              66 :     fpOutput = NULL;
      54              66 :     nOffsetBounds = -1;
      55              66 :     dfMinLat = 90;
      56              66 :     dfMinLon = 180;
      57              66 :     dfMaxLat = -90;
      58              66 :     dfMaxLon = -180;
      59                 : 
      60              66 :     pszName = NULL;
      61              66 :     pszVersion = NULL;
      62              66 : }
      63                 : 
      64                 : /************************************************************************/
      65                 : /*                         ~OGRGPXDataSource()                          */
      66                 : /************************************************************************/
      67                 : 
      68             132 : OGRGPXDataSource::~OGRGPXDataSource()
      69                 : 
      70                 : {
      71              66 :     if ( fpOutput != NULL )
      72                 :     {
      73               2 :         VSIFPrintf(fpOutput, "</gpx>\n");
      74               2 :         if ( fpOutput != stdout )
      75                 :         {
      76                 :             /* Write the <bound> element in the reserved space */
      77               2 :             if (dfMinLon <= dfMaxLon)
      78                 :             {
      79                 :                 char szMetadata[SPACE_FOR_METADATA+1];
      80                 :                 sprintf(szMetadata, "<metadata><bounds minlat=\"%.15f\" minlon=\"%.15f\" maxlat=\"%.15f\" maxlon=\"%.15f\"/></metadata>",
      81               2 :                         dfMinLat, dfMinLon, dfMaxLat, dfMaxLon);
      82               2 :                 VSIFSeek(fpOutput, nOffsetBounds, SEEK_SET);
      83               2 :                 VSIFWrite(szMetadata, 1, strlen(szMetadata), fpOutput);
      84                 :             }
      85               2 :             VSIFClose( fpOutput);
      86                 :         }
      87                 :     }
      88                 : 
      89              85 :     for( int i = 0; i < nLayers; i++ )
      90              19 :         delete papoLayers[i];
      91              66 :     CPLFree( papoLayers );
      92              66 :     CPLFree( pszExtensionsNS );
      93              66 :     CPLFree( pszName );
      94              66 :     CPLFree( pszVersion );
      95             132 : }
      96                 : 
      97                 : /************************************************************************/
      98                 : /*                           TestCapability()                           */
      99                 : /************************************************************************/
     100                 : 
     101               0 : int OGRGPXDataSource::TestCapability( const char * pszCap )
     102                 : 
     103                 : {
     104               0 :     if( EQUAL(pszCap,ODsCCreateLayer) )
     105               0 :         return TRUE;
     106               0 :     else if( EQUAL(pszCap,ODsCDeleteLayer) )
     107               0 :         return FALSE;
     108                 :     else
     109               0 :         return FALSE;
     110                 : }
     111                 : 
     112                 : /************************************************************************/
     113                 : /*                              GetLayer()                              */
     114                 : /************************************************************************/
     115                 : 
     116              28 : OGRLayer *OGRGPXDataSource::GetLayer( int iLayer )
     117                 : 
     118                 : {
     119              28 :     if( iLayer < 0 || iLayer >= nLayers )
     120               0 :         return NULL;
     121                 :     else
     122              28 :         return papoLayers[iLayer];
     123                 : }
     124                 : 
     125                 : /************************************************************************/
     126                 : /*                            CreateLayer()                             */
     127                 : /************************************************************************/
     128                 : 
     129               4 : OGRLayer * OGRGPXDataSource::CreateLayer( const char * pszLayerName,
     130                 :                                           OGRSpatialReference *poSRS,
     131                 :                                           OGRwkbGeometryType eType,
     132                 :                                           char ** papszOptions )
     133                 : 
     134                 : {
     135                 :     GPXGeometryType gpxGeomType;
     136               6 :     if (eType == wkbPoint || eType == wkbPoint25D)
     137                 :     {
     138               2 :         gpxGeomType = GPX_WPT;
     139                 :     }
     140               3 :     else if (eType == wkbLineString || eType == wkbLineString25D)
     141                 :     {
     142               1 :         const char *pszForceGPXTrack = CSLFetchNameValue( papszOptions, "FORCE_GPX_TRACK");
     143               1 :         if (pszForceGPXTrack && CSLTestBoolean(pszForceGPXTrack))
     144               0 :             gpxGeomType = GPX_TRACK;
     145                 :         else
     146               1 :             gpxGeomType = GPX_ROUTE;
     147                 :     }
     148               2 :     else if (eType == wkbMultiLineString || eType == wkbMultiLineString25D)
     149                 :     {
     150               1 :         const char *pszForceGPXRoute = CSLFetchNameValue( papszOptions, "FORCE_GPX_ROUTE");
     151               1 :         if (pszForceGPXRoute && CSLTestBoolean(pszForceGPXRoute))
     152               0 :             gpxGeomType = GPX_ROUTE;
     153                 :         else
     154               1 :             gpxGeomType = GPX_TRACK;
     155                 :     }
     156               0 :     else if (eType == wkbUnknown)
     157                 :     {
     158                 :         CPLError(CE_Failure, CPLE_NotSupported,
     159               0 :                  "Cannot create GPX layer %s with unknown geometry type", pszLayerName);
     160               0 :         return NULL;
     161                 :     }
     162                 :     else
     163                 :     {
     164                 :         CPLError( CE_Failure, CPLE_NotSupported,
     165                 :                     "Geometry type of `%s' not supported in GPX.\n",
     166               0 :                     OGRGeometryTypeToName(eType) );
     167               0 :         return NULL;
     168                 :     }
     169               4 :     nLayers++;
     170               4 :     papoLayers = (OGRGPXLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGPXLayer*));
     171               4 :     papoLayers[nLayers-1] = new OGRGPXLayer( pszName, pszLayerName, gpxGeomType, this, TRUE );
     172                 :     
     173               4 :     return papoLayers[nLayers-1];
     174                 : }
     175                 : 
     176                 : #ifdef HAVE_EXPAT
     177                 : 
     178                 : /************************************************************************/
     179                 : /*                startElementValidateCbk()                             */
     180                 : /************************************************************************/
     181                 : 
     182             645 : void OGRGPXDataSource::startElementValidateCbk(const char *pszName, const char **ppszAttr)
     183                 : {
     184             645 :     if (validity == GPX_VALIDITY_UNKNOWN)
     185                 :     {
     186              20 :         if (strcmp(pszName, "gpx") == 0)
     187                 :         {
     188                 :             int i;
     189               3 :             validity = GPX_VALIDITY_VALID;
     190               4 :             for(i=0; ppszAttr[i] != NULL; i+= 2)
     191                 :             {
     192               4 :                 if (strcmp(ppszAttr[i], "version") == 0)
     193                 :                 {
     194               3 :                     pszVersion = CPLStrdup(ppszAttr[i+1]);
     195               3 :                     break;
     196                 :                 }
     197                 :             }
     198                 :         }
     199                 :         else
     200                 :         {
     201              17 :             validity = GPX_VALIDITY_INVALID;
     202                 :         }
     203                 :     }
     204             625 :     else if (validity == GPX_VALIDITY_VALID)
     205                 :     {
     206              96 :         if (strcmp(pszName, "extensions") == 0)
     207                 :         {
     208               3 :             bUseExtensions = TRUE;
     209                 :         }
     210              96 :         nElementsRead++;
     211                 :     }
     212             645 : }
     213                 : 
     214                 : 
     215                 : /************************************************************************/
     216                 : /*                      dataHandlerValidateCbk()                        */
     217                 : /************************************************************************/
     218                 : 
     219            1912 : void OGRGPXDataSource::dataHandlerValidateCbk(const char *data, int nLen)
     220                 : {
     221            1912 :     nDataHandlerCounter ++;
     222            1912 :     if (nDataHandlerCounter >= BUFSIZ)
     223                 :     {
     224               0 :         CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
     225               0 :         XML_StopParser(oCurrentParser, XML_FALSE);
     226                 :     }
     227            1912 : }
     228                 : 
     229                 : 
     230             645 : static void XMLCALL startElementValidateCbk(void *pUserData, const char *pszName, const char **ppszAttr)
     231                 : {
     232             645 :     OGRGPXDataSource* poDS = (OGRGPXDataSource*) pUserData;
     233             645 :     poDS->startElementValidateCbk(pszName, ppszAttr);
     234             645 : }
     235                 : 
     236            1912 : static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data, int nLen)
     237                 : {
     238            1912 :     OGRGPXDataSource* poDS = (OGRGPXDataSource*) pUserData;
     239            1912 :     poDS->dataHandlerValidateCbk(data, nLen);
     240            1912 : }
     241                 : #endif
     242                 : 
     243                 : /************************************************************************/
     244                 : /*                                Open()                                */
     245                 : /************************************************************************/
     246                 : 
     247              64 : int OGRGPXDataSource::Open( const char * pszFilename, int bUpdateIn)
     248                 : 
     249                 : {
     250              64 :     if (bUpdateIn)
     251                 :     {
     252                 :         CPLError(CE_Failure, CPLE_NotSupported,
     253               0 :                     "OGR/GPX driver does not support opening a file in update mode");
     254               0 :         return FALSE;
     255                 :     }
     256                 : #ifdef HAVE_EXPAT
     257              64 :     pszName = CPLStrdup( pszFilename );
     258                 : 
     259                 : /* -------------------------------------------------------------------- */
     260                 : /*      Determine what sort of object this is.                          */
     261                 : /* -------------------------------------------------------------------- */
     262                 :     VSIStatBufL sStatBuf;
     263                 : 
     264              64 :     if( VSIStatL( pszFilename, &sStatBuf ) != 0 )
     265               5 :         return FALSE;
     266                 :     
     267              59 :     if( VSI_ISDIR(sStatBuf.st_mode) )
     268               1 :         return FALSE;
     269                 : 
     270              58 :     FILE* fp = VSIFOpenL(pszFilename, "r");
     271              58 :     if (fp == NULL)
     272               0 :         return FALSE;
     273                 :     
     274              58 :     validity = GPX_VALIDITY_UNKNOWN;
     275              58 :     CPLFree(pszVersion);
     276              58 :     pszVersion = NULL;
     277              58 :     bUseExtensions = FALSE;
     278              58 :     nElementsRead = 0;
     279                 :     
     280              58 :     XML_Parser oParser = OGRCreateExpatXMLParser();
     281              58 :     oCurrentParser = oParser;
     282              58 :     XML_SetUserData(oParser, this);
     283              58 :     XML_SetElementHandler(oParser, ::startElementValidateCbk, NULL);
     284              58 :     XML_SetCharacterDataHandler(oParser, ::dataHandlerValidateCbk);
     285                 :     
     286                 :     char aBuf[BUFSIZ];
     287                 :     int nDone;
     288                 :     unsigned int nLen;
     289              58 :     int nCount = 0;
     290                 :     
     291                 :     /* Begin to parse the file and look for the <gpx> element */
     292                 :     /* It *MUST* be the first element of an XML file */
     293                 :     /* So once we have read the first element, we know if we can */
     294                 :     /* handle the file or not with that driver */
     295               1 :     do
     296                 :     {
     297              58 :         nDataHandlerCounter = 0;
     298              58 :         nLen = (unsigned int) VSIFReadL( aBuf, 1, sizeof(aBuf), fp );
     299              58 :         nDone = VSIFEofL(fp);
     300              58 :         if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
     301                 :         {
     302              39 :             if (nLen <= BUFSIZ-1)
     303              29 :                 aBuf[nLen] = 0;
     304                 :             else
     305              10 :                 aBuf[BUFSIZ-1] = 0;
     306              39 :             if (strstr(aBuf, "<?xml") && strstr(aBuf, "<gpx"))
     307                 :             {
     308                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     309                 :                         "XML parsing of GPX file failed : %s at line %d, column %d",
     310                 :                         XML_ErrorString(XML_GetErrorCode(oParser)),
     311                 :                         (int)XML_GetCurrentLineNumber(oParser),
     312               0 :                         (int)XML_GetCurrentColumnNumber(oParser));
     313                 :             }
     314              39 :             validity = GPX_VALIDITY_INVALID;
     315              39 :             break;
     316                 :         }
     317              19 :         if (validity == GPX_VALIDITY_INVALID)
     318                 :         {
     319              16 :             break;
     320                 :         }
     321               3 :         else if (validity == GPX_VALIDITY_VALID)
     322                 :         {
     323                 :             /* If we have recognized the <gpx> element, now we try */
     324                 :             /* to recognize if they are <extensions> tags */
     325                 :             /* But we stop to look for after an arbitrary number of tags */
     326               3 :             if (bUseExtensions)
     327               2 :                 break;
     328               1 :             else if (nElementsRead > 200)
     329               0 :                 break;
     330                 :         }
     331                 :         else
     332                 :         {
     333                 :             /* After reading 50 * BUFSIZE bytes, and not finding whether the file */
     334                 :             /* is GPX or not, we give up and fail silently */
     335               0 :             nCount ++;
     336               0 :             if (nCount == 50)
     337               0 :                 break;
     338                 :         }
     339                 :     } while (!nDone && nLen > 0 );
     340                 :     
     341              58 :     XML_ParserFree(oParser);
     342                 :     
     343              58 :     VSIFCloseL(fp);
     344                 :     
     345              58 :     if (validity == GPX_VALIDITY_VALID)
     346                 :     {
     347               3 :         CPLDebug("GPX", "%s seems to be a GPX file.", pszFilename);
     348               3 :         if (bUseExtensions)
     349               2 :             CPLDebug("GPX", "It uses <extensions>");
     350                 : 
     351               3 :         if (pszVersion == NULL)
     352                 :         {
     353                 :             /* Default to 1.1 */
     354                 :             CPLError(CE_Warning, CPLE_AppDefined, "GPX schema version is unknown. "
     355               0 :                      "The driver may not be able to handle the file correctly and will behave as if it is GPX 1.1.");
     356               0 :             pszVersion = CPLStrdup("1.1");
     357                 :         }
     358               3 :         else if (strcmp(pszVersion, "1.0") == 0 || strcmp(pszVersion, "1.1") == 0)
     359                 :         {
     360                 :             /* Fine */
     361                 :         }
     362                 :         else
     363                 :         {
     364                 :             CPLError(CE_Warning, CPLE_AppDefined,
     365                 :                      "GPX schema version '%s' is not handled by the driver. "
     366               0 :                      "The driver may not be able to handle the file correctly and will behave as if it is GPX 1.1.", pszVersion);
     367                 :         }
     368                 : 
     369               3 :         nLayers = 5;
     370               3 :         papoLayers = (OGRGPXLayer **) CPLRealloc(papoLayers, nLayers * sizeof(OGRGPXLayer*));
     371               3 :         papoLayers[0] = new OGRGPXLayer( pszName, "waypoints", GPX_WPT, this, FALSE );
     372               6 :         papoLayers[1] = new OGRGPXLayer( pszName, "routes", GPX_ROUTE, this, FALSE );
     373               6 :         papoLayers[2] = new OGRGPXLayer( pszName, "tracks", GPX_TRACK, this, FALSE );
     374               6 :         papoLayers[3] = new OGRGPXLayer( pszName, "route_points", GPX_ROUTE_POINT, this, FALSE );
     375               6 :         papoLayers[4] = new OGRGPXLayer( pszName, "track_points", GPX_TRACK_POINT, this, FALSE );
     376                 :     }
     377                 : 
     378              58 :     return (validity == GPX_VALIDITY_VALID);
     379                 : #else
     380                 :     char aBuf[256];
     381                 :     FILE* fp = VSIFOpenL(pszFilename, "r");
     382                 :     if (fp)
     383                 :     {
     384                 :         unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, 255, fp );
     385                 :         aBuf[nLen] = 0;
     386                 :         if (strstr(aBuf, "<?xml") && strstr(aBuf, "<gpx"))
     387                 :         {
     388                 :             CPLError(CE_Failure, CPLE_NotSupported,
     389                 :                     "OGR/GPX driver has not been built with read support. Expat library required");
     390                 :         }
     391                 :         VSIFCloseL(fp);
     392                 :     }
     393                 :     return FALSE;
     394                 : #endif
     395                 : }
     396                 : 
     397                 : 
     398                 : /************************************************************************/
     399                 : /*                               Create()                               */
     400                 : /************************************************************************/
     401                 : 
     402               2 : int OGRGPXDataSource::Create( const char *pszFilename, 
     403                 :                               char **papszOptions )
     404                 : {
     405               2 :     if( fpOutput != NULL)
     406                 :     {
     407                 :         CPLAssert( FALSE );
     408               0 :         return FALSE;
     409                 :     }
     410                 : 
     411                 : /* -------------------------------------------------------------------- */
     412                 : /*     Do not override exiting file.                                    */
     413                 : /* -------------------------------------------------------------------- */
     414                 :     VSIStatBufL sStatBuf;
     415                 : 
     416               2 :     if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
     417                 :     {
     418                 :         CPLError(CE_Failure, CPLE_NotSupported,
     419                 :                  "You have to delete %s before being able to create it with the GPX driver",
     420               0 :                  pszFilename);
     421               0 :         return FALSE;
     422                 :     }
     423                 :     
     424                 : /* -------------------------------------------------------------------- */
     425                 : /*      Create the output file.                                         */
     426                 : /* -------------------------------------------------------------------- */
     427               2 :     pszName = CPLStrdup( pszFilename );
     428                 : 
     429               2 :     if( EQUAL(pszFilename,"stdout") )
     430               0 :         fpOutput = stdout;
     431                 :     else
     432               2 :         fpOutput = VSIFOpen( pszFilename, "w+" );
     433               2 :     if( fpOutput == NULL )
     434                 :     {
     435                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     436                 :                   "Failed to create GPX file %s.", 
     437               0 :                   pszFilename );
     438               0 :         return FALSE;
     439                 :     }
     440                 :     
     441                 : /* -------------------------------------------------------------------- */
     442                 : /*      Look at use extensions options.                                 */
     443                 : /* -------------------------------------------------------------------- */
     444               2 :     const char* pszUseExtensions = CSLFetchNameValue( papszOptions, "GPX_USE_EXTENSIONS");
     445               2 :     const char* pszExtensionsNSURL = NULL;
     446               2 :     if (pszUseExtensions && CSLTestBoolean(pszUseExtensions))
     447                 :     {
     448               1 :         bUseExtensions = TRUE;
     449                 : 
     450               1 :         const char* pszExtensionsNSOption = CSLFetchNameValue( papszOptions, "GPX_EXTENSIONS_NS");
     451               1 :         const char* pszExtensionsNSURLOption = CSLFetchNameValue( papszOptions, "GPX_EXTENSIONS_NS_URL");
     452               1 :         if (pszExtensionsNSOption && pszExtensionsNSURLOption)
     453                 :         {
     454               0 :             pszExtensionsNS = CPLStrdup(pszExtensionsNSOption);
     455               0 :             pszExtensionsNSURL = pszExtensionsNSURLOption;
     456                 :         }
     457                 :         else
     458                 :         {
     459               1 :             pszExtensionsNS = CPLStrdup("ogr");
     460               1 :             pszExtensionsNSURL = "http://osgeo.org/gdal";
     461                 :         }
     462                 :     }
     463                 :     
     464                 : /* -------------------------------------------------------------------- */
     465                 : /*     Output header of GPX file.                                       */
     466                 : /* -------------------------------------------------------------------- */
     467               2 :     VSIFPrintf(fpOutput, "<?xml version=\"1.0\"?>\n");
     468               2 :     VSIFPrintf(fpOutput, "<gpx version=\"1.1\" creator=\"GDAL " GDAL_RELEASE_NAME "\" ");
     469               2 :     VSIFPrintf(fpOutput, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
     470               2 :     if (bUseExtensions)
     471               1 :         VSIFPrintf(fpOutput, "xmlns:%s=\"%s\" ", pszExtensionsNS, pszExtensionsNSURL);
     472               2 :     VSIFPrintf(fpOutput, "xmlns=\"http://www.topografix.com/GPX/1/1\" ");
     473               2 :     VSIFPrintf(fpOutput, "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n");
     474               2 :     if (fpOutput != stdout)
     475                 :     {
     476                 :       /* Reserve space for <metadata><bounds/></metadata> */
     477                 :       char szMetadata[SPACE_FOR_METADATA+1];
     478               2 :       memset(szMetadata, ' ', SPACE_FOR_METADATA);
     479               2 :       szMetadata[SPACE_FOR_METADATA] = '\0';
     480               2 :       nOffsetBounds = VSIFTell(fpOutput);
     481               2 :       VSIFPrintf(fpOutput, "%s\n", szMetadata);
     482                 :     }
     483                 : 
     484               2 :     return TRUE;
     485                 : }
     486                 : 
     487                 : /************************************************************************/
     488                 : /*                             AddCoord()                               */
     489                 : /************************************************************************/
     490                 : 
     491              11 : void OGRGPXDataSource::AddCoord(double dfLon, double dfLat)
     492                 : {
     493              11 :     if (dfLon < dfMinLon) dfMinLon = dfLon;
     494              11 :     if (dfLat < dfMinLat) dfMinLat = dfLat;
     495              11 :     if (dfLon > dfMaxLon) dfMaxLon = dfLon;
     496              11 :     if (dfLat > dfMaxLat) dfMaxLat = dfLat;
     497              11 : }

Generated by: LCOV version 1.7