static CPLErr GDALMultiFilter( GDALRasterBandH hTargetBand, GDALRasterBandH hTargetMaskBand, GDALRasterBandH hFiltMaskBand, int nIterations, GDALProgressFunc pfnProgress, void * pProgressArg ) { const int nXSize = GDALGetRasterBandXSize(hTargetBand); const int nYSize = GDALGetRasterBandYSize(hTargetBand); /* -------------------------------------------------------------------- */ /* Report starting progress value. */ /* -------------------------------------------------------------------- */ if( !pfnProgress( 0.0, "Smoothing Filter...", pProgressArg ) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Allocate rotating buffers. */ /* -------------------------------------------------------------------- */ const int nBufLines = nIterations + 2; GByte *pabyTMaskBuf = static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXSize, nBufLines)); GByte *pabyFMaskBuf = static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXSize, nBufLines)); float *paf3PassLineBuf = static_cast<float *>( VSI_MALLOC3_VERBOSE(nXSize, nBufLines, 3 * sizeof(float))); if( pabyTMaskBuf == nullptr || pabyFMaskBuf == nullptr || paf3PassLineBuf == nullptr ) { CPLFree( pabyTMaskBuf ); CPLFree( pabyFMaskBuf ); CPLFree( paf3PassLineBuf ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Process rotating buffers. */ /* -------------------------------------------------------------------- */ CPLErr eErr = CE_None; int iPassCounter = 0; for( int nNewLine = 0; // Line being loaded (zero based scanline). eErr == CE_None && nNewLine < nYSize+nIterations; nNewLine++ ) { /* -------------------------------------------------------------------- */ /* Rotate pass buffers. */ /* -------------------------------------------------------------------- */ iPassCounter = (iPassCounter + 1) % 3; float * const pafSLastPass = paf3PassLineBuf + ((iPassCounter + 0) % 3) * nXSize * nBufLines; float * const pafLastPass = paf3PassLineBuf + ((iPassCounter + 1) % 3) * nXSize * nBufLines; float * const pafThisPass = paf3PassLineBuf + ((iPassCounter + 2) % 3) * nXSize * nBufLines; /* -------------------------------------------------------------------- */ /* Where does the new line go in the rotating buffer? */ /* -------------------------------------------------------------------- */ const int iBufOffset = nNewLine % nBufLines; /* -------------------------------------------------------------------- */ /* Read the new data line if it is't off the bottom of the */ /* image. */ /* -------------------------------------------------------------------- */ if( nNewLine < nYSize ) { eErr = GDALRasterIO( hTargetMaskBand, GF_Read, 0, nNewLine, nXSize, 1, pabyTMaskBuf + nXSize * iBufOffset, nXSize, 1, GDT_Byte, 0, 0 ); if( eErr != CE_None ) break; eErr = GDALRasterIO( hFiltMaskBand, GF_Read, 0, nNewLine, nXSize, 1, pabyFMaskBuf + nXSize * iBufOffset, nXSize, 1, GDT_Byte, 0, 0 ); if( eErr != CE_None ) break; eErr = GDALRasterIO( hTargetBand, GF_Read, 0, nNewLine, nXSize, 1, pafThisPass + nXSize * iBufOffset, nXSize, 1, GDT_Float32, 0, 0 ); if( eErr != CE_None ) break; } /* -------------------------------------------------------------------- */ /* Loop over the loaded data, applying the filter to all loaded */ /* lines with neighbours. */ /* -------------------------------------------------------------------- */ for( int iFLine = nNewLine-1; eErr == CE_None && iFLine >= nNewLine-nIterations; iFLine-- ) { const int iLastOffset = (iFLine-1) % nBufLines; const int iThisOffset = (iFLine ) % nBufLines; const int iNextOffset = (iFLine+1) % nBufLines; // Default to preserving the old value. if( iFLine >= 0 ) memcpy( pafThisPass + iThisOffset * nXSize, pafLastPass + iThisOffset * nXSize, sizeof(float) * nXSize ); // TODO: Enable first and last line. // Skip the first and last line. if( iFLine < 1 || iFLine >= nYSize-1 ) { continue; } GDALFilterLine( pafSLastPass + iLastOffset * nXSize, pafLastPass + iThisOffset * nXSize, pafThisPass + iNextOffset * nXSize, pafThisPass + iThisOffset * nXSize, pabyTMaskBuf + iLastOffset * nXSize, pabyTMaskBuf + iThisOffset * nXSize, pabyTMaskBuf + iNextOffset * nXSize, pabyFMaskBuf + iThisOffset * nXSize, nXSize ); } /* -------------------------------------------------------------------- */ /* Write out the top data line that will be rolling out of our */ /* buffer. */ /* -------------------------------------------------------------------- */ const int iLineToSave = nNewLine - nIterations; if( iLineToSave >= 0 && eErr == CE_None ) { const int iBufOffset2 = iLineToSave % nBufLines; eErr = GDALRasterIO( hTargetBand, GF_Write, 0, iLineToSave, nXSize, 1, pafThisPass + nXSize * iBufOffset2, nXSize, 1, GDT_Float32, 0, 0 ); } /* -------------------------------------------------------------------- */ /* Report progress. */ /* -------------------------------------------------------------------- */ if( eErr == CE_None && !pfnProgress( (nNewLine + 1) / static_cast<double>(nYSize+nIterations), "Smoothing Filter...", pProgressArg) ) { CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" ); eErr = CE_Failure; } } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ CPLFree( pabyTMaskBuf ); CPLFree( pabyFMaskBuf ); CPLFree( paf3PassLineBuf ); return eErr; }
CPLErr GDALNoDataMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff, void * pImage ) { GDALDataType eWrkDT = GetWorkDataType( poParent->GetRasterDataType() ); /* -------------------------------------------------------------------- */ /* Read the image data. */ /* -------------------------------------------------------------------- */ // TODO(schwehr): pabySrc would probably be better as a void ptr. GByte *pabySrc = static_cast<GByte *>( VSI_MALLOC3_VERBOSE( GDALGetDataTypeSizeBytes(eWrkDT), nBlockXSize, nBlockYSize ) ); if (pabySrc == nullptr) { return CE_Failure; } int nXSizeRequest = nBlockXSize; if (nXBlockOff * nBlockXSize + nBlockXSize > nRasterXSize) nXSizeRequest = nRasterXSize - nXBlockOff * nBlockXSize; int nYSizeRequest = nBlockYSize; if (nYBlockOff * nBlockYSize + nBlockYSize > nRasterYSize) nYSizeRequest = nRasterYSize - nYBlockOff * nBlockYSize; if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize) { // memset the whole buffer to avoid Valgrind warnings in case RasterIO // fetches a partial block. memset( pabySrc, 0, GDALGetDataTypeSizeBytes(eWrkDT) * nBlockXSize * nBlockYSize ); } CPLErr eErr = poParent->RasterIO( GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize, nXSizeRequest, nYSizeRequest, pabySrc, nXSizeRequest, nYSizeRequest, eWrkDT, 0, nBlockXSize * GDALGetDataTypeSizeBytes(eWrkDT), nullptr ); if( eErr != CE_None ) { CPLFree(pabySrc); return eErr; } const bool bIsNoDataNan = CPLIsNan(dfNoDataValue) != 0; /* -------------------------------------------------------------------- */ /* Process different cases. */ /* -------------------------------------------------------------------- */ switch( eWrkDT ) { case GDT_Byte: { GByte byNoData = static_cast<GByte>( dfNoDataValue ); for( int i = 0; i < nBlockXSize * nBlockYSize; i++ ) { static_cast<GByte *>(pImage)[i] = pabySrc[i] == byNoData ? 0: 255; } } break; case GDT_UInt32: { GUInt32 nNoData = static_cast<GUInt32>( dfNoDataValue ); for( int i = 0; i < nBlockXSize * nBlockYSize; i++ ) { static_cast<GByte *>(pImage)[i] = reinterpret_cast<GUInt32 *>(pabySrc)[i] == nNoData ? 0 : 255; } } break; case GDT_Int32: { GInt32 nNoData = static_cast<GInt32>( dfNoDataValue ); for( int i = 0; i < nBlockXSize * nBlockYSize; i++ ) { static_cast<GByte *>(pImage)[i] = reinterpret_cast<GInt32 *>(pabySrc)[i] == nNoData ? 0 : 255; } } break; case GDT_Float32: { float fNoData = static_cast<float>( dfNoDataValue ); for( int i = 0; i < nBlockXSize * nBlockYSize; i++ ) { const float fVal = reinterpret_cast<float *>(pabySrc)[i]; if( bIsNoDataNan && CPLIsNan(fVal)) static_cast<GByte *>(pImage)[i] = 0; else if( ARE_REAL_EQUAL(fVal, fNoData) ) static_cast<GByte *>(pImage)[i] = 0; else static_cast<GByte *>(pImage)[i] = 255; } } break; case GDT_Float64: { for( int i = 0; i < nBlockXSize * nBlockYSize; i++ ) { const double dfVal = reinterpret_cast<double *>(pabySrc)[i]; if( bIsNoDataNan && CPLIsNan(dfVal)) static_cast<GByte *>(pImage)[i] = 0; else if( ARE_REAL_EQUAL(dfVal, dfNoDataValue) ) static_cast<GByte *>(pImage)[i] = 0; else static_cast<GByte *>(pImage)[i] = 255; } } break; default: CPLAssert( false ); break; } CPLFree( pabySrc ); return CE_None; }
CPLErr GDALNoDataMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff, void * pImage ) { GDALDataType eWrkDT; /* -------------------------------------------------------------------- */ /* Decide on a working type. */ /* -------------------------------------------------------------------- */ switch( poParent->GetRasterDataType() ) { case GDT_Byte: eWrkDT = GDT_Byte; break; case GDT_UInt16: case GDT_UInt32: eWrkDT = GDT_UInt32; break; case GDT_Int16: case GDT_Int32: case GDT_CInt16: case GDT_CInt32: eWrkDT = GDT_Int32; break; case GDT_Float32: case GDT_CFloat32: eWrkDT = GDT_Float32; break; case GDT_Float64: case GDT_CFloat64: eWrkDT = GDT_Float64; break; default: CPLAssert( FALSE ); eWrkDT = GDT_Float64; break; } /* -------------------------------------------------------------------- */ /* Read the image data. */ /* -------------------------------------------------------------------- */ CPLErr eErr; GByte *pabySrc = static_cast<GByte *>( VSI_MALLOC3_VERBOSE( GDALGetDataTypeSizeBytes(eWrkDT), nBlockXSize, nBlockYSize ) ); if (pabySrc == NULL) { return CE_Failure; } int nXSizeRequest = nBlockXSize; if (nXBlockOff * nBlockXSize + nBlockXSize > nRasterXSize) nXSizeRequest = nRasterXSize - nXBlockOff * nBlockXSize; int nYSizeRequest = nBlockYSize; if (nYBlockOff * nBlockYSize + nBlockYSize > nRasterYSize) nYSizeRequest = nRasterYSize - nYBlockOff * nBlockYSize; if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize) { /* memset the whole buffer to avoid Valgrind warnings in case we can't */ /* fetch a full block */ memset( pabySrc, 0, GDALGetDataTypeSizeBytes(eWrkDT) * nBlockXSize * nBlockYSize ); } eErr = poParent->RasterIO( GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize, nXSizeRequest, nYSizeRequest, pabySrc, nXSizeRequest, nYSizeRequest, eWrkDT, 0, nBlockXSize * GDALGetDataTypeSizeBytes(eWrkDT), NULL ); if( eErr != CE_None ) { CPLFree(pabySrc); return eErr; } int bIsNoDataNan = CPLIsNan(dfNoDataValue); /* -------------------------------------------------------------------- */ /* Process different cases. */ /* -------------------------------------------------------------------- */ int i; switch( eWrkDT ) { case GDT_Byte: { GByte byNoData = (GByte) dfNoDataValue; for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { if( pabySrc[i] == byNoData ) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } } break; case GDT_UInt32: { GUInt32 nNoData = (GUInt32) dfNoDataValue; for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { if( ((GUInt32 *)pabySrc)[i] == nNoData ) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } } break; case GDT_Int32: { GInt32 nNoData = (GInt32) dfNoDataValue; for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { if( ((GInt32 *)pabySrc)[i] == nNoData ) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } } break; case GDT_Float32: { float fNoData = (float) dfNoDataValue; for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { float fVal =((float *)pabySrc)[i]; if( bIsNoDataNan && CPLIsNan(fVal)) ((GByte *) pImage)[i] = 0; else if( ARE_REAL_EQUAL(fVal, fNoData) ) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } } break; case GDT_Float64: { for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { double dfVal =((double *)pabySrc)[i]; if( bIsNoDataNan && CPLIsNan(dfVal)) ((GByte *) pImage)[i] = 0; else if( ARE_REAL_EQUAL(dfVal, dfNoDataValue) ) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } } break; default: CPLAssert( FALSE ); break; } CPLFree( pabySrc ); return CE_None; }
CPLErr VRTFilteredSource::RasterIO( GDALDataType eBandDataType, int nXOff, int nYOff, int nXSize, int nYSize, void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg* psExtraArg ) { /* -------------------------------------------------------------------- */ /* For now we don't support filtered access to non-full */ /* resolution requests. Just collect the data directly without */ /* any operator. */ /* -------------------------------------------------------------------- */ if( nBufXSize != nXSize || nBufYSize != nYSize ) { return VRTComplexSource::RasterIO( eBandDataType, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg ); } // The window we will actually request from the source raster band. double dfReqXOff = 0.0; double dfReqYOff = 0.0; double dfReqXSize = 0.0; double dfReqYSize = 0.0; int nReqXOff = 0; int nReqYOff = 0; int nReqXSize = 0; int nReqYSize = 0; // The window we will actual set _within_ the pData buffer. int nOutXOff = 0; int nOutYOff = 0; int nOutXSize = 0; int nOutYSize = 0; if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ) return CE_None; pData = reinterpret_cast<GByte *>( pData ) + nPixelSpace * nOutXOff + nLineSpace * nOutYOff; /* -------------------------------------------------------------------- */ /* Determine the data type we want to request. We try to match */ /* the source or destination request, and if both those fail we */ /* fallback to the first supported type at least as expressive */ /* as the request. */ /* -------------------------------------------------------------------- */ GDALDataType eOperDataType = GDT_Unknown; if( IsTypeSupported( eBufType ) ) eOperDataType = eBufType; if( eOperDataType == GDT_Unknown && IsTypeSupported( m_poRasterBand->GetRasterDataType() ) ) eOperDataType = m_poRasterBand->GetRasterDataType(); if( eOperDataType == GDT_Unknown ) { for( int i = 0; i < m_nSupportedTypesCount; i++ ) { if( GDALDataTypeUnion( m_aeSupportedTypes[i], eBufType ) == m_aeSupportedTypes[i] ) { eOperDataType = m_aeSupportedTypes[i]; } } } if( eOperDataType == GDT_Unknown ) { eOperDataType = m_aeSupportedTypes[0]; for( int i = 1; i < m_nSupportedTypesCount; i++ ) { if( GDALGetDataTypeSize( m_aeSupportedTypes[i] ) > GDALGetDataTypeSize( eOperDataType ) ) { eOperDataType = m_aeSupportedTypes[i]; } } } /* -------------------------------------------------------------------- */ /* Allocate the buffer of data into which our imagery will be */ /* read, with the extra edge pixels as well. This will be the */ /* source data fed into the filter. */ /* -------------------------------------------------------------------- */ if( nOutXSize > INT_MAX - 2 * m_nExtraEdgePixels || nOutYSize > INT_MAX - 2 * m_nExtraEdgePixels ) { return CE_Failure; } const int nExtraXSize = nOutXSize + 2 * m_nExtraEdgePixels; const int nExtraYSize = nOutYSize + 2 * m_nExtraEdgePixels; GByte *pabyWorkData = static_cast<GByte *>( VSI_MALLOC3_VERBOSE( nExtraXSize, nExtraYSize, GDALGetDataTypeSizeBytes(eOperDataType)) ); if( pabyWorkData == nullptr ) { return CE_Failure; } const GPtrDiff_t nPixelOffset = GDALGetDataTypeSizeBytes( eOperDataType ); const GPtrDiff_t nLineOffset = nPixelOffset * nExtraXSize; memset( pabyWorkData, 0, nLineOffset * nExtraYSize ); /* -------------------------------------------------------------------- */ /* Allocate the output buffer in the same dimensions as the work */ /* buffer. This allows the filter process to write edge pixels */ /* if needed for two-pass (separable) filtering. */ /* -------------------------------------------------------------------- */ GByte *pabyOutData = static_cast<GByte *>( VSI_MALLOC3_VERBOSE( nExtraXSize, nExtraYSize, nPixelOffset ) ); if( pabyOutData == nullptr ) { CPLFree( pabyWorkData ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Figure out the extended window that we want to load. Note */ /* that we keep track of the file window as well as the amount */ /* we will need to edge fill past the edge of the source dataset. */ /* -------------------------------------------------------------------- */ int nFileXOff = nReqXOff - m_nExtraEdgePixels; int nFileYOff = nReqYOff - m_nExtraEdgePixels; int nFileXSize = nExtraXSize; int nFileYSize = nExtraYSize; int nTopFill = 0; int nLeftFill = 0; int nRightFill = 0; int nBottomFill = 0; if( nFileXOff < 0 ) { nLeftFill = -nFileXOff; nFileXOff = 0; nFileXSize -= nLeftFill; } if( nFileYOff < 0 ) { nTopFill = -nFileYOff; nFileYOff = 0; nFileYSize -= nTopFill; } if( nFileXOff + nFileXSize > m_poRasterBand->GetXSize() ) { nRightFill = nFileXOff + nFileXSize - m_poRasterBand->GetXSize(); nFileXSize -= nRightFill; } if( nFileYOff + nFileYSize > m_poRasterBand->GetYSize() ) { nBottomFill = nFileYOff + nFileYSize - m_poRasterBand->GetYSize(); nFileYSize -= nBottomFill; } /* -------------------------------------------------------------------- */ /* Load the data. */ /* -------------------------------------------------------------------- */ { const bool bIsComplex = CPL_TO_BOOL( GDALDataTypeIsComplex(eOperDataType) ); const CPLErr eErr = VRTComplexSource::RasterIOInternal<float>( nFileXOff, nFileYOff, nFileXSize, nFileYSize, pabyWorkData + nLineOffset * nTopFill + nPixelOffset * nLeftFill, nFileXSize, nFileYSize, eOperDataType, nPixelOffset, nLineOffset, psExtraArg, bIsComplex ? GDT_CFloat32 : GDT_Float32 ); if( eErr != CE_None ) { VSIFree( pabyWorkData ); VSIFree( pabyOutData ); return eErr; } } /* -------------------------------------------------------------------- */ /* Fill in missing areas. Note that we replicate the edge */ /* valid values out. We don't using "mirroring" which might be */ /* more suitable for some times of filters. We also don't mark */ /* these pixels as "nodata" though perhaps we should. */ /* -------------------------------------------------------------------- */ if( nLeftFill != 0 || nRightFill != 0 ) { for( int i = nTopFill; i < nExtraYSize - nBottomFill; i++ ) { if( nLeftFill != 0 ) GDALCopyWords( pabyWorkData + nPixelOffset * nLeftFill + i * nLineOffset, eOperDataType, 0, pabyWorkData + i * nLineOffset, eOperDataType, static_cast<int>(nPixelOffset), nLeftFill ); if( nRightFill != 0 ) GDALCopyWords( pabyWorkData + i * nLineOffset + nPixelOffset * (nExtraXSize - nRightFill - 1), eOperDataType, 0, pabyWorkData + i * nLineOffset + nPixelOffset * (nExtraXSize - nRightFill), eOperDataType, static_cast<int>(nPixelOffset), nRightFill ); } } for( int i = 0; i < nTopFill; i++ ) { memcpy( pabyWorkData + i * nLineOffset, pabyWorkData + nTopFill * nLineOffset, nLineOffset ); } for( int i = nExtraYSize - nBottomFill; i < nExtraYSize; i++ ) { memcpy( pabyWorkData + i * nLineOffset, pabyWorkData + (nExtraYSize - nBottomFill - 1) * nLineOffset, nLineOffset ); } /* -------------------------------------------------------------------- */ /* Filter the data. */ /* -------------------------------------------------------------------- */ const CPLErr eErr = FilterData( nExtraXSize, nExtraYSize, eOperDataType, pabyWorkData, pabyOutData ); VSIFree( pabyWorkData ); if( eErr != CE_None ) { VSIFree( pabyOutData ); return eErr; } /* -------------------------------------------------------------------- */ /* Copy from work buffer to target buffer. */ /* -------------------------------------------------------------------- */ GByte *pabySrcRow = pabyOutData + (nLineOffset + nPixelOffset) * m_nExtraEdgePixels; GByte *pabyDstRow = reinterpret_cast<GByte *>( pData ); for( int i = 0; i < nOutYSize; i++, pabySrcRow += nLineOffset, pabyDstRow += nLineSpace ) { GDALCopyWords( pabySrcRow, eOperDataType, static_cast<int>(nPixelOffset), pabyDstRow, eBufType, static_cast<int>(nPixelSpace), nOutXSize ); } VSIFree( pabyOutData ); return CE_None; }
CPLErr GDALNoDataValuesMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff, void * pImage ) { int iBand; GDALDataType eWrkDT; /* -------------------------------------------------------------------- */ /* Decide on a working type. */ /* -------------------------------------------------------------------- */ switch( poDS->GetRasterBand(1)->GetRasterDataType() ) { case GDT_Byte: eWrkDT = GDT_Byte; break; case GDT_UInt16: case GDT_UInt32: eWrkDT = GDT_UInt32; break; case GDT_Int16: case GDT_Int32: case GDT_CInt16: case GDT_CInt32: eWrkDT = GDT_Int32; break; case GDT_Float32: case GDT_CFloat32: eWrkDT = GDT_Float32; break; case GDT_Float64: case GDT_CFloat64: eWrkDT = GDT_Float64; break; default: CPLAssert( FALSE ); eWrkDT = GDT_Float64; break; } /* -------------------------------------------------------------------- */ /* Read the image data. */ /* -------------------------------------------------------------------- */ CPLErr eErr; int nBands = poDS->GetRasterCount(); GByte *pabySrc = static_cast<GByte *>( VSI_MALLOC3_VERBOSE( nBands * GDALGetDataTypeSizeBytes(eWrkDT), nBlockXSize, nBlockYSize ) ); if (pabySrc == NULL) { return CE_Failure; } int nXSizeRequest = nBlockXSize; if (nXBlockOff * nBlockXSize + nBlockXSize > nRasterXSize) nXSizeRequest = nRasterXSize - nXBlockOff * nBlockXSize; int nYSizeRequest = nBlockYSize; if (nYBlockOff * nBlockYSize + nBlockYSize > nRasterYSize) nYSizeRequest = nRasterYSize - nYBlockOff * nBlockYSize; if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize) { /* memset the whole buffer to avoid Valgrind warnings in case we can't */ /* fetch a full block */ memset( pabySrc, 0, nBands * GDALGetDataTypeSizeBytes(eWrkDT) * nBlockXSize * nBlockYSize ); } int nBlockOffsetPixels = nBlockXSize * nBlockYSize; const int nBandOffsetByte = GDALGetDataTypeSizeBytes(eWrkDT) * nBlockXSize * nBlockYSize; for(iBand=0;iBand<nBands;iBand++) { eErr = poDS->GetRasterBand(iBand + 1)->RasterIO( GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize, nXSizeRequest, nYSizeRequest, pabySrc + iBand * nBandOffsetByte, nXSizeRequest, nYSizeRequest, eWrkDT, 0, nBlockXSize * GDALGetDataTypeSizeBytes(eWrkDT), NULL ); if( eErr != CE_None ) return eErr; } /* -------------------------------------------------------------------- */ /* Process different cases. */ /* -------------------------------------------------------------------- */ int i; switch( eWrkDT ) { case GDT_Byte: { GByte* pabyNoData = (GByte*) CPLMalloc(nBands * sizeof(GByte)); for(iBand=0;iBand<nBands;iBand++) { pabyNoData[iBand] = (GByte)padfNodataValues[iBand]; } for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { int nCountNoData = 0; for(iBand=0;iBand<nBands;iBand++) { if( pabySrc[i + iBand * nBlockOffsetPixels] == pabyNoData[iBand] ) nCountNoData ++; } if (nCountNoData == nBands) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } CPLFree(pabyNoData); } break; case GDT_UInt32: { GUInt32* panNoData = (GUInt32*) CPLMalloc(nBands * sizeof(GUInt32)); for(iBand=0;iBand<nBands;iBand++) { panNoData[iBand] = (GUInt32)padfNodataValues[iBand]; } for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { int nCountNoData = 0; for(iBand=0;iBand<nBands;iBand++) { if( ((GUInt32 *)pabySrc)[i + iBand * nBlockOffsetPixels] == panNoData[iBand] ) nCountNoData ++; } if (nCountNoData == nBands) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } CPLFree(panNoData); } break; case GDT_Int32: { GInt32* panNoData = (GInt32*) CPLMalloc(nBands * sizeof(GInt32)); for(iBand=0;iBand<nBands;iBand++) { panNoData[iBand] = (GInt32)padfNodataValues[iBand]; } for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { int nCountNoData = 0; for(iBand=0;iBand<nBands;iBand++) { if( ((GInt32 *)pabySrc)[i + iBand * nBlockOffsetPixels] == panNoData[iBand] ) nCountNoData ++; } if (nCountNoData == nBands) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } CPLFree(panNoData); } break; case GDT_Float32: { float* pafNoData = (float*) CPLMalloc(nBands * sizeof(float)); for(iBand=0;iBand<nBands;iBand++) { pafNoData[iBand] = (float)padfNodataValues[iBand]; } for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { int nCountNoData = 0; for(iBand=0;iBand<nBands;iBand++) { if( ((float *)pabySrc)[i + iBand * nBlockOffsetPixels] == pafNoData[iBand] ) nCountNoData ++; } if (nCountNoData == nBands) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } CPLFree(pafNoData); } break; case GDT_Float64: { double* padfNoData = (double*) CPLMalloc(nBands * sizeof(double)); for(iBand=0;iBand<nBands;iBand++) { padfNoData[iBand] = (double)padfNodataValues[iBand]; } for( i = nBlockXSize * nBlockYSize - 1; i >= 0; i-- ) { int nCountNoData = 0; for(iBand=0;iBand<nBands;iBand++) { if( ((double *)pabySrc)[i + iBand * nBlockOffsetPixels] == padfNoData[iBand] ) nCountNoData ++; } if (nCountNoData == nBands) ((GByte *) pImage)[i] = 0; else ((GByte *) pImage)[i] = 255; } CPLFree(padfNoData); } break; default: CPLAssert( FALSE ); break; } CPLFree( pabySrc ); return CE_None; }
static int GeoLocLoadFullData( GDALGeoLocTransformInfo *psTransform ) { int nXSize, nYSize; int nXSize_XBand = GDALGetRasterXSize( psTransform->hDS_X ); int nYSize_XBand = GDALGetRasterYSize( psTransform->hDS_X ); int nXSize_YBand = GDALGetRasterXSize( psTransform->hDS_Y ); int nYSize_YBand = GDALGetRasterYSize( psTransform->hDS_Y ); if (nYSize_XBand == 1 && nYSize_YBand == 1) { nXSize = nXSize_XBand; nYSize = nXSize_YBand; } else { nXSize = nXSize_XBand; nYSize = nYSize_XBand; } psTransform->nGeoLocXSize = nXSize; psTransform->nGeoLocYSize = nYSize; psTransform->padfGeoLocY = (double *) VSI_MALLOC3_VERBOSE(sizeof(double), nXSize, nYSize); psTransform->padfGeoLocX = (double *) VSI_MALLOC3_VERBOSE(sizeof(double), nXSize, nYSize); if( psTransform->padfGeoLocX == NULL || psTransform->padfGeoLocY == NULL ) { return FALSE; } if (nYSize_XBand == 1 && nYSize_YBand == 1) { /* Case of regular grid */ /* The XBAND contains the x coordinates for all lines */ /* The YBAND contains the y coordinates for all columns */ double* padfTempX = (double*)VSI_MALLOC2_VERBOSE(nXSize, sizeof(double)); double* padfTempY = (double*)VSI_MALLOC2_VERBOSE(nYSize, sizeof(double)); if (padfTempX == NULL || padfTempY == NULL) { CPLFree(padfTempX); CPLFree(padfTempY); return FALSE; } CPLErr eErr = CE_None; eErr = GDALRasterIO( psTransform->hBand_X, GF_Read, 0, 0, nXSize, 1, padfTempX, nXSize, 1, GDT_Float64, 0, 0 ); int i,j; for(j=0;j<nYSize;j++) { memcpy( psTransform->padfGeoLocX + j * nXSize, padfTempX, nXSize * sizeof(double) ); } if (eErr == CE_None) { eErr = GDALRasterIO( psTransform->hBand_Y, GF_Read, 0, 0, nYSize, 1, padfTempY, nYSize, 1, GDT_Float64, 0, 0 ); for(j=0;j<nYSize;j++) { for(i=0;i<nXSize;i++) { psTransform->padfGeoLocY[j * nXSize + i] = padfTempY[j]; } } } CPLFree(padfTempX); CPLFree(padfTempY); if (eErr != CE_None) return FALSE; } else { if( GDALRasterIO( psTransform->hBand_X, GF_Read, 0, 0, nXSize, nYSize, psTransform->padfGeoLocX, nXSize, nYSize, GDT_Float64, 0, 0 ) != CE_None || GDALRasterIO( psTransform->hBand_Y, GF_Read, 0, 0, nXSize, nYSize, psTransform->padfGeoLocY, nXSize, nYSize, GDT_Float64, 0, 0 ) != CE_None ) return FALSE; } psTransform->dfNoDataX = GDALGetRasterNoDataValue( psTransform->hBand_X, &(psTransform->bHasNoData) ); return TRUE; }
static int GeoLocGenerateBackMap( GDALGeoLocTransformInfo *psTransform ) { int nXSize = psTransform->nGeoLocXSize; int nYSize = psTransform->nGeoLocYSize; int nMaxIter = 3; /* -------------------------------------------------------------------- */ /* Scan forward map for lat/long extents. */ /* -------------------------------------------------------------------- */ double dfMinX=0, dfMaxX=0, dfMinY=0, dfMaxY=0; int i, bInit = FALSE; for( i = nXSize * nYSize - 1; i >= 0; i-- ) { if( !psTransform->bHasNoData || psTransform->padfGeoLocX[i] != psTransform->dfNoDataX ) { if( bInit ) { dfMinX = MIN(dfMinX,psTransform->padfGeoLocX[i]); dfMaxX = MAX(dfMaxX,psTransform->padfGeoLocX[i]); dfMinY = MIN(dfMinY,psTransform->padfGeoLocY[i]); dfMaxY = MAX(dfMaxY,psTransform->padfGeoLocY[i]); } else { bInit = TRUE; dfMinX = dfMaxX = psTransform->padfGeoLocX[i]; dfMinY = dfMaxY = psTransform->padfGeoLocY[i]; } } } /* -------------------------------------------------------------------- */ /* Decide on resolution for backmap. We aim for slightly */ /* higher resolution than the source but we can't easily */ /* establish how much dead space there is in the backmap, so it */ /* is approximate. */ /* -------------------------------------------------------------------- */ double dfTargetPixels = (nXSize * nYSize * 1.3); double dfPixelSize = sqrt((dfMaxX - dfMinX) * (dfMaxY - dfMinY) / dfTargetPixels); int nBMXSize, nBMYSize; nBMYSize = psTransform->nBackMapHeight = (int) ((dfMaxY - dfMinY) / dfPixelSize + 1); nBMXSize= psTransform->nBackMapWidth = (int) ((dfMaxX - dfMinX) / dfPixelSize + 1); if (nBMXSize > INT_MAX / nBMYSize) { CPLError(CE_Failure, CPLE_AppDefined, "Int overflow : %d x %d", nBMXSize, nBMYSize); return FALSE; } dfMinX -= dfPixelSize/2.0; dfMaxY += dfPixelSize/2.0; psTransform->adfBackMapGeoTransform[0] = dfMinX; psTransform->adfBackMapGeoTransform[1] = dfPixelSize; psTransform->adfBackMapGeoTransform[2] = 0.0; psTransform->adfBackMapGeoTransform[3] = dfMaxY; psTransform->adfBackMapGeoTransform[4] = 0.0; psTransform->adfBackMapGeoTransform[5] = -dfPixelSize; /* -------------------------------------------------------------------- */ /* Allocate backmap, and initialize to nodata value (-1.0). */ /* -------------------------------------------------------------------- */ GByte *pabyValidFlag; pabyValidFlag = (GByte *) VSI_CALLOC_VERBOSE(nBMXSize, nBMYSize); psTransform->pafBackMapX = (float *) VSI_MALLOC3_VERBOSE(nBMXSize, nBMYSize, sizeof(float)); psTransform->pafBackMapY = (float *) VSI_MALLOC3_VERBOSE(nBMXSize, nBMYSize, sizeof(float)); if( pabyValidFlag == NULL || psTransform->pafBackMapX == NULL || psTransform->pafBackMapY == NULL ) { CPLFree( pabyValidFlag ); return FALSE; } for( i = nBMXSize * nBMYSize - 1; i >= 0; i-- ) { psTransform->pafBackMapX[i] = -1.0; psTransform->pafBackMapY[i] = -1.0; } /* -------------------------------------------------------------------- */ /* Run through the whole geoloc array forward projecting and */ /* pushing into the backmap. */ /* Initialize to the nMaxIter+1 value so we can spot genuinely */ /* valid pixels in the hole-filling loop. */ /* -------------------------------------------------------------------- */ int iBMX, iBMY; int iX, iY; for( iY = 0; iY < nYSize; iY++ ) { for( iX = 0; iX < nXSize; iX++ ) { if( psTransform->bHasNoData && psTransform->padfGeoLocX[iX + iY * nXSize] == psTransform->dfNoDataX ) continue; i = iX + iY * nXSize; iBMX = (int) ((psTransform->padfGeoLocX[i] - dfMinX) / dfPixelSize); iBMY = (int) ((dfMaxY - psTransform->padfGeoLocY[i]) / dfPixelSize); if( iBMX < 0 || iBMY < 0 || iBMX >= nBMXSize || iBMY >= nBMYSize ) continue; psTransform->pafBackMapX[iBMX + iBMY * nBMXSize] = (float)(iX * psTransform->dfPIXEL_STEP + psTransform->dfPIXEL_OFFSET); psTransform->pafBackMapY[iBMX + iBMY * nBMXSize] = (float)(iY * psTransform->dfLINE_STEP + psTransform->dfLINE_OFFSET); pabyValidFlag[iBMX + iBMY * nBMXSize] = (GByte) (nMaxIter+1); } } /* -------------------------------------------------------------------- */ /* Now, loop over the backmap trying to fill in holes with */ /* nearby values. */ /* -------------------------------------------------------------------- */ int iIter; int nNumValid; for( iIter = 0; iIter < nMaxIter; iIter++ ) { nNumValid = 0; for( iBMY = 0; iBMY < nBMYSize; iBMY++ ) { for( iBMX = 0; iBMX < nBMXSize; iBMX++ ) { // if this point is already set, ignore it. if( pabyValidFlag[iBMX + iBMY*nBMXSize] ) { nNumValid++; continue; } int nCount = 0; double dfXSum = 0.0, dfYSum = 0.0; int nMarkedAsGood = nMaxIter - iIter; // left? if( iBMX > 0 && pabyValidFlag[iBMX-1+iBMY*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX-1+iBMY*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX-1+iBMY*nBMXSize]; nCount++; } // right? if( iBMX + 1 < nBMXSize && pabyValidFlag[iBMX+1+iBMY*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX+1+iBMY*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX+1+iBMY*nBMXSize]; nCount++; } // top? if( iBMY > 0 && pabyValidFlag[iBMX+(iBMY-1)*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX+(iBMY-1)*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX+(iBMY-1)*nBMXSize]; nCount++; } // bottom? if( iBMY + 1 < nBMYSize && pabyValidFlag[iBMX+(iBMY+1)*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX+(iBMY+1)*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX+(iBMY+1)*nBMXSize]; nCount++; } // top-left? if( iBMX > 0 && iBMY > 0 && pabyValidFlag[iBMX-1+(iBMY-1)*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX-1+(iBMY-1)*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX-1+(iBMY-1)*nBMXSize]; nCount++; } // top-right? if( iBMX + 1 < nBMXSize && iBMY > 0 && pabyValidFlag[iBMX+1+(iBMY-1)*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX+1+(iBMY-1)*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX+1+(iBMY-1)*nBMXSize]; nCount++; } // bottom-left? if( iBMX > 0 && iBMY + 1 < nBMYSize && pabyValidFlag[iBMX-1+(iBMY+1)*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX-1+(iBMY+1)*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX-1+(iBMY+1)*nBMXSize]; nCount++; } // bottom-right? if( iBMX + 1 < nBMXSize && iBMY + 1 < nBMYSize && pabyValidFlag[iBMX+1+(iBMY+1)*nBMXSize] > nMarkedAsGood ) { dfXSum += psTransform->pafBackMapX[iBMX+1+(iBMY+1)*nBMXSize]; dfYSum += psTransform->pafBackMapY[iBMX+1+(iBMY+1)*nBMXSize]; nCount++; } if( nCount > 0 ) { psTransform->pafBackMapX[iBMX + iBMY * nBMXSize] = (float)(dfXSum/nCount); psTransform->pafBackMapY[iBMX + iBMY * nBMXSize] = (float)(dfYSum/nCount); // genuinely valid points will have value iMaxIter+1 // On each iteration mark newly valid points with a // descending value so that it will not be used on the // current iteration only on subsequent ones. pabyValidFlag[iBMX+iBMY*nBMXSize] = (GByte) (nMaxIter - iIter); } } } if (nNumValid == nBMXSize * nBMYSize) break; } #ifdef notdef GDALDatasetH hBMDS = GDALCreate( GDALGetDriverByName( "GTiff" ), "backmap.tif", nBMXSize, nBMYSize, 2, GDT_Float32, NULL ); GDALSetGeoTransform( hBMDS, psTransform->adfBackMapGeoTransform ); GDALRasterIO( GDALGetRasterBand(hBMDS,1), GF_Write, 0, 0, nBMXSize, nBMYSize, psTransform->pafBackMapX, nBMXSize, nBMYSize, GDT_Float32, 0, 0 ); GDALRasterIO( GDALGetRasterBand(hBMDS,2), GF_Write, 0, 0, nBMXSize, nBMYSize, psTransform->pafBackMapY, nBMXSize, nBMYSize, GDT_Float32, 0, 0 ); GDALClose( hBMDS ); #endif CPLFree( pabyValidFlag ); return TRUE; }