GDALDataset *XYZDataset::Open( GDALOpenInfo * poOpenInfo ) { int i; int bHasHeaderLine; int nCommentLineCount = 0; if (!IdentifyEx(poOpenInfo, bHasHeaderLine, nCommentLineCount)) return NULL; CPLString osFilename(poOpenInfo->pszFilename); /* GZipped .xyz files are common, so automagically open them */ /* if the /vsigzip/ has not been explicitly passed */ if (strlen(poOpenInfo->pszFilename) > 6 && EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "xyz.gz") && !EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9)) { osFilename = "/vsigzip/"; osFilename += poOpenInfo->pszFilename; } /* -------------------------------------------------------------------- */ /* Find dataset characteristics */ /* -------------------------------------------------------------------- */ VSILFILE* fp = VSIFOpenL(osFilename.c_str(), "rb"); if (fp == NULL) return NULL; /* For better performance of CPLReadLine2L() we create a buffered reader */ /* (except for /vsigzip/ since it has one internally) */ if (!EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9)) fp = (VSILFILE*) VSICreateBufferedReaderHandle((VSIVirtualHandle*)fp); const char* pszLine; int nXIndex = -1, nYIndex = -1, nZIndex = -1; int nMinTokens = 0; for(i=0;i<nCommentLineCount;i++) CPLReadLine2L(fp, 100, NULL); /* -------------------------------------------------------------------- */ /* Parse header line */ /* -------------------------------------------------------------------- */ if (bHasHeaderLine) { pszLine = CPLReadLine2L(fp, 100, NULL); if (pszLine == NULL) { VSIFCloseL(fp); return NULL; } char** papszTokens = CSLTokenizeString2( pszLine, " ,\t;", CSLT_HONOURSTRINGS ); int nTokens = CSLCount(papszTokens); if (nTokens < 3) { CPLError(CE_Failure, CPLE_AppDefined, "At line %d, found %d tokens. Expected 3 at least", 1, nTokens); CSLDestroy(papszTokens); VSIFCloseL(fp); return NULL; } int i; for(i=0;i<nTokens;i++) { if (EQUAL(papszTokens[i], "x") || EQUALN(papszTokens[i], "lon", 3) || EQUALN(papszTokens[i], "east", 4)) nXIndex = i; else if (EQUAL(papszTokens[i], "y") || EQUALN(papszTokens[i], "lat", 3) || EQUALN(papszTokens[i], "north", 5)) nYIndex = i; else if (EQUAL(papszTokens[i], "z") || EQUALN(papszTokens[i], "alt", 3) || EQUAL(papszTokens[i], "height")) nZIndex = i; } CSLDestroy(papszTokens); papszTokens = NULL; if (nXIndex < 0 || nYIndex < 0 || nZIndex < 0) { CPLError(CE_Warning, CPLE_AppDefined, "Could not find one of the X, Y or Z column names in header line. Defaulting to the first 3 columns"); nXIndex = 0; nYIndex = 1; nZIndex = 2; } nMinTokens = 1 + MAX(MAX(nXIndex, nYIndex), nZIndex); } else { nXIndex = 0; nYIndex = 1; nZIndex = 2; nMinTokens = 3; } /* -------------------------------------------------------------------- */ /* Parse data lines */ /* -------------------------------------------------------------------- */ int nLineNum = 0; int nDataLineNum = 0; double dfX = 0, dfY = 0, dfZ = 0; double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0; double dfMinZ = 0, dfMaxZ = 0; double dfLastX = 0, dfLastY = 0; std::vector<double> adfStepX, adfStepY; GDALDataType eDT = GDT_Byte; int bSameNumberOfValuesPerLine = TRUE; char chDecimalSep = '\0'; int bStepYSign = 0; while((pszLine = CPLReadLine2L(fp, 100, NULL)) != NULL) { nLineNum ++; const char* pszPtr = pszLine; char ch; int nCol = 0; int bLastWasSep = TRUE; if( chDecimalSep == '\0' ) { int nCountComma = 0; int nCountFieldSep = 0; while((ch = *pszPtr) != '\0') { if( ch == '.' ) { chDecimalSep = '.'; break; } else if( ch == ',' ) { nCountComma ++; bLastWasSep = FALSE; } else if( ch == ' ' ) { if (!bLastWasSep) nCountFieldSep ++; bLastWasSep = TRUE; } else if( ch == '\t' || ch == ';' ) { nCountFieldSep ++; bLastWasSep = TRUE; } else bLastWasSep = FALSE; pszPtr ++; } if( chDecimalSep == '\0' ) { /* 1,2,3 */ if( nCountComma >= 2 && nCountFieldSep == 0 ) chDecimalSep = '.'; /* 23,5;33;45 */ else if ( nCountComma > 0 && nCountFieldSep > 0 ) chDecimalSep = ','; } pszPtr = pszLine; bLastWasSep = TRUE; } char chLocalDecimalSep = chDecimalSep ? chDecimalSep : '.'; while((ch = *pszPtr) != '\0') { if (ch == ' ') { if (!bLastWasSep) nCol ++; bLastWasSep = TRUE; } else if ((ch == ',' && chLocalDecimalSep != ',') || ch == '\t' || ch == ';') { nCol ++; bLastWasSep = TRUE; } else { if (bLastWasSep) { if (nCol == nXIndex) dfX = CPLAtofDelim(pszPtr, chLocalDecimalSep); else if (nCol == nYIndex) dfY = CPLAtofDelim(pszPtr, chLocalDecimalSep); else if (nCol == nZIndex) { dfZ = CPLAtofDelim(pszPtr, chLocalDecimalSep); if( nDataLineNum == 0 ) dfMinZ = dfMaxZ = dfZ; else if( dfZ < dfMinZ ) dfMinZ = dfZ; else if( dfZ > dfMaxZ ) dfMaxZ = dfZ; int nZ = (int)dfZ; if ((double)nZ != dfZ) { eDT = GDT_Float32; } else if ((eDT == GDT_Byte || eDT == GDT_Int16) && (nZ < 0 || nZ > 255)) { if (nZ < -32768 || nZ > 32767) eDT = GDT_Int32; else eDT = GDT_Int16; } } } bLastWasSep = FALSE; } pszPtr ++; } /* skip empty lines */ if (bLastWasSep && nCol == 0) { continue; } nDataLineNum ++; nCol ++; if (nCol < nMinTokens) { CPLError(CE_Failure, CPLE_AppDefined, "At line %d, found %d tokens. Expected %d at least", nLineNum, nCol, nMinTokens); VSIFCloseL(fp); return NULL; } if (nDataLineNum == 1) { dfMinX = dfMaxX = dfX; dfMinY = dfMaxY = dfY; } else { double dfStepY = dfY - dfLastY; if( dfStepY == 0.0 ) { double dfStepX = dfX - dfLastX; if( dfStepX <= 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line %d, X spacing was %f. Expected >0 value", nLineNum, dfStepX); VSIFCloseL(fp); return NULL; } if( std::find(adfStepX.begin(), adfStepX.end(), dfStepX) == adfStepX.end() ) { int bAddNewValue = TRUE; std::vector<double>::iterator oIter = adfStepX.begin(); while( oIter != adfStepX.end() ) { if( dfStepX < *oIter && fmod( *oIter, dfStepX ) < 1e-8 ) { adfStepX.erase(oIter); } else if( dfStepX > *oIter && fmod( dfStepX, *oIter ) < 1e-8 ) { bAddNewValue = FALSE; break; } else { ++ oIter; } } if( bAddNewValue ) { adfStepX.push_back(dfStepX); if( adfStepX.size() == 10 ) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: too many stepX values"); VSIFCloseL(fp); return NULL; } } } } else { int bNewStepYSign = (dfStepY < 0.0) ? -1 : 1; if( bStepYSign == 0 ) bStepYSign = bNewStepYSign; else if( bStepYSign != bNewStepYSign ) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line %d, change of Y direction", nLineNum); VSIFCloseL(fp); return NULL; } if( bNewStepYSign < 0 ) dfStepY = -dfStepY; if( adfStepY.size() == 0 ) adfStepY.push_back(dfStepY); else if( adfStepY[0] != dfStepY ) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line %d, too many stepY values", nLineNum); VSIFCloseL(fp); return NULL; } } if (dfX < dfMinX) dfMinX = dfX; if (dfX > dfMaxX) dfMaxX = dfX; if (dfY < dfMinY) dfMinY = dfY; if (dfY > dfMaxY) dfMaxY = dfY; } dfLastX = dfX; dfLastY = dfY; } if (adfStepX.size() != 1) { CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine X spacing"); VSIFCloseL(fp); return NULL; } if (adfStepY.size() != 1) { CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine Y spacing"); VSIFCloseL(fp); return NULL; } double dfStepX = adfStepX[0]; double dfStepY = adfStepY[0] * bStepYSign; int nXSize = 1 + int((dfMaxX - dfMinX) / dfStepX + 0.5); int nYSize = 1 + int((dfMaxY - dfMinY) / fabs(dfStepY) + 0.5); //CPLDebug("XYZ", "minx=%f maxx=%f stepx=%f", dfMinX, dfMaxX, dfStepX); //CPLDebug("XYZ", "miny=%f maxy=%f stepy=%f", dfMinY, dfMaxY, dfStepY); if (nDataLineNum != nXSize * nYSize) { bSameNumberOfValuesPerLine = FALSE; } if (poOpenInfo->eAccess == GA_Update) { CPLError( CE_Failure, CPLE_NotSupported, "The XYZ driver does not support update access to existing" " datasets.\n" ); VSIFCloseL(fp); return NULL; } /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ XYZDataset *poDS; poDS = new XYZDataset(); poDS->fp = fp; poDS->bHasHeaderLine = bHasHeaderLine; poDS->nCommentLineCount = nCommentLineCount; poDS->chDecimalSep = chDecimalSep ? chDecimalSep : '.'; poDS->nXIndex = nXIndex; poDS->nYIndex = nYIndex; poDS->nZIndex = nZIndex; poDS->nMinTokens = nMinTokens; poDS->nRasterXSize = nXSize; poDS->nRasterYSize = nYSize; poDS->adfGeoTransform[0] = dfMinX - dfStepX / 2; poDS->adfGeoTransform[1] = dfStepX; poDS->adfGeoTransform[3] = (dfStepY < 0) ? dfMaxY - dfStepY / 2 : dfMinY - dfStepY / 2; poDS->adfGeoTransform[5] = dfStepY; poDS->bSameNumberOfValuesPerLine = bSameNumberOfValuesPerLine; poDS->dfMinZ = dfMinZ; poDS->dfMaxZ = dfMaxZ; //CPLDebug("XYZ", "bSameNumberOfValuesPerLine = %d", bSameNumberOfValuesPerLine); if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize)) { delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ poDS->nBands = 1; for( i = 0; i < poDS->nBands; i++ ) poDS->SetBand( i+1, new XYZRasterBand( poDS, i+1, eDT ) ); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Support overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return( poDS ); }
GDALDataset *XYZDataset::Open( GDALOpenInfo * poOpenInfo ) { int bHasHeaderLine; int nCommentLineCount = 0; if (!IdentifyEx(poOpenInfo, bHasHeaderLine, nCommentLineCount)) return NULL; CPLString osFilename(poOpenInfo->pszFilename); /* GZipped .xyz files are common, so automagically open them */ /* if the /vsigzip/ has not been explicitly passed */ if (strlen(poOpenInfo->pszFilename) > 6 && EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "xyz.gz") && !STARTS_WITH_CI(poOpenInfo->pszFilename, "/vsigzip/")) { osFilename = "/vsigzip/"; osFilename += poOpenInfo->pszFilename; } /* -------------------------------------------------------------------- */ /* Find dataset characteristics */ /* -------------------------------------------------------------------- */ VSILFILE* fp = VSIFOpenL(osFilename.c_str(), "rb"); if (fp == NULL) return NULL; /* For better performance of CPLReadLine2L() we create a buffered reader */ /* (except for /vsigzip/ since it has one internally) */ if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "/vsigzip/")) fp = reinterpret_cast<VSILFILE *>( VSICreateBufferedReaderHandle( reinterpret_cast<VSIVirtualHandle *>( fp ) ) ); int nXIndex = -1; int nYIndex = -1; int nZIndex = -1; int nMinTokens = 0; for( int i = 0; i < nCommentLineCount; i++ ) { if( CPLReadLine2L(fp, 100, NULL) == NULL ) { VSIFCloseL(fp); return NULL; } } /* -------------------------------------------------------------------- */ /* Parse header line */ /* -------------------------------------------------------------------- */ if (bHasHeaderLine) { const char* pszLine = CPLReadLine2L(fp, 100, NULL); if (pszLine == NULL) { VSIFCloseL(fp); return NULL; } char** papszTokens = CSLTokenizeString2( pszLine, " ,\t;", CSLT_HONOURSTRINGS ); int nTokens = CSLCount(papszTokens); if (nTokens < 3) { CPLError(CE_Failure, CPLE_AppDefined, "At line %d, found %d tokens. Expected 3 at least", 1, nTokens); CSLDestroy(papszTokens); VSIFCloseL(fp); return NULL; } for( int i = 0; i < nTokens; i++ ) { if (EQUAL(papszTokens[i], "x") || STARTS_WITH_CI(papszTokens[i], "lon") || STARTS_WITH_CI(papszTokens[i], "east")) nXIndex = i; else if (EQUAL(papszTokens[i], "y") || STARTS_WITH_CI(papszTokens[i], "lat") || STARTS_WITH_CI(papszTokens[i], "north")) nYIndex = i; else if (EQUAL(papszTokens[i], "z") || STARTS_WITH_CI(papszTokens[i], "alt") || EQUAL(papszTokens[i], "height")) nZIndex = i; } CSLDestroy(papszTokens); papszTokens = NULL; if (nXIndex < 0 || nYIndex < 0 || nZIndex < 0) { CPLError(CE_Warning, CPLE_AppDefined, "Could not find one of the X, Y or Z column names in header line. Defaulting to the first 3 columns"); nXIndex = 0; nYIndex = 1; nZIndex = 2; } nMinTokens = 1 + std::max(std::max(nXIndex, nYIndex), nZIndex); } else { nXIndex = 0; nYIndex = 1; nZIndex = 2; nMinTokens = 3; } /* -------------------------------------------------------------------- */ /* Parse data lines */ /* -------------------------------------------------------------------- */ GIntBig nLineNum = 0; GIntBig nDataLineNum = 0; double dfX = 0.0; double dfY = 0.0; double dfZ = 0.0; double dfMinX = 0.0; double dfMinY = 0.0; double dfMaxX = 0.0; double dfMaxY = 0.0; double dfMinZ = 0.0; double dfMaxZ = 0.0; double dfLastX = 0.0; double dfLastY = 0.0; std::vector<double> adfStepX; std::vector<double> adfStepY; GDALDataType eDT = GDT_Byte; bool bSameNumberOfValuesPerLine = true; char chDecimalSep = '\0'; int bStepYSign = 0; const char* pszLine; GIntBig nCountStepX = 0; GIntBig nCountStepY = 0; while((pszLine = CPLReadLine2L(fp, 100, NULL)) != NULL) { nLineNum ++; const char* pszPtr = pszLine; char ch; int nCol = 0; bool bLastWasSep = true; if( chDecimalSep == '\0' ) { int nCountComma = 0; int nCountFieldSep = 0; while((ch = *pszPtr) != '\0') { if( ch == '.' ) { chDecimalSep = '.'; break; } else if( ch == ',' ) { nCountComma ++; bLastWasSep = false; } else if( ch == ' ' ) { if (!bLastWasSep) nCountFieldSep ++; bLastWasSep = true; } else if( ch == '\t' || ch == ';' ) { nCountFieldSep ++; bLastWasSep = true; } else bLastWasSep = false; pszPtr ++; } if( chDecimalSep == '\0' ) { /* 1,2,3 */ if( nCountComma >= 2 && nCountFieldSep == 0 ) chDecimalSep = '.'; /* 23,5;33;45 */ else if ( nCountComma > 0 && nCountFieldSep > 0 ) chDecimalSep = ','; } pszPtr = pszLine; bLastWasSep = true; } char chLocalDecimalSep = chDecimalSep ? chDecimalSep : '.'; int nUsefulColsFound = 0; while((ch = *pszPtr) != '\0') { if (ch == ' ') { if (!bLastWasSep) nCol ++; bLastWasSep = true; } else if ((ch == ',' && chLocalDecimalSep != ',') || ch == '\t' || ch == ';') { nCol ++; bLastWasSep = true; } else { if (bLastWasSep) { if (nCol == nXIndex) { nUsefulColsFound ++; dfX = CPLAtofDelim(pszPtr, chLocalDecimalSep); } else if (nCol == nYIndex) { nUsefulColsFound ++; dfY = CPLAtofDelim(pszPtr, chLocalDecimalSep); } else if (nCol == nZIndex) { nUsefulColsFound ++; dfZ = CPLAtofDelim(pszPtr, chLocalDecimalSep); if( nDataLineNum == 0 ) { dfMinZ = dfZ; dfMaxZ = dfZ; } else if( dfZ < dfMinZ ) { dfMinZ = dfZ; } else if( dfZ > dfMaxZ ) { dfMaxZ = dfZ; } if( dfZ < INT_MIN || dfZ > INT_MAX ) { eDT = GDT_Float32; } else { int nZ = static_cast<int>( dfZ ); if( static_cast<double>( nZ ) != dfZ ) { eDT = GDT_Float32; } else if ((eDT == GDT_Byte || eDT == GDT_Int16) && (nZ < 0 || nZ > 255)) { if (nZ < -32768 || nZ > 32767) eDT = GDT_Int32; else eDT = GDT_Int16; } } } } bLastWasSep = false; } pszPtr ++; } /* skip empty lines */ if (bLastWasSep && nCol == 0) { continue; } nDataLineNum ++; nCol ++; if (nCol < nMinTokens) { CPLError(CE_Failure, CPLE_AppDefined, "At line " CPL_FRMT_GIB ", found %d tokens. Expected %d at least", nLineNum, nCol, nMinTokens); VSIFCloseL(fp); return NULL; } if( nUsefulColsFound != 3 ) { CPLError(CE_Failure, CPLE_AppDefined, "At line " CPL_FRMT_GIB ", did not find X, Y and/or Z values", nLineNum); VSIFCloseL(fp); return NULL; } if (nDataLineNum == 1) { dfMinX = dfX; dfMaxX = dfX; dfMinY = dfY; dfMaxY = dfY; } else { double dfStepY = dfY - dfLastY; if( dfStepY == 0.0 ) { const double dfStepX = dfX - dfLastX; if( dfStepX <= 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line " CPL_FRMT_GIB ", X spacing was %f. Expected >0 value", nLineNum, dfStepX); VSIFCloseL(fp); return NULL; } if( std::find(adfStepX.begin(), adfStepX.end(), dfStepX) == adfStepX.end() ) { bool bAddNewValue = true; std::vector<double>::iterator oIter = adfStepX.begin(); std::vector<double> adfStepXNew; while( oIter != adfStepX.end() ) { if( fabs(( dfStepX - *oIter ) / dfStepX ) < RELATIVE_ERROR ) { double dfNewVal = *oIter; if( nCountStepX > 0 ) { // Update mean step /* n * mean(n) = (n-1) * mean(n-1) + val(n) mean(n) = mean(n-1) + (val(n) - mean(n-1)) / n */ nCountStepX ++; dfNewVal += ( dfStepX - *oIter ) / nCountStepX; } adfStepXNew.push_back( dfNewVal ); bAddNewValue = false; break; } else if( dfStepX < *oIter && fabs(*oIter - static_cast<int>(*oIter / dfStepX + 0.5) * dfStepX) / dfStepX < RELATIVE_ERROR ) { nCountStepX = -1; // disable update of mean ++ oIter; } else if( dfStepX > *oIter && fabs(dfStepX - static_cast<int>(dfStepX / *oIter + 0.5) * (*oIter)) / dfStepX < RELATIVE_ERROR ) { nCountStepX = -1; // disable update of mean bAddNewValue = false; adfStepXNew.push_back( *oIter ); break; } else { adfStepXNew.push_back( *oIter ); ++ oIter; } } adfStepX = adfStepXNew; if( bAddNewValue ) { CPLDebug("XYZ", "New stepX=%.15f", dfStepX); adfStepX.push_back(dfStepX); if( adfStepX.size() == 1 && nCountStepX == 0) { nCountStepX ++; } else if( adfStepX.size() == 2 ) { nCountStepX = -1; // disable update of mean } else if( adfStepX.size() == 10 ) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: too many stepX values"); VSIFCloseL(fp); return NULL; } } } } else { int bNewStepYSign = (dfStepY < 0.0) ? -1 : 1; if( bStepYSign == 0 ) bStepYSign = bNewStepYSign; else if( bStepYSign != bNewStepYSign ) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line " CPL_FRMT_GIB ", change of Y direction", nLineNum); VSIFCloseL(fp); return NULL; } if( bNewStepYSign < 0 ) dfStepY = -dfStepY; nCountStepY ++; if( adfStepY.empty() ) { adfStepY.push_back(dfStepY); } else if( fabs( (adfStepY[0] - dfStepY) / dfStepY ) > RELATIVE_ERROR ) { CPLDebug("XYZ", "New stepY=%.15f prev stepY=%.15f", dfStepY, adfStepY[0]); CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line " CPL_FRMT_GIB ", too many stepY values", nLineNum); VSIFCloseL(fp); return NULL; } else { // Update mean step adfStepY[0] += ( dfStepY - adfStepY[0] ) / nCountStepY; } } if (dfX < dfMinX) dfMinX = dfX; if (dfX > dfMaxX) dfMaxX = dfX; if (dfY < dfMinY) dfMinY = dfY; if (dfY > dfMaxY) dfMaxY = dfY; } dfLastX = dfX; dfLastY = dfY; } if (adfStepX.size() != 1) { CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine X spacing"); VSIFCloseL(fp); return NULL; } if (adfStepY.size() != 1) { CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine Y spacing"); VSIFCloseL(fp); return NULL; } const double dfXSize = 1 + ((dfMaxX - dfMinX) / adfStepX[0] + 0.5); const double dfYSize = 1 + ((dfMaxY - dfMinY) / adfStepY[0] + 0.5); if( dfXSize <= 0 || dfXSize > INT_MAX || dfYSize <= 0 || dfYSize > INT_MAX ) { CPLError(CE_Failure, CPLE_AppDefined, "Invalid dimensions"); VSIFCloseL(fp); return NULL; } const int nXSize = static_cast<int>(dfXSize); const int nYSize = static_cast<int>(dfYSize); const double dfStepX = (dfMaxX - dfMinX) / (nXSize - 1); const double dfStepY = (dfMaxY - dfMinY) / (nYSize - 1)* bStepYSign; #ifdef DEBUG_VERBOSE CPLDebug("XYZ", "minx=%f maxx=%f stepx=%f", dfMinX, dfMaxX, dfStepX); CPLDebug("XYZ", "miny=%f maxy=%f stepy=%f", dfMinY, dfMaxY, dfStepY); #endif if (nDataLineNum != static_cast<GIntBig>(nXSize) * nYSize) { bSameNumberOfValuesPerLine = false; } if (poOpenInfo->eAccess == GA_Update) { CPLError( CE_Failure, CPLE_NotSupported, "The XYZ driver does not support update access to existing" " datasets.\n" ); VSIFCloseL(fp); return NULL; } /* -------------------------------------------------------------------- */ /* Create a corresponding GDALDataset. */ /* -------------------------------------------------------------------- */ XYZDataset *poDS = new XYZDataset(); poDS->fp = fp; poDS->bHasHeaderLine = bHasHeaderLine; poDS->nCommentLineCount = nCommentLineCount; poDS->chDecimalSep = chDecimalSep ? chDecimalSep : '.'; poDS->nXIndex = nXIndex; poDS->nYIndex = nYIndex; poDS->nZIndex = nZIndex; poDS->nMinTokens = nMinTokens; poDS->nRasterXSize = nXSize; poDS->nRasterYSize = nYSize; poDS->adfGeoTransform[0] = dfMinX - dfStepX / 2; poDS->adfGeoTransform[1] = dfStepX; poDS->adfGeoTransform[3] = (dfStepY < 0) ? dfMaxY - dfStepY / 2 : dfMinY - dfStepY / 2; poDS->adfGeoTransform[5] = dfStepY; poDS->bSameNumberOfValuesPerLine = bSameNumberOfValuesPerLine; poDS->dfMinZ = dfMinZ; poDS->dfMaxZ = dfMaxZ; #ifdef DEBUG_VERBOSE CPLDebug( "XYZ", "bSameNumberOfValuesPerLine = %d", bSameNumberOfValuesPerLine ); #endif if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize)) { delete poDS; return NULL; } /* -------------------------------------------------------------------- */ /* Create band information objects. */ /* -------------------------------------------------------------------- */ poDS->nBands = 1; for( int i = 0; i < poDS->nBands; i++ ) poDS->SetBand( i+1, new XYZRasterBand( poDS, i+1, eDT ) ); /* -------------------------------------------------------------------- */ /* Initialize any PAM information. */ /* -------------------------------------------------------------------- */ poDS->SetDescription( poOpenInfo->pszFilename ); poDS->TryLoadXML(); /* -------------------------------------------------------------------- */ /* Support overviews. */ /* -------------------------------------------------------------------- */ poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); return poDS; }
CPLErr XYZRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff, void * pImage ) { XYZDataset *poGDS = (XYZDataset *) poDS; if (poGDS->fp == NULL) return CE_Failure; if( pImage ) { int bSuccess = FALSE; double dfNoDataValue = GetNoDataValue(&bSuccess); if( !bSuccess ) dfNoDataValue = 0.0; GDALCopyWords(&dfNoDataValue, GDT_Float64, 0, pImage, eDataType, GDALGetDataTypeSize(eDataType) / 8, nRasterXSize); } int nLineInFile = nBlockYOff * nBlockXSize; // only valid if bSameNumberOfValuesPerLine if ( (poGDS->bSameNumberOfValuesPerLine && poGDS->nDataLineNum > nLineInFile) || (!poGDS->bSameNumberOfValuesPerLine && (nLastYOff == -1 || nBlockYOff == 0)) ) { poGDS->nDataLineNum = 0; poGDS->nLineNum = 0; VSIFSeekL(poGDS->fp, 0, SEEK_SET); for(int i=0;i<poGDS->nCommentLineCount;i++) { CPLReadLine2L(poGDS->fp, 100, NULL); poGDS->nLineNum ++; } if (poGDS->bHasHeaderLine) { const char* pszLine = CPLReadLine2L(poGDS->fp, 100, 0); if (pszLine == NULL) return CE_Failure; poGDS->nLineNum ++; } } if( !poGDS->bSameNumberOfValuesPerLine && nBlockYOff != nLastYOff + 1 ) { int iY; if( nBlockYOff < nLastYOff ) { nLastYOff = -1; for(iY = 0; iY < nBlockYOff; iY++) { if( IReadBlock(0, iY, NULL) != CE_None ) return CE_Failure; } } else { for(iY = nLastYOff + 1; iY < nBlockYOff; iY++) { if( IReadBlock(0, iY, NULL) != CE_None ) return CE_Failure; } } } else if( poGDS->bSameNumberOfValuesPerLine ) { while(poGDS->nDataLineNum < nLineInFile) { const char* pszLine = CPLReadLine2L(poGDS->fp, 100, 0); if (pszLine == NULL) return CE_Failure; poGDS->nLineNum ++; const char* pszPtr = pszLine; char ch; int nCol = 0; int bLastWasSep = TRUE; while((ch = *pszPtr) != '\0') { if (ch == ' ') { if (!bLastWasSep) nCol ++; bLastWasSep = TRUE; } else if ((ch == ',' && poGDS->chDecimalSep != ',') || ch == '\t' || ch == ';') { nCol ++; bLastWasSep = TRUE; } else { bLastWasSep = FALSE; } pszPtr ++; } /* Skip empty line */ if (nCol == 0 && bLastWasSep) continue; poGDS->nDataLineNum ++; } } double dfExpectedY = poGDS->adfGeoTransform[3] + (0.5 + nBlockYOff) * poGDS->adfGeoTransform[5]; int idx = -1; while(TRUE) { int nCol; int bLastWasSep; do { vsi_l_offset nOffsetBefore = VSIFTellL(poGDS->fp); const char* pszLine = CPLReadLine2L(poGDS->fp, 100, 0); if (pszLine == NULL) { if( poGDS->bSameNumberOfValuesPerLine ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot read line %d", poGDS->nLineNum + 1); return CE_Failure; } else { nLastYOff = nBlockYOff; return CE_None; } } poGDS->nLineNum ++; const char* pszPtr = pszLine; char ch; nCol = 0; bLastWasSep = TRUE; double dfX = 0.0, dfY = 0.0, dfZ = 0.0; int bUsefulColsFound = 0; while((ch = *pszPtr) != '\0') { if (ch == ' ') { if (!bLastWasSep) nCol ++; bLastWasSep = TRUE; } else if ((ch == ',' && poGDS->chDecimalSep != ',') || ch == '\t' || ch == ';') { nCol ++; bLastWasSep = TRUE; } else { if (bLastWasSep) { if (nCol == poGDS->nXIndex) { bUsefulColsFound ++; if( !poGDS->bSameNumberOfValuesPerLine ) dfX = CPLAtofDelim(pszPtr, poGDS->chDecimalSep); } else if (nCol == poGDS->nYIndex) { bUsefulColsFound ++; if( !poGDS->bSameNumberOfValuesPerLine ) dfY = CPLAtofDelim(pszPtr, poGDS->chDecimalSep); } else if( nCol == poGDS->nZIndex) { bUsefulColsFound ++; dfZ = CPLAtofDelim(pszPtr, poGDS->chDecimalSep); } } bLastWasSep = FALSE; } pszPtr ++; } nCol ++; if( bUsefulColsFound == 3 ) { if( poGDS->bSameNumberOfValuesPerLine ) { idx ++; } else { if( fabs(dfY - dfExpectedY) > 1e-8 ) { if( idx < 0 ) { CPLError(CE_Failure, CPLE_AppDefined, "At line %d, found %f instead of %f for nBlockYOff = %d", poGDS->nLineNum, dfY, dfExpectedY, nBlockYOff); return CE_Failure; } VSIFSeekL(poGDS->fp, nOffsetBefore, SEEK_SET); nLastYOff = nBlockYOff; poGDS->nLineNum --; return CE_None; } idx = (int)((dfX - 0.5 * poGDS->adfGeoTransform[1] - poGDS->adfGeoTransform[0]) / poGDS->adfGeoTransform[1] + 0.5); } CPLAssert(idx >= 0 && idx < nRasterXSize); if( pImage ) { if (eDataType == GDT_Float32) { ((float*)pImage)[idx] = (float)dfZ; } else if (eDataType == GDT_Int32) { ((GInt32*)pImage)[idx] = (GInt32)dfZ; } else if (eDataType == GDT_Int16) { ((GInt16*)pImage)[idx] = (GInt16)dfZ; } else { ((GByte*)pImage)[idx] = (GByte)dfZ; } } } /* Skip empty line */ } while (nCol == 1 && bLastWasSep); poGDS->nDataLineNum ++; if (nCol < poGDS->nMinTokens) return CE_Failure; if( idx + 1 == nRasterXSize ) break; } if( poGDS->bSameNumberOfValuesPerLine ) { CPLAssert(poGDS->nDataLineNum == (nBlockYOff + 1) * nBlockXSize); } nLastYOff = nBlockYOff; return CE_None; }
CPLErr XYZRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff, void * pImage ) { XYZDataset *poGDS = reinterpret_cast<XYZDataset *>( poDS ); if (poGDS->fp == NULL) return CE_Failure; if( pImage ) { int bSuccess = FALSE; double dfNoDataValue = GetNoDataValue(&bSuccess); if( !bSuccess ) dfNoDataValue = 0.0; GDALCopyWords(&dfNoDataValue, GDT_Float64, 0, pImage, eDataType, GDALGetDataTypeSize(eDataType) / 8, nRasterXSize); } // Only valid if bSameNumberOfValuesPerLine. const GIntBig nLineInFile = static_cast<GIntBig>(nBlockYOff) * nBlockXSize; if ( (poGDS->bSameNumberOfValuesPerLine && poGDS->nDataLineNum > nLineInFile) || (!poGDS->bSameNumberOfValuesPerLine && (nLastYOff == -1 || nBlockYOff == 0)) ) { poGDS->nDataLineNum = 0; poGDS->nLineNum = 0; poGDS->bEOF = false; VSIFSeekL(poGDS->fp, 0, SEEK_SET); for(int i=0;i<poGDS->nCommentLineCount;i++) { if( CPLReadLine2L(poGDS->fp, 100, NULL) == NULL ) { poGDS->bEOF = true; return CE_Failure; } poGDS->nLineNum ++; } if (poGDS->bHasHeaderLine) { const char* pszLine = CPLReadLine2L(poGDS->fp, 100, NULL); if (pszLine == NULL) { poGDS->bEOF = true; return CE_Failure; } poGDS->nLineNum ++; } } if( !poGDS->bSameNumberOfValuesPerLine ) { if( nBlockYOff < nLastYOff ) { nLastYOff = -1; for( int iY = 0; iY < nBlockYOff; iY++ ) { if( IReadBlock(0, iY, NULL) != CE_None ) return CE_Failure; } } else { if( poGDS->bEOF ) { return CE_Failure; } for( int iY = nLastYOff + 1; iY < nBlockYOff; iY++ ) { if( IReadBlock(0, iY, NULL) != CE_None ) return CE_Failure; } } } else { if( poGDS->bEOF ) { return CE_Failure; } while(poGDS->nDataLineNum < nLineInFile) { const char* pszLine = CPLReadLine2L(poGDS->fp, 100, NULL); if (pszLine == NULL) { poGDS->bEOF = true; return CE_Failure; } poGDS->nLineNum ++; const char* pszPtr = pszLine; char ch; int nCol = 0; bool bLastWasSep = true; while((ch = *pszPtr) != '\0') { if (ch == ' ') { if (!bLastWasSep) nCol ++; bLastWasSep = true; } else if ((ch == ',' && poGDS->chDecimalSep != ',') || ch == '\t' || ch == ';') { nCol ++; bLastWasSep = true; } else { bLastWasSep = false; } pszPtr ++; } /* Skip empty line */ if (nCol == 0 && bLastWasSep) continue; poGDS->nDataLineNum ++; } } const double dfExpectedY = poGDS->adfGeoTransform[3] + (0.5 + nBlockYOff) * poGDS->adfGeoTransform[5]; int idx = -1; while(true) { int nCol; bool bLastWasSep; do { const vsi_l_offset nOffsetBefore = VSIFTellL(poGDS->fp); const char* pszLine = CPLReadLine2L(poGDS->fp, 100, NULL); if (pszLine == NULL) { poGDS->bEOF = true; if( poGDS->bSameNumberOfValuesPerLine ) { CPLError(CE_Failure, CPLE_AppDefined, "Cannot read line " CPL_FRMT_GIB, poGDS->nLineNum + 1); return CE_Failure; } else { nLastYOff = nBlockYOff; return CE_None; } } poGDS->nLineNum ++; const char* pszPtr = pszLine; char ch; nCol = 0; bLastWasSep = true; double dfX = 0.0; double dfY = 0.0; double dfZ = 0.0; int nUsefulColsFound = 0; while((ch = *pszPtr) != '\0') { if (ch == ' ') { if (!bLastWasSep) nCol ++; bLastWasSep = true; } else if ( ( ch == ',' && poGDS->chDecimalSep != ',' ) || ch == '\t' || ch == ';' ) { nCol ++; bLastWasSep = true; } else { if (bLastWasSep) { if (nCol == poGDS->nXIndex) { nUsefulColsFound ++; if( !poGDS->bSameNumberOfValuesPerLine ) dfX = CPLAtofDelim(pszPtr, poGDS->chDecimalSep); } else if (nCol == poGDS->nYIndex) { nUsefulColsFound ++; if( !poGDS->bSameNumberOfValuesPerLine ) dfY = CPLAtofDelim(pszPtr, poGDS->chDecimalSep); } else if( nCol == poGDS->nZIndex) { nUsefulColsFound ++; dfZ = CPLAtofDelim(pszPtr, poGDS->chDecimalSep); } } bLastWasSep = false; } pszPtr ++; } nCol ++; if( nUsefulColsFound == 3 ) { if( poGDS->bSameNumberOfValuesPerLine ) { idx ++; } else { if( fabs( (dfY - dfExpectedY) / poGDS->adfGeoTransform[5] ) > RELATIVE_ERROR ) { if( idx < 0 ) { CPLError( CE_Failure, CPLE_AppDefined, "At line " CPL_FRMT_GIB", found %f instead of %f " "for nBlockYOff = %d", poGDS->nLineNum, dfY, dfExpectedY, nBlockYOff); return CE_Failure; } VSIFSeekL(poGDS->fp, nOffsetBefore, SEEK_SET); nLastYOff = nBlockYOff; poGDS->nLineNum --; return CE_None; } idx = static_cast<int>( ( dfX - 0.5 * poGDS->adfGeoTransform[1] - poGDS->adfGeoTransform[0] ) / poGDS->adfGeoTransform[1] + 0.5 ); } CPLAssert(idx >= 0 && idx < nRasterXSize); if( pImage ) { if (eDataType == GDT_Float32) { reinterpret_cast<float *>( pImage )[idx] = static_cast<float>(dfZ); } else if (eDataType == GDT_Int32) { reinterpret_cast<GInt32 *>( pImage )[idx] = static_cast<GInt32>( dfZ ); } else if (eDataType == GDT_Int16) { reinterpret_cast<GInt16 *>( pImage )[idx] = static_cast<GInt16>( dfZ ); } else { reinterpret_cast<GByte *>( pImage )[idx] = static_cast<GByte>( dfZ ); } } } /* Skip empty line */ } while (nCol == 1 && bLastWasSep); poGDS->nDataLineNum ++; if (nCol < poGDS->nMinTokens) return CE_Failure; if( idx + 1 == nRasterXSize ) break; } if( poGDS->bSameNumberOfValuesPerLine ) { if( poGDS->nDataLineNum != static_cast<GIntBig>(nBlockYOff + 1) * nBlockXSize ) { CPLError(CE_Failure, CPLE_AssertionFailed, "The file has not the same number of values per " "line as initialy thought. It must be somehow corrupted"); return CE_Failure; } } nLastYOff = nBlockYOff; return CE_None; }