Line data Source code
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 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_http.h"
15 : #include "gdal_pam.h"
16 : #include "gdal_rasterblock.h"
17 :
18 : #include <algorithm>
19 : #include <cassert>
20 :
21 : #include "wcsdataset.h"
22 : #include "wcsrasterband.h"
23 :
24 : /************************************************************************/
25 : /* WCSRasterBand() */
26 : /************************************************************************/
27 :
28 765 : WCSRasterBand::WCSRasterBand(WCSDataset *poDSIn, int nBandIn, int iOverviewIn)
29 : : iOverview(iOverviewIn),
30 765 : nResFactor(1 << (iOverviewIn + 1)), // iOverview == -1 is base layer
31 765 : poODS(poDSIn), nOverviewCount(0), papoOverviews(nullptr)
32 : {
33 765 : poDS = poDSIn;
34 765 : nBand = nBandIn;
35 :
36 765 : eDataType = GDALGetDataTypeByName(
37 765 : CPLGetXMLValue(poDSIn->psService, "BandType", "Byte"));
38 :
39 : /* -------------------------------------------------------------------- */
40 : /* Establish resolution reduction for this overview level. */
41 : /* -------------------------------------------------------------------- */
42 :
43 : /* -------------------------------------------------------------------- */
44 : /* Establish block size. */
45 : /* -------------------------------------------------------------------- */
46 765 : nRasterXSize = poDS->GetRasterXSize() / nResFactor;
47 765 : nRasterYSize = poDS->GetRasterYSize() / nResFactor;
48 :
49 765 : nBlockXSize = atoi(CPLGetXMLValue(poDSIn->psService, "BlockXSize", "0"));
50 765 : nBlockYSize = atoi(CPLGetXMLValue(poDSIn->psService, "BlockYSize", "0"));
51 :
52 765 : if (nBlockXSize < 1)
53 : {
54 765 : if (nRasterXSize > 1800)
55 417 : nBlockXSize = 1024;
56 : else
57 348 : nBlockXSize = nRasterXSize;
58 : }
59 :
60 765 : if (nBlockYSize < 1)
61 : {
62 765 : if (nRasterYSize > 900)
63 621 : nBlockYSize = 512;
64 : else
65 144 : nBlockYSize = nRasterYSize;
66 : }
67 :
68 : /* -------------------------------------------------------------------- */
69 : /* If this is the base layer, create the overview layers. */
70 : /* -------------------------------------------------------------------- */
71 765 : if (iOverview == -1)
72 : {
73 135 : nOverviewCount =
74 135 : atoi(CPLGetXMLValue(poODS->psService, "OverviewCount", "-1"));
75 135 : if (nOverviewCount < 0)
76 : {
77 765 : for (nOverviewCount = 0; (std::max(nRasterXSize, nRasterYSize) /
78 765 : (1 << nOverviewCount)) > 900;
79 630 : nOverviewCount++)
80 : {
81 : }
82 : }
83 0 : else if (nOverviewCount > 30)
84 : {
85 : /* There's no reason to have more than 30 overviews, because */
86 : /* 2^(30+1) overflows a int32 */
87 0 : nOverviewCount = 30;
88 : }
89 :
90 135 : papoOverviews =
91 135 : (WCSRasterBand **)CPLCalloc(nOverviewCount, sizeof(void *));
92 :
93 765 : for (int i = 0; i < nOverviewCount; i++)
94 630 : papoOverviews[i] = new WCSRasterBand(poODS, nBand, i);
95 : }
96 765 : }
97 :
98 : /************************************************************************/
99 : /* ~WCSRasterBand() */
100 : /************************************************************************/
101 :
102 1530 : WCSRasterBand::~WCSRasterBand()
103 :
104 : {
105 765 : FlushCache(true);
106 :
107 765 : if (nOverviewCount > 0)
108 : {
109 759 : for (int i = 0; i < nOverviewCount; i++)
110 630 : delete papoOverviews[i];
111 :
112 129 : CPLFree(papoOverviews);
113 : }
114 1530 : }
115 :
116 : /************************************************************************/
117 : /* IReadBlock() */
118 : /************************************************************************/
119 :
120 24 : CPLErr WCSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
121 :
122 : {
123 : CPLErr eErr;
124 24 : CPLHTTPResult *psResult = nullptr;
125 :
126 : // if INTERLEAVE is set to PIXEL, then we'll request all bands.
127 : // That is necessary at least with MapServer, which seems to often
128 : // return all bands instead of requested.
129 : // todo: in 2.0.1 the band list in this dataset may be user-defined
130 :
131 24 : int band_count = 1;
132 24 : if (EQUAL(CPLGetXMLValue(poODS->psService, "INTERLEAVE", ""), "PIXEL"))
133 : {
134 24 : band_count = 0;
135 : }
136 :
137 48 : eErr = poODS->GetCoverage(
138 24 : nBlockXOff * nBlockXSize * nResFactor,
139 24 : nBlockYOff * nBlockYSize * nResFactor, nBlockXSize * nResFactor,
140 24 : nBlockYSize * nResFactor, nBlockXSize, nBlockYSize, band_count, &nBand,
141 : nullptr, &psResult);
142 24 : if (eErr != CE_None)
143 0 : return eErr;
144 :
145 : /* -------------------------------------------------------------------- */
146 : /* Try and open result as a dataset. */
147 : /* -------------------------------------------------------------------- */
148 24 : GDALDataset *poTileDS = poODS->GDALOpenResult(psResult);
149 :
150 24 : if (poTileDS == nullptr)
151 0 : return CE_Failure;
152 :
153 : /* -------------------------------------------------------------------- */
154 : /* Verify configuration. */
155 : /* -------------------------------------------------------------------- */
156 48 : if (poTileDS->GetRasterXSize() != nBlockXSize ||
157 24 : poTileDS->GetRasterYSize() != nBlockYSize)
158 : {
159 0 : CPLError(CE_Failure, CPLE_AppDefined,
160 : "Returned tile does not match expected configuration.\n"
161 : "Got %dx%d instead of %dx%d.",
162 : poTileDS->GetRasterXSize(), poTileDS->GetRasterYSize(),
163 : nBlockXSize, nBlockYSize);
164 0 : delete poTileDS;
165 0 : return CE_Failure;
166 : }
167 :
168 24 : if (band_count == 1 &&
169 0 : ((!poODS->osBandIdentifier.empty() &&
170 0 : poTileDS->GetRasterCount() != 1) ||
171 0 : (poODS->osBandIdentifier.empty() &&
172 0 : poTileDS->GetRasterCount() != poODS->GetRasterCount())))
173 : {
174 0 : CPLString msg;
175 0 : if (!poODS->osBandIdentifier.empty() && poTileDS->GetRasterCount() != 1)
176 : {
177 : msg.Printf("Got %d bands instead of one although the coverage has "
178 : "band range type.\n",
179 0 : poTileDS->GetRasterCount());
180 : }
181 : else
182 : {
183 : msg.Printf(
184 : "Response has %d bands while this dataset has %d bands.\n",
185 0 : poTileDS->GetRasterCount(), poODS->GetRasterCount());
186 : }
187 0 : CPLError(
188 : CE_Failure, CPLE_AppDefined,
189 : "Returned tile does not match expected band configuration.\n%s",
190 : msg.c_str());
191 0 : delete poTileDS;
192 0 : return CE_Failure;
193 : }
194 :
195 : /* -------------------------------------------------------------------- */
196 : /* Process all bands of memory result, copying into pBuffer, or */
197 : /* pushing into cache for other bands. */
198 : /* -------------------------------------------------------------------- */
199 : int iBand;
200 24 : eErr = CE_None;
201 :
202 69 : for (iBand = 0; iBand < poTileDS->GetRasterCount() && eErr == CE_None;
203 : iBand++)
204 : {
205 45 : GDALRasterBand *poTileBand = poTileDS->GetRasterBand(iBand + 1);
206 :
207 45 : if (iBand + 1 == GetBand() ||
208 0 : (band_count == 1 && !poODS->osBandIdentifier.empty()))
209 : {
210 24 : eErr = poTileBand->RasterIO(GF_Read, 0, 0, nBlockXSize, nBlockYSize,
211 : pImage, nBlockXSize, nBlockYSize,
212 : eDataType, 0, 0, nullptr);
213 : }
214 : else
215 : {
216 21 : GDALRasterBand *poTargBand = poODS->GetRasterBand(iBand + 1);
217 :
218 21 : if (iOverview != -1)
219 0 : poTargBand = poTargBand->GetOverview(iOverview);
220 :
221 21 : assert(poTargBand);
222 : #if defined(__GNUC__)
223 : #pragma GCC diagnostic push
224 : #pragma GCC diagnostic ignored "-Wnull-dereference"
225 : #endif
226 : GDALRasterBlock *poBlock =
227 21 : poTargBand->GetLockedBlockRef(nBlockXOff, nBlockYOff, TRUE);
228 : #if defined(__GNUC__)
229 : #pragma GCC diagnostic pop
230 : #endif
231 :
232 21 : if (poBlock != nullptr)
233 : {
234 21 : eErr = poTileBand->RasterIO(GF_Read, 0, 0, nBlockXSize,
235 : nBlockYSize, poBlock->GetDataRef(),
236 : nBlockXSize, nBlockYSize, eDataType,
237 : 0, 0, nullptr);
238 21 : poBlock->DropLock();
239 : }
240 : else
241 0 : eErr = CE_Failure;
242 : }
243 : }
244 :
245 : /* -------------------------------------------------------------------- */
246 : /* Cleanup */
247 : /* -------------------------------------------------------------------- */
248 24 : delete poTileDS;
249 :
250 24 : poODS->FlushMemoryResult();
251 :
252 24 : return eErr;
253 : }
254 :
255 : /************************************************************************/
256 : /* IRasterIO() */
257 : /************************************************************************/
258 :
259 58 : CPLErr WCSRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
260 : int nXSize, int nYSize, void *pData,
261 : int nBufXSize, int nBufYSize,
262 : GDALDataType eBufType, GSpacing nPixelSpace,
263 : GSpacing nLineSpace,
264 : GDALRasterIOExtraArg *psExtraArg)
265 :
266 : {
267 58 : if ((poODS->nMaxCols > 0 && poODS->nMaxCols < nBufXSize) ||
268 58 : (poODS->nMaxRows > 0 && poODS->nMaxRows < nBufYSize))
269 0 : return CE_Failure;
270 :
271 58 : if (poODS->TestUseBlockIO(nXOff, nYOff, nXSize, nYSize, nBufXSize,
272 58 : nBufYSize))
273 45 : return GDALPamRasterBand::IRasterIO(
274 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
275 45 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
276 : else
277 26 : return poODS->DirectRasterIO(eRWFlag, nXOff * nResFactor,
278 13 : nYOff * nResFactor, nXSize * nResFactor,
279 13 : nYSize * nResFactor, pData, nBufXSize,
280 13 : nBufYSize, eBufType, 1, &nBand,
281 13 : nPixelSpace, nLineSpace, 0, psExtraArg);
282 : }
283 :
284 : /************************************************************************/
285 : /* GetNoDataValue() */
286 : /************************************************************************/
287 :
288 252 : double WCSRasterBand::GetNoDataValue(int *pbSuccess)
289 :
290 : {
291 : const char *pszSV =
292 252 : CPLGetXMLValue(poODS->psService, "NoDataValue", nullptr);
293 :
294 252 : if (pszSV == nullptr)
295 96 : return GDALPamRasterBand::GetNoDataValue(pbSuccess);
296 : else
297 : {
298 156 : if (pbSuccess)
299 126 : *pbSuccess = TRUE;
300 156 : return CPLAtof(pszSV);
301 : }
302 : }
303 :
304 : /************************************************************************/
305 : /* GetOverviewCount() */
306 : /************************************************************************/
307 :
308 96 : int WCSRasterBand::GetOverviewCount()
309 :
310 : {
311 96 : return nOverviewCount;
312 : }
313 :
314 : /************************************************************************/
315 : /* GetOverview() */
316 : /************************************************************************/
317 :
318 0 : GDALRasterBand *WCSRasterBand::GetOverview(int iOverviewIn)
319 :
320 : {
321 0 : if (iOverviewIn < 0 || iOverviewIn >= nOverviewCount)
322 0 : return nullptr;
323 : else
324 0 : return papoOverviews[iOverviewIn];
325 : }
|