LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_mosaic_stack_common.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 137 143 95.8 %
Date: 2025-06-19 12:30:01 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Common code of "raster mosaic" and "raster stack"
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_raster_mosaic_stack_common.h"
      14             : #include "gdalalg_raster_write.h"
      15             : 
      16             : #include "cpl_conv.h"
      17             : #include "cpl_vsi_virtual.h"
      18             : 
      19             : #include "gdal_priv.h"
      20             : #include "gdal_utils.h"
      21             : 
      22             : //! @cond Doxygen_Suppress
      23             : 
      24             : #ifndef _
      25             : #define _(x) (x)
      26             : #endif
      27             : 
      28             : /************************************************************************/
      29             : /*                          GetConstructorOptions()                     */
      30             : /************************************************************************/
      31             : 
      32             : /* static */ GDALRasterMosaicStackCommonAlgorithm::ConstructorOptions
      33          91 : GDALRasterMosaicStackCommonAlgorithm::GetConstructorOptions(bool standaloneStep)
      34             : {
      35          91 :     ConstructorOptions opts;
      36          91 :     opts.SetStandaloneStep(standaloneStep);
      37          91 :     opts.SetAutoOpenInputDatasets(false);
      38             :     opts.SetInputDatasetHelpMsg(
      39             :         _("Input raster datasets (or specify a @<filename> to point to a "
      40          91 :           "file containing filenames)"));
      41          91 :     opts.SetAddDefaultArguments(false);
      42          91 :     opts.SetInputDatasetMaxCount(INT_MAX);
      43          91 :     return opts;
      44             : }
      45             : 
      46             : /************************************************************************/
      47             : /*                  GDALRasterMosaicStackCommonAlgorithm()              */
      48             : /************************************************************************/
      49             : 
      50          91 : GDALRasterMosaicStackCommonAlgorithm::GDALRasterMosaicStackCommonAlgorithm(
      51             :     const std::string &name, const std::string &description,
      52          91 :     const std::string &helpURL, bool bStandalone)
      53             :     : GDALRasterPipelineStepAlgorithm(name, description, helpURL,
      54          91 :                                       GetConstructorOptions(bStandalone))
      55             : {
      56          91 :     AddRasterInputArgs(/* openForMixedRasterVector = */ false,
      57             :                        /* hiddenForCLI = */ false);
      58          91 :     if (bStandalone)
      59             :     {
      60          51 :         AddProgressArg();
      61          51 :         AddRasterOutputArgs(false);
      62             :     }
      63             : 
      64          91 :     AddBandArg(&m_bands);
      65             :     AddAbsolutePathArg(
      66             :         &m_writeAbsolutePaths,
      67             :         _("Whether the path to the input datasets should be stored as an "
      68          91 :           "absolute path"));
      69             :     {
      70             :         auto &arg =
      71             :             AddArg("resolution", 0,
      72             :                    _("Target resolution (in destination CRS units)"),
      73         182 :                    &m_resolution)
      74          91 :                 .SetDefault("same")
      75          91 :                 .SetMetaVar("<xres>,<yres>|same|average|common|highest|lowest");
      76             :         arg.AddValidationAction(
      77          13 :             [this, &arg]()
      78             :             {
      79          20 :                 const std::string val = arg.Get<std::string>();
      80          19 :                 if (val != "average" && val != "highest" && val != "lowest" &&
      81          19 :                     val != "same" && val != "common")
      82             :                 {
      83             :                     const auto aosTokens =
      84           5 :                         CPLStringList(CSLTokenizeString2(val.c_str(), ",", 0));
      85           5 :                     if (aosTokens.size() != 2 ||
      86           3 :                         CPLGetValueType(aosTokens[0]) == CPL_VALUE_STRING ||
      87           3 :                         CPLGetValueType(aosTokens[1]) == CPL_VALUE_STRING ||
      88          10 :                         CPLAtof(aosTokens[0]) <= 0 ||
      89           2 :                         CPLAtof(aosTokens[1]) <= 0)
      90             :                     {
      91           3 :                         ReportError(
      92             :                             CE_Failure, CPLE_AppDefined,
      93             :                             "resolution: two comma separated positive "
      94             :                             "values should be provided, or 'same', "
      95             :                             "'average', 'common', 'highest' or 'lowest'");
      96           3 :                         return false;
      97             :                     }
      98             :                 }
      99           7 :                 return true;
     100          91 :             });
     101             :     }
     102             :     AddBBOXArg(&m_bbox, _("Target bounding box as xmin,ymin,xmax,ymax (in "
     103          91 :                           "destination CRS units)"));
     104             :     AddArg("target-aligned-pixels", 0,
     105             :            _("Round target extent to target resolution"),
     106         182 :            &m_targetAlignedPixels)
     107          91 :         .AddHiddenAlias("tap");
     108             :     AddArg("src-nodata", 0, _("Set nodata values for input bands."),
     109         182 :            &m_srcNoData)
     110          91 :         .SetMinCount(1)
     111          91 :         .SetRepeatedArgAllowed(false);
     112             :     AddArg("dst-nodata", 0,
     113         182 :            _("Set nodata values at the destination band level."), &m_dstNoData)
     114          91 :         .SetMinCount(1)
     115          91 :         .SetRepeatedArgAllowed(false);
     116             :     AddArg("hide-nodata", 0,
     117             :            _("Makes the destination band not report the NoData."),
     118          91 :            &m_hideNoData);
     119          91 : }
     120             : 
     121             : /************************************************************************/
     122             : /*     GDALRasterMosaicStackCommonAlgorithm::GetInputDatasetNames()     */
     123             : /************************************************************************/
     124             : 
     125          33 : bool GDALRasterMosaicStackCommonAlgorithm::GetInputDatasetNames(
     126             :     GDALPipelineStepRunContext &ctxt,
     127             :     std::vector<GDALDatasetH> &ahInputDatasets,
     128             :     CPLStringList &aosInputDatasetNames, bool &foundByName)
     129             : {
     130          33 :     bool foundByRef = false;
     131          78 :     for (auto &ds : m_inputDataset)
     132             :     {
     133          47 :         if (ds.GetDatasetRef())
     134             :         {
     135          30 :             foundByRef = true;
     136          30 :             ahInputDatasets.push_back(
     137          30 :                 GDALDataset::ToHandle(ds.GetDatasetRef()));
     138             :         }
     139          17 :         else if (!ds.GetName().empty())
     140             :         {
     141          17 :             foundByName = true;
     142          17 :             if (ds.GetName()[0] == '@')
     143             :             {
     144             :                 auto f = VSIVirtualHandleUniquePtr(
     145           3 :                     VSIFOpenL(ds.GetName().c_str() + 1, "r"));
     146           3 :                 if (!f)
     147             :                 {
     148           2 :                     ReportError(CE_Failure, CPLE_FileIO, "Cannot open %s",
     149           2 :                                 ds.GetName().c_str() + 1);
     150           2 :                     return false;
     151             :                 }
     152           2 :                 while (const char *filename = CPLReadLineL(f.get()))
     153             :                 {
     154           1 :                     aosInputDatasetNames.push_back(filename);
     155           1 :                 }
     156             :             }
     157          14 :             else if (ds.GetName().find_first_of("*?[") != std::string::npos)
     158             :             {
     159           1 :                 CPLStringList aosMatches(VSIGlob(ds.GetName().c_str(), nullptr,
     160             :                                                  ctxt.m_pfnProgress,
     161           2 :                                                  ctxt.m_pProgressData));
     162           2 :                 for (const char *pszStr : aosMatches)
     163             :                 {
     164           1 :                     aosInputDatasetNames.push_back(pszStr);
     165             :                 }
     166             :             }
     167             :             else
     168             :             {
     169          26 :                 std::string osDatasetName = ds.GetName();
     170          13 :                 if (!GetReferencePathForRelativePaths().empty())
     171             :                 {
     172           0 :                     osDatasetName = GDALDataset::BuildFilename(
     173             :                         osDatasetName.c_str(),
     174           0 :                         GetReferencePathForRelativePaths().c_str(), true);
     175             :                 }
     176          13 :                 aosInputDatasetNames.push_back(osDatasetName.c_str());
     177             :             }
     178             :         }
     179             :     }
     180          31 :     if (foundByName && foundByRef)
     181             :     {
     182           0 :         ReportError(CE_Failure, CPLE_NotSupported,
     183             :                     "Input datasets should be provided either all by reference "
     184             :                     "or all by name");
     185           0 :         return false;
     186             :     }
     187             : 
     188          31 :     return true;
     189             : }
     190             : 
     191             : /************************************************************************/
     192             : /*      GDALRasterMosaicStackCommonAlgorithm::SetBuildVRTOptions()      */
     193             : /************************************************************************/
     194             : 
     195          31 : void GDALRasterMosaicStackCommonAlgorithm::SetBuildVRTOptions(
     196             :     CPLStringList &aosOptions)
     197             : {
     198             :     const auto aosTokens =
     199          62 :         CPLStringList(CSLTokenizeString2(m_resolution.c_str(), ",", 0));
     200          31 :     if (aosTokens.size() == 2)
     201             :     {
     202           2 :         aosOptions.push_back("-tr");
     203           2 :         aosOptions.push_back(aosTokens[0]);
     204           2 :         aosOptions.push_back(aosTokens[1]);
     205             :     }
     206             :     else
     207             :     {
     208          29 :         aosOptions.push_back("-resolution");
     209          29 :         aosOptions.push_back(m_resolution);
     210             :     }
     211             : 
     212          31 :     if (!m_bbox.empty())
     213             :     {
     214           1 :         aosOptions.push_back("-te");
     215           1 :         aosOptions.push_back(CPLSPrintf("%.17g", m_bbox[0]));
     216           1 :         aosOptions.push_back(CPLSPrintf("%.17g", m_bbox[1]));
     217           1 :         aosOptions.push_back(CPLSPrintf("%.17g", m_bbox[2]));
     218           1 :         aosOptions.push_back(CPLSPrintf("%.17g", m_bbox[3]));
     219             :     }
     220          31 :     if (m_targetAlignedPixels)
     221             :     {
     222           1 :         aosOptions.push_back("-tap");
     223             :     }
     224          31 :     if (!m_srcNoData.empty())
     225             :     {
     226           2 :         aosOptions.push_back("-srcnodata");
     227           4 :         std::string s;
     228           4 :         for (double v : m_srcNoData)
     229             :         {
     230           2 :             if (!s.empty())
     231           0 :                 s += " ";
     232           2 :             s += CPLSPrintf("%.17g", v);
     233             :         }
     234           2 :         aosOptions.push_back(s);
     235             :     }
     236          31 :     if (!m_dstNoData.empty())
     237             :     {
     238           4 :         aosOptions.push_back("-vrtnodata");
     239           8 :         std::string s;
     240           8 :         for (double v : m_dstNoData)
     241             :         {
     242           4 :             if (!s.empty())
     243           0 :                 s += " ";
     244           4 :             s += CPLSPrintf("%.17g", v);
     245             :         }
     246           4 :         aosOptions.push_back(s);
     247             :     }
     248          33 :     for (const int b : m_bands)
     249             :     {
     250           2 :         aosOptions.push_back("-b");
     251           2 :         aosOptions.push_back(CPLSPrintf("%d", b));
     252             :     }
     253          31 :     if (m_hideNoData)
     254             :     {
     255           1 :         aosOptions.push_back("-hidenodata");
     256             :     }
     257          31 :     if (m_writeAbsolutePaths)
     258             :     {
     259           2 :         aosOptions.push_back("-write_absolute_path");
     260             :     }
     261          31 : }
     262             : 
     263             : /************************************************************************/
     264             : /*             GDALRasterMosaicStackCommonAlgorithm::RunImpl()          */
     265             : /************************************************************************/
     266             : 
     267          62 : bool GDALRasterMosaicStackCommonAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
     268             :                                                    void *pProgressData)
     269             : {
     270          62 :     if (m_standaloneStep)
     271             :     {
     272          31 :         GDALRasterWriteAlgorithm writeAlg;
     273         310 :         for (auto &arg : writeAlg.GetArgs())
     274             :         {
     275         279 :             auto stepArg = GetArg(arg->GetName());
     276         279 :             if (stepArg && stepArg->IsExplicitlySet())
     277             :             {
     278          90 :                 arg->SetSkipIfAlreadySet(true);
     279          90 :                 arg->SetFrom(*stepArg);
     280             :             }
     281             :         }
     282             : 
     283             :         // Already checked by GDALAlgorithm::Run()
     284          31 :         CPLAssert(!m_executionForStreamOutput ||
     285             :                   EQUAL(m_format.c_str(), "stream"));
     286             : 
     287          31 :         m_standaloneStep = false;
     288          31 :         bool ret = Run(pfnProgress, pProgressData);
     289          31 :         m_standaloneStep = true;
     290          31 :         if (ret)
     291             :         {
     292          27 :             if (m_format == "stream")
     293             :             {
     294          19 :                 ret = true;
     295             :             }
     296             :             else
     297             :             {
     298           8 :                 writeAlg.m_inputDataset.clear();
     299           8 :                 writeAlg.m_inputDataset.resize(1);
     300           8 :                 writeAlg.m_inputDataset[0].Set(m_outputDataset.GetDatasetRef());
     301           8 :                 if (writeAlg.Run(pfnProgress, pProgressData))
     302             :                 {
     303           8 :                     m_outputDataset.Set(
     304             :                         writeAlg.m_outputDataset.GetDatasetRef());
     305           8 :                     ret = true;
     306             :                 }
     307             :             }
     308             :         }
     309             : 
     310          31 :         return ret;
     311             :     }
     312             :     else
     313             :     {
     314          31 :         GDALPipelineStepRunContext stepCtxt;
     315          31 :         stepCtxt.m_pfnProgress = pfnProgress;
     316          31 :         stepCtxt.m_pProgressData = pProgressData;
     317          31 :         return RunStep(stepCtxt);
     318             :     }
     319             : }
     320             : 
     321             : //! @endcond

Generated by: LCOV version 1.14