1 /******************************************************************************
2 *
3 * Project: WCS Client Driver
4 * Purpose: Implementation of RasterBand classes for WCS.
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 2006, Frank Warmerdam
9 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_http.h"
31 #include "gdal_pam.h"
32
33 #include <algorithm>
34
35 #include "wcsdataset.h"
36 #include "wcsrasterband.h"
37
38 /************************************************************************/
39 /* WCSRasterBand() */
40 /************************************************************************/
41
WCSRasterBand(WCSDataset * poDSIn,int nBandIn,int iOverviewIn)42 WCSRasterBand::WCSRasterBand( WCSDataset *poDSIn, int nBandIn,
43 int iOverviewIn ) :
44 iOverview(iOverviewIn),
45 nResFactor(1 << (iOverviewIn+1)), // iOverview == -1 is base layer
46 poODS(poDSIn),
47 nOverviewCount(0),
48 papoOverviews(nullptr)
49 {
50 poDS = poDSIn;
51 nBand = nBandIn;
52
53 eDataType = GDALGetDataTypeByName(
54 CPLGetXMLValue( poDSIn->psService, "BandType", "Byte" ) );
55
56 /* -------------------------------------------------------------------- */
57 /* Establish resolution reduction for this overview level. */
58 /* -------------------------------------------------------------------- */
59
60 /* -------------------------------------------------------------------- */
61 /* Establish block size. */
62 /* -------------------------------------------------------------------- */
63 nRasterXSize = poDS->GetRasterXSize() / nResFactor;
64 nRasterYSize = poDS->GetRasterYSize() / nResFactor;
65
66 nBlockXSize = atoi(CPLGetXMLValue( poDSIn->psService, "BlockXSize", "0" ) );
67 nBlockYSize = atoi(CPLGetXMLValue( poDSIn->psService, "BlockYSize", "0" ) );
68
69 if( nBlockXSize < 1 )
70 {
71 if( nRasterXSize > 1800 )
72 nBlockXSize = 1024;
73 else
74 nBlockXSize = nRasterXSize;
75 }
76
77 if( nBlockYSize < 1 )
78 {
79 if( nRasterYSize > 900 )
80 nBlockYSize = 512;
81 else
82 nBlockYSize = nRasterYSize;
83 }
84
85 /* -------------------------------------------------------------------- */
86 /* If this is the base layer, create the overview layers. */
87 /* -------------------------------------------------------------------- */
88 if( iOverview == -1 )
89 {
90 nOverviewCount = atoi(CPLGetXMLValue(poODS->psService,"OverviewCount",
91 "-1"));
92 if( nOverviewCount < 0 )
93 {
94 for( nOverviewCount = 0;
95 (std::max(nRasterXSize, nRasterYSize) /
96 (1 << nOverviewCount)) > 900;
97 nOverviewCount++ ) {}
98 }
99 else if( nOverviewCount > 30 )
100 {
101 /* There's no reason to have more than 30 overviews, because */
102 /* 2^(30+1) overflows a int32 */
103 nOverviewCount = 30;
104 }
105
106 papoOverviews = (WCSRasterBand **)
107 CPLCalloc( nOverviewCount, sizeof(void*) );
108
109 for( int i = 0; i < nOverviewCount; i++ )
110 papoOverviews[i] = new WCSRasterBand( poODS, nBand, i );
111 }
112 }
113
114 /************************************************************************/
115 /* ~WCSRasterBand() */
116 /************************************************************************/
117
~WCSRasterBand()118 WCSRasterBand::~WCSRasterBand()
119
120 {
121 FlushCache();
122
123 if( nOverviewCount > 0 )
124 {
125 for( int i = 0; i < nOverviewCount; i++ )
126 delete papoOverviews[i];
127
128 CPLFree( papoOverviews );
129 }
130 }
131
132 /************************************************************************/
133 /* IReadBlock() */
134 /************************************************************************/
135
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)136 CPLErr WCSRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
137 void * pImage )
138
139 {
140 CPLErr eErr;
141 CPLHTTPResult *psResult = nullptr;
142
143 // if INTERLEAVE is set to PIXEL, then we'll request all bands.
144 // That is necessary at least with MapServer, which seems to often
145 // return all bands instead of requested.
146 // todo: in 2.0.1 the band list in this dataset may be user-defined
147
148 int band_count = 1;
149 if (EQUAL(CPLGetXMLValue(poODS->psService, "INTERLEAVE", ""), "PIXEL")) {
150 band_count = 0;
151 }
152
153 eErr = poODS->GetCoverage( nBlockXOff * nBlockXSize * nResFactor,
154 nBlockYOff * nBlockYSize * nResFactor,
155 nBlockXSize * nResFactor,
156 nBlockYSize * nResFactor,
157 nBlockXSize, nBlockYSize,
158 band_count, &nBand, nullptr, &psResult );
159 if( eErr != CE_None )
160 return eErr;
161
162 /* -------------------------------------------------------------------- */
163 /* Try and open result as a dataset. */
164 /* -------------------------------------------------------------------- */
165 GDALDataset *poTileDS = poODS->GDALOpenResult( psResult );
166
167 if( poTileDS == nullptr )
168 return CE_Failure;
169
170 /* -------------------------------------------------------------------- */
171 /* Verify configuration. */
172 /* -------------------------------------------------------------------- */
173 if( poTileDS->GetRasterXSize() != nBlockXSize
174 || poTileDS->GetRasterYSize() != nBlockYSize )
175 {
176 CPLError( CE_Failure, CPLE_AppDefined,
177 "Returned tile does not match expected configuration.\n"
178 "Got %dx%d instead of %dx%d.",
179 poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(),
180 nBlockXSize, nBlockYSize );
181 delete poTileDS;
182 return CE_Failure;
183 }
184
185 if( band_count == 1
186 && ((strlen(poODS->osBandIdentifier) && poTileDS->GetRasterCount() != 1)
187 || (!strlen(poODS->osBandIdentifier)
188 && poTileDS->GetRasterCount() != poODS->GetRasterCount())) )
189 {
190 CPLString msg;
191 if (strlen(poODS->osBandIdentifier) && poTileDS->GetRasterCount() != 1)
192 {
193 msg.Printf("Got %d bands instead of one although the coverage has band range type.\n",
194 poTileDS->GetRasterCount());
195 } else {
196 msg.Printf("Response has %d bands while this dataset has %d bands.\n",
197 poTileDS->GetRasterCount(), poODS->GetRasterCount());
198 }
199 CPLError( CE_Failure, CPLE_AppDefined,
200 "Returned tile does not match expected band configuration.\n%s", msg.c_str());
201 delete poTileDS;
202 return CE_Failure;
203 }
204
205 /* -------------------------------------------------------------------- */
206 /* Process all bands of memory result, copying into pBuffer, or */
207 /* pushing into cache for other bands. */
208 /* -------------------------------------------------------------------- */
209 int iBand;
210 eErr = CE_None;
211
212 for( iBand = 0;
213 iBand < poTileDS->GetRasterCount() && eErr == CE_None;
214 iBand++ )
215 {
216 GDALRasterBand *poTileBand = poTileDS->GetRasterBand( iBand+1 );
217
218 if( iBand+1 == GetBand() || (band_count == 1 && strlen(poODS->osBandIdentifier)) )
219 {
220 eErr = poTileBand->RasterIO( GF_Read,
221 0, 0, nBlockXSize, nBlockYSize,
222 pImage, nBlockXSize, nBlockYSize,
223 eDataType, 0, 0, nullptr );
224 }
225 else
226 {
227 GDALRasterBand *poTargBand = poODS->GetRasterBand( iBand+1 );
228
229 if( iOverview != -1 )
230 poTargBand = poTargBand->GetOverview( iOverview );
231
232 GDALRasterBlock *poBlock = poTargBand->GetLockedBlockRef(
233 nBlockXOff, nBlockYOff, TRUE );
234
235 if( poBlock != nullptr )
236 {
237 eErr = poTileBand->RasterIO( GF_Read,
238 0, 0, nBlockXSize, nBlockYSize,
239 poBlock->GetDataRef(),
240 nBlockXSize, nBlockYSize,
241 eDataType, 0, 0, nullptr );
242 poBlock->DropLock();
243 }
244 else
245 eErr = CE_Failure;
246 }
247 }
248
249 /* -------------------------------------------------------------------- */
250 /* Cleanup */
251 /* -------------------------------------------------------------------- */
252 delete poTileDS;
253
254 poODS->FlushMemoryResult();
255
256 return eErr;
257 }
258
259 /************************************************************************/
260 /* IRasterIO() */
261 /************************************************************************/
262
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)263 CPLErr WCSRasterBand::IRasterIO( GDALRWFlag eRWFlag,
264 int nXOff, int nYOff, int nXSize, int nYSize,
265 void * pData, int nBufXSize, int nBufYSize,
266 GDALDataType eBufType,
267 GSpacing nPixelSpace, GSpacing nLineSpace,
268 GDALRasterIOExtraArg* psExtraArg)
269
270 {
271 if( (poODS->nMaxCols > 0 && poODS->nMaxCols < nBufXSize)
272 || (poODS->nMaxRows > 0 && poODS->nMaxRows < nBufYSize) )
273 return CE_Failure;
274
275 if( poODS->TestUseBlockIO( nXOff, nYOff, nXSize, nYSize,
276 nBufXSize,nBufYSize ) )
277 return GDALPamRasterBand::IRasterIO(
278 eRWFlag, nXOff, nYOff, nXSize, nYSize,
279 pData, nBufXSize, nBufYSize, eBufType,
280 nPixelSpace, nLineSpace, psExtraArg );
281 else
282 return poODS->DirectRasterIO(
283 eRWFlag,
284 nXOff * nResFactor, nYOff * nResFactor,
285 nXSize * nResFactor, nYSize * nResFactor,
286 pData, nBufXSize, nBufYSize, eBufType,
287 1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg );
288 }
289
290 /************************************************************************/
291 /* GetNoDataValue() */
292 /************************************************************************/
293
GetNoDataValue(int * pbSuccess)294 double WCSRasterBand::GetNoDataValue( int *pbSuccess )
295
296 {
297 const char *pszSV = CPLGetXMLValue( poODS->psService, "NoDataValue", nullptr);
298
299 if( pszSV == nullptr )
300 return GDALPamRasterBand::GetNoDataValue( pbSuccess );
301 else
302 {
303 if( pbSuccess )
304 *pbSuccess = TRUE;
305 return CPLAtof(pszSV);
306 }
307 }
308
309 /************************************************************************/
310 /* GetOverviewCount() */
311 /************************************************************************/
312
GetOverviewCount()313 int WCSRasterBand::GetOverviewCount()
314
315 {
316 return nOverviewCount;
317 }
318
319 /************************************************************************/
320 /* GetOverview() */
321 /************************************************************************/
322
GetOverview(int iOverviewIn)323 GDALRasterBand *WCSRasterBand::GetOverview( int iOverviewIn )
324
325 {
326 if( iOverviewIn < 0 || iOverviewIn >= nOverviewCount )
327 return nullptr;
328 else
329 return papoOverviews[iOverviewIn];
330 }
331