LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_footprint.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 143 143 100.0 %
Date: 2025-05-15 18:21:54 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster footprint" subcommand
       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_footprint.h"
      14             : 
      15             : #include "cpl_conv.h"
      16             : 
      17             : #include "gdal_priv.h"
      18             : #include "gdal_utils.h"
      19             : 
      20             : //! @cond Doxygen_Suppress
      21             : 
      22             : #ifndef _
      23             : #define _(x) (x)
      24             : #endif
      25             : 
      26             : /************************************************************************/
      27             : /*      GDALRasterFootprintAlgorithm::GDALRasterFootprintAlgorithm()    */
      28             : /************************************************************************/
      29             : 
      30          37 : GDALRasterFootprintAlgorithm::GDALRasterFootprintAlgorithm()
      31          37 :     : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL)
      32             : {
      33          37 :     AddProgressArg();
      34             : 
      35          37 :     AddOpenOptionsArg(&m_openOptions);
      36          37 :     AddInputFormatsArg(&m_inputFormats)
      37          74 :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_RASTER});
      38          37 :     AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER);
      39             : 
      40          37 :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR)
      41          37 :         .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
      42             :     AddOutputFormatArg(&m_format, /* bStreamAllowed = */ false,
      43          37 :                        /* bGDALGAllowed = */ false)
      44             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      45         111 :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE});
      46          74 :     AddArg("output-layer", 0, _("Output layer name"), &m_outputLayerName)
      47          37 :         .SetDefault(m_outputLayerName);
      48          37 :     AddCreationOptionsArg(&m_creationOptions);
      49          37 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
      50          37 :     AddAppendUpdateArg(&m_append);
      51          37 :     AddOverwriteArg(&m_overwrite);
      52             : 
      53          37 :     AddBandArg(&m_bands);
      54             :     AddArg("combine-bands", 0,
      55             :            _("Defines how the mask bands of the selected bands are combined to "
      56             :              "generate a single mask band, before being vectorized."),
      57          74 :            &m_combineBands)
      58          37 :         .SetChoices("union", "intersection")
      59          37 :         .SetDefault(m_combineBands);
      60             :     AddArg("overview", 0, _("Which overview level of source file must be used"),
      61          74 :            &m_overview)
      62          74 :         .SetMutualExclusionGroup("overview-srcnodata")
      63          37 :         .SetMinValueIncluded(0);
      64             :     AddArg("src-nodata", 0, _("Set nodata values for input bands."),
      65          74 :            &m_srcNoData)
      66          37 :         .SetMinCount(1)
      67          37 :         .SetRepeatedArgAllowed(false)
      68          37 :         .SetMutualExclusionGroup("overview-srcnodata");
      69             :     AddArg("coordinate-system", 0, _("Target coordinate system"),
      70          74 :            &m_coordinateSystem)
      71          37 :         .SetChoices("georeferenced", "pixel");
      72          74 :     AddArg("dst-crs", 0, _("Destination CRS"), &m_dstCrs)
      73          74 :         .SetIsCRSArg()
      74          37 :         .AddHiddenAlias("t_srs");
      75             :     AddArg("split-multipolygons", 0,
      76             :            _("Whether to split multipolygons as several features each with one "
      77             :              "single polygon"),
      78          37 :            &m_splitMultiPolygons);
      79             :     AddArg("convex-hull", 0,
      80             :            _("Whether to compute the convex hull of the footprint"),
      81          37 :            &m_convexHull);
      82             :     AddArg("densify-distance", 0,
      83             :            _("Maximum distance between 2 consecutive points of the output "
      84             :              "geometry."),
      85          74 :            &m_densifyVal)
      86          37 :         .SetMinValueExcluded(0);
      87             :     AddArg(
      88             :         "simplify-tolerance", 0,
      89             :         _("Tolerance used to merge consecutive points of the output geometry."),
      90          74 :         &m_simplifyVal)
      91          37 :         .SetMinValueExcluded(0);
      92             :     AddArg("min-ring-area", 0, _("Minimum value for the area of a ring"),
      93          74 :            &m_minRingArea)
      94          37 :         .SetMinValueIncluded(0);
      95             :     AddArg("max-points", 0,
      96          74 :            _("Maximum number of points of each output geometry"), &m_maxPoints)
      97          37 :         .SetDefault(m_maxPoints)
      98             :         .AddValidationAction(
      99           7 :             [this]()
     100             :             {
     101           2 :                 if (m_maxPoints != "unlimited")
     102             :                 {
     103           2 :                     char *endptr = nullptr;
     104             :                     const auto nVal =
     105           2 :                         std::strtoll(m_maxPoints.c_str(), &endptr, 10);
     106           3 :                     if (nVal < 4 ||
     107           1 :                         endptr != m_maxPoints.c_str() + m_maxPoints.size())
     108             :                     {
     109           1 :                         ReportError(
     110             :                             CE_Failure, CPLE_IllegalArg,
     111             :                             "Value of 'max-points' should be a positive "
     112             :                             "integer greater or equal to 4, or 'unlimited'");
     113           1 :                         return false;
     114             :                     }
     115             :                 }
     116           1 :                 return true;
     117          37 :             });
     118             :     AddArg("location-field", 0,
     119             :            _("Name of the field where the path of the input dataset will be "
     120             :              "stored."),
     121          74 :            &m_locationField)
     122          37 :         .SetDefault(m_locationField)
     123          37 :         .SetMutualExclusionGroup("location");
     124             :     AddArg("no-location-field", 0,
     125             :            _("Disable creating a field with the path of the input dataset"),
     126          74 :            &m_noLocation)
     127          37 :         .SetMutualExclusionGroup("location");
     128             :     AddArg("absolute-path", 0,
     129             :            _("Whether the path to the input dataset should be stored as an "
     130             :              "absolute path"),
     131          37 :            &m_writeAbsolutePaths);
     132             : 
     133          37 :     AddValidationAction(
     134          71 :         [this]
     135             :         {
     136          33 :             if (auto poSrcDS = m_inputDataset.GetDatasetRef())
     137             :             {
     138             :                 const int nOvrCount =
     139          33 :                     poSrcDS->GetRasterBand(1)->GetOverviewCount();
     140          36 :                 if (m_overview >= 0 && poSrcDS->GetRasterCount() > 0 &&
     141           3 :                     m_overview >= nOvrCount)
     142             :                 {
     143           2 :                     if (nOvrCount == 0)
     144             :                     {
     145           1 :                         ReportError(
     146             :                             CE_Failure, CPLE_IllegalArg,
     147             :                             "Source dataset has no overviews. "
     148             :                             "Argument 'overview' should not be specified.");
     149             :                     }
     150             :                     else
     151             :                     {
     152           1 :                         ReportError(
     153             :                             CE_Failure, CPLE_IllegalArg,
     154             :                             "Source dataset has only %d overview levels. "
     155             :                             "'overview' "
     156             :                             "value should be strictly lower than this number.",
     157             :                             nOvrCount);
     158             :                     }
     159           2 :                     return false;
     160             :                 }
     161             :             }
     162          31 :             return true;
     163             :         });
     164          37 : }
     165             : 
     166             : /************************************************************************/
     167             : /*                 GDALRasterFootprintAlgorithm::RunImpl()              */
     168             : /************************************************************************/
     169             : 
     170          30 : bool GDALRasterFootprintAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
     171             :                                            void *pProgressData)
     172             : {
     173          60 :     CPLStringList aosOptions;
     174          36 :     for (int band : m_bands)
     175             :     {
     176           6 :         aosOptions.push_back("-b");
     177           6 :         aosOptions.push_back(CPLSPrintf("%d", band));
     178             :     }
     179             : 
     180          30 :     aosOptions.push_back("-combine_bands");
     181          30 :     aosOptions.push_back(m_combineBands);
     182             : 
     183          30 :     if (m_overview >= 0)
     184             :     {
     185           1 :         aosOptions.push_back("-ovr");
     186           1 :         aosOptions.push_back(CPLSPrintf("%d", m_overview));
     187             :     }
     188             : 
     189          30 :     if (!m_srcNoData.empty())
     190             :     {
     191           2 :         aosOptions.push_back("-srcnodata");
     192           4 :         std::string s;
     193           5 :         for (double v : m_srcNoData)
     194             :         {
     195           3 :             if (!s.empty())
     196           1 :                 s += " ";
     197           3 :             s += CPLSPrintf("%.17g", v);
     198             :         }
     199           2 :         aosOptions.push_back(s);
     200             :     }
     201             : 
     202          30 :     if (m_coordinateSystem == "pixel")
     203             :     {
     204           1 :         aosOptions.push_back("-t_cs");
     205           1 :         aosOptions.push_back("pixel");
     206             :     }
     207          29 :     else if (m_coordinateSystem == "georeferenced")
     208             :     {
     209           1 :         aosOptions.push_back("-t_cs");
     210           1 :         aosOptions.push_back("georef");
     211             :     }
     212             : 
     213          30 :     if (!m_dstCrs.empty())
     214             :     {
     215           1 :         aosOptions.push_back("-t_srs");
     216           1 :         aosOptions.push_back(m_dstCrs);
     217             :     }
     218             : 
     219          30 :     if (!m_format.empty())
     220             :     {
     221          25 :         aosOptions.push_back("-of");
     222          25 :         aosOptions.push_back(m_format.c_str());
     223             :     }
     224             : 
     225          31 :     for (const auto &co : m_creationOptions)
     226             :     {
     227           1 :         aosOptions.push_back("-dsco");
     228           1 :         aosOptions.push_back(co.c_str());
     229             :     }
     230             : 
     231          31 :     for (const auto &co : m_layerCreationOptions)
     232             :     {
     233           1 :         aosOptions.push_back("-lco");
     234           1 :         aosOptions.push_back(co.c_str());
     235             :     }
     236             : 
     237          30 :     if (GetArg("output-layer")->IsExplicitlySet())
     238             :     {
     239           5 :         aosOptions.push_back("-lyr_name");
     240           5 :         aosOptions.push_back(m_outputLayerName.c_str());
     241             :     }
     242             : 
     243          30 :     if (m_splitMultiPolygons)
     244           1 :         aosOptions.push_back("-split_polys");
     245             : 
     246          30 :     if (m_convexHull)
     247           1 :         aosOptions.push_back("-convex_hull");
     248             : 
     249          30 :     if (m_densifyVal > 0)
     250             :     {
     251           1 :         aosOptions.push_back("-densify");
     252           1 :         aosOptions.push_back(CPLSPrintf("%.17g", m_densifyVal));
     253             :     }
     254             : 
     255          30 :     if (m_simplifyVal > 0)
     256             :     {
     257           1 :         aosOptions.push_back("-simplify");
     258           1 :         aosOptions.push_back(CPLSPrintf("%.17g", m_simplifyVal));
     259             :     }
     260             : 
     261          30 :     aosOptions.push_back("-min_ring_area");
     262          30 :     aosOptions.push_back(CPLSPrintf("%.17g", m_minRingArea));
     263             : 
     264          30 :     aosOptions.push_back("-max_points");
     265          30 :     aosOptions.push_back(m_maxPoints);
     266             : 
     267          30 :     if (m_noLocation)
     268             :     {
     269           1 :         aosOptions.push_back("-no_location");
     270             :     }
     271             :     else
     272             :     {
     273          29 :         aosOptions.push_back("-location_field_name");
     274          29 :         aosOptions.push_back(m_locationField);
     275             : 
     276          29 :         if (m_writeAbsolutePaths)
     277           1 :             aosOptions.push_back("-write_absolute_path");
     278             :     }
     279             : 
     280          30 :     bool bOK = false;
     281             :     std::unique_ptr<GDALFootprintOptions, decltype(&GDALFootprintOptionsFree)>
     282             :         psOptions{GDALFootprintOptionsNew(aosOptions.List(), nullptr),
     283          30 :                   GDALFootprintOptionsFree};
     284          30 :     if (psOptions)
     285             :     {
     286          30 :         GDALFootprintOptionsSetProgress(psOptions.get(), pfnProgress,
     287             :                                         pProgressData);
     288             : 
     289             :         GDALDatasetH hSrcDS =
     290          30 :             GDALDataset::ToHandle(m_inputDataset.GetDatasetRef());
     291             :         GDALDatasetH hDstDS =
     292          30 :             GDALDataset::ToHandle(m_outputDataset.GetDatasetRef());
     293          30 :         auto poRetDS = GDALDataset::FromHandle(
     294          30 :             GDALFootprint(m_outputDataset.GetName().c_str(), hDstDS, hSrcDS,
     295          30 :                           psOptions.get(), nullptr));
     296          30 :         bOK = poRetDS != nullptr;
     297          30 :         if (bOK && !hDstDS)
     298             :         {
     299          27 :             m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
     300             :         }
     301             :     }
     302             : 
     303          60 :     return bOK;
     304             : }
     305             : 
     306             : //! @endcond

Generated by: LCOV version 1.14