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