LCOV - code coverage report
Current view: top level - frmts/vrt - vrtfilters.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 240 275 87.3 %
Date: 2024-11-21 22:18:42 Functions: 14 15 93.3 %

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

Generated by: LCOV version 1.14