1 /******************************************************************************
2 *
3 * Project: GDAL Core
4 * Purpose: Implementation of a dataset overview warping class
5 * Author: Even Rouault, <even dot rouault at spatialys dot com>
6 *
7 ******************************************************************************
8 * Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ****************************************************************************/
28
29 #include "cpl_port.h"
30 #include "gdal_priv.h"
31
32 #include <cstring>
33
34 #include "cpl_conv.h"
35 #include "cpl_error.h"
36 #include "cpl_progress.h"
37 #include "cpl_string.h"
38 #include "gdal.h"
39 #include "gdal_mdreader.h"
40 #include "gdal_proxy.h"
41
42 CPL_CVSID("$Id: gdaloverviewdataset.cpp 126b0897e64c233ed06ca072549e110bb6b28ced 2021-04-20 16:42:23 +0200 Even Rouault $")
43
44 /** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that may
45 have no parent dataset. This can be inconvenient in certain contexts, where
46 cross-band processing must be done, or when API expect a fully fledged
47 dataset. Furthermore even if overview band has a container dataset, that
48 one often fails to declare its projection, geotransform, etc... which make
49 it somehow useless. GDALOverviewDataset remedies to those deficiencies.
50 */
51
52 class GDALOverviewBand;
53
54 /* ******************************************************************** */
55 /* GDALOverviewDataset */
56 /* ******************************************************************** */
57
58 class GDALOverviewDataset final: public GDALDataset
59 {
60 private:
61 friend class GDALOverviewBand;
62
63 GDALDataset* poMainDS = nullptr;
64
65 GDALDataset* poOvrDS = nullptr; // Will be often NULL.
66 int nOvrLevel = 0;
67 int bThisLevelOnly = 0;
68
69 int nGCPCount = 0;
70 GDAL_GCP *pasGCPList = nullptr;
71 char **papszMD_RPC = nullptr;
72 char **papszMD_GEOLOCATION = nullptr;
73 GDALOverviewBand* m_poMaskBand = nullptr;
74
75 static void Rescale( char**& papszMD, const char* pszItem,
76 double dfRatio, double dfDefaultVal );
77
78 protected:
79 CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
80 void *, int, int, GDALDataType,
81 int, int *,
82 GSpacing, GSpacing, GSpacing,
83 GDALRasterIOExtraArg* psExtraArg ) override;
84
85 public:
86 GDALOverviewDataset( GDALDataset* poMainDS,
87 int nOvrLevel,
88 int bThisLevelOnly );
89 ~GDALOverviewDataset() override;
90
91 const OGRSpatialReference* GetSpatialRef() const override;
92 CPLErr GetGeoTransform( double * ) override;
93
94 int GetGCPCount() override;
95 const OGRSpatialReference *GetGCPSpatialRef() const override;
96 const GDAL_GCP *GetGCPs() override;
97
98 char **GetMetadata( const char * pszDomain = "" ) override;
99 const char *GetMetadataItem( const char * pszName,
100 const char * pszDomain = "" ) override;
101
102 int CloseDependentDatasets() override;
103
104 private:
105 CPL_DISALLOW_COPY_ASSIGN(GDALOverviewDataset)
106 };
107
108 /* ******************************************************************** */
109 /* GDALOverviewBand */
110 /* ******************************************************************** */
111
112 class GDALOverviewBand final: public GDALProxyRasterBand
113 {
114 protected:
115 friend class GDALOverviewDataset;
116
117 GDALRasterBand* poUnderlyingBand = nullptr;
118 GDALRasterBand* RefUnderlyingRasterBand() override;
119
120 CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
121 void *, int, int, GDALDataType,
122 GSpacing, GSpacing,
123 GDALRasterIOExtraArg* psExtraArg ) override;
124
125 public:
126 GDALOverviewBand( GDALOverviewDataset* poDS, int nBand );
127 ~GDALOverviewBand() override;
128
129 CPLErr FlushCache() override;
130
131 int GetOverviewCount() override;
132 GDALRasterBand *GetOverview( int ) override;
133
134 int GetMaskFlags() override;
135 GDALRasterBand* GetMaskBand() override;
136
137 private:
138 CPL_DISALLOW_COPY_ASSIGN(GDALOverviewBand)
139 };
140
141 /************************************************************************/
142 /* GetOverviewEx() */
143 /************************************************************************/
144
GetOverviewEx(GDALRasterBand * poBand,int nLevel)145 static GDALRasterBand* GetOverviewEx(GDALRasterBand* poBand, int nLevel)
146 {
147 if( nLevel == -1 )
148 return poBand;
149 return poBand->GetOverview(nLevel);
150 }
151
152 /************************************************************************/
153 /* GDALCreateOverviewDataset() */
154 /************************************************************************/
155
156 // Takes a reference on poMainDS in case of success.
157 // nOvrLevel=-1 means the full resolution dataset (only useful if
158 // bThisLevelOnly = false to expose a dataset without its overviews)
GDALCreateOverviewDataset(GDALDataset * poMainDS,int nOvrLevel,int bThisLevelOnly)159 GDALDataset* GDALCreateOverviewDataset( GDALDataset* poMainDS, int nOvrLevel,
160 int bThisLevelOnly )
161 {
162 // Sanity checks.
163 const int nBands = poMainDS->GetRasterCount();
164 if( nBands == 0 )
165 return nullptr;
166
167 auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
168 for( int i = 1; i<= nBands; ++i )
169 {
170 auto poBand = GetOverviewEx(poMainDS->GetRasterBand(i), nOvrLevel);
171 if( poBand == nullptr )
172 {
173 return nullptr;
174 }
175 if( poBand->GetXSize() != poFirstBand->GetXSize() ||
176 poBand->GetYSize() != poFirstBand->GetYSize() )
177 {
178 return nullptr;
179 }
180 }
181
182 return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly);
183 }
184
185 /************************************************************************/
186 /* GDALOverviewDataset() */
187 /************************************************************************/
188
GDALOverviewDataset(GDALDataset * poMainDSIn,int nOvrLevelIn,int bThisLevelOnlyIn)189 GDALOverviewDataset::GDALOverviewDataset( GDALDataset* poMainDSIn,
190 int nOvrLevelIn,
191 int bThisLevelOnlyIn ) :
192 poMainDS(poMainDSIn),
193 nOvrLevel(nOvrLevelIn),
194 bThisLevelOnly(bThisLevelOnlyIn)
195 {
196 poMainDSIn->Reference();
197 eAccess = poMainDS->GetAccess();
198 auto poFirstBand = GetOverviewEx(poMainDS->GetRasterBand(1), nOvrLevel);
199 nRasterXSize = poFirstBand->GetXSize();
200 nRasterYSize = poFirstBand->GetYSize();
201 poOvrDS = poFirstBand->GetDataset();
202 if( nOvrLevel != -1 && poOvrDS != nullptr && poOvrDS == poMainDS )
203 {
204 CPLDebug( "GDAL",
205 "Dataset of overview is the same as the main band. "
206 "This is not expected");
207 poOvrDS = nullptr;
208 }
209 nBands = poMainDS->GetRasterCount();
210 for( int i = 0; i < nBands; ++i )
211 {
212 SetBand(i+1, new GDALOverviewBand(this, i+1));
213 }
214
215 if( poFirstBand->GetMaskFlags() == GMF_PER_DATASET )
216 {
217 auto poOvrMaskBand = poFirstBand->GetMaskBand();
218 if( poOvrMaskBand && poOvrMaskBand->GetXSize() == nRasterXSize &&
219 poOvrMaskBand->GetYSize() == nRasterYSize )
220 {
221 m_poMaskBand = new GDALOverviewBand(this, 0);
222 }
223 }
224
225 // We create a fake driver that has the same name as the original
226 // one, but we cannot use the real driver object, so that code
227 // doesn't try to cast the GDALOverviewDataset* as a native dataset
228 // object.
229 if( poMainDS->GetDriver() != nullptr )
230 {
231 poDriver = new GDALDriver();
232 poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
233 poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
234 }
235
236 if( poOvrDS )
237 poOvrDS->SetEnableOverviews(false);
238
239 SetDescription( poMainDS->GetDescription() );
240
241 CPLDebug( "GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
242 poMainDS->GetDescription(), this );
243
244 papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
245 // Add OVERVIEW_LEVEL if not called from GDALOpenEx(), but directly.
246 papszOpenOptions = CSLSetNameValue(papszOpenOptions, "OVERVIEW_LEVEL",
247 nOvrLevel == -1 ? "NONE" :
248 CPLSPrintf("%d%s", nOvrLevel, bThisLevelOnly ? " only" :""));
249 }
250
251 /************************************************************************/
252 /* ~GDALOverviewDataset() */
253 /************************************************************************/
254
~GDALOverviewDataset()255 GDALOverviewDataset::~GDALOverviewDataset()
256 {
257 GDALOverviewDataset::FlushCache();
258
259 GDALOverviewDataset::CloseDependentDatasets();
260
261 if( nGCPCount > 0 )
262 {
263 GDALDeinitGCPs( nGCPCount, pasGCPList );
264 CPLFree( pasGCPList );
265 }
266 CSLDestroy(papszMD_RPC);
267
268 CSLDestroy(papszMD_GEOLOCATION);
269
270 delete poDriver;
271 }
272
273 /************************************************************************/
274 /* CloseDependentDatasets() */
275 /************************************************************************/
276
CloseDependentDatasets()277 int GDALOverviewDataset::CloseDependentDatasets()
278 {
279 bool bRet = false;
280
281 if( poMainDS )
282 {
283 for( int i = 0; i < nBands; ++i )
284 {
285 GDALOverviewBand* const band =
286 cpl::down_cast<GDALOverviewBand*>(papoBands[i]);
287 band->poUnderlyingBand = nullptr;
288 }
289 if( poMainDS->ReleaseRef() )
290 bRet = true;
291 poMainDS = nullptr;
292 }
293
294 if( m_poMaskBand )
295 {
296 m_poMaskBand->poUnderlyingBand = nullptr;
297 delete m_poMaskBand;
298 m_poMaskBand = nullptr;
299 }
300
301 return bRet;
302 }
303
304 /************************************************************************/
305 /* IRasterIO() */
306 /* */
307 /* The default implementation of IRasterIO() is to pass the */
308 /* request off to each band objects rasterio methods with */
309 /* appropriate arguments. */
310 /************************************************************************/
311
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpace,GSpacing nLineSpace,GSpacing nBandSpace,GDALRasterIOExtraArg * psExtraArg)312 CPLErr GDALOverviewDataset::IRasterIO( GDALRWFlag eRWFlag,
313 int nXOff, int nYOff,
314 int nXSize, int nYSize,
315 void * pData,
316 int nBufXSize, int nBufYSize,
317 GDALDataType eBufType,
318 int nBandCount, int *panBandMap,
319 GSpacing nPixelSpace,
320 GSpacing nLineSpace,
321 GSpacing nBandSpace,
322 GDALRasterIOExtraArg* psExtraArg )
323
324 {
325 // Try to pass the request to the most appropriate overview dataset.
326 if( nBufXSize < nXSize && nBufYSize < nYSize )
327 {
328 int bTried = FALSE;
329 const CPLErr eErr =
330 TryOverviewRasterIO( eRWFlag,
331 nXOff, nYOff, nXSize, nYSize,
332 pData, nBufXSize, nBufYSize,
333 eBufType,
334 nBandCount, panBandMap,
335 nPixelSpace, nLineSpace,
336 nBandSpace,
337 psExtraArg,
338 &bTried );
339 if( bTried )
340 return eErr;
341 }
342
343 // In case the overview bands are really linked to a dataset, then issue
344 // the request to that dataset.
345 if( nOvrLevel != -1 && poOvrDS != nullptr )
346 {
347 return poOvrDS->RasterIO(
348 eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
349 eBufType, nBandCount, panBandMap, nPixelSpace,
350 nLineSpace, nBandSpace,
351 psExtraArg);
352 }
353
354 GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
355 void *pProgressDataGlobal = psExtraArg->pProgressData;
356 CPLErr eErr = CE_None;
357
358 for( int iBandIndex = 0;
359 iBandIndex < nBandCount && eErr == CE_None;
360 ++iBandIndex )
361 {
362 GDALOverviewBand *poBand =
363 cpl::down_cast<GDALOverviewBand *>(
364 GetRasterBand(panBandMap[iBandIndex]) );
365 GByte *pabyBandData =
366 static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
367
368 psExtraArg->pfnProgress = GDALScaledProgress;
369 psExtraArg->pProgressData =
370 GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
371 1.0 * (iBandIndex + 1) / nBandCount,
372 pfnProgressGlobal,
373 pProgressDataGlobal );
374
375 eErr = poBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
376 pabyBandData,
377 nBufXSize, nBufYSize,
378 eBufType, nPixelSpace,
379 nLineSpace, psExtraArg );
380
381 GDALDestroyScaledProgress( psExtraArg->pProgressData );
382 }
383
384 psExtraArg->pfnProgress = pfnProgressGlobal;
385 psExtraArg->pProgressData = pProgressDataGlobal;
386
387 return eErr;
388 }
389
390 /************************************************************************/
391 /* GetSpatialRef() */
392 /************************************************************************/
393
GetSpatialRef() const394 const OGRSpatialReference *GDALOverviewDataset::GetSpatialRef() const
395
396 {
397 return poMainDS->GetSpatialRef();
398 }
399
400 /************************************************************************/
401 /* GetGeoTransform() */
402 /************************************************************************/
403
GetGeoTransform(double * padfTransform)404 CPLErr GDALOverviewDataset::GetGeoTransform( double * padfTransform )
405
406 {
407 double adfGeoTransform[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
408 if( poMainDS->GetGeoTransform(adfGeoTransform) != CE_None )
409 return CE_Failure;
410
411 adfGeoTransform[1] *=
412 static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
413 adfGeoTransform[2] *=
414 static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
415 adfGeoTransform[4] *=
416 static_cast<double>(poMainDS->GetRasterXSize()) / nRasterXSize;
417 adfGeoTransform[5] *=
418 static_cast<double>(poMainDS->GetRasterYSize()) / nRasterYSize;
419
420 memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
421
422 return CE_None;
423 }
424
425 /************************************************************************/
426 /* GetGCPCount() */
427 /************************************************************************/
428
GetGCPCount()429 int GDALOverviewDataset::GetGCPCount()
430
431 {
432 return poMainDS->GetGCPCount();
433 }
434
435 /************************************************************************/
436 /* GetGCPSpatialRef() */
437 /************************************************************************/
438
GetGCPSpatialRef() const439 const OGRSpatialReference *GDALOverviewDataset::GetGCPSpatialRef() const
440
441 {
442 return poMainDS->GetGCPSpatialRef();
443 }
444
445 /************************************************************************/
446 /* GetGCPs() */
447 /************************************************************************/
448
GetGCPs()449 const GDAL_GCP *GDALOverviewDataset::GetGCPs()
450
451 {
452 if( pasGCPList != nullptr )
453 return pasGCPList;
454
455 const GDAL_GCP* pasGCPsMain = poMainDS->GetGCPs();
456 if( pasGCPsMain == nullptr )
457 return nullptr;
458 nGCPCount = poMainDS->GetGCPCount();
459
460 pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPsMain );
461 for( int i = 0; i < nGCPCount; ++i )
462 {
463 pasGCPList[i].dfGCPPixel *= static_cast<double>(nRasterXSize) /
464 poMainDS->GetRasterXSize();
465 pasGCPList[i].dfGCPLine *= static_cast<double>(nRasterYSize) /
466 poMainDS->GetRasterYSize();
467 }
468 return pasGCPList;
469 }
470
471 /************************************************************************/
472 /* Rescale() */
473 /************************************************************************/
474
Rescale(char ** & papszMD,const char * pszItem,double dfRatio,double dfDefaultVal)475 void GDALOverviewDataset::Rescale( char**& papszMD, const char* pszItem,
476 double dfRatio, double dfDefaultVal )
477 {
478 double dfVal =
479 CPLAtofM( CSLFetchNameValueDef(papszMD, pszItem,
480 CPLSPrintf("%.18g", dfDefaultVal)) );
481 dfVal *= dfRatio;
482 papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.18g", dfVal));
483 }
484
485 /************************************************************************/
486 /* GetMetadata() */
487 /************************************************************************/
488
GetMetadata(const char * pszDomain)489 char **GDALOverviewDataset::GetMetadata( const char * pszDomain )
490 {
491 if( poOvrDS != nullptr )
492 {
493 char** papszMD = poOvrDS->GetMetadata(pszDomain);
494 if( papszMD != nullptr )
495 return papszMD;
496 }
497
498 char** papszMD = poMainDS->GetMetadata(pszDomain);
499
500 // We may need to rescale some values from the RPC metadata domain.
501 if( pszDomain != nullptr && EQUAL(pszDomain, MD_DOMAIN_RPC) &&
502 papszMD != nullptr )
503 {
504 if( papszMD_RPC )
505 return papszMD_RPC;
506 papszMD_RPC = CSLDuplicate(papszMD);
507
508 Rescale( papszMD_RPC, RPC_LINE_OFF,
509 static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
510 0.0 );
511 Rescale( papszMD_RPC, RPC_LINE_SCALE,
512 static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
513 1.0 );
514 Rescale( papszMD_RPC, RPC_SAMP_OFF,
515 static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
516 0.0 );
517 Rescale( papszMD_RPC, RPC_SAMP_SCALE,
518 static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
519 1.0 );
520
521 papszMD = papszMD_RPC;
522 }
523
524 // We may need to rescale some values from the GEOLOCATION metadata domain.
525 if( pszDomain != nullptr && EQUAL(pszDomain, "GEOLOCATION") &&
526 papszMD != nullptr )
527 {
528 if( papszMD_GEOLOCATION )
529 return papszMD_GEOLOCATION;
530 papszMD_GEOLOCATION = CSLDuplicate(papszMD);
531
532 Rescale( papszMD_GEOLOCATION, "PIXEL_OFFSET",
533 static_cast<double>(poMainDS->GetRasterXSize()) /
534 nRasterXSize, 0.0 );
535 Rescale( papszMD_GEOLOCATION, "LINE_OFFSET",
536 static_cast<double>(poMainDS->GetRasterYSize()) /
537 nRasterYSize, 0.0 );
538
539 Rescale( papszMD_GEOLOCATION, "PIXEL_STEP",
540 static_cast<double>(nRasterXSize) / poMainDS->GetRasterXSize(),
541 1.0 );
542 Rescale( papszMD_GEOLOCATION, "LINE_STEP",
543 static_cast<double>(nRasterYSize) / poMainDS->GetRasterYSize(),
544 1.0 );
545
546 papszMD = papszMD_GEOLOCATION;
547 }
548
549 return papszMD;
550 }
551
552 /************************************************************************/
553 /* GetMetadataItem() */
554 /************************************************************************/
555
GetMetadataItem(const char * pszName,const char * pszDomain)556 const char *GDALOverviewDataset::GetMetadataItem( const char * pszName,
557 const char * pszDomain )
558 {
559 if( poOvrDS != nullptr )
560 {
561 const char* pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
562 if( pszValue != nullptr )
563 return pszValue;
564 }
565
566 if( pszDomain != nullptr && (EQUAL(pszDomain, "RPC") ||
567 EQUAL(pszDomain, "GEOLOCATION")) )
568 {
569 char** papszMD = GetMetadata(pszDomain);
570 return CSLFetchNameValue(papszMD, pszName);
571 }
572
573 return poMainDS->GetMetadataItem(pszName, pszDomain);
574 }
575
576 /************************************************************************/
577 /* GDALOverviewBand() */
578 /************************************************************************/
579
GDALOverviewBand(GDALOverviewDataset * poDSIn,int nBandIn)580 GDALOverviewBand::GDALOverviewBand( GDALOverviewDataset* poDSIn, int nBandIn )
581 {
582 poDS = poDSIn;
583 nBand = nBandIn;
584 nRasterXSize = poDSIn->nRasterXSize;
585 nRasterYSize = poDSIn->nRasterYSize;
586 if( nBandIn == 0 )
587 {
588 poUnderlyingBand =
589 GetOverviewEx(poDSIn->poMainDS->GetRasterBand(1), poDSIn->nOvrLevel)->GetMaskBand();
590 }
591 else
592 {
593 poUnderlyingBand =
594 GetOverviewEx(poDSIn->poMainDS->GetRasterBand(nBandIn), poDSIn->nOvrLevel);
595 }
596 eDataType = poUnderlyingBand->GetRasterDataType();
597 poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
598 }
599
600 /************************************************************************/
601 /* ~GDALOverviewBand() */
602 /************************************************************************/
603
~GDALOverviewBand()604 GDALOverviewBand::~GDALOverviewBand()
605 {
606 GDALOverviewBand::FlushCache();
607 }
608
609 /************************************************************************/
610 /* FlushCache() */
611 /************************************************************************/
612
FlushCache()613 CPLErr GDALOverviewBand::FlushCache()
614 {
615 if( poUnderlyingBand )
616 return poUnderlyingBand->FlushCache();
617 return CE_None;
618 }
619
620 /************************************************************************/
621 /* RefUnderlyingRasterBand() */
622 /************************************************************************/
623
RefUnderlyingRasterBand()624 GDALRasterBand* GDALOverviewBand::RefUnderlyingRasterBand()
625 {
626 if( poUnderlyingBand )
627 return poUnderlyingBand;
628
629 return nullptr;
630 }
631
632 /************************************************************************/
633 /* GetOverviewCount() */
634 /************************************************************************/
635
GetOverviewCount()636 int GDALOverviewBand::GetOverviewCount()
637 {
638 GDALOverviewDataset * const poOvrDS =
639 cpl::down_cast<GDALOverviewDataset *>(poDS);
640 if( poOvrDS->bThisLevelOnly )
641 return 0;
642 GDALDataset * const poMainDS = poOvrDS->poMainDS;
643 GDALRasterBand* poMainBand =
644 ( nBand == 0 ) ? poMainDS->GetRasterBand(1)->GetMaskBand() :
645 poMainDS->GetRasterBand(nBand);
646 auto poUnderlyingDS = poUnderlyingBand ? poUnderlyingBand->GetDataset() : nullptr;
647 if( poUnderlyingDS )
648 poUnderlyingDS->SetEnableOverviews(true);
649 const int nRet = poMainBand->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
650 if( poUnderlyingDS )
651 poUnderlyingDS->SetEnableOverviews(false);
652 return nRet;
653 }
654
655 /************************************************************************/
656 /* GetOverview() */
657 /************************************************************************/
658
GetOverview(int iOvr)659 GDALRasterBand *GDALOverviewBand::GetOverview( int iOvr )
660 {
661 if( iOvr < 0 || iOvr >= GetOverviewCount() )
662 return nullptr;
663 GDALOverviewDataset * const poOvrDS =
664 cpl::down_cast<GDALOverviewDataset *>(poDS);
665 GDALDataset * const poMainDS = poOvrDS->poMainDS;
666 GDALRasterBand* poMainBand =
667 ( nBand == 0 ) ? poMainDS->GetRasterBand(1)->GetMaskBand() :
668 poMainDS->GetRasterBand(nBand);
669 auto poUnderlyingDS = poUnderlyingBand ? poUnderlyingBand->GetDataset() : nullptr;
670 if( poUnderlyingDS )
671 poUnderlyingDS->SetEnableOverviews(true);
672 auto poRet = poMainBand->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
673 if( poUnderlyingDS )
674 poUnderlyingDS->SetEnableOverviews(false);
675 return poRet;
676 }
677
678 /************************************************************************/
679 /* GetMaskFlags() */
680 /************************************************************************/
681
GetMaskFlags()682 int GDALOverviewBand::GetMaskFlags()
683 {
684 GDALOverviewDataset * const poOvrDS = cpl::down_cast<GDALOverviewDataset *>(poDS);
685 if( nBand != 0 && poOvrDS->m_poMaskBand )
686 return GMF_PER_DATASET;
687 return GDALProxyRasterBand::GetMaskFlags();
688 }
689
690 /************************************************************************/
691 /* GetMaskBand() */
692 /************************************************************************/
693
GetMaskBand()694 GDALRasterBand* GDALOverviewBand::GetMaskBand()
695 {
696 GDALOverviewDataset * const poOvrDS = cpl::down_cast<GDALOverviewDataset *>(poDS);
697 if( nBand != 0 && poOvrDS->m_poMaskBand )
698 return poOvrDS->m_poMaskBand;
699 return GDALProxyRasterBand::GetMaskBand();
700 }
701
702 /************************************************************************/
703 /* IRasterIO() */
704 /************************************************************************/
705
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)706 CPLErr GDALOverviewBand::IRasterIO( GDALRWFlag eRWFlag,
707 int nXOff, int nYOff, int nXSize, int nYSize,
708 void * pData, int nBufXSize, int nBufYSize,
709 GDALDataType eBufType,
710 GSpacing nPixelSpace, GSpacing nLineSpace,
711 GDALRasterIOExtraArg* psExtraArg )
712 {
713 // Try to pass the request to the most appropriate overview.
714 if( nBufXSize < nXSize && nBufYSize < nYSize )
715 {
716 int bTried = FALSE;
717 const CPLErr eErr =
718 TryOverviewRasterIO( eRWFlag,
719 nXOff, nYOff, nXSize, nYSize,
720 pData, nBufXSize, nBufYSize,
721 eBufType,
722 nPixelSpace, nLineSpace,
723 psExtraArg,
724 &bTried );
725 if( bTried )
726 return eErr;
727 }
728
729 return GDALProxyRasterBand::IRasterIO(eRWFlag,
730 nXOff, nYOff, nXSize, nYSize,
731 pData, nBufXSize, nBufYSize,
732 eBufType,
733 nPixelSpace, nLineSpace,
734 psExtraArg);
735 }
736