LCOV - code coverage report
Current view: top level - frmts/vrt - vrtfilters.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 248 283 87.6 %
Date: 2024-05-06 22:33:47 Functions: 15 16 93.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Virtual GDAL Datasets
       4             :  * Purpose:  Implementation of some filter types.
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
       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_port.h"
      31             : #include "vrtdataset.h"
      32             : 
      33             : #include <cmath>
      34             : #include <cstddef>
      35             : #include <cstdlib>
      36             : #include <cstring>
      37             : #include <limits>
      38             : 
      39             : #include "cpl_conv.h"
      40             : #include "cpl_error.h"
      41             : #include "cpl_minixml.h"
      42             : #include "cpl_string.h"
      43             : #include "cpl_vsi.h"
      44             : #include "gdal.h"
      45             : #include "gdal_priv.h"
      46             : 
      47             : /*! @cond Doxygen_Suppress */
      48             : 
      49             : /************************************************************************/
      50             : /* ==================================================================== */
      51             : /*                          VRTFilteredSource                           */
      52             : /* ==================================================================== */
      53             : /************************************************************************/
      54             : 
      55             : /************************************************************************/
      56             : /*                         VRTFilteredSource()                          */
      57             : /************************************************************************/
      58             : 
      59          13 : VRTFilteredSource::VRTFilteredSource()
      60          13 :     : m_nSupportedTypesCount(1), m_nExtraEdgePixels(0)
      61             : {
      62         273 :     for (size_t i = 0; i < CPL_ARRAYSIZE(m_aeSupportedTypes); ++i)
      63         260 :         m_aeSupportedTypes[i] = GDT_Unknown;
      64             : 
      65          13 :     m_aeSupportedTypes[0] = GDT_Float32;
      66          13 : }
      67             : 
      68             : /************************************************************************/
      69             : /*                         ~VRTFilteredSource()                         */
      70             : /************************************************************************/
      71             : 
      72          13 : VRTFilteredSource::~VRTFilteredSource()
      73             : {
      74          13 : }
      75             : 
      76             : /************************************************************************/
      77             : /*                         SetExtraEdgePixels()                         */
      78             : /************************************************************************/
      79             : 
      80          11 : void VRTFilteredSource::SetExtraEdgePixels(int nEdgePixels)
      81             : 
      82             : {
      83          11 :     m_nExtraEdgePixels = nEdgePixels;
      84          11 : }
      85             : 
      86             : /************************************************************************/
      87             : /*                   SetFilteringDataTypesSupported()                   */
      88             : /************************************************************************/
      89             : 
      90          13 : void VRTFilteredSource::SetFilteringDataTypesSupported(int nTypeCount,
      91             :                                                        GDALDataType *paeTypes)
      92             : 
      93             : {
      94          13 :     if (nTypeCount >
      95             :         static_cast<int>(sizeof(m_aeSupportedTypes) / sizeof(GDALDataType)))
      96             :     {
      97           0 :         CPLAssert(false);
      98             :         nTypeCount =
      99             :             static_cast<int>(sizeof(m_aeSupportedTypes) / sizeof(GDALDataType));
     100             :     }
     101             : 
     102          13 :     m_nSupportedTypesCount = nTypeCount;
     103          13 :     memcpy(m_aeSupportedTypes, paeTypes, sizeof(GDALDataType) * nTypeCount);
     104          13 : }
     105             : 
     106             : /************************************************************************/
     107             : /*                          IsTypeSupported()                           */
     108             : /************************************************************************/
     109             : 
     110          28 : int VRTFilteredSource::IsTypeSupported(GDALDataType eTestType) const
     111             : 
     112             : {
     113          56 :     for (int i = 0; i < m_nSupportedTypesCount; i++)
     114             :     {
     115          28 :         if (eTestType == m_aeSupportedTypes[i])
     116           0 :             return TRUE;
     117             :     }
     118             : 
     119          28 :     return FALSE;
     120             : }
     121             : 
     122             : /************************************************************************/
     123             : /*                              RasterIO()                              */
     124             : /************************************************************************/
     125             : 
     126          14 : CPLErr VRTFilteredSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
     127             :                                    int nYOff, int nXSize, int nYSize,
     128             :                                    void *pData, int nBufXSize, int nBufYSize,
     129             :                                    GDALDataType eBufType, GSpacing nPixelSpace,
     130             :                                    GSpacing nLineSpace,
     131             :                                    GDALRasterIOExtraArg *psExtraArg,
     132             :                                    WorkingState &oWorkingState)
     133             : 
     134             : {
     135             :     /* -------------------------------------------------------------------- */
     136             :     /*      For now we don't support filtered access to non-full            */
     137             :     /*      resolution requests. Just collect the data directly without     */
     138             :     /*      any operator.                                                   */
     139             :     /* -------------------------------------------------------------------- */
     140          14 :     if (nBufXSize != nXSize || nBufYSize != nYSize)
     141             :     {
     142           0 :         return VRTComplexSource::RasterIO(
     143             :             eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     144             :             nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg,
     145           0 :             oWorkingState);
     146             :     }
     147             : 
     148          14 :     double dfXOff = nXOff;
     149          14 :     double dfYOff = nYOff;
     150          14 :     double dfXSize = nXSize;
     151          14 :     double dfYSize = nYSize;
     152          14 :     if (psExtraArg != nullptr && psExtraArg->bFloatingPointWindowValidity)
     153             :     {
     154           4 :         dfXOff = psExtraArg->dfXOff;
     155           4 :         dfYOff = psExtraArg->dfYOff;
     156           4 :         dfXSize = psExtraArg->dfXSize;
     157           4 :         dfYSize = psExtraArg->dfYSize;
     158             :     }
     159             : 
     160             :     // The window we will actually request from the source raster band.
     161          14 :     double dfReqXOff = 0.0;
     162          14 :     double dfReqYOff = 0.0;
     163          14 :     double dfReqXSize = 0.0;
     164          14 :     double dfReqYSize = 0.0;
     165          14 :     int nReqXOff = 0;
     166          14 :     int nReqYOff = 0;
     167          14 :     int nReqXSize = 0;
     168          14 :     int nReqYSize = 0;
     169             : 
     170             :     // The window we will actual set _within_ the pData buffer.
     171          14 :     int nOutXOff = 0;
     172          14 :     int nOutYOff = 0;
     173          14 :     int nOutXSize = 0;
     174          14 :     int nOutYSize = 0;
     175             : 
     176          14 :     bool bError = false;
     177          14 :     if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
     178             :                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
     179             :                          &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
     180             :                          &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
     181             :     {
     182           0 :         return bError ? CE_Failure : CE_None;
     183             :     }
     184             : 
     185          14 :     pData = reinterpret_cast<GByte *>(pData) + nPixelSpace * nOutXOff +
     186          14 :             nLineSpace * nOutYOff;
     187             : 
     188             :     /* -------------------------------------------------------------------- */
     189             :     /*      Determine the data type we want to request.  We try to match    */
     190             :     /*      the source or destination request, and if both those fail we    */
     191             :     /*      fallback to the first supported type at least as expressive     */
     192             :     /*      as the request.                                                 */
     193             :     /* -------------------------------------------------------------------- */
     194          14 :     GDALDataType eOperDataType = GDT_Unknown;
     195             : 
     196          14 :     if (IsTypeSupported(eBufType))
     197           0 :         eOperDataType = eBufType;
     198             : 
     199          14 :     auto l_band = GetRasterBand();
     200          14 :     if (!l_band)
     201           0 :         return CE_Failure;
     202             : 
     203          28 :     if (eOperDataType == GDT_Unknown &&
     204          14 :         IsTypeSupported(l_band->GetRasterDataType()))
     205           0 :         eOperDataType = l_band->GetRasterDataType();
     206             : 
     207          14 :     if (eOperDataType == GDT_Unknown)
     208             :     {
     209          28 :         for (int i = 0; i < m_nSupportedTypesCount; i++)
     210             :         {
     211          14 :             if (GDALDataTypeUnion(m_aeSupportedTypes[i], eBufType) ==
     212          14 :                 m_aeSupportedTypes[i])
     213             :             {
     214           0 :                 eOperDataType = m_aeSupportedTypes[i];
     215             :             }
     216             :         }
     217             :     }
     218             : 
     219          14 :     if (eOperDataType == GDT_Unknown)
     220             :     {
     221          14 :         eOperDataType = m_aeSupportedTypes[0];
     222             : 
     223          14 :         for (int i = 1; i < m_nSupportedTypesCount; i++)
     224             :         {
     225           0 :             if (GDALGetDataTypeSize(m_aeSupportedTypes[i]) >
     226           0 :                 GDALGetDataTypeSize(eOperDataType))
     227             :             {
     228           0 :                 eOperDataType = m_aeSupportedTypes[i];
     229             :             }
     230             :         }
     231             :     }
     232             : 
     233             :     /* -------------------------------------------------------------------- */
     234             :     /*      Allocate the buffer of data into which our imagery will be      */
     235             :     /*      read, with the extra edge pixels as well. This will be the      */
     236             :     /*      source data fed into the filter.                                */
     237             :     /* -------------------------------------------------------------------- */
     238          14 :     if (nOutXSize > INT_MAX - 2 * m_nExtraEdgePixels ||
     239          14 :         nOutYSize > INT_MAX - 2 * m_nExtraEdgePixels)
     240             :     {
     241           0 :         return CE_Failure;
     242             :     }
     243          14 :     const int nExtraXSize = nOutXSize + 2 * m_nExtraEdgePixels;
     244          14 :     const int nExtraYSize = nOutYSize + 2 * m_nExtraEdgePixels;
     245             : 
     246          14 :     GByte *pabyWorkData = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
     247             :         nExtraXSize, nExtraYSize, GDALGetDataTypeSizeBytes(eOperDataType)));
     248             : 
     249          14 :     if (pabyWorkData == nullptr)
     250             :     {
     251           0 :         return CE_Failure;
     252             :     }
     253             : 
     254          14 :     const GPtrDiff_t nPixelOffset = GDALGetDataTypeSizeBytes(eOperDataType);
     255          14 :     const GPtrDiff_t nLineOffset = nPixelOffset * nExtraXSize;
     256             : 
     257          14 :     memset(pabyWorkData, 0, nLineOffset * nExtraYSize);
     258             : 
     259             :     /* -------------------------------------------------------------------- */
     260             :     /*      Allocate the output buffer in the same dimensions as the work   */
     261             :     /*      buffer. This allows the filter process to write edge pixels     */
     262             :     /*      if needed for two-pass (separable) filtering.                   */
     263             :     /* -------------------------------------------------------------------- */
     264             :     GByte *pabyOutData = static_cast<GByte *>(
     265          14 :         VSI_MALLOC3_VERBOSE(nExtraXSize, nExtraYSize, nPixelOffset));
     266          14 :     if (pabyOutData == nullptr)
     267             :     {
     268           0 :         CPLFree(pabyWorkData);
     269           0 :         return CE_Failure;
     270             :     }
     271             : 
     272             :     /* -------------------------------------------------------------------- */
     273             :     /*      Figure out the extended window that we want to load.  Note      */
     274             :     /*      that we keep track of the file window as well as the amount     */
     275             :     /*      we will need to edge fill past the edge of the source dataset.  */
     276             :     /* -------------------------------------------------------------------- */
     277          14 :     int nFileXOff = nReqXOff - m_nExtraEdgePixels;
     278          14 :     int nFileYOff = nReqYOff - m_nExtraEdgePixels;
     279          14 :     int nFileXSize = nExtraXSize;
     280          14 :     int nFileYSize = nExtraYSize;
     281             : 
     282          14 :     int nTopFill = 0;
     283          14 :     int nLeftFill = 0;
     284          14 :     int nRightFill = 0;
     285          14 :     int nBottomFill = 0;
     286             : 
     287          14 :     if (nFileXOff < 0)
     288             :     {
     289          14 :         nLeftFill = -nFileXOff;
     290          14 :         nFileXOff = 0;
     291          14 :         nFileXSize -= nLeftFill;
     292             :     }
     293             : 
     294          14 :     if (nFileYOff < 0)
     295             :     {
     296           8 :         nTopFill = -nFileYOff;
     297           8 :         nFileYOff = 0;
     298           8 :         nFileYSize -= nTopFill;
     299             :     }
     300             : 
     301          14 :     if (nFileXOff + nFileXSize > l_band->GetXSize())
     302             :     {
     303          14 :         nRightFill = nFileXOff + nFileXSize - l_band->GetXSize();
     304          14 :         nFileXSize -= nRightFill;
     305             :     }
     306             : 
     307          14 :     if (nFileYOff + nFileYSize > l_band->GetYSize())
     308             :     {
     309           8 :         nBottomFill = nFileYOff + nFileYSize - l_band->GetYSize();
     310           8 :         nFileYSize -= nBottomFill;
     311             :     }
     312             : 
     313             :     /* -------------------------------------------------------------------- */
     314             :     /*      Load the data.                                                  */
     315             :     /* -------------------------------------------------------------------- */
     316             :     {
     317             :         GDALRasterIOExtraArg sExtraArgs;
     318          14 :         INIT_RASTERIO_EXTRA_ARG(sExtraArgs);
     319             :         const bool bIsComplex =
     320          14 :             CPL_TO_BOOL(GDALDataTypeIsComplex(eOperDataType));
     321          14 :         const CPLErr eErr = VRTComplexSource::RasterIOInternal<float>(
     322             :             l_band, eVRTBandDataType, nFileXOff, nFileYOff, nFileXSize,
     323             :             nFileYSize,
     324          14 :             pabyWorkData + nLineOffset * nTopFill + nPixelOffset * nLeftFill,
     325             :             nFileXSize, nFileYSize, eOperDataType, nPixelOffset, nLineOffset,
     326             :             &sExtraArgs, bIsComplex ? GDT_CFloat32 : GDT_Float32,
     327             :             oWorkingState);
     328             : 
     329          14 :         if (eErr != CE_None)
     330             :         {
     331           0 :             VSIFree(pabyWorkData);
     332           0 :             VSIFree(pabyOutData);
     333             : 
     334           0 :             return eErr;
     335             :         }
     336             :     }
     337             : 
     338             :     /* -------------------------------------------------------------------- */
     339             :     /*      Fill in missing areas.  Note that we replicate the edge         */
     340             :     /*      valid values out.  We don't using "mirroring" which might be    */
     341             :     /*      more suitable for some times of filters.  We also don't mark    */
     342             :     /*      these pixels as "nodata" though perhaps we should.              */
     343             :     /* -------------------------------------------------------------------- */
     344          14 :     if (nLeftFill != 0 || nRightFill != 0)
     345             :     {
     346        1296 :         for (int i = nTopFill; i < nExtraYSize - nBottomFill; i++)
     347             :         {
     348        1282 :             if (nLeftFill != 0)
     349        1282 :                 GDALCopyWords(
     350        1282 :                     pabyWorkData + nPixelOffset * nLeftFill + i * nLineOffset,
     351        1282 :                     eOperDataType, 0, pabyWorkData + i * nLineOffset,
     352             :                     eOperDataType, static_cast<int>(nPixelOffset), nLeftFill);
     353             : 
     354        1282 :             if (nRightFill != 0)
     355        1282 :                 GDALCopyWords(pabyWorkData + i * nLineOffset +
     356        1282 :                                   nPixelOffset * (nExtraXSize - nRightFill - 1),
     357             :                               eOperDataType, 0,
     358        1282 :                               pabyWorkData + i * nLineOffset +
     359        1282 :                                   nPixelOffset * (nExtraXSize - nRightFill),
     360             :                               eOperDataType, static_cast<int>(nPixelOffset),
     361             :                               nRightFill);
     362             :         }
     363             :     }
     364             : 
     365          27 :     for (int i = 0; i < nTopFill; i++)
     366             :     {
     367          13 :         memcpy(pabyWorkData + i * nLineOffset,
     368          13 :                pabyWorkData + nTopFill * nLineOffset, nLineOffset);
     369             :     }
     370             : 
     371          27 :     for (int i = nExtraYSize - nBottomFill; i < nExtraYSize; i++)
     372             :     {
     373          13 :         memcpy(pabyWorkData + i * nLineOffset,
     374          13 :                pabyWorkData + (nExtraYSize - nBottomFill - 1) * nLineOffset,
     375             :                nLineOffset);
     376             :     }
     377             : 
     378             :     /* -------------------------------------------------------------------- */
     379             :     /*      Filter the data.                                                */
     380             :     /* -------------------------------------------------------------------- */
     381          28 :     const CPLErr eErr = FilterData(nExtraXSize, nExtraYSize, eOperDataType,
     382          14 :                                    pabyWorkData, pabyOutData);
     383             : 
     384          14 :     VSIFree(pabyWorkData);
     385          14 :     if (eErr != CE_None)
     386             :     {
     387           0 :         VSIFree(pabyOutData);
     388             : 
     389           0 :         return eErr;
     390             :     }
     391             : 
     392             :     /* -------------------------------------------------------------------- */
     393             :     /*      Copy from work buffer to target buffer.                         */
     394             :     /* -------------------------------------------------------------------- */
     395          14 :     GByte *pabySrcRow =
     396          14 :         pabyOutData + (nLineOffset + nPixelOffset) * m_nExtraEdgePixels;
     397          14 :     GByte *pabyDstRow = reinterpret_cast<GByte *>(pData);
     398             : 
     399        1284 :     for (int i = 0; i < nOutYSize;
     400        1270 :          i++, pabySrcRow += nLineOffset, pabyDstRow += nLineSpace)
     401             :     {
     402        1270 :         GDALCopyWords(pabySrcRow, eOperDataType, static_cast<int>(nPixelOffset),
     403             :                       pabyDstRow, eBufType, static_cast<int>(nPixelSpace),
     404             :                       nOutXSize);
     405             :     }
     406             : 
     407          14 :     VSIFree(pabyOutData);
     408             : 
     409          14 :     return CE_None;
     410             : }
     411             : 
     412             : /************************************************************************/
     413             : /* ==================================================================== */
     414             : /*                       VRTKernelFilteredSource                        */
     415             : /* ==================================================================== */
     416             : /************************************************************************/
     417             : 
     418             : /************************************************************************/
     419             : /*                      VRTKernelFilteredSource()                       */
     420             : /************************************************************************/
     421             : 
     422          13 : VRTKernelFilteredSource::VRTKernelFilteredSource()
     423             :     : m_nKernelSize(0), m_bSeparable(FALSE), m_padfKernelCoefs(nullptr),
     424          13 :       m_bNormalized(FALSE)
     425             : {
     426          13 :     GDALDataType aeSupTypes[] = {GDT_Float32};
     427          13 :     SetFilteringDataTypesSupported(1, aeSupTypes);
     428          13 : }
     429             : 
     430             : /************************************************************************/
     431             : /*                      ~VRTKernelFilteredSource()                      */
     432             : /************************************************************************/
     433             : 
     434          26 : VRTKernelFilteredSource::~VRTKernelFilteredSource()
     435             : 
     436             : {
     437          13 :     CPLFree(m_padfKernelCoefs);
     438          26 : }
     439             : 
     440             : /************************************************************************/
     441             : /*                           SetNormalized()                            */
     442             : /************************************************************************/
     443             : 
     444          11 : void VRTKernelFilteredSource::SetNormalized(int bNormalizedIn)
     445             : 
     446             : {
     447          11 :     m_bNormalized = bNormalizedIn;
     448          11 : }
     449             : 
     450             : /************************************************************************/
     451             : /*                             SetKernel()                              */
     452             : /************************************************************************/
     453             : 
     454          11 : CPLErr VRTKernelFilteredSource::SetKernel(int nNewKernelSize, bool bSeparable,
     455             :                                           double *padfNewCoefs)
     456             : 
     457             : {
     458          11 :     if (nNewKernelSize < 1 || (nNewKernelSize % 2) != 1)
     459             :     {
     460           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     461             :                  "Illegal filtering kernel size %d, "
     462             :                  "must be odd positive number.",
     463             :                  nNewKernelSize);
     464           0 :         return CE_Failure;
     465             :     }
     466             : 
     467          11 :     CPLFree(m_padfKernelCoefs);
     468          11 :     m_nKernelSize = nNewKernelSize;
     469          11 :     m_bSeparable = bSeparable;
     470             : 
     471          11 :     int nKernelBufferSize = m_nKernelSize * (m_bSeparable ? 1 : m_nKernelSize);
     472             : 
     473          11 :     m_padfKernelCoefs =
     474          11 :         static_cast<double *>(CPLMalloc(sizeof(double) * nKernelBufferSize));
     475          11 :     memcpy(m_padfKernelCoefs, padfNewCoefs, sizeof(double) * nKernelBufferSize);
     476             : 
     477          11 :     SetExtraEdgePixels((nNewKernelSize - 1) / 2);
     478             : 
     479          11 :     return CE_None;
     480             : }
     481             : 
     482             : /************************************************************************/
     483             : /*                             FilterData()                             */
     484             : /************************************************************************/
     485             : 
     486          14 : CPLErr VRTKernelFilteredSource::FilterData(int nXSize, int nYSize,
     487             :                                            GDALDataType eType,
     488             :                                            GByte *pabySrcData,
     489             :                                            GByte *pabyDstData)
     490             : 
     491             : {
     492             :     /* -------------------------------------------------------------------- */
     493             :     /*      Validate data type.                                             */
     494             :     /* -------------------------------------------------------------------- */
     495          14 :     if (eType != GDT_Float32)
     496             :     {
     497           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     498             :                  "Unsupported data type (%s) in "
     499             :                  "VRTKernelFilteredSource::FilterData()",
     500             :                  GDALGetDataTypeName(eType));
     501           0 :         return CE_Failure;
     502             :     }
     503             : 
     504          14 :     CPLAssert(m_nExtraEdgePixels * 2 + 1 == m_nKernelSize ||
     505             :               (m_nKernelSize == 0 && m_nExtraEdgePixels == 0));
     506             : 
     507             :     /* -------------------------------------------------------------------- */
     508             :     /*      Float32 case.                                                   */
     509             :     /* -------------------------------------------------------------------- */
     510             :     // if( eType == GDT_Float32 )
     511             :     {
     512          14 :         float *pafSrcData = reinterpret_cast<float *>(pabySrcData);
     513          14 :         float *pafDstData = reinterpret_cast<float *>(pabyDstData);
     514             : 
     515          14 :         int bHasNoData = FALSE;
     516          14 :         auto l_poBand = GetRasterBand();
     517          14 :         if (!l_poBand)
     518           0 :             return CE_Failure;
     519             :         const float fNoData =
     520          14 :             static_cast<float>(l_poBand->GetNoDataValue(&bHasNoData));
     521             : 
     522          14 :         const int nAxisCount = m_bSeparable ? 2 : 1;
     523             : 
     524          29 :         for (int nAxis = 0; nAxis < nAxisCount; ++nAxis)
     525             :         {
     526          15 :             const int nISize = nAxis == 0 ? nYSize : nXSize;
     527          15 :             const int nJSize = nAxis == 0 ? nXSize : nYSize;
     528          15 :             const int nIStride = nAxis == 0 ? nXSize : 1;
     529          15 :             const int nJStride = nAxis == 0 ? 1 : nXSize;
     530             : 
     531          15 :             const int nIMin = m_nExtraEdgePixels;
     532          15 :             const int nIMax = nISize - m_nExtraEdgePixels;
     533          15 :             const int nJMin = (m_bSeparable ? 0 : m_nExtraEdgePixels);
     534          15 :             const int nJMax = nJSize - (m_bSeparable ? 0 : m_nExtraEdgePixels);
     535             : 
     536        4359 :             for (GPtrDiff_t iJ = nJMin; iJ < nJMax; ++iJ)
     537             :             {
     538        4344 :                 if (nAxis == 1)
     539          62 :                     memcpy(pafSrcData + iJ * nJStride,
     540          62 :                            pafDstData + iJ * nJStride, sizeof(float) * nXSize);
     541             : 
     542      520944 :                 for (int iI = nIMin; iI < nIMax; ++iI)
     543             :                 {
     544      516600 :                     const GPtrDiff_t iIndex =
     545      516600 :                         static_cast<GPtrDiff_t>(iI) * nIStride + iJ * nJStride;
     546             : 
     547      516600 :                     if (bHasNoData && pafSrcData[iIndex] == fNoData)
     548             :                     {
     549         200 :                         pafDstData[iIndex] = fNoData;
     550         200 :                         continue;
     551             :                     }
     552             : 
     553      516400 :                     double dfSum = 0.0, dfKernSum = 0.0;
     554             : 
     555     2127600 :                     for (GPtrDiff_t iII = -m_nExtraEdgePixels, iK = 0;
     556     2127600 :                          iII <= m_nExtraEdgePixels; ++iII)
     557             :                     {
     558     6283600 :                         for (GPtrDiff_t iJJ =
     559     1611200 :                                  (m_bSeparable ? 0 : -m_nExtraEdgePixels);
     560     6283600 :                              iJJ <= (m_bSeparable ? 0 : m_nExtraEdgePixels);
     561             :                              ++iJJ, ++iK)
     562             :                         {
     563     4672400 :                             const float *pfData = pafSrcData + iIndex +
     564     4672400 :                                                   iII * nIStride +
     565     4672400 :                                                   iJJ * nJStride;
     566     4672400 :                             if (bHasNoData && *pfData == fNoData)
     567         836 :                                 continue;
     568     4671560 :                             dfSum += *pfData * m_padfKernelCoefs[iK];
     569     4671560 :                             dfKernSum += m_padfKernelCoefs[iK];
     570             :                         }
     571             :                     }
     572             : 
     573             :                     double fResult;
     574             : 
     575      516400 :                     if (!m_bNormalized)
     576      510000 :                         fResult = dfSum;
     577        6400 :                     else if (dfKernSum == 0.0)
     578           0 :                         fResult = 0.0;
     579             :                     else
     580        6400 :                         fResult = dfSum / dfKernSum;
     581      516400 :                     pafDstData[iIndex] = static_cast<float>(fResult);
     582             :                 }
     583             :             }
     584             :         }
     585             :     }
     586             : 
     587          14 :     return CE_None;
     588             : }
     589             : 
     590             : /************************************************************************/
     591             : /*                              XMLInit()                               */
     592             : /************************************************************************/
     593             : 
     594          13 : CPLErr VRTKernelFilteredSource::XMLInit(
     595             :     const CPLXMLNode *psTree, const char *pszVRTPath,
     596             :     std::map<CPLString, GDALDataset *> &oMapSharedSources)
     597             : 
     598             : {
     599             :     {
     600             :         const CPLErr eErr =
     601          13 :             VRTFilteredSource::XMLInit(psTree, pszVRTPath, oMapSharedSources);
     602          13 :         if (eErr != CE_None)
     603           0 :             return eErr;
     604             :     }
     605             : 
     606          13 :     const int nNewKernelSize = atoi(CPLGetXMLValue(psTree, "Kernel.Size", "0"));
     607             : 
     608          13 :     if (nNewKernelSize == 0)
     609           0 :         return CE_None;
     610             :     // To prevent a integer overflow when computing nNewKernelSize *
     611             :     // nNewKernelSize
     612          25 :     if (nNewKernelSize < 0 ||
     613          12 :         nNewKernelSize > static_cast<int>(std::sqrt(static_cast<double>(
     614          12 :                              std::numeric_limits<int>::max()))))
     615             :     {
     616           2 :         CPLError(CE_Failure, CPLE_IllegalArg,
     617             :                  "Invalid value for kernel size: %d", nNewKernelSize);
     618           2 :         return CE_Failure;
     619             :     }
     620             : 
     621             :     char **papszCoefItems =
     622          11 :         CSLTokenizeString(CPLGetXMLValue(psTree, "Kernel.Coefs", ""));
     623             : 
     624          11 :     const int nCoefs = CSLCount(papszCoefItems);
     625             : 
     626          11 :     const bool bSquare = nCoefs == nNewKernelSize * nNewKernelSize;
     627          11 :     const bool bSeparable = nCoefs == nNewKernelSize && nCoefs != 1;
     628             : 
     629          11 :     if (!bSquare && !bSeparable)
     630             :     {
     631           0 :         CSLDestroy(papszCoefItems);
     632           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     633             :                  "Got wrong number of filter kernel coefficients (%s).  "
     634             :                  "Expected %d or %d, got %d.",
     635             :                  CPLGetXMLValue(psTree, "Kernel.Coefs", ""),
     636             :                  nNewKernelSize * nNewKernelSize, nNewKernelSize, nCoefs);
     637           0 :         return CE_Failure;
     638             :     }
     639             : 
     640             :     double *padfNewCoefs =
     641          11 :         static_cast<double *>(CPLMalloc(sizeof(double) * nCoefs));
     642             : 
     643         118 :     for (int i = 0; i < nCoefs; i++)
     644         107 :         padfNewCoefs[i] = CPLAtof(papszCoefItems[i]);
     645             : 
     646          11 :     const CPLErr eErr = SetKernel(nNewKernelSize, bSeparable, padfNewCoefs);
     647             : 
     648          11 :     CPLFree(padfNewCoefs);
     649          11 :     CSLDestroy(papszCoefItems);
     650             : 
     651          11 :     SetNormalized(atoi(CPLGetXMLValue(psTree, "Kernel.normalized", "0")));
     652             : 
     653          11 :     return eErr;
     654             : }
     655             : 
     656             : /************************************************************************/
     657             : /*                           SerializeToXML()                           */
     658             : /************************************************************************/
     659             : 
     660           1 : CPLXMLNode *VRTKernelFilteredSource::SerializeToXML(const char *pszVRTPath)
     661             : 
     662             : {
     663           1 :     CPLXMLNode *psSrc = VRTFilteredSource::SerializeToXML(pszVRTPath);
     664             : 
     665           1 :     if (psSrc == nullptr)
     666           0 :         return nullptr;
     667             : 
     668           1 :     CPLFree(psSrc->pszValue);
     669           1 :     psSrc->pszValue = CPLStrdup("KernelFilteredSource");
     670             : 
     671           1 :     if (m_nKernelSize == 0)
     672           0 :         return psSrc;
     673             : 
     674           1 :     CPLXMLNode *psKernel = CPLCreateXMLNode(psSrc, CXT_Element, "Kernel");
     675             : 
     676           1 :     if (m_bNormalized)
     677           0 :         CPLCreateXMLNode(
     678             :             CPLCreateXMLNode(psKernel, CXT_Attribute, "normalized"), CXT_Text,
     679             :             "1");
     680             :     else
     681           1 :         CPLCreateXMLNode(
     682             :             CPLCreateXMLNode(psKernel, CXT_Attribute, "normalized"), CXT_Text,
     683             :             "0");
     684             : 
     685           1 :     const int nCoefCount = m_nKernelSize * m_nKernelSize;
     686           1 :     const size_t nBufLen = nCoefCount * 32;
     687           1 :     char *pszKernelCoefs = static_cast<char *>(CPLMalloc(nBufLen));
     688             : 
     689           1 :     strcpy(pszKernelCoefs, "");
     690          10 :     for (int iCoef = 0; iCoef < nCoefCount; iCoef++)
     691           9 :         CPLsnprintf(pszKernelCoefs + strlen(pszKernelCoefs),
     692           9 :                     nBufLen - strlen(pszKernelCoefs), "%.8g ",
     693           9 :                     m_padfKernelCoefs[iCoef]);
     694             : 
     695           1 :     CPLSetXMLValue(psKernel, "Size", CPLSPrintf("%d", m_nKernelSize));
     696           1 :     CPLSetXMLValue(psKernel, "Coefs", pszKernelCoefs);
     697             : 
     698           1 :     CPLFree(pszKernelCoefs);
     699             : 
     700           1 :     return psSrc;
     701             : }
     702             : 
     703             : /************************************************************************/
     704             : /*                       VRTParseFilterSources()                        */
     705             : /************************************************************************/
     706             : 
     707             : VRTSource *
     708          13 : VRTParseFilterSources(const CPLXMLNode *psChild, const char *pszVRTPath,
     709             :                       std::map<CPLString, GDALDataset *> &oMapSharedSources)
     710             : 
     711             : {
     712          13 :     if (EQUAL(psChild->pszValue, "KernelFilteredSource"))
     713             :     {
     714          13 :         VRTSource *poSrc = new VRTKernelFilteredSource();
     715          13 :         if (poSrc->XMLInit(psChild, pszVRTPath, oMapSharedSources) == CE_None)
     716          11 :             return poSrc;
     717             : 
     718           2 :         delete poSrc;
     719             :     }
     720             : 
     721           2 :     return nullptr;
     722             : }
     723             : 
     724             : /*! @endcond */

Generated by: LCOV version 1.14