LCOV - code coverage report
Current view: top level - gcore - gdalnodatamaskband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 190 218 87.2 %
Date: 2024-05-04 12:52:34 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Implementation of GDALNoDataMaskBand, a class implementing all
       5             :  *           a default band mask based on nodata values.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2007, Frank Warmerdam
      10             :  * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "cpl_port.h"
      32             : #include "gdal_priv.h"
      33             : 
      34             : #include <algorithm>
      35             : #include <cstring>
      36             : 
      37             : #include "cpl_conv.h"
      38             : #include "cpl_error.h"
      39             : #include "cpl_vsi.h"
      40             : #include "gdal.h"
      41             : #include "gdal_priv_templates.hpp"
      42             : 
      43             : //! @cond Doxygen_Suppress
      44             : /************************************************************************/
      45             : /*                        GDALNoDataMaskBand()                          */
      46             : /************************************************************************/
      47             : 
      48         734 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn)
      49         734 :     : m_poParent(poParentIn)
      50             : {
      51         734 :     poDS = nullptr;
      52         734 :     nBand = 0;
      53             : 
      54         734 :     nRasterXSize = m_poParent->GetXSize();
      55         734 :     nRasterYSize = m_poParent->GetYSize();
      56             : 
      57         734 :     eDataType = GDT_Byte;
      58         734 :     m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
      59             : 
      60         734 :     const auto eParentDT = m_poParent->GetRasterDataType();
      61         734 :     if (eParentDT == GDT_Int64)
      62           8 :         m_nNoDataValueInt64 = m_poParent->GetNoDataValueAsInt64();
      63         726 :     else if (eParentDT == GDT_UInt64)
      64           7 :         m_nNoDataValueUInt64 = m_poParent->GetNoDataValueAsUInt64();
      65             :     else
      66         719 :         m_dfNoDataValue = m_poParent->GetNoDataValue();
      67         734 : }
      68             : 
      69             : /************************************************************************/
      70             : /*                        GDALNoDataMaskBand()                          */
      71             : /************************************************************************/
      72             : 
      73           1 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn,
      74           1 :                                        double dfNoDataValue)
      75           1 :     : m_poParent(poParentIn)
      76             : {
      77           1 :     poDS = nullptr;
      78           1 :     nBand = 0;
      79             : 
      80           1 :     nRasterXSize = m_poParent->GetXSize();
      81           1 :     nRasterYSize = m_poParent->GetYSize();
      82             : 
      83           1 :     eDataType = GDT_Byte;
      84           1 :     m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
      85             : 
      86           1 :     const auto eParentDT = m_poParent->GetRasterDataType();
      87           1 :     if (eParentDT == GDT_Int64)
      88           0 :         m_nNoDataValueInt64 = static_cast<int64_t>(dfNoDataValue);
      89           1 :     else if (eParentDT == GDT_UInt64)
      90           0 :         m_nNoDataValueUInt64 = static_cast<uint64_t>(dfNoDataValue);
      91             :     else
      92           1 :         m_dfNoDataValue = dfNoDataValue;
      93           1 : }
      94             : 
      95             : /************************************************************************/
      96             : /*                       ~GDALNoDataMaskBand()                          */
      97             : /************************************************************************/
      98             : 
      99             : GDALNoDataMaskBand::~GDALNoDataMaskBand() = default;
     100             : 
     101             : /************************************************************************/
     102             : /*                          GetWorkDataType()                           */
     103             : /************************************************************************/
     104             : 
     105       10212 : static GDALDataType GetWorkDataType(GDALDataType eDataType)
     106             : {
     107       10212 :     GDALDataType eWrkDT = GDT_Unknown;
     108       10212 :     switch (eDataType)
     109             :     {
     110         752 :         case GDT_Byte:
     111         752 :             eWrkDT = GDT_Byte;
     112         752 :             break;
     113             : 
     114          77 :         case GDT_UInt16:
     115             :         case GDT_UInt32:
     116          77 :             eWrkDT = GDT_UInt32;
     117          77 :             break;
     118             : 
     119        1826 :         case GDT_Int8:
     120             :         case GDT_Int16:
     121             :         case GDT_Int32:
     122             :         case GDT_CInt16:
     123             :         case GDT_CInt32:
     124        1826 :             eWrkDT = GDT_Int32;
     125        1826 :             break;
     126             : 
     127        7480 :         case GDT_Float32:
     128             :         case GDT_CFloat32:
     129        7480 :             eWrkDT = GDT_Float32;
     130        7480 :             break;
     131             : 
     132          69 :         case GDT_Float64:
     133             :         case GDT_CFloat64:
     134          69 :             eWrkDT = GDT_Float64;
     135          69 :             break;
     136             : 
     137           8 :         case GDT_Int64:
     138             :         case GDT_UInt64:
     139           8 :             eWrkDT = eDataType;
     140           8 :             break;
     141             : 
     142           0 :         default:
     143           0 :             CPLAssert(false);
     144             :             eWrkDT = GDT_Float64;
     145             :             break;
     146             :     }
     147       10212 :     return eWrkDT;
     148             : }
     149             : 
     150             : /************************************************************************/
     151             : /*                          IsNoDataInRange()                           */
     152             : /************************************************************************/
     153             : 
     154         749 : bool GDALNoDataMaskBand::IsNoDataInRange(double dfNoDataValue,
     155             :                                          GDALDataType eDataTypeIn)
     156             : {
     157         749 :     GDALDataType eWrkDT = GetWorkDataType(eDataTypeIn);
     158         749 :     switch (eWrkDT)
     159             :     {
     160         316 :         case GDT_Byte:
     161             :         {
     162         316 :             return GDALIsValueInRange<GByte>(dfNoDataValue);
     163             :         }
     164             : 
     165          58 :         case GDT_UInt32:
     166             :         {
     167          58 :             return GDALIsValueInRange<GUInt32>(dfNoDataValue);
     168             :         }
     169             : 
     170          80 :         case GDT_Int32:
     171             :         {
     172          80 :             return GDALIsValueInRange<GInt32>(dfNoDataValue);
     173             :         }
     174             : 
     175           0 :         case GDT_UInt64:
     176             :         {
     177           0 :             return GDALIsValueInRange<uint64_t>(dfNoDataValue);
     178             :         }
     179             : 
     180           0 :         case GDT_Int64:
     181             :         {
     182           0 :             return GDALIsValueInRange<int64_t>(dfNoDataValue);
     183             :         }
     184             : 
     185         250 :         case GDT_Float32:
     186             :         {
     187         490 :             return CPLIsNan(dfNoDataValue) || CPLIsInf(dfNoDataValue) ||
     188         490 :                    GDALIsValueInRange<float>(dfNoDataValue);
     189             :         }
     190             : 
     191          45 :         case GDT_Float64:
     192             :         {
     193          45 :             return true;
     194             :         }
     195             : 
     196           0 :         default:
     197           0 :             CPLAssert(false);
     198             :             return false;
     199             :     }
     200             : }
     201             : 
     202             : /************************************************************************/
     203             : /*                             IReadBlock()                             */
     204             : /************************************************************************/
     205             : 
     206          18 : CPLErr GDALNoDataMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
     207             :                                       void *pImage)
     208             : 
     209             : {
     210          18 :     const int nXOff = nXBlockOff * nBlockXSize;
     211          18 :     const int nXSizeRequest = std::min(nBlockXSize, nRasterXSize - nXOff);
     212          18 :     const int nYOff = nYBlockOff * nBlockYSize;
     213          18 :     const int nYSizeRequest = std::min(nBlockYSize, nRasterYSize - nYOff);
     214             : 
     215          18 :     if (nBlockXSize != nXSizeRequest || nBlockYSize != nYSizeRequest)
     216             :     {
     217           0 :         memset(pImage, 0, static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
     218             :     }
     219             : 
     220             :     GDALRasterIOExtraArg sExtraArg;
     221          18 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     222          18 :     return IRasterIO(GF_Read, nXOff, nYOff, nXSizeRequest, nYSizeRequest,
     223             :                      pImage, nXSizeRequest, nYSizeRequest, GDT_Byte, 1,
     224          36 :                      nBlockXSize, &sExtraArg);
     225             : }
     226             : 
     227             : /************************************************************************/
     228             : /*                             IRasterIO()                              */
     229             : /************************************************************************/
     230             : 
     231        9463 : CPLErr GDALNoDataMaskBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     232             :                                      int nXSize, int nYSize, void *pData,
     233             :                                      int nBufXSize, int nBufYSize,
     234             :                                      GDALDataType eBufType,
     235             :                                      GSpacing nPixelSpace, GSpacing nLineSpace,
     236             :                                      GDALRasterIOExtraArg *psExtraArg)
     237             : {
     238        9463 :     if (eRWFlag != GF_Read)
     239             :     {
     240           0 :         return CE_Failure;
     241             :     }
     242        9463 :     const auto eParentDT = m_poParent->GetRasterDataType();
     243        9463 :     const GDALDataType eWrkDT = GetWorkDataType(eParentDT);
     244             : 
     245             :     // Optimization in common use case (#4488).
     246             :     // This avoids triggering the block cache on this band, which helps
     247             :     // reducing the global block cache consumption.
     248        9463 :     if (eBufType == GDT_Byte && eWrkDT == GDT_Byte)
     249             :     {
     250         375 :         const CPLErr eErr = m_poParent->RasterIO(
     251             :             GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     252             :             eBufType, nPixelSpace, nLineSpace, psExtraArg);
     253         375 :         if (eErr != CE_None)
     254           0 :             return eErr;
     255             : 
     256         375 :         GByte *pabyData = static_cast<GByte *>(pData);
     257         375 :         const GByte byNoData = static_cast<GByte>(m_dfNoDataValue);
     258             : 
     259         375 :         if (nPixelSpace == 1 && nLineSpace == nBufXSize)
     260             :         {
     261         375 :             const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize;
     262     4064130 :             for (size_t i = 0; i < nBufSize; ++i)
     263             :             {
     264     4063760 :                 pabyData[i] = pabyData[i] == byNoData ? 0 : 255;
     265         375 :             }
     266             :         }
     267             :         else
     268             :         {
     269           0 :             for (int iY = 0; iY < nBufYSize; iY++)
     270             :             {
     271           0 :                 GByte *pabyLine = pabyData + iY * nLineSpace;
     272           0 :                 for (int iX = 0; iX < nBufXSize; iX++)
     273             :                 {
     274           0 :                     *pabyLine = *pabyLine == byNoData ? 0 : 255;
     275           0 :                     pabyLine += nPixelSpace;
     276             :                 }
     277             :             }
     278             :         }
     279         375 :         return CE_None;
     280             :     }
     281             : 
     282        9088 :     if (eBufType == GDT_Byte)
     283             :     {
     284        9009 :         const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
     285        9009 :         void *pTemp = VSI_MALLOC3_VERBOSE(nWrkDTSize, nBufXSize, nBufYSize);
     286        9009 :         if (pTemp == nullptr)
     287             :         {
     288           0 :             return GDALRasterBand::IRasterIO(
     289             :                 eRWFlag, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize,
     290             :                 nBufYSize, eWrkDT, nWrkDTSize,
     291           0 :                 static_cast<GSpacing>(nBufXSize) * nWrkDTSize, psExtraArg);
     292             :         }
     293             : 
     294       18018 :         const CPLErr eErr = m_poParent->RasterIO(
     295             :             GF_Read, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize, nBufYSize,
     296        9009 :             eWrkDT, nWrkDTSize, static_cast<GSpacing>(nBufXSize) * nWrkDTSize,
     297             :             psExtraArg);
     298        9009 :         if (eErr != CE_None)
     299             :         {
     300           0 :             VSIFree(pTemp);
     301           0 :             return eErr;
     302             :         }
     303             : 
     304        9009 :         const bool bIsNoDataNan = CPLIsNan(m_dfNoDataValue) != 0;
     305        9009 :         GByte *pabyDest = static_cast<GByte *>(pData);
     306             : 
     307             :         /* --------------------------------------------------------------------
     308             :          */
     309             :         /*      Process different cases. */
     310             :         /* --------------------------------------------------------------------
     311             :          */
     312        9009 :         switch (eWrkDT)
     313             :         {
     314          15 :             case GDT_UInt32:
     315             :             {
     316          15 :                 const GUInt32 nNoData = static_cast<GUInt32>(m_dfNoDataValue);
     317          15 :                 const GUInt32 *panSrc = static_cast<const GUInt32 *>(pTemp);
     318             : 
     319          15 :                 size_t i = 0;
     320          53 :                 for (int iY = 0; iY < nBufYSize; iY++)
     321             :                 {
     322          38 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     323         260 :                     for (int iX = 0; iX < nBufXSize; iX++)
     324             :                     {
     325         222 :                         *pabyLineDest = panSrc[i] == nNoData ? 0 : 255;
     326         222 :                         ++i;
     327         222 :                         pabyLineDest += nPixelSpace;
     328             :                     }
     329             :                 }
     330             :             }
     331          15 :             break;
     332             : 
     333        1742 :             case GDT_Int32:
     334             :             {
     335        1742 :                 const GInt32 nNoData = static_cast<GInt32>(m_dfNoDataValue);
     336        1742 :                 const GInt32 *panSrc = static_cast<const GInt32 *>(pTemp);
     337             : 
     338        1742 :                 size_t i = 0;
     339        3540 :                 for (int iY = 0; iY < nBufYSize; iY++)
     340             :                 {
     341        1798 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     342      821115 :                     for (int iX = 0; iX < nBufXSize; iX++)
     343             :                     {
     344      819317 :                         *pabyLineDest = panSrc[i] == nNoData ? 0 : 255;
     345      819317 :                         ++i;
     346      819317 :                         pabyLineDest += nPixelSpace;
     347             :                     }
     348             :                 }
     349             :             }
     350        1742 :             break;
     351             : 
     352        7225 :             case GDT_Float32:
     353             :             {
     354        7225 :                 const float fNoData = static_cast<float>(m_dfNoDataValue);
     355        7225 :                 const float *pafSrc = static_cast<const float *>(pTemp);
     356             : 
     357        7225 :                 size_t i = 0;
     358       14512 :                 for (int iY = 0; iY < nBufYSize; iY++)
     359             :                 {
     360        7287 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     361     1962100 :                     for (int iX = 0; iX < nBufXSize; iX++)
     362             :                     {
     363     1954810 :                         const float fVal = pafSrc[i];
     364     1954810 :                         if (bIsNoDataNan && CPLIsNan(fVal))
     365          20 :                             *pabyLineDest = 0;
     366     1954790 :                         else if (ARE_REAL_EQUAL(fVal, fNoData))
     367      876101 :                             *pabyLineDest = 0;
     368             :                         else
     369     1078690 :                             *pabyLineDest = 255;
     370     1954810 :                         ++i;
     371     1954810 :                         pabyLineDest += nPixelSpace;
     372             :                     }
     373             :                 }
     374             :             }
     375        7225 :             break;
     376             : 
     377          19 :             case GDT_Float64:
     378             :             {
     379          19 :                 const double *padfSrc = static_cast<const double *>(pTemp);
     380             : 
     381          19 :                 size_t i = 0;
     382          60 :                 for (int iY = 0; iY < nBufYSize; iY++)
     383             :                 {
     384          41 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     385         194 :                     for (int iX = 0; iX < nBufXSize; iX++)
     386             :                     {
     387         153 :                         const double dfVal = padfSrc[i];
     388         153 :                         if (bIsNoDataNan && CPLIsNan(dfVal))
     389          20 :                             *pabyLineDest = 0;
     390         133 :                         else if (ARE_REAL_EQUAL(dfVal, m_dfNoDataValue))
     391          71 :                             *pabyLineDest = 0;
     392             :                         else
     393          62 :                             *pabyLineDest = 255;
     394         153 :                         ++i;
     395         153 :                         pabyLineDest += nPixelSpace;
     396             :                     }
     397             :                 }
     398             :             }
     399          19 :             break;
     400             : 
     401           4 :             case GDT_Int64:
     402             :             {
     403           4 :                 const auto *panSrc = static_cast<const int64_t *>(pTemp);
     404             : 
     405           4 :                 size_t i = 0;
     406           8 :                 for (int iY = 0; iY < nBufYSize; iY++)
     407             :                 {
     408           4 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     409           8 :                     for (int iX = 0; iX < nBufXSize; iX++)
     410             :                     {
     411           4 :                         const auto nVal = panSrc[i];
     412           4 :                         if (nVal == m_nNoDataValueInt64)
     413           3 :                             *pabyLineDest = 0;
     414             :                         else
     415           1 :                             *pabyLineDest = 255;
     416           4 :                         ++i;
     417           4 :                         pabyLineDest += nPixelSpace;
     418             :                     }
     419             :                 }
     420             :             }
     421           4 :             break;
     422             : 
     423           4 :             case GDT_UInt64:
     424             :             {
     425           4 :                 const auto *panSrc = static_cast<const uint64_t *>(pTemp);
     426             : 
     427           4 :                 size_t i = 0;
     428           8 :                 for (int iY = 0; iY < nBufYSize; iY++)
     429             :                 {
     430           4 :                     GByte *pabyLineDest = pabyDest + iY * nLineSpace;
     431           8 :                     for (int iX = 0; iX < nBufXSize; iX++)
     432             :                     {
     433           4 :                         const auto nVal = panSrc[i];
     434           4 :                         if (nVal == m_nNoDataValueUInt64)
     435           3 :                             *pabyLineDest = 0;
     436             :                         else
     437           1 :                             *pabyLineDest = 255;
     438           4 :                         ++i;
     439           4 :                         pabyLineDest += nPixelSpace;
     440             :                     }
     441             :                 }
     442             :             }
     443           4 :             break;
     444             : 
     445           0 :             default:
     446           0 :                 CPLAssert(false);
     447             :                 break;
     448             :         }
     449             : 
     450        9009 :         VSIFree(pTemp);
     451        9009 :         return CE_None;
     452             :     }
     453             : 
     454             :     // Output buffer is non-Byte. Ask for Byte and expand to user requested
     455             :     // type
     456             :     GByte *pabyBuf =
     457          79 :         static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBufXSize, nBufYSize));
     458          79 :     if (pabyBuf == nullptr)
     459             :     {
     460           0 :         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     461             :                                          pData, nBufXSize, nBufYSize, eBufType,
     462           0 :                                          nPixelSpace, nLineSpace, psExtraArg);
     463             :     }
     464             :     const CPLErr eErr =
     465         158 :         IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pabyBuf, nBufXSize,
     466          79 :                   nBufYSize, GDT_Byte, 1, nBufXSize, psExtraArg);
     467          79 :     if (eErr != CE_None)
     468             :     {
     469           0 :         VSIFree(pabyBuf);
     470           0 :         return eErr;
     471             :     }
     472             : 
     473         186 :     for (int iY = 0; iY < nBufYSize; iY++)
     474             :     {
     475         107 :         GDALCopyWords(pabyBuf + static_cast<size_t>(iY) * nBufXSize, GDT_Byte,
     476         107 :                       1, static_cast<GByte *>(pData) + iY * nLineSpace,
     477             :                       eBufType, static_cast<int>(nPixelSpace), nBufXSize);
     478             :     }
     479          79 :     VSIFree(pabyBuf);
     480          79 :     return CE_None;
     481             : }
     482             : 
     483             : //! @endcond

Generated by: LCOV version 1.14