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