int QgsRasterCalculator::processCalculation( QProgressDialog* p ) { //prepare search string / tree QString errorString; QgsRasterCalcNode* calcNode = QgsRasterCalcNode::parseRasterCalcString( mFormulaString, errorString ); if ( !calcNode ) { //error } double targetGeoTransform[6]; outputGeoTransform( targetGeoTransform ); //open all input rasters for reading QMap< QString, GDALRasterBandH > mInputRasterBands; //raster references and corresponding scanline data QMap< QString, QgsRasterMatrix* > inputScanLineData; //stores raster references and corresponding scanline data QVector< GDALDatasetH > mInputDatasets; //raster references and corresponding dataset QVector<QgsRasterCalculatorEntry>::const_iterator it = mRasterEntries.constBegin(); for ( ; it != mRasterEntries.constEnd(); ++it ) { if ( !it->raster ) // no raster layer in entry { return 2; } GDALDatasetH inputDataset = GDALOpen( it->raster->source().toLocal8Bit().data(), GA_ReadOnly ); if ( inputDataset == NULL ) { return 2; } //check if the input dataset is south up or rotated. If yes, use GDALAutoCreateWarpedVRT to create a north up raster double inputGeoTransform[6]; if ( GDALGetGeoTransform( inputDataset, inputGeoTransform ) == CE_None && ( inputGeoTransform[1] < 0.0 || inputGeoTransform[2] != 0.0 || inputGeoTransform[4] != 0.0 || inputGeoTransform[5] > 0.0 ) ) { GDALDatasetH vDataset = GDALAutoCreateWarpedVRT( inputDataset, NULL, NULL, GRA_NearestNeighbour, 0.2, NULL ); mInputDatasets.push_back( vDataset ); mInputDatasets.push_back( inputDataset ); inputDataset = vDataset; } else { mInputDatasets.push_back( inputDataset ); } GDALRasterBandH inputRasterBand = GDALGetRasterBand( inputDataset, it->bandNumber ); if ( inputRasterBand == NULL ) { return 2; } int nodataSuccess; double nodataValue = GDALGetRasterNoDataValue( inputRasterBand, &nodataSuccess ); mInputRasterBands.insert( it->ref, inputRasterBand ); inputScanLineData.insert( it->ref, new QgsRasterMatrix( mNumOutputColumns, 1, new float[mNumOutputColumns], nodataValue ) ); } //open output dataset for writing GDALDriverH outputDriver = openOutputDriver(); if ( outputDriver == NULL ) { return 1; } GDALDatasetH outputDataset = openOutputFile( outputDriver ); GDALRasterBandH outputRasterBand = GDALGetRasterBand( outputDataset, 1 ); float outputNodataValue = -FLT_MAX; GDALSetRasterNoDataValue( outputRasterBand, outputNodataValue ); float* resultScanLine = ( float * ) CPLMalloc( sizeof( float ) * mNumOutputColumns ); if ( p ) { p->setMaximum( mNumOutputRows ); } QgsRasterMatrix resultMatrix; //read / write line by line for ( int i = 0; i < mNumOutputRows; ++i ) { if ( p ) { p->setValue( i ); } if ( p && p->wasCanceled() ) { break; } //fill buffers QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin(); for ( ; bufferIt != inputScanLineData.end(); ++bufferIt ) { double sourceTransformation[6]; GDALRasterBandH sourceRasterBand = mInputRasterBands[bufferIt.key()]; GDALGetGeoTransform( GDALGetBandDataset( sourceRasterBand ), sourceTransformation ); //the function readRasterPart calls GDALRasterIO (and ev. does some conversion if raster transformations are not the same) readRasterPart( targetGeoTransform, 0, i, mNumOutputColumns, 1, sourceTransformation, sourceRasterBand, bufferIt.value()->data() ); } if ( calcNode->calculate( inputScanLineData, resultMatrix ) ) { bool resultIsNumber = resultMatrix.isNumber(); float* calcData; if ( resultIsNumber ) //scalar result. Insert number for every pixel { calcData = new float[mNumOutputColumns]; for ( int j = 0; j < mNumOutputColumns; ++j ) { calcData[j] = resultMatrix.number(); } } else //result is real matrix { calcData = resultMatrix.data(); } //replace all matrix nodata values with output nodatas for ( int j = 0; j < mNumOutputColumns; ++j ) { if ( calcData[j] == resultMatrix.nodataValue() ) { calcData[j] = outputNodataValue; } } //write scanline to the dataset if ( GDALRasterIO( outputRasterBand, GF_Write, 0, i, mNumOutputColumns, 1, calcData, mNumOutputColumns, 1, GDT_Float32, 0, 0 ) != CE_None ) { qWarning( "RasterIO error!" ); } if ( resultIsNumber ) { delete[] calcData; } } } if ( p ) { p->setValue( mNumOutputRows ); } //close datasets and release memory delete calcNode; QMap< QString, QgsRasterMatrix* >::iterator bufferIt = inputScanLineData.begin(); for ( ; bufferIt != inputScanLineData.end(); ++bufferIt ) { delete bufferIt.value(); } inputScanLineData.clear(); QVector< GDALDatasetH >::iterator datasetIt = mInputDatasets.begin(); for ( ; datasetIt != mInputDatasets.end(); ++ datasetIt ) { GDALClose( *datasetIt ); } if ( p && p->wasCanceled() ) { //delete the dataset without closing (because it is faster) GDALDeleteDataset( outputDriver, mOutputFile.toLocal8Bit().data() ); return 3; } GDALClose( outputDataset ); CPLFree( resultScanLine ); return 0; }
CPLErr CPL_STDCALL GDALFPolygonize( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand, OGRLayerH hOutLayer, int iPixValField, char **papszOptions, GDALProgressFunc pfnProgress, void * pProgressArg ) { #ifndef OGR_ENABLED CPLError(CE_Failure, CPLE_NotSupported, "GDALFPolygonize() unimplemented in a non OGR build"); return CE_Failure; #else VALIDATE_POINTER1( hSrcBand, "GDALFPolygonize", CE_Failure ); VALIDATE_POINTER1( hOutLayer, "GDALFPolygonize", CE_Failure ); if( pfnProgress == NULL ) pfnProgress = GDALDummyProgress; int nConnectedness = CSLFetchNameValue( papszOptions, "8CONNECTED" ) ? 8 : 4; /* -------------------------------------------------------------------- */ /* Confirm our output layer will support feature creation. */ /* -------------------------------------------------------------------- */ if( !OGR_L_TestCapability( hOutLayer, OLCSequentialWrite ) ) { CPLError( CE_Failure, CPLE_AppDefined, "Output feature layer does not appear to support creation\n" "of features in GDALFPolygonize()." ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Allocate working buffers. */ /* -------------------------------------------------------------------- */ CPLErr eErr = CE_None; int nXSize = GDALGetRasterBandXSize( hSrcBand ); int nYSize = GDALGetRasterBandYSize( hSrcBand ); float *pafLastLineVal = (float *) VSIMalloc2(sizeof(float),nXSize + 2); float *pafThisLineVal = (float *) VSIMalloc2(sizeof(float),nXSize + 2); GInt32 *panLastLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2); GInt32 *panThisLineId = (GInt32 *) VSIMalloc2(sizeof(GInt32),nXSize + 2); GByte *pabyMaskLine = (hMaskBand != NULL) ? (GByte *) VSIMalloc(nXSize) : NULL; if (pafLastLineVal == NULL || pafThisLineVal == NULL || panLastLineId == NULL || panThisLineId == NULL || (hMaskBand != NULL && pabyMaskLine == NULL)) { CPLError(CE_Failure, CPLE_OutOfMemory, "Could not allocate enough memory for temporary buffers"); CPLFree( panThisLineId ); CPLFree( panLastLineId ); CPLFree( pafThisLineVal ); CPLFree( pafLastLineVal ); CPLFree( pabyMaskLine ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Get the geotransform, if there is one, so we can convert the */ /* vectors into georeferenced coordinates. */ /* -------------------------------------------------------------------- */ GDALDatasetH hSrcDS = GDALGetBandDataset( hSrcBand ); double adfGeoTransform[6] = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 }; if( hSrcDS ) GDALGetGeoTransform( hSrcDS, adfGeoTransform ); /* -------------------------------------------------------------------- */ /* The first pass over the raster is only used to build up the */ /* polygon id map so we will know in advance what polygons are */ /* what on the second pass. */ /* -------------------------------------------------------------------- */ int iY; GDALRasterFPolygonEnumerator oFirstEnum(nConnectedness); for( iY = 0; eErr == CE_None && iY < nYSize; iY++ ) { eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1, pafThisLineVal, nXSize, 1, GDT_Float32, 0, 0 ); if( eErr == CE_None && hMaskBand != NULL ) eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, pafThisLineVal ); if( iY == 0 ) oFirstEnum.ProcessLine( NULL, pafThisLineVal, NULL, panThisLineId, nXSize ); else oFirstEnum.ProcessLine( pafLastLineVal, pafThisLineVal, panLastLineId, panThisLineId, nXSize ); // swap lines float * pafTmp = pafLastLineVal; pafLastLineVal = pafThisLineVal; pafThisLineVal = pafTmp; GInt32 * panTmp = panThisLineId; panThisLineId = panLastLineId; panLastLineId = panTmp; /* -------------------------------------------------------------------- */ /* Report progress, and support interrupts. */ /* -------------------------------------------------------------------- */ if( eErr == CE_None && !pfnProgress( 0.10 * ((iY+1) / (double) nYSize), "", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" ); eErr = CE_Failure; } } /* -------------------------------------------------------------------- */ /* Make a pass through the maps, ensuring every polygon id */ /* points to the final id it should use, not an intermediate */ /* value. */ /* -------------------------------------------------------------------- */ oFirstEnum.CompleteMerges(); /* -------------------------------------------------------------------- */ /* Initialize ids to -1 to serve as a nodata value for the */ /* previous line, and past the beginning and end of the */ /* scanlines. */ /* -------------------------------------------------------------------- */ int iX; panThisLineId[0] = -1; panThisLineId[nXSize+1] = -1; for( iX = 0; iX < nXSize+2; iX++ ) panLastLineId[iX] = -1; /* -------------------------------------------------------------------- */ /* We will use a new enumerator for the second pass primariliy */ /* so we can preserve the first pass map. */ /* -------------------------------------------------------------------- */ GDALRasterFPolygonEnumerator oSecondEnum(nConnectedness); RPolygonF **papoPoly = (RPolygonF **) CPLCalloc(sizeof(RPolygonF*),oFirstEnum.nNextPolygonId); /* ==================================================================== */ /* Second pass during which we will actually collect polygon */ /* edges as geometries. */ /* ==================================================================== */ for( iY = 0; eErr == CE_None && iY < nYSize+1; iY++ ) { /* -------------------------------------------------------------------- */ /* Read the image data. */ /* -------------------------------------------------------------------- */ if( iY < nYSize ) { eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1, pafThisLineVal, nXSize, 1, GDT_Float32, 0, 0 ); if( eErr == CE_None && hMaskBand != NULL ) eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, pafThisLineVal ); } if( eErr != CE_None ) continue; /* -------------------------------------------------------------------- */ /* Determine what polygon the various pixels belong to (redoing */ /* the same thing done in the first pass above). */ /* -------------------------------------------------------------------- */ if( iY == nYSize ) { for( iX = 0; iX < nXSize+2; iX++ ) panThisLineId[iX] = -1; } else if( iY == 0 ) oSecondEnum.ProcessLine( NULL, pafThisLineVal, NULL, panThisLineId+1, nXSize ); else oSecondEnum.ProcessLine( pafLastLineVal, pafThisLineVal, panLastLineId+1, panThisLineId+1, nXSize ); /* -------------------------------------------------------------------- */ /* Add polygon edges to our polygon list for the pixel */ /* boundaries within and above this line. */ /* -------------------------------------------------------------------- */ for( iX = 0; iX < nXSize+1; iX++ ) { AddEdges( panThisLineId, panLastLineId, oFirstEnum.panPolyIdMap, oFirstEnum.pafPolyValue, papoPoly, iX, iY ); } /* -------------------------------------------------------------------- */ /* Periodically we scan out polygons and write out those that */ /* haven't been added to on the last line as we can be sure */ /* they are complete. */ /* -------------------------------------------------------------------- */ if( iY % 8 == 7 ) { for( iX = 0; eErr == CE_None && iX < oSecondEnum.nNextPolygonId; iX++ ) { if( papoPoly[iX] && papoPoly[iX]->nLastLineUpdated < iY-1 ) { if( hMaskBand == NULL || !GDALFloatEquals(papoPoly[iX]->fPolyValue, GP_NODATA_MARKER) ) { eErr = EmitPolygonToLayer( hOutLayer, iPixValField, papoPoly[iX], adfGeoTransform ); } delete papoPoly[iX]; papoPoly[iX] = NULL; } } } /* -------------------------------------------------------------------- */ /* Swap pixel value, and polygon id lines to be ready for the */ /* next line. */ /* -------------------------------------------------------------------- */ float *pafTmp = pafLastLineVal; pafLastLineVal = pafThisLineVal; pafThisLineVal = pafTmp; GInt32 *panTmp = panThisLineId; panThisLineId = panLastLineId; panLastLineId = panTmp; /* -------------------------------------------------------------------- */ /* Report progress, and support interrupts. */ /* -------------------------------------------------------------------- */ if( eErr == CE_None && !pfnProgress( 0.10 + 0.90 * ((iY+1) / (double) nYSize), "", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" ); eErr = CE_Failure; } } /* -------------------------------------------------------------------- */ /* Make a cleanup pass for all unflushed polygons. */ /* -------------------------------------------------------------------- */ for( iX = 0; eErr == CE_None && iX < oSecondEnum.nNextPolygonId; iX++ ) { if( papoPoly[iX] ) { if( hMaskBand == NULL || !GDALFloatEquals(papoPoly[iX]->fPolyValue, GP_NODATA_MARKER) ) { eErr = EmitPolygonToLayer( hOutLayer, iPixValField, papoPoly[iX], adfGeoTransform ); } delete papoPoly[iX]; papoPoly[iX] = NULL; } } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ CPLFree( panThisLineId ); CPLFree( panLastLineId ); CPLFree( pafThisLineVal ); CPLFree( pafLastLineVal ); CPLFree( pabyMaskLine ); CPLFree( papoPoly ); return eErr; #endif // OGR_ENABLED }
CPLErr CPL_STDCALL GDALComputeProximity(GDALRasterBandH hSrcBand, GDALRasterBandH hProximityBand, char **papszOptions, GDALProgressFunc pfnProgress, void *pProgressArg) { int nXSize, nYSize, i, bFixedBufVal = FALSE; const char *pszOpt; double dfMaxDist; double dfFixedBufVal = 0.0; VALIDATE_POINTER1(hSrcBand, "GDALComputeProximity", CE_Failure); VALIDATE_POINTER1(hProximityBand, "GDALComputeProximity", CE_Failure); if (pfnProgress == NULL) pfnProgress = GDALDummyProgress; /* -------------------------------------------------------------------- */ /* Are we using pixels or georeferenced coordinates for distances? */ /* -------------------------------------------------------------------- */ double dfDistMult = 1.0; pszOpt = CSLFetchNameValue(papszOptions, "DISTUNITS"); if (pszOpt) { if (EQUAL(pszOpt, "GEO")) { GDALDatasetH hSrcDS = GDALGetBandDataset(hSrcBand); if (hSrcDS) { double adfGeoTransform[6]; GDALGetGeoTransform(hSrcDS, adfGeoTransform); if (ABS(adfGeoTransform[1]) != ABS(adfGeoTransform[5])) CPLError(CE_Warning, CPLE_AppDefined, "Pixels not square, distances will be inaccurate."); dfDistMult = ABS(adfGeoTransform[1]); } } else if (!EQUAL(pszOpt, "PIXEL")) { CPLError(CE_Failure, CPLE_AppDefined, "Unrecognised DISTUNITS value '%s', should be GEO or PIXEL.", pszOpt); return CE_Failure; } } /* -------------------------------------------------------------------- */ /* What is our maxdist value? */ /* -------------------------------------------------------------------- */ pszOpt = CSLFetchNameValue(papszOptions, "MAXDIST"); if (pszOpt) dfMaxDist = atof(pszOpt) / dfDistMult; else dfMaxDist = GDALGetRasterBandXSize(hSrcBand) + GDALGetRasterBandYSize(hSrcBand); CPLDebug("GDAL", "MAXDIST=%g, DISTMULT=%g", dfMaxDist, dfDistMult); /* -------------------------------------------------------------------- */ /* Verify the source and destination are compatible. */ /* -------------------------------------------------------------------- */ nXSize = GDALGetRasterBandXSize(hSrcBand); nYSize = GDALGetRasterBandYSize(hSrcBand); if (nXSize != GDALGetRasterBandXSize(hProximityBand) || nYSize != GDALGetRasterBandYSize(hProximityBand)) { CPLError(CE_Failure, CPLE_AppDefined, "Source and proximity bands are not the same size."); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Get output NODATA value. */ /* -------------------------------------------------------------------- */ float fNoDataValue; pszOpt = CSLFetchNameValue(papszOptions, "NODATA"); if (pszOpt != NULL) fNoDataValue = (float) atof(pszOpt); else { int bSuccess; fNoDataValue = (float) GDALGetRasterNoDataValue(hProximityBand, &bSuccess); if (!bSuccess) fNoDataValue = 65535.0; } /* -------------------------------------------------------------------- */ /* Is there a fixed value we wish to force the buffer area to? */ /* -------------------------------------------------------------------- */ pszOpt = CSLFetchNameValue(papszOptions, "FIXED_BUF_VAL"); if (pszOpt) { dfFixedBufVal = atof(pszOpt); bFixedBufVal = TRUE; } /* -------------------------------------------------------------------- */ /* Get the target value(s). */ /* -------------------------------------------------------------------- */ int *panTargetValues = NULL; int nTargetValues = 0; pszOpt = CSLFetchNameValue(papszOptions, "VALUES"); if (pszOpt != NULL) { char **papszValuesTokens; papszValuesTokens = CSLTokenizeStringComplex(pszOpt, ",", FALSE, FALSE); nTargetValues = CSLCount(papszValuesTokens); panTargetValues = (int*) CPLCalloc(sizeof(int), nTargetValues); for (i = 0; i < nTargetValues; i++) panTargetValues[i] = atoi(papszValuesTokens[i]); CSLDestroy(papszValuesTokens); } /* -------------------------------------------------------------------- */ /* Initialize progress counter. */ /* -------------------------------------------------------------------- */ if (!pfnProgress(0.0, "", pProgressArg)) { CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); CPLFree(panTargetValues); return CE_Failure; } /* -------------------------------------------------------------------- */ /* We need a signed type for the working proximity values kept */ /* on disk. If our proximity band is not signed, then create a */ /* temporary file for this purpose. */ /* -------------------------------------------------------------------- */ GDALRasterBandH hWorkProximityBand = hProximityBand; GDALDatasetH hWorkProximityDS = NULL; GDALDataType eProxType = GDALGetRasterDataType(hProximityBand); int *panNearX = NULL, *panNearY = NULL; float *pafProximity = NULL; GInt32 *panSrcScanline = NULL; int iLine; CPLErr eErr = CE_None; if (eProxType == GDT_Byte || eProxType == GDT_UInt16 || eProxType == GDT_UInt32) { GDALDriverH hDriver = GDALGetDriverByName("GTiff"); if (hDriver == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "GDALComputeProximity needs GTiff driver"); eErr = CE_Failure; goto end; } CPLString osTmpFile = CPLGenerateTempFilename("proximity"); hWorkProximityDS = GDALCreate(hDriver, osTmpFile, nXSize, nYSize, 1, GDT_Float32, NULL); if (hWorkProximityDS == NULL) { eErr = CE_Failure; goto end; } hWorkProximityBand = GDALGetRasterBand(hWorkProximityDS, 1); } /* -------------------------------------------------------------------- */ /* Allocate buffer for two scanlines of distances as floats */ /* (the current and last line). */ /* -------------------------------------------------------------------- */ pafProximity = (float*) VSIMalloc2(sizeof(float), nXSize); panNearX = (int*) VSIMalloc2(sizeof(int), nXSize); panNearY = (int*) VSIMalloc2(sizeof(int), nXSize); panSrcScanline = (GInt32*) VSIMalloc2(sizeof(GInt32), nXSize); if (pafProximity == NULL || panNearX == NULL || panNearY == NULL || panSrcScanline == NULL) { CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory allocating working buffers."); eErr = CE_Failure; goto end; } /* -------------------------------------------------------------------- */ /* Loop from top to bottom of the image. */ /* -------------------------------------------------------------------- */ for (i = 0; i < nXSize; i++) panNearX[i] = panNearY[i] = -1; for (iLine = 0; eErr == CE_None && iLine < nYSize; iLine++) { // Read for target values. eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iLine, nXSize, 1, panSrcScanline, nXSize, 1, GDT_Int32, 0, 0); if (eErr != CE_None) break; for (i = 0; i < nXSize; i++) pafProximity[i] = -1.0; // Left to right ProcessProximityLine(panSrcScanline, panNearX, panNearY, TRUE, iLine, nXSize, dfMaxDist, pafProximity, nTargetValues, panTargetValues); // Right to Left ProcessProximityLine(panSrcScanline, panNearX, panNearY, FALSE, iLine, nXSize, dfMaxDist, pafProximity, nTargetValues, panTargetValues); // Write out results. eErr = GDALRasterIO(hWorkProximityBand, GF_Write, 0, iLine, nXSize, 1, pafProximity, nXSize, 1, GDT_Float32, 0, 0); if (eErr != CE_None) break; if (!pfnProgress(0.5 * (iLine + 1) / (double) nYSize, "", pProgressArg)) { CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); eErr = CE_Failure; } } /* -------------------------------------------------------------------- */ /* Loop from bottom to top of the image. */ /* -------------------------------------------------------------------- */ for (i = 0; i < nXSize; i++) panNearX[i] = panNearY[i] = -1; for (iLine = nYSize - 1; eErr == CE_None && iLine >= 0; iLine--) { // Read first pass proximity eErr = GDALRasterIO(hWorkProximityBand, GF_Read, 0, iLine, nXSize, 1, pafProximity, nXSize, 1, GDT_Float32, 0, 0); if (eErr != CE_None) break; // Read pixel values. eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iLine, nXSize, 1, panSrcScanline, nXSize, 1, GDT_Int32, 0, 0); if (eErr != CE_None) break; // Right to left ProcessProximityLine(panSrcScanline, panNearX, panNearY, FALSE, iLine, nXSize, dfMaxDist, pafProximity, nTargetValues, panTargetValues); // Left to right ProcessProximityLine(panSrcScanline, panNearX, panNearY, TRUE, iLine, nXSize, dfMaxDist, pafProximity, nTargetValues, panTargetValues); // Final post processing of distances. for (i = 0; i < nXSize; i++) { if (pafProximity[i] < 0.0) pafProximity[i] = fNoDataValue; else if (pafProximity[i] > 0.0) { if (bFixedBufVal) pafProximity[i] = (float) dfFixedBufVal; else pafProximity[i] = (float)(pafProximity[i] * dfDistMult); } } // Write out results. eErr = GDALRasterIO(hProximityBand, GF_Write, 0, iLine, nXSize, 1, pafProximity, nXSize, 1, GDT_Float32, 0, 0); if (eErr != CE_None) break; if (!pfnProgress(0.5 + 0.5 * (nYSize - iLine) / (double) nYSize, "", pProgressArg)) { CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); eErr = CE_Failure; } } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ end: CPLFree(panNearX); CPLFree(panNearY); CPLFree(panSrcScanline); CPLFree(pafProximity); CPLFree(panTargetValues); if (hWorkProximityDS != NULL) { CPLString osProxFile = GDALGetDescription(hWorkProximityDS); GDALClose(hWorkProximityDS); GDALDeleteDataset(GDALGetDriverByName("GTiff"), osProxFile); } return eErr; }