/****************************************************************************** * * Project: WCS Client Driver * Purpose: Implementation of RasterBand classes for WCS. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 2006, Frank Warmerdam * Copyright (c) 2008-2013, Even Rouault * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "cpl_http.h" #include "gdal_pam.h" #include #include "wcsdataset.h" #include "wcsrasterband.h" /************************************************************************/ /* WCSRasterBand() */ /************************************************************************/ WCSRasterBand::WCSRasterBand( WCSDataset *poDSIn, int nBandIn, int iOverviewIn ) : iOverview(iOverviewIn), nResFactor(1 << (iOverviewIn+1)), // iOverview == -1 is base layer poODS(poDSIn), nOverviewCount(0), papoOverviews(nullptr) { poDS = poDSIn; nBand = nBandIn; eDataType = GDALGetDataTypeByName( CPLGetXMLValue( poDSIn->psService, "BandType", "Byte" ) ); /* -------------------------------------------------------------------- */ /* Establish resolution reduction for this overview level. */ /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ /* Establish block size. */ /* -------------------------------------------------------------------- */ nRasterXSize = poDS->GetRasterXSize() / nResFactor; nRasterYSize = poDS->GetRasterYSize() / nResFactor; nBlockXSize = atoi(CPLGetXMLValue( poDSIn->psService, "BlockXSize", "0" ) ); nBlockYSize = atoi(CPLGetXMLValue( poDSIn->psService, "BlockYSize", "0" ) ); if( nBlockXSize < 1 ) { if( nRasterXSize > 1800 ) nBlockXSize = 1024; else nBlockXSize = nRasterXSize; } if( nBlockYSize < 1 ) { if( nRasterYSize > 900 ) nBlockYSize = 512; else nBlockYSize = nRasterYSize; } /* -------------------------------------------------------------------- */ /* If this is the base layer, create the overview layers. */ /* -------------------------------------------------------------------- */ if( iOverview == -1 ) { nOverviewCount = atoi(CPLGetXMLValue(poODS->psService,"OverviewCount", "-1")); if( nOverviewCount < 0 ) { for( nOverviewCount = 0; (std::max(nRasterXSize, nRasterYSize) / (1 << nOverviewCount)) > 900; nOverviewCount++ ) {} } else if( nOverviewCount > 30 ) { /* There's no reason to have more than 30 overviews, because */ /* 2^(30+1) overflows a int32 */ nOverviewCount = 30; } papoOverviews = (WCSRasterBand **) CPLCalloc( nOverviewCount, sizeof(void*) ); for( int i = 0; i < nOverviewCount; i++ ) papoOverviews[i] = new WCSRasterBand( poODS, nBand, i ); } } /************************************************************************/ /* ~WCSRasterBand() */ /************************************************************************/ WCSRasterBand::~WCSRasterBand() { FlushCache(); if( nOverviewCount > 0 ) { for( int i = 0; i < nOverviewCount; i++ ) delete papoOverviews[i]; CPLFree( papoOverviews ); } } /************************************************************************/ /* IReadBlock() */ /************************************************************************/ CPLErr WCSRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage ) { CPLErr eErr; CPLHTTPResult *psResult = nullptr; // if INTERLEAVE is set to PIXEL, then we'll request all bands. // That is necessary at least with MapServer, which seems to often // return all bands instead of requested. // todo: in 2.0.1 the band list in this dataset may be user-defined int band_count = 1; if (EQUAL(CPLGetXMLValue(poODS->psService, "INTERLEAVE", ""), "PIXEL")) { band_count = 0; } eErr = poODS->GetCoverage( nBlockXOff * nBlockXSize * nResFactor, nBlockYOff * nBlockYSize * nResFactor, nBlockXSize * nResFactor, nBlockYSize * nResFactor, nBlockXSize, nBlockYSize, band_count, &nBand, nullptr, &psResult ); if( eErr != CE_None ) return eErr; /* -------------------------------------------------------------------- */ /* Try and open result as a dataset. */ /* -------------------------------------------------------------------- */ GDALDataset *poTileDS = poODS->GDALOpenResult( psResult ); if( poTileDS == nullptr ) return CE_Failure; /* -------------------------------------------------------------------- */ /* Verify configuration. */ /* -------------------------------------------------------------------- */ if( poTileDS->GetRasterXSize() != nBlockXSize || poTileDS->GetRasterYSize() != nBlockYSize ) { CPLError( CE_Failure, CPLE_AppDefined, "Returned tile does not match expected configuration.\n" "Got %dx%d instead of %dx%d.", poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(), nBlockXSize, nBlockYSize ); delete poTileDS; return CE_Failure; } if( band_count == 1 && ((strlen(poODS->osBandIdentifier) && poTileDS->GetRasterCount() != 1) || (!strlen(poODS->osBandIdentifier) && poTileDS->GetRasterCount() != poODS->GetRasterCount())) ) { CPLString msg; if (strlen(poODS->osBandIdentifier) && poTileDS->GetRasterCount() != 1) { msg.Printf("Got %d bands instead of one although the coverage has band range type.\n", poTileDS->GetRasterCount()); } else { msg.Printf("Response has %d bands while this dataset has %d bands.\n", poTileDS->GetRasterCount(), poODS->GetRasterCount()); } CPLError( CE_Failure, CPLE_AppDefined, "Returned tile does not match expected band configuration.\n%s", msg.c_str()); delete poTileDS; return CE_Failure; } /* -------------------------------------------------------------------- */ /* Process all bands of memory result, copying into pBuffer, or */ /* pushing into cache for other bands. */ /* -------------------------------------------------------------------- */ int iBand; eErr = CE_None; for( iBand = 0; iBand < poTileDS->GetRasterCount() && eErr == CE_None; iBand++ ) { GDALRasterBand *poTileBand = poTileDS->GetRasterBand( iBand+1 ); if( iBand+1 == GetBand() || (band_count == 1 && strlen(poODS->osBandIdentifier)) ) { eErr = poTileBand->RasterIO( GF_Read, 0, 0, nBlockXSize, nBlockYSize, pImage, nBlockXSize, nBlockYSize, eDataType, 0, 0, nullptr ); } else { GDALRasterBand *poTargBand = poODS->GetRasterBand( iBand+1 ); if( iOverview != -1 ) poTargBand = poTargBand->GetOverview( iOverview ); GDALRasterBlock *poBlock = poTargBand->GetLockedBlockRef( nBlockXOff, nBlockYOff, TRUE ); if( poBlock != nullptr ) { eErr = poTileBand->RasterIO( GF_Read, 0, 0, nBlockXSize, nBlockYSize, poBlock->GetDataRef(), nBlockXSize, nBlockYSize, eDataType, 0, 0, nullptr ); poBlock->DropLock(); } else eErr = CE_Failure; } } /* -------------------------------------------------------------------- */ /* Cleanup */ /* -------------------------------------------------------------------- */ delete poTileDS; poODS->FlushMemoryResult(); return eErr; } /************************************************************************/ /* IRasterIO() */ /************************************************************************/ CPLErr WCSRasterBand::IRasterIO( GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, void * pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg* psExtraArg) { if( (poODS->nMaxCols > 0 && poODS->nMaxCols < nBufXSize) || (poODS->nMaxRows > 0 && poODS->nMaxRows < nBufYSize) ) return CE_Failure; if( poODS->TestUseBlockIO( nXOff, nYOff, nXSize, nYSize, nBufXSize,nBufYSize ) ) return GDALPamRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg ); else return poODS->DirectRasterIO( eRWFlag, nXOff * nResFactor, nYOff * nResFactor, nXSize * nResFactor, nYSize * nResFactor, pData, nBufXSize, nBufYSize, eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg ); } /************************************************************************/ /* GetNoDataValue() */ /************************************************************************/ double WCSRasterBand::GetNoDataValue( int *pbSuccess ) { const char *pszSV = CPLGetXMLValue( poODS->psService, "NoDataValue", nullptr); if( pszSV == nullptr ) return GDALPamRasterBand::GetNoDataValue( pbSuccess ); else { if( pbSuccess ) *pbSuccess = TRUE; return CPLAtof(pszSV); } } /************************************************************************/ /* GetOverviewCount() */ /************************************************************************/ int WCSRasterBand::GetOverviewCount() { return nOverviewCount; } /************************************************************************/ /* GetOverview() */ /************************************************************************/ GDALRasterBand *WCSRasterBand::GetOverview( int iOverviewIn ) { if( iOverviewIn < 0 || iOverviewIn >= nOverviewCount ) return nullptr; else return papoOverviews[iOverviewIn]; }