Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: "reproject" step of "vector pipeline" 5 : * Author: Even Rouault <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "gdalalg_vector_reproject.h" 14 : 15 : #include "gdal_priv.h" 16 : #include "ogr_spatialref.h" 17 : #include "ogrsf_frmts.h" 18 : #include "ogrwarpedlayer.h" 19 : 20 : //! @cond Doxygen_Suppress 21 : 22 : #ifndef _ 23 : #define _(x) (x) 24 : #endif 25 : 26 : /************************************************************************/ 27 : /* GDALVectorReprojectAlgorithm::GDALVectorReprojectAlgorithm() */ 28 : /************************************************************************/ 29 : 30 113 : GDALVectorReprojectAlgorithm::GDALVectorReprojectAlgorithm(bool standaloneStep) 31 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 32 113 : standaloneStep) 33 : { 34 113 : AddActiveLayerArg(&m_activeLayer); 35 226 : AddArg(GDAL_ARG_NAME_INPUT_CRS, 's', _("Input CRS"), &m_srcCrs) 36 226 : .SetIsCRSArg() 37 226 : .AddHiddenAlias("src-crs") 38 113 : .AddHiddenAlias("s_srs"); 39 226 : AddArg(GDAL_ARG_NAME_OUTPUT_CRS, 'd', _("Output CRS"), &m_dstCrs) 40 226 : .SetIsCRSArg() 41 226 : .AddHiddenAlias("dst-crs") 42 226 : .AddHiddenAlias("t_srs") 43 113 : .SetMutualExclusionGroup("output-crs"); 44 : AddArg("like", 0, _("Dataset from which an output CRS should be extracted"), 45 226 : &m_likeDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR) 46 226 : .SetMetaVar("DATASET") 47 113 : .SetMutualExclusionGroup("output-crs"); 48 : AddArg("like-layer", 0, ("Name of the layer of the 'like' dataset"), 49 226 : &m_likeLayer) 50 113 : .SetMetaVar("LAYER-NAME"); 51 113 : } 52 : 53 : /************************************************************************/ 54 : /* GDALVectorReprojectAlgorithm::RunStep() */ 55 : /************************************************************************/ 56 : 57 23 : bool GDALVectorReprojectAlgorithm::RunStep(GDALPipelineStepRunContext &) 58 : { 59 23 : auto poSrcDS = m_inputDataset[0].GetDatasetRef(); 60 23 : CPLAssert(poSrcDS); 61 : 62 23 : CPLAssert(m_outputDataset.GetName().empty()); 63 23 : CPLAssert(!m_outputDataset.GetDatasetRef()); 64 : 65 23 : std::unique_ptr<OGRSpatialReference> poSrcCRS; 66 23 : if (!m_srcCrs.empty()) 67 : { 68 3 : poSrcCRS = std::make_unique<OGRSpatialReference>(); 69 3 : poSrcCRS->SetFromUserInput(m_srcCrs.c_str()); 70 3 : poSrcCRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); 71 : } 72 : 73 46 : OGRSpatialReference oDstCRS; 74 23 : if (!m_dstCrs.empty()) 75 : { 76 14 : oDstCRS.SetFromUserInput(m_dstCrs.c_str()); 77 14 : oDstCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); 78 : } 79 9 : else if (auto *poLikeDS = m_likeDataset.GetDatasetRef()) 80 : { 81 5 : if (!m_likeLayer.empty()) 82 : { 83 : const auto *poLikeLayer = 84 3 : poLikeDS->GetLayerByName(m_likeLayer.c_str()); 85 3 : if (!poLikeLayer) 86 : { 87 1 : ReportError(CE_Failure, CPLE_AppDefined, 88 : "Specified layer '%s' not found.", 89 : m_likeLayer.c_str()); 90 1 : return false; 91 : } 92 2 : if (!poLikeLayer->GetSpatialRef()) 93 : { 94 0 : ReportError( 95 : CE_Failure, CPLE_AppDefined, 96 : "Specified layer '%s' has no spatial reference system.", 97 : m_likeLayer.c_str()); 98 0 : return false; 99 : } 100 : 101 2 : oDstCRS = *poLikeLayer->GetSpatialRef(); 102 : } 103 : else 104 : { 105 2 : const auto *poLikeCRS = poLikeDS->GetSpatialRef(); 106 : 107 2 : if (!poLikeCRS) 108 : { 109 0 : ReportError( 110 : CE_Failure, CPLE_AppDefined, 111 : "Dataset specified by --like has no spatial reference " 112 : "system, or has multiple layers with different spatial " 113 : "reference systems. An individual layer can be specified " 114 : "with --like-layer."); 115 0 : return false; 116 : } 117 2 : oDstCRS = *poLikeCRS; 118 : } 119 : } 120 : else 121 : { 122 4 : ReportError(CE_Failure, CPLE_AppDefined, 123 : "Must specify --output-crs or --like"); 124 4 : return false; 125 : } 126 : 127 : auto reprojectedDataset = 128 36 : std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS); 129 : 130 18 : const int nLayerCount = poSrcDS->GetLayerCount(); 131 18 : bool ret = true; 132 52 : for (int i = 0; ret && i < nLayerCount; ++i) 133 : { 134 35 : auto poSrcLayer = poSrcDS->GetLayer(i); 135 35 : ret = (poSrcLayer != nullptr); 136 35 : if (ret) 137 : { 138 35 : if ((m_activeLayer.empty() && 139 53 : poSrcLayer->GetGeomType() != wkbNone) || 140 18 : m_activeLayer == poSrcLayer->GetDescription()) 141 : { 142 : const OGRSpatialReference *poSrcLayerCRS; 143 18 : if (poSrcCRS) 144 3 : poSrcLayerCRS = poSrcCRS.get(); 145 : else 146 15 : poSrcLayerCRS = poSrcLayer->GetSpatialRef(); 147 18 : if (!poSrcLayerCRS) 148 : { 149 1 : ReportError(CE_Failure, CPLE_AppDefined, 150 : "Layer '%s' has no spatial reference system", 151 1 : poSrcLayer->GetName()); 152 1 : return false; 153 : } 154 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>( 155 34 : OGRCreateCoordinateTransformation(poSrcLayerCRS, &oDstCRS)); 156 : auto poReversedCT = 157 : std::unique_ptr<OGRCoordinateTransformation>( 158 : OGRCreateCoordinateTransformation(&oDstCRS, 159 34 : poSrcLayerCRS)); 160 17 : ret = (poCT != nullptr) && (poReversedCT != nullptr); 161 17 : if (ret) 162 : { 163 34 : reprojectedDataset->AddLayer( 164 : *poSrcLayer, 165 17 : std::make_unique<OGRWarpedLayer>( 166 0 : poSrcLayer, /* iGeomField = */ 0, 167 34 : /*bTakeOwnership = */ false, std::move(poCT), 168 17 : std::move(poReversedCT))); 169 : } 170 : } 171 : else 172 : { 173 34 : reprojectedDataset->AddLayer( 174 : *poSrcLayer, 175 34 : std::make_unique<GDALVectorPipelinePassthroughLayer>( 176 : *poSrcLayer)); 177 : } 178 : } 179 : } 180 : 181 17 : if (ret) 182 17 : m_outputDataset.Set(std::move(reprojectedDataset)); 183 : 184 17 : return ret; 185 : } 186 : 187 : GDALVectorReprojectAlgorithmStandalone:: 188 : ~GDALVectorReprojectAlgorithmStandalone() = default; 189 : 190 : //! @endcond