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