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 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 explicitely 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 nXSize = 0, nYSize = 0; int nLineNum = 0; int nDataLineNum = 0; double dfFirstX = 0; double dfX = 0, dfY = 0, dfZ = 0; double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0; double dfLastX = 0, dfLastY = 0; double dfStepX = 0, dfStepY = 0; GDALDataType eDT = GDT_Byte; while((pszLine = CPLReadLine2L(fp, 100, NULL)) != NULL) { nLineNum ++; const char* pszPtr = pszLine; char ch; int nCol = 0; int bLastWasSep = TRUE; while((ch = *pszPtr) != '\0') { if (ch == ' ' || ch == ',' || ch == '\t' || ch == ';') { if (!bLastWasSep) nCol ++; bLastWasSep = TRUE; } else { if (bLastWasSep) { if (nCol == nXIndex) dfX = CPLAtofM(pszPtr); else if (nCol == nYIndex) dfY = CPLAtofM(pszPtr); else if (nCol == nZIndex && eDT != GDT_Float32) { dfZ = CPLAtofM(pszPtr); 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) { dfFirstX = dfMinX = dfMaxX = dfX; dfMinY = dfMaxY = dfY; } else { if (dfX < dfMinX) dfMinX = dfX; if (dfX > dfMaxX) dfMaxX = dfX; if (dfY < dfMinY) dfMinY = dfY; if (dfY > dfMaxY) dfMaxY = dfY; } if (nDataLineNum == 2) { 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; } } else if (nDataLineNum > 2) { double dfNewStepX = dfX - dfLastX; double dfNewStepY = dfY - dfLastY; if (dfNewStepY != 0) { nYSize ++; if (dfStepY == 0) { nXSize = nDataLineNum - 1; double dfAdjustedStepX = (dfMaxX - dfMinX) / (nXSize - 1); if (fabs(dfStepX - dfAdjustedStepX) > 1e-8) { CPLDebug("XYZ", "Adjusting stepx from %f to %f", dfStepX, dfAdjustedStepX); } dfStepX = dfAdjustedStepX; } if (dfStepY != 0 && fabs(dfX - dfFirstX) > 1e-8) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line %d, X is %f, where as %f was expected", nLineNum, dfX, dfFirstX); VSIFCloseL(fp); return NULL; } if (dfStepY != 0 && fabs(dfLastX - dfMaxX) > 1e-8) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line %d, X is %f, where as %f was expected", nLineNum - 1, dfLastX, dfMaxX); VSIFCloseL(fp); return NULL; } /*if (dfStepY != 0 && fabs(dfNewStepY - dfStepY) > 1e-8) { CPLError(CE_Failure, CPLE_AppDefined, "Ungridded dataset: At line %d, Y spacing was %f, whereas it was %f before", nLineNum, dfNewStepY, dfStepY); VSIFCloseL(fp); return NULL; }*/ dfStepY = dfNewStepY; } else if (dfNewStepX != 0) { /*if (dfStepX != 0 && fabs(dfNewStepX - dfStepX) > 1e-8) { CPLError(CE_Failure, CPLE_AppDefined, "At line %d, X spacing was %f, whereas it was %f before", nLineNum, dfNewStepX, dfStepX); VSIFCloseL(fp); return NULL; }*/ } } dfLastX = dfX; dfLastY = dfY; } nYSize ++; if (dfStepX == 0) { CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine X spacing"); VSIFCloseL(fp); return NULL; } if (dfStepY == 0) { CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine Y spacing"); VSIFCloseL(fp); return NULL; } double dfAdjustedStepY = ((dfStepY < 0) ? -1 : 1) * (dfMaxY - dfMinY) / (nYSize - 1); if (fabs(dfStepY - dfAdjustedStepY) > 1e-8) { CPLDebug("XYZ", "Adjusting stepy from %f to %f", dfStepY, dfAdjustedStepY); } dfStepY = dfAdjustedStepY; //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) { CPLError(CE_Failure, CPLE_AppDefined, "Found %d lines. Expected %d", nDataLineNum,nXSize * nYSize); VSIFCloseL(fp); return NULL; } 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->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; 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 ); }
int XYZDataset::Identify( GDALOpenInfo * poOpenInfo ) { int bHasHeaderLine, nCommentLineCount; return IdentifyEx(poOpenInfo, bHasHeaderLine, nCommentLineCount); }
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; }