LCOV - code coverage report
Current view: directory - frmts/xyz - xyzdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 437 350 80.1 %
Date: 2012-12-26 Functions: 16 11 68.8 %

       1                 : /******************************************************************************
       2                 :  * $Id: xyzdataset.cpp 24593 2012-06-16 18:58:42Z rouault $
       3                 :  *
       4                 :  * Project:  XYZ driver
       5                 :  * Purpose:  GDALDataset driver for XYZ dataset.
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, 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 "cpl_vsi_virtual.h"
      31                 : #include "cpl_string.h"
      32                 : #include "gdal_pam.h"
      33                 : 
      34                 : CPL_CVSID("$Id: xyzdataset.cpp 24593 2012-06-16 18:58:42Z rouault $");
      35                 : 
      36                 : CPL_C_START
      37                 : void    GDALRegister_XYZ(void);
      38                 : CPL_C_END
      39                 : 
      40                 : /************************************************************************/
      41                 : /* ==================================================================== */
      42                 : /*                              XYZDataset                              */
      43                 : /* ==================================================================== */
      44                 : /************************************************************************/
      45                 : 
      46                 : class XYZRasterBand;
      47                 : 
      48                 : class XYZDataset : public GDALPamDataset
      49                 : {
      50                 :     friend class XYZRasterBand;
      51                 :     
      52                 :     VSILFILE   *fp;
      53                 :     int         bHasHeaderLine;
      54                 :     int         nCommentLineCount;
      55                 :     int         nXIndex;
      56                 :     int         nYIndex;
      57                 :     int         nZIndex;
      58                 :     int         nMinTokens;
      59                 :     int         nLineNum;     /* any line */
      60                 :     int         nDataLineNum; /* line with values (header line and empty lines ignored) */
      61                 :     double      adfGeoTransform[6];
      62                 :     
      63                 :     static int          IdentifyEx( GDALOpenInfo *, int&, int& nCommentLineCount );
      64                 : 
      65                 :   public:
      66                 :                  XYZDataset();
      67                 :     virtual     ~XYZDataset();
      68                 :     
      69                 :     virtual CPLErr GetGeoTransform( double * );
      70                 :     
      71                 :     static GDALDataset *Open( GDALOpenInfo * );
      72                 :     static int          Identify( GDALOpenInfo * );
      73                 :     static GDALDataset *CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
      74                 :                                     int bStrict, char ** papszOptions, 
      75                 :                                     GDALProgressFunc pfnProgress, void * pProgressData );
      76                 : };
      77                 : 
      78                 : /************************************************************************/
      79                 : /* ==================================================================== */
      80                 : /*                            XYZRasterBand                             */
      81                 : /* ==================================================================== */
      82                 : /************************************************************************/
      83                 : 
      84                 : class XYZRasterBand : public GDALPamRasterBand
      85              18 : {
      86                 :     friend class XYZDataset;
      87                 : 
      88                 :   public:
      89                 : 
      90                 :                 XYZRasterBand( XYZDataset *, int, GDALDataType );
      91                 : 
      92                 :     virtual CPLErr IReadBlock( int, int, void * );
      93                 : };
      94                 : 
      95                 : 
      96                 : /************************************************************************/
      97                 : /*                           XYZRasterBand()                            */
      98                 : /************************************************************************/
      99                 : 
     100              18 : XYZRasterBand::XYZRasterBand( XYZDataset *poDS, int nBand, GDALDataType eDT )
     101                 : 
     102                 : {
     103              18 :     this->poDS = poDS;
     104              18 :     this->nBand = nBand;
     105                 : 
     106              18 :     eDataType = eDT;
     107                 : 
     108              18 :     nBlockXSize = poDS->GetRasterXSize();
     109              18 :     nBlockYSize = 1;
     110              18 : }
     111                 : 
     112                 : /************************************************************************/
     113                 : /*                             IReadBlock()                             */
     114                 : /************************************************************************/
     115                 : 
     116             445 : CPLErr XYZRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     117                 :                                   void * pImage )
     118                 : 
     119                 : {
     120             445 :     XYZDataset *poGDS = (XYZDataset *) poDS;
     121                 :     
     122             445 :     if (poGDS->fp == NULL)
     123               0 :         return CE_Failure;
     124                 : 
     125             445 :     int nLineInFile = nBlockYOff * nBlockXSize;
     126             445 :     if (poGDS->nDataLineNum > nLineInFile)
     127                 :     {
     128               7 :         poGDS->nDataLineNum = 0;
     129               7 :         VSIFSeekL(poGDS->fp, 0, SEEK_SET);
     130                 : 
     131               7 :         for(int i=0;i<poGDS->nCommentLineCount;i++)
     132               0 :             CPLReadLine2L(poGDS->fp, 100, NULL);
     133                 : 
     134               7 :         if (poGDS->bHasHeaderLine)
     135                 :         {
     136               5 :             const char* pszLine = CPLReadLine2L(poGDS->fp, 100, 0);
     137               5 :             if (pszLine == NULL)
     138                 :             {
     139               0 :                 memset(pImage, 0, nBlockXSize * (GDALGetDataTypeSize(eDataType) / 8));
     140               0 :                 return CE_Failure;
     141                 :             }
     142               5 :             poGDS->nLineNum ++;
     143                 :         }
     144                 :     }
     145                 : 
     146             902 :     while(poGDS->nDataLineNum < nLineInFile)
     147                 :     {
     148              12 :         const char* pszLine = CPLReadLine2L(poGDS->fp, 100, 0);
     149              12 :         if (pszLine == NULL)
     150                 :         {
     151               0 :             memset(pImage, 0, nBlockXSize * (GDALGetDataTypeSize(eDataType) / 8));
     152               0 :             return CE_Failure;
     153                 :         }
     154              12 :         poGDS->nLineNum ++;
     155                 : 
     156              12 :         const char* pszPtr = pszLine;
     157                 :         char ch;
     158              12 :         int nCol = 0;
     159              12 :         int bLastWasSep = TRUE;
     160              60 :         while((ch = *pszPtr) != '\0')
     161                 :         {
     162              48 :             if (ch == ' ' || ch == ',' || ch == '\t' || ch == ';')
     163                 :             {
     164              12 :                 if (!bLastWasSep)
     165              12 :                     nCol ++;
     166              12 :                 bLastWasSep = TRUE;
     167                 :             }
     168                 :             else
     169                 :             {
     170              24 :                 bLastWasSep = FALSE;
     171                 :             }
     172              36 :             pszPtr ++;
     173                 :         }
     174                 : 
     175                 :         /* Skip empty line */
     176              12 :         if (nCol == 0 && bLastWasSep)
     177               6 :             continue;
     178                 : 
     179               6 :         poGDS->nDataLineNum ++;
     180                 :     }
     181                 : 
     182                 :     int i;
     183           82053 :     for(i=0;i<nBlockXSize;i++)
     184                 :     {
     185                 :         int nCol;
     186                 :         int bLastWasSep;
     187           81612 :         do
     188                 :         {
     189           81612 :             const char* pszLine = CPLReadLine2L(poGDS->fp, 100, 0);
     190           81612 :             if (pszLine == NULL)
     191                 :             {
     192               0 :                 memset(pImage, 0, nBlockXSize * (GDALGetDataTypeSize(eDataType) / 8));
     193               0 :                 return CE_Failure;
     194                 :             }
     195           81612 :             poGDS->nLineNum ++;
     196                 : 
     197           81612 :             const char* pszPtr = pszLine;
     198                 :             char ch;
     199           81612 :             nCol = 0;
     200           81612 :             bLastWasSep = TRUE;
     201         2799048 :             while((ch = *pszPtr) != '\0')
     202                 :             {
     203         2799040 :                 if (ch == ' ' || ch == ',' || ch == '\t' || ch == ';')
     204                 :                 {
     205          163216 :                     if (!bLastWasSep)
     206          163216 :                         nCol ++;
     207          163216 :                     bLastWasSep = TRUE;
     208                 :                 }
     209                 :                 else
     210                 :                 {
     211         2472608 :                     if (bLastWasSep && nCol == poGDS->nZIndex)
     212                 :                     {
     213           81608 :                         double dfZ = CPLAtofM(pszPtr);
     214           81608 :                         if (eDataType == GDT_Float32)
     215                 :                         {
     216           80802 :                             ((float*)pImage)[i] = (float)dfZ;
     217                 :                         }
     218             806 :                         else if (eDataType == GDT_Int32)
     219                 :                         {
     220             400 :                             ((GInt32*)pImage)[i] = (GInt32)dfZ;
     221                 :                         }
     222             406 :                         else if (eDataType == GDT_Int16)
     223                 :                         {
     224               0 :                             ((GInt16*)pImage)[i] = (GInt16)dfZ;
     225                 :                         }
     226                 :                         else
     227                 :                         {
     228             406 :                             ((GByte*)pImage)[i] = (GByte)dfZ;
     229                 :                         }
     230                 :                     }
     231         2472608 :                     bLastWasSep = FALSE;
     232                 :                 }
     233         2635824 :                 pszPtr ++;
     234                 :             }
     235                 : 
     236                 :             /* Skip empty line */
     237                 :         }
     238                 :         while (nCol == 0 && bLastWasSep);
     239                 : 
     240           81608 :         poGDS->nDataLineNum ++;
     241           81608 :         nCol ++;
     242           81608 :         if (nCol < poGDS->nMinTokens)
     243                 :         {
     244               0 :             memset(pImage, 0, nBlockXSize * (GDALGetDataTypeSize(eDataType) / 8));
     245               0 :             return CE_Failure;
     246                 :         }
     247                 :     }
     248             445 :     CPLAssert(poGDS->nDataLineNum == (nBlockYOff + 1) * nBlockXSize);
     249                 : 
     250             445 :     return CE_None;
     251                 : }
     252                 : 
     253                 : /************************************************************************/
     254                 : /*                            ~XYZDataset()                            */
     255                 : /************************************************************************/
     256                 : 
     257              18 : XYZDataset::XYZDataset()
     258                 : {
     259              18 :     fp = NULL;
     260              18 :     nDataLineNum = INT_MAX;
     261              18 :     nLineNum = 0;
     262              18 :     nCommentLineCount = 0;
     263              18 :     bHasHeaderLine = FALSE;
     264              18 :     nXIndex = -1;
     265              18 :     nYIndex = -1;
     266              18 :     nZIndex = -1;
     267              18 :     nMinTokens = 0;
     268              18 :     adfGeoTransform[0] = 0;
     269              18 :     adfGeoTransform[1] = 1;
     270              18 :     adfGeoTransform[2] = 0;
     271              18 :     adfGeoTransform[3] = 0;
     272              18 :     adfGeoTransform[4] = 0;
     273              18 :     adfGeoTransform[5] = 1;
     274              18 : }
     275                 : 
     276                 : /************************************************************************/
     277                 : /*                            ~XYZDataset()                            */
     278                 : /************************************************************************/
     279                 : 
     280              18 : XYZDataset::~XYZDataset()
     281                 : 
     282                 : {
     283              18 :     FlushCache();
     284              18 :     if (fp)
     285              18 :         VSIFCloseL(fp);
     286              18 : }
     287                 : 
     288                 : /************************************************************************/
     289                 : /*                             Identify()                               */
     290                 : /************************************************************************/
     291                 : 
     292           10064 : int XYZDataset::Identify( GDALOpenInfo * poOpenInfo )
     293                 : {
     294                 :     int bHasHeaderLine, nCommentLineCount;
     295           10064 :     return IdentifyEx(poOpenInfo, bHasHeaderLine, nCommentLineCount);
     296                 : }
     297                 : 
     298                 : /************************************************************************/
     299                 : /*                            IdentifyEx()                              */
     300                 : /************************************************************************/
     301                 : 
     302                 : 
     303           11611 : int XYZDataset::IdentifyEx( GDALOpenInfo * poOpenInfo,
     304                 :                             int& bHasHeaderLine,
     305                 :                             int& nCommentLineCount)
     306                 : 
     307                 : {
     308                 :     int         i;
     309                 : 
     310           11611 :     bHasHeaderLine = FALSE;
     311           11611 :     nCommentLineCount = 0;
     312                 : 
     313           11611 :     CPLString osFilename(poOpenInfo->pszFilename);
     314                 : 
     315           11611 :     GDALOpenInfo* poOpenInfoToDelete = NULL;
     316                 :     /*  GZipped .xyz files are common, so automagically open them */
     317                 :     /*  if the /vsigzip/ has not been explicitely passed */
     318           11611 :     if (strlen(poOpenInfo->pszFilename) > 6 &&
     319                 :         EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "xyz.gz") &&
     320                 :         !EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9))
     321                 :     {
     322               0 :         osFilename = "/vsigzip/";
     323               0 :         osFilename += poOpenInfo->pszFilename;
     324                 :         poOpenInfo = poOpenInfoToDelete =
     325                 :                 new GDALOpenInfo(osFilename.c_str(), GA_ReadOnly,
     326               0 :                                  poOpenInfo->papszSiblingFiles);
     327                 :     }
     328                 : 
     329           11611 :     if (poOpenInfo->nHeaderBytes == 0)
     330                 :     {
     331           11216 :         delete poOpenInfoToDelete;
     332           11216 :         return FALSE;
     333                 :     }
     334                 : 
     335                 : /* -------------------------------------------------------------------- */
     336                 : /*      Chech that it looks roughly as a XYZ dataset                    */
     337                 : /* -------------------------------------------------------------------- */
     338             395 :     const char* pszData = (const char*)poOpenInfo->pabyHeader;
     339                 : 
     340                 :     /* Skip comments line at the beginning such as in */
     341                 :     /* http://pubs.usgs.gov/of/2003/ofr-03-230/DATA/NSLCU.XYZ */
     342             395 :     i=0;
     343             395 :     if (pszData[i] == '/')
     344                 :     {
     345               0 :         nCommentLineCount ++;
     346                 : 
     347               0 :         i++;
     348               0 :         for(;i<poOpenInfo->nHeaderBytes;i++)
     349                 :         {
     350               0 :             char ch = pszData[i];
     351               0 :             if (ch == 13 || ch == 10)
     352                 :             {
     353               0 :                 if (ch == 13 && pszData[i+1] == 10)
     354               0 :                     i++;
     355               0 :                 if (pszData[i+1] == '/')
     356                 :                 {
     357               0 :                     nCommentLineCount ++;
     358               0 :                     i++;
     359                 :                 }
     360                 :                 else
     361               0 :                     break;
     362                 :             }
     363                 :         }
     364                 :     }
     365                 : 
     366           14008 :     for(;i<poOpenInfo->nHeaderBytes;i++)
     367                 :     {
     368           13994 :         char ch = pszData[i];
     369           13994 :         if (ch == 13 || ch == 10)
     370                 :         {
     371               5 :             break;
     372                 :         }
     373           13989 :         else if (ch == ' ' || ch == ',' || ch == '\t' || ch == ';')
     374                 :             ;
     375            1132 :         else if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '+' ||
     376                 :                  ch == '-' || ch == 'e' || ch == 'E')
     377                 :             ;
     378             854 :         else if (ch == '"' || (ch >= 'a' && ch <= 'z') ||
     379                 :                               (ch >= 'A' && ch <= 'Z'))
     380             239 :             bHasHeaderLine = TRUE;
     381                 :         else
     382                 :         {
     383             376 :             delete poOpenInfoToDelete;
     384             376 :             return FALSE;
     385                 :         }
     386                 :     }
     387              19 :     int bHasFoundNewLine = FALSE;
     388              19 :     int bPrevWasSep = TRUE;
     389              19 :     int nCols = 0;
     390              19 :     int nMaxCols = 0;
     391            4118 :     for(;i<poOpenInfo->nHeaderBytes;i++)
     392                 :     {
     393            4099 :         char ch = pszData[i];
     394            4318 :         if (ch == 13 || ch == 10)
     395                 :         {
     396             219 :             bHasFoundNewLine = TRUE;
     397             219 :             if (!bPrevWasSep)
     398                 :             {
     399             208 :                 nCols ++;
     400             208 :                 if (nCols > nMaxCols)
     401               5 :                     nMaxCols = nCols;
     402                 :             }
     403             219 :             bPrevWasSep = TRUE;
     404             219 :             nCols = 0;
     405                 :         }
     406            4298 :         else if (ch == ' ' || ch == ',' || ch == '\t' || ch == ';')
     407                 :         {
     408             418 :             if (!bPrevWasSep)
     409                 :             {
     410             418 :                 nCols ++;
     411             418 :                 if (nCols > nMaxCols)
     412              10 :                     nMaxCols = nCols;
     413                 :             }
     414             418 :             bPrevWasSep = TRUE;
     415                 :         }
     416            6924 :         else if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '+' ||
     417                 :                  ch == '-' || ch == 'e' || ch == 'E')
     418                 :         {
     419            3462 :             bPrevWasSep = FALSE;
     420                 :         }
     421                 :         else
     422                 :         {
     423               0 :             delete poOpenInfoToDelete;
     424               0 :             return FALSE;
     425                 :         }
     426                 :     }
     427                 : 
     428              19 :     delete poOpenInfoToDelete;
     429              19 :     return bHasFoundNewLine && nMaxCols >= 3;
     430                 : }
     431                 : 
     432                 : /************************************************************************/
     433                 : /*                                Open()                                */
     434                 : /************************************************************************/
     435                 : 
     436            1547 : GDALDataset *XYZDataset::Open( GDALOpenInfo * poOpenInfo )
     437                 : 
     438                 : {
     439                 :     int         i;
     440                 :     int         bHasHeaderLine;
     441            1547 :     int         nCommentLineCount = 0;
     442                 : 
     443            1547 :     if (!IdentifyEx(poOpenInfo, bHasHeaderLine, nCommentLineCount))
     444            1542 :         return NULL;
     445                 : 
     446               5 :     CPLString osFilename(poOpenInfo->pszFilename);
     447                 : 
     448                 :     /*  GZipped .xyz files are common, so automagically open them */
     449                 :     /*  if the /vsigzip/ has not been explicitely passed */
     450               5 :     if (strlen(poOpenInfo->pszFilename) > 6 &&
     451                 :         EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "xyz.gz") &&
     452                 :         !EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9))
     453                 :     {
     454               0 :         osFilename = "/vsigzip/";
     455               0 :         osFilename += poOpenInfo->pszFilename;
     456                 :     }
     457                 : 
     458                 : /* -------------------------------------------------------------------- */
     459                 : /*      Find dataset characteristics                                    */
     460                 : /* -------------------------------------------------------------------- */
     461               5 :     VSILFILE* fp = VSIFOpenL(osFilename.c_str(), "rb");
     462               5 :     if (fp == NULL)
     463               0 :         return NULL;
     464                 : 
     465                 :     /* For better performance of CPLReadLine2L() we create a buffered reader */
     466                 :     /* (except for /vsigzip/ since it has one internally) */
     467               5 :     if (!EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9))
     468               5 :         fp = (VSILFILE*) VSICreateBufferedReaderHandle((VSIVirtualHandle*)fp);
     469                 :     
     470                 :     const char* pszLine;
     471               5 :     int nXIndex = -1, nYIndex = -1, nZIndex = -1;
     472               5 :     int nMinTokens = 0;
     473                 : 
     474                 : 
     475               5 :     for(i=0;i<nCommentLineCount;i++)
     476               0 :         CPLReadLine2L(fp, 100, NULL);
     477                 : 
     478                 : /* -------------------------------------------------------------------- */
     479                 : /*      Parse header line                                               */
     480                 : /* -------------------------------------------------------------------- */
     481               5 :     if (bHasHeaderLine)
     482                 :     {
     483               3 :         pszLine = CPLReadLine2L(fp, 100, NULL);
     484               3 :         if (pszLine == NULL)
     485                 :         {
     486               0 :             VSIFCloseL(fp);
     487               0 :             return NULL;
     488                 :         }
     489                 :         char** papszTokens = CSLTokenizeString2( pszLine, " ,\t;",
     490               3 :                                                  CSLT_HONOURSTRINGS );
     491               3 :         int nTokens = CSLCount(papszTokens);
     492               3 :         if (nTokens < 3)
     493                 :         {
     494                 :             CPLError(CE_Failure, CPLE_AppDefined,
     495                 :                      "At line %d, found %d tokens. Expected 3 at least",
     496               0 :                       1, nTokens);
     497               0 :             CSLDestroy(papszTokens);
     498               0 :             VSIFCloseL(fp);
     499               0 :             return NULL;
     500                 :         }
     501                 :         int i;
     502              12 :         for(i=0;i<nTokens;i++)
     503                 :         {
     504              24 :             if (EQUAL(papszTokens[i], "x") ||
     505               6 :                 EQUALN(papszTokens[i], "lon", 3) ||
     506               6 :                 EQUALN(papszTokens[i], "east", 4))
     507               3 :                 nXIndex = i;
     508              15 :             else if (EQUAL(papszTokens[i], "y") ||
     509               3 :                      EQUALN(papszTokens[i], "lat", 3) ||
     510               3 :                      EQUALN(papszTokens[i], "north", 5))
     511               3 :                 nYIndex = i;
     512               3 :             else if (EQUAL(papszTokens[i], "z") ||
     513               0 :                      EQUALN(papszTokens[i], "alt", 3) ||
     514               0 :                      EQUAL(papszTokens[i], "height"))
     515               3 :                 nZIndex = i;
     516                 :         }
     517               3 :         CSLDestroy(papszTokens);
     518               3 :         papszTokens = NULL;
     519               3 :         if (nXIndex < 0 || nYIndex < 0 || nZIndex < 0)
     520                 :         {
     521                 :             CPLError(CE_Warning, CPLE_AppDefined,
     522               0 :                      "Could not find one of the X, Y or Z column names in header line. Defaulting to the first 3 columns");
     523               0 :             nXIndex = 0;
     524               0 :             nYIndex = 1;
     525               0 :             nZIndex = 2;
     526                 :         }
     527               3 :         nMinTokens = 1 + MAX(MAX(nXIndex, nYIndex), nZIndex);
     528                 :     }
     529                 :     else
     530                 :     {
     531               2 :         nXIndex = 0;
     532               2 :         nYIndex = 1;
     533               2 :         nZIndex = 2;
     534               2 :         nMinTokens = 3;
     535                 :     }
     536                 :     
     537                 : /* -------------------------------------------------------------------- */
     538                 : /*      Parse data lines                                                */
     539                 : /* -------------------------------------------------------------------- */
     540                 : 
     541               5 :     int nXSize = 0, nYSize = 0;
     542               5 :     int nLineNum = 0;
     543               5 :     int nDataLineNum = 0;
     544               5 :     double dfFirstX = 0;
     545               5 :     double dfX = 0, dfY = 0, dfZ = 0;
     546               5 :     double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0;
     547               5 :     double dfLastX = 0, dfLastY = 0;
     548               5 :     double dfStepX = 0, dfStepY = 0;
     549               5 :     GDALDataType eDT = GDT_Byte;
     550           81624 :     while((pszLine = CPLReadLine2L(fp, 100, NULL)) != NULL)
     551                 :     {
     552           81614 :         nLineNum ++;
     553                 : 
     554           81614 :         const char* pszPtr = pszLine;
     555                 :         char ch;
     556           81614 :         int nCol = 0;
     557           81614 :         int bLastWasSep = TRUE;
     558         2799052 :         while((ch = *pszPtr) != '\0')
     559                 :         {
     560         2799040 :             if (ch == ' ' || ch == ',' || ch == '\t' || ch == ';')
     561                 :             {
     562          163216 :                 if (!bLastWasSep)
     563          163216 :                     nCol ++;
     564          163216 :                 bLastWasSep = TRUE;
     565                 :             }
     566                 :             else
     567                 :             {
     568         2472608 :                 if (bLastWasSep)
     569                 :                 {
     570          244824 :                     if (nCol == nXIndex)
     571           81608 :                         dfX = CPLAtofM(pszPtr);
     572          163216 :                     else if (nCol == nYIndex)
     573           81608 :                         dfY = CPLAtofM(pszPtr);
     574           81608 :                     else if (nCol == nZIndex && eDT != GDT_Float32)
     575                 :                     {
     576            9356 :                         dfZ = CPLAtofM(pszPtr);
     577            9356 :                         int nZ = (int)dfZ;
     578            9356 :                         if ((double)nZ != dfZ)
     579                 :                         {
     580               2 :                             eDT = GDT_Float32;
     581                 :                         }
     582            9354 :                         else if ((eDT == GDT_Byte || eDT == GDT_Int16) && (nZ < 0 || nZ > 255))
     583                 :                         {
     584               0 :                             if (nZ < -32768 || nZ > 32767)
     585               0 :                                 eDT = GDT_Int32;
     586                 :                             else
     587               0 :                                 eDT = GDT_Int16;
     588                 :                         }
     589                 :                     }
     590                 :                 }
     591         2472608 :                 bLastWasSep = FALSE;
     592                 :             }
     593         2635824 :             pszPtr ++;
     594                 :         }
     595                 :         /* skip empty lines */
     596           81614 :         if (bLastWasSep && nCol == 0)
     597                 :         {
     598               6 :             continue;
     599                 :         }
     600           81608 :         nDataLineNum ++;
     601           81608 :         nCol ++;
     602           81608 :         if (nCol < nMinTokens)
     603                 :         {
     604                 :             CPLError(CE_Failure, CPLE_AppDefined,
     605                 :                      "At line %d, found %d tokens. Expected %d at least",
     606               0 :                       nLineNum, nCol, nMinTokens);
     607               0 :             VSIFCloseL(fp);
     608               0 :             return NULL;
     609                 :         }
     610                 : 
     611           81608 :         if (nDataLineNum == 1)
     612                 :         {
     613               5 :             dfFirstX = dfMinX = dfMaxX = dfX;
     614               5 :             dfMinY = dfMaxY = dfY;
     615                 :         }
     616                 :         else
     617                 :         {
     618           81603 :             if (dfX < dfMinX) dfMinX = dfX;
     619           81603 :             if (dfX > dfMaxX) dfMaxX = dfX;
     620           81603 :             if (dfY < dfMinY) dfMinY = dfY;
     621           81603 :             if (dfY > dfMaxY) dfMaxY = dfY;
     622                 :         }
     623           81608 :         if (nDataLineNum == 2)
     624                 :         {
     625               5 :             dfStepX = dfX - dfLastX;
     626               5 :             if (dfStepX <= 0)
     627                 :             {
     628                 :                 CPLError(CE_Failure, CPLE_AppDefined,
     629                 :                          "Ungridded dataset: At line %d, X spacing was %f. Expected >0 value",
     630               0 :                          nLineNum, dfStepX);
     631               0 :                 VSIFCloseL(fp);
     632               0 :                 return NULL;
     633                 :             }
     634                 :         }
     635           81603 :         else if (nDataLineNum > 2)
     636                 :         {
     637           81598 :             double dfNewStepX = dfX - dfLastX;
     638           81598 :             double dfNewStepY = dfY - dfLastY;
     639           81598 :             if (dfNewStepY != 0)
     640                 :             {
     641             440 :                 nYSize ++;
     642             440 :                 if (dfStepY == 0)
     643                 :                 {
     644               5 :                     nXSize = nDataLineNum - 1;
     645               5 :                     double dfAdjustedStepX = (dfMaxX - dfMinX) / (nXSize - 1);
     646               5 :                     if (fabs(dfStepX - dfAdjustedStepX) > 1e-8)
     647                 :                     {
     648               0 :                         CPLDebug("XYZ", "Adjusting stepx from %f to %f", dfStepX, dfAdjustedStepX);
     649                 :                     }
     650               5 :                     dfStepX = dfAdjustedStepX;
     651                 :                 }
     652             440 :                 if (dfStepY != 0 && fabs(dfX - dfFirstX) > 1e-8)
     653                 :                 {
     654                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     655                 :                              "Ungridded dataset: At line %d, X is %f, where as %f was expected",
     656               0 :                              nLineNum, dfX, dfFirstX);
     657               0 :                     VSIFCloseL(fp);
     658               0 :                     return NULL;
     659                 :                 }
     660             440 :                 if (dfStepY != 0 && fabs(dfLastX - dfMaxX) > 1e-8)
     661                 :                 {
     662                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     663                 :                              "Ungridded dataset: At line %d, X is %f, where as %f was expected",
     664               0 :                              nLineNum - 1, dfLastX, dfMaxX);
     665               0 :                     VSIFCloseL(fp);
     666               0 :                     return NULL;
     667                 :                 }
     668                 :                 /*if (dfStepY != 0 && fabs(dfNewStepY - dfStepY) > 1e-8)
     669                 :                 {
     670                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     671                 :                              "Ungridded dataset: At line %d, Y spacing was %f, whereas it was %f before",
     672                 :                              nLineNum, dfNewStepY, dfStepY);
     673                 :                     VSIFCloseL(fp);
     674                 :                     return NULL;
     675                 :                 }*/
     676             440 :                 dfStepY = dfNewStepY;
     677                 :             }
     678                 :             else if (dfNewStepX != 0)
     679                 :             {
     680                 :                 /*if (dfStepX != 0 && fabs(dfNewStepX - dfStepX) > 1e-8)
     681                 :                 {
     682                 :                     CPLError(CE_Failure, CPLE_AppDefined,
     683                 :                              "At line %d, X spacing was %f, whereas it was %f before",
     684                 :                              nLineNum, dfNewStepX, dfStepX);
     685                 :                     VSIFCloseL(fp);
     686                 :                     return NULL;
     687                 :                 }*/
     688                 :             }
     689                 :         }
     690           81608 :         dfLastX = dfX;
     691           81608 :         dfLastY = dfY;
     692                 :     }
     693               5 :     nYSize ++;
     694                 : 
     695               5 :     if (dfStepX == 0)
     696                 :     {
     697               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine X spacing");
     698               0 :         VSIFCloseL(fp);
     699               0 :         return NULL;
     700                 :     }
     701                 : 
     702               5 :     if (dfStepY == 0)
     703                 :     {
     704               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine Y spacing");
     705               0 :         VSIFCloseL(fp);
     706               0 :         return NULL;
     707                 :     }
     708                 : 
     709               5 :     double dfAdjustedStepY = ((dfStepY < 0) ? -1 : 1) * (dfMaxY - dfMinY) / (nYSize - 1);
     710               5 :     if (fabs(dfStepY - dfAdjustedStepY) > 1e-8)
     711                 :     {
     712               0 :         CPLDebug("XYZ", "Adjusting stepy from %f to %f", dfStepY, dfAdjustedStepY);
     713                 :     }
     714               5 :     dfStepY = dfAdjustedStepY;
     715                 : 
     716                 :     //CPLDebug("XYZ", "minx=%f maxx=%f stepx=%f", dfMinX, dfMaxX, dfStepX);
     717                 :     //CPLDebug("XYZ", "miny=%f maxy=%f stepy=%f", dfMinY, dfMaxY, dfStepY);
     718                 : 
     719               5 :     if (nDataLineNum != nXSize * nYSize)
     720                 :     {
     721                 :         CPLError(CE_Failure, CPLE_AppDefined, "Found %d lines. Expected %d",
     722               0 :                  nDataLineNum,nXSize * nYSize);
     723               0 :         VSIFCloseL(fp);
     724               0 :         return NULL;
     725                 :     }
     726                 :     
     727               5 :     if (poOpenInfo->eAccess == GA_Update)
     728                 :     {
     729                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     730                 :                   "The XYZ driver does not support update access to existing"
     731               0 :                   " datasets.\n" );
     732               0 :         VSIFCloseL(fp);
     733               0 :         return NULL;
     734                 :     }
     735                 : 
     736                 : /* -------------------------------------------------------------------- */
     737                 : /*      Create a corresponding GDALDataset.                             */
     738                 : /* -------------------------------------------------------------------- */
     739                 :     XYZDataset         *poDS;
     740                 : 
     741               5 :     poDS = new XYZDataset();
     742               5 :     poDS->fp = fp;
     743               5 :     poDS->bHasHeaderLine = bHasHeaderLine;
     744               5 :     poDS->nCommentLineCount = nCommentLineCount;
     745               5 :     poDS->nXIndex = nXIndex;
     746               5 :     poDS->nYIndex = nYIndex;
     747               5 :     poDS->nZIndex = nZIndex;
     748               5 :     poDS->nMinTokens = nMinTokens;
     749               5 :     poDS->nRasterXSize = nXSize;
     750               5 :     poDS->nRasterYSize = nYSize;
     751               5 :     poDS->adfGeoTransform[0] = dfMinX - dfStepX / 2;
     752               5 :     poDS->adfGeoTransform[1] = dfStepX;
     753                 :     poDS->adfGeoTransform[3] = (dfStepY < 0) ? dfMaxY - dfStepY / 2 :
     754               9 :                                                dfMinY - dfStepY / 2;
     755               5 :     poDS->adfGeoTransform[5] = dfStepY;
     756                 : 
     757               5 :     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     758                 :     {
     759               0 :         delete poDS;
     760               0 :         return NULL;
     761                 :     }
     762                 : 
     763                 : /* -------------------------------------------------------------------- */
     764                 : /*      Create band information objects.                                */
     765                 : /* -------------------------------------------------------------------- */
     766               5 :     poDS->nBands = 1;
     767              10 :     for( i = 0; i < poDS->nBands; i++ )
     768               5 :         poDS->SetBand( i+1, new XYZRasterBand( poDS, i+1, eDT ) );
     769                 : 
     770                 : /* -------------------------------------------------------------------- */
     771                 : /*      Initialize any PAM information.                                 */
     772                 : /* -------------------------------------------------------------------- */
     773               5 :     poDS->SetDescription( poOpenInfo->pszFilename );
     774               5 :     poDS->TryLoadXML();
     775                 : 
     776                 : /* -------------------------------------------------------------------- */
     777                 : /*      Support overviews.                                              */
     778                 : /* -------------------------------------------------------------------- */
     779               5 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
     780               5 :     return( poDS );
     781                 : }
     782                 : 
     783                 : /************************************************************************/
     784                 : /*                             CreateCopy()                             */
     785                 : /************************************************************************/
     786                 : 
     787              31 : GDALDataset* XYZDataset::CreateCopy( const char * pszFilename,
     788                 :                                      GDALDataset *poSrcDS, 
     789                 :                                      int bStrict, char ** papszOptions, 
     790                 :                                      GDALProgressFunc pfnProgress,
     791                 :                                      void * pProgressData )
     792                 : {
     793                 : /* -------------------------------------------------------------------- */
     794                 : /*      Some some rudimentary checks                                    */
     795                 : /* -------------------------------------------------------------------- */
     796              31 :     int nBands = poSrcDS->GetRasterCount();
     797              31 :     if (nBands == 0)
     798                 :     {
     799                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     800               1 :                   "XYZ driver does not support source dataset with zero band.\n");
     801               1 :         return NULL;
     802                 :     }
     803                 : 
     804              30 :     if (nBands != 1)
     805                 :     {
     806                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, 
     807               4 :                   "XYZ driver only uses the first band of the dataset.\n");
     808               4 :         if (bStrict)
     809               4 :             return NULL;
     810                 :     }
     811                 : 
     812              26 :     if( pfnProgress && !pfnProgress( 0.0, NULL, pProgressData ) )
     813               0 :         return NULL;
     814                 : 
     815                 : /* -------------------------------------------------------------------- */
     816                 : /*      Get source dataset info                                         */
     817                 : /* -------------------------------------------------------------------- */
     818                 : 
     819              26 :     int nXSize = poSrcDS->GetRasterXSize();
     820              26 :     int nYSize = poSrcDS->GetRasterYSize();
     821                 :     double adfGeoTransform[6];
     822              26 :     poSrcDS->GetGeoTransform(adfGeoTransform);
     823              26 :     if (adfGeoTransform[2] != 0 || adfGeoTransform[4] != 0)
     824                 :     {
     825                 :         CPLError( CE_Failure, CPLE_NotSupported, 
     826               0 :                   "XYZ driver does not support CreateCopy() from skewed or rotated dataset.\n");
     827               0 :         return NULL;
     828                 :     }
     829                 : 
     830              26 :     GDALDataType eSrcDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
     831                 :     GDALDataType eReqDT;
     832              37 :     if (eSrcDT == GDT_Byte || eSrcDT == GDT_Int16 ||
     833                 :         eSrcDT == GDT_UInt16 || eSrcDT == GDT_Int32)
     834              11 :         eReqDT = GDT_Int32;
     835                 :     else
     836              15 :         eReqDT = GDT_Float32;
     837                 : 
     838                 : /* -------------------------------------------------------------------- */
     839                 : /*      Create target file                                              */
     840                 : /* -------------------------------------------------------------------- */
     841                 : 
     842              26 :     VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
     843              26 :     if (fp == NULL)
     844                 :     {
     845                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     846              13 :                   "Cannot create %s", pszFilename );
     847              13 :         return NULL;
     848                 :     }
     849                 : 
     850                 : /* -------------------------------------------------------------------- */
     851                 : /*      Read creation options                                           */
     852                 : /* -------------------------------------------------------------------- */
     853                 :     const char* pszColSep =
     854              13 :             CSLFetchNameValue(papszOptions, "COLUMN_SEPARATOR");
     855              13 :     if (pszColSep == NULL)
     856              12 :         pszColSep = " ";
     857               1 :     else if (EQUAL(pszColSep, "COMMA"))
     858               0 :         pszColSep = ",";
     859               1 :     else if (EQUAL(pszColSep, "SPACE"))
     860               0 :         pszColSep = " ";
     861               1 :     else if (EQUAL(pszColSep, "SEMICOLON"))
     862               0 :         pszColSep = ";";
     863               1 :     else if (EQUAL(pszColSep, "\\t") || EQUAL(pszColSep, "TAB"))
     864               0 :         pszColSep = "\t";
     865                 : 
     866                 :     const char* pszAddHeaderLine =
     867              13 :             CSLFetchNameValue(papszOptions, "ADD_HEADER_LINE");
     868              13 :     if (pszAddHeaderLine != NULL && CSLTestBoolean(pszAddHeaderLine))
     869                 :     {
     870               1 :         VSIFPrintfL(fp, "X%sY%sZ\n", pszColSep, pszColSep);
     871                 :     }
     872                 : 
     873                 : /* -------------------------------------------------------------------- */
     874                 : /*      Copy imagery                                                    */
     875                 : /* -------------------------------------------------------------------- */
     876              13 :     void* pLineBuffer = (void*) CPLMalloc(nXSize * sizeof(int));
     877                 :     int i, j;
     878              13 :     CPLErr eErr = CE_None;
     879              13 :     for(j=0;j<nYSize && eErr == CE_None;j++)
     880                 :     {
     881                 :         eErr = poSrcDS->GetRasterBand(1)->RasterIO(
     882                 :                                             GF_Read, 0, j, nXSize, 1,
     883                 :                                             pLineBuffer, nXSize, 1,
     884             331 :                                             eReqDT, 0, 0);
     885             331 :         if (eErr != CE_None)
     886               0 :             break;
     887             331 :         double dfY = adfGeoTransform[3] + (j + 0.5) * adfGeoTransform[5];
     888             331 :         CPLString osBuf;
     889           42232 :         for(i=0;i<nXSize;i++)
     890                 :         {
     891                 :             char szBuf[256];
     892           41901 :             double dfX = adfGeoTransform[0] + (i + 0.5) * adfGeoTransform[1];
     893           41901 :             if (eReqDT == GDT_Int32)
     894             800 :                 sprintf(szBuf, "%.18g%c%.18g%c%d\n", dfX, pszColSep[0], dfY, pszColSep[0], ((int*)pLineBuffer)[i]);
     895                 :             else
     896           41101 :                 sprintf(szBuf, "%.18g%c%.18g%c%.18g\n", dfX, pszColSep[0], dfY, pszColSep[0], ((float*)pLineBuffer)[i]);
     897           41901 :             osBuf += szBuf;
     898           41901 :             if( (i & 1023) == 0 || i == nXSize - 1 )
     899                 :             {
     900             662 :                 if ( VSIFWriteL( osBuf, (int)osBuf.size(), 1, fp ) != 1 )
     901                 :                 {
     902               0 :                     eErr = CE_Failure;
     903                 :                     CPLError( CE_Failure, CPLE_AppDefined, 
     904               0 :                               "Write failed, disk full?\n" );
     905               0 :                     break;
     906                 :                 }
     907             662 :                 osBuf = "";
     908                 :             }
     909                 :         }
     910             331 :         if (!pfnProgress( (j+1) * 1.0 / nYSize, NULL, pProgressData))
     911                 :         {
     912               0 :             eErr = CE_Failure;
     913                 :             break;
     914                 :         }
     915                 :     }
     916              13 :     CPLFree(pLineBuffer);
     917              13 :     VSIFCloseL(fp);
     918                 :     
     919              13 :     if (eErr != CE_None)
     920               0 :         return NULL;
     921                 : 
     922                 : /* -------------------------------------------------------------------- */
     923                 : /*      We don't want to call GDALOpen() since it will be expensive,    */
     924                 : /*      so we "hand prepare" an XYZ dataset referencing our file.       */
     925                 : /* -------------------------------------------------------------------- */
     926              13 :     XYZDataset* poXYZ_DS = new XYZDataset();
     927              13 :     poXYZ_DS->nRasterXSize = nXSize;
     928              13 :     poXYZ_DS->nRasterYSize = nYSize;
     929              13 :     poXYZ_DS->nBands = 1;
     930              26 :     poXYZ_DS->SetBand( 1, new XYZRasterBand( poXYZ_DS, 1, eReqDT ) );
     931                 :     /* If outputing to stdout, we can't reopen it --> silence warning */
     932              13 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     933              13 :     poXYZ_DS->fp = VSIFOpenL( pszFilename, "r" );
     934              13 :     CPLPopErrorHandler();
     935              13 :     memcpy( &(poXYZ_DS->adfGeoTransform), adfGeoTransform, sizeof(double)*6 );
     936              13 :     poXYZ_DS->nXIndex = 0;
     937              13 :     poXYZ_DS->nYIndex = 1;
     938              13 :     poXYZ_DS->nZIndex = 2;
     939              13 :     if( pszAddHeaderLine )
     940                 :     {
     941               1 :         poXYZ_DS->nDataLineNum = 1;
     942               1 :         poXYZ_DS->bHasHeaderLine = TRUE;
     943                 :     }
     944                 : 
     945              13 :     return poXYZ_DS;
     946                 : }
     947                 : 
     948                 : /************************************************************************/
     949                 : /*                          GetGeoTransform()                           */
     950                 : /************************************************************************/
     951                 : 
     952               1 : CPLErr XYZDataset::GetGeoTransform( double * padfTransform )
     953                 : 
     954                 : {
     955               1 :     memcpy(padfTransform, adfGeoTransform, 6 * sizeof(double));
     956                 : 
     957               1 :     return( CE_None );
     958                 : }
     959                 : 
     960                 : /************************************************************************/
     961                 : /*                         GDALRegister_XYZ()                           */
     962                 : /************************************************************************/
     963                 : 
     964             582 : void GDALRegister_XYZ()
     965                 : 
     966                 : {
     967                 :     GDALDriver  *poDriver;
     968                 : 
     969             582 :     if( GDALGetDriverByName( "XYZ" ) == NULL )
     970                 :     {
     971             561 :         poDriver = new GDALDriver();
     972                 :         
     973             561 :         poDriver->SetDescription( "XYZ" );
     974                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
     975             561 :                                    "ASCII Gridded XYZ" );
     976                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
     977             561 :                                    "frmt_xyz.html" );
     978             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xyz" );
     979                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
     980                 : "<CreationOptionList>"
     981                 : "   <Option name='COLUMN_SEPARATOR' type='string' default=' ' description='Separator between fields.'/>"
     982                 : "   <Option name='ADD_HEADER_LINE' type='boolean' default='false' description='Add an header line with column names.'/>"
     983             561 : "</CreationOptionList>");
     984                 : 
     985             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     986                 : 
     987             561 :         poDriver->pfnOpen = XYZDataset::Open;
     988             561 :         poDriver->pfnIdentify = XYZDataset::Identify;
     989             561 :         poDriver->pfnCreateCopy = XYZDataset::CreateCopy;
     990                 : 
     991             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     992                 :     }
     993             582 : }
     994                 : 

Generated by: LCOV version 1.7