PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/gdal-1.9.1-fedora/frmts/xyz/xyzdataset.cpp

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