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 12 : GDALVectorReprojectAlgorithm::GDALVectorReprojectAlgorithm(bool standaloneStep) 31 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL, 32 12 : standaloneStep) 33 : { 34 24 : AddArg("src-crs", 's', _("Source CRS"), &m_srsCrs) 35 12 : .SetIsCRSArg() 36 12 : .AddHiddenAlias("s_srs"); 37 24 : AddArg("dst-crs", 'd', _("Destination CRS"), &m_dstCrs) 38 12 : .SetIsCRSArg() 39 12 : .SetRequired() 40 12 : .AddHiddenAlias("t_srs"); 41 12 : } 42 : 43 : /************************************************************************/ 44 : /* GDALVectorReprojectAlgorithmDataset */ 45 : /************************************************************************/ 46 : 47 : namespace 48 : { 49 : class GDALVectorReprojectAlgorithmDataset final : public GDALDataset 50 : { 51 : std::vector<std::unique_ptr<OGRLayer>> m_layers{}; 52 : 53 : public: 54 3 : GDALVectorReprojectAlgorithmDataset() = default; 55 : 56 2 : void AddLayer(std::unique_ptr<OGRLayer> poLayer) 57 : { 58 2 : m_layers.push_back(std::move(poLayer)); 59 2 : } 60 : 61 6 : int GetLayerCount() override 62 : { 63 6 : return static_cast<int>(m_layers.size()); 64 : } 65 : 66 2 : OGRLayer *GetLayer(int idx) override 67 : { 68 2 : return idx >= 0 && idx < GetLayerCount() ? m_layers[idx].get() 69 2 : : nullptr; 70 : } 71 : }; 72 : } // namespace 73 : 74 : /************************************************************************/ 75 : /* GDALVectorReprojectAlgorithm::RunStep() */ 76 : /************************************************************************/ 77 : 78 3 : bool GDALVectorReprojectAlgorithm::RunStep(GDALProgressFunc, void *) 79 : { 80 3 : CPLAssert(m_inputDataset.GetDatasetRef()); 81 3 : CPLAssert(m_outputDataset.GetName().empty()); 82 3 : CPLAssert(!m_outputDataset.GetDatasetRef()); 83 : 84 3 : std::unique_ptr<OGRSpatialReference> poSrcCRS; 85 3 : if (!m_srsCrs.empty()) 86 : { 87 1 : poSrcCRS = std::make_unique<OGRSpatialReference>(); 88 1 : poSrcCRS->SetFromUserInput(m_srsCrs.c_str()); 89 1 : poSrcCRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); 90 : } 91 : 92 6 : OGRSpatialReference oDstCRS; 93 3 : oDstCRS.SetFromUserInput(m_dstCrs.c_str()); 94 3 : oDstCRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); 95 : 96 3 : auto poSrcDS = m_inputDataset.GetDatasetRef(); 97 : 98 : auto reprojectedDataset = 99 6 : std::make_unique<GDALVectorReprojectAlgorithmDataset>(); 100 3 : reprojectedDataset->SetDescription(poSrcDS->GetDescription()); 101 : 102 3 : const int nLayerCount = poSrcDS->GetLayerCount(); 103 3 : bool ret = true; 104 5 : for (int i = 0; ret && i < nLayerCount; ++i) 105 : { 106 3 : auto poSrcLayer = poSrcDS->GetLayer(i); 107 3 : ret = (poSrcLayer != nullptr); 108 3 : if (ret) 109 : { 110 : OGRSpatialReference *poSrcLayerCRS; 111 3 : if (poSrcCRS) 112 1 : poSrcLayerCRS = poSrcCRS.get(); 113 : else 114 2 : poSrcLayerCRS = poSrcLayer->GetSpatialRef(); 115 3 : if (!poSrcLayerCRS) 116 : { 117 1 : ReportError(CE_Failure, CPLE_AppDefined, 118 : "Layer '%s' has no spatial reference system", 119 1 : poSrcLayer->GetName()); 120 1 : return false; 121 : } 122 : auto poCT = std::unique_ptr<OGRCoordinateTransformation>( 123 4 : OGRCreateCoordinateTransformation(poSrcLayerCRS, &oDstCRS)); 124 : auto poReversedCT = std::unique_ptr<OGRCoordinateTransformation>( 125 4 : OGRCreateCoordinateTransformation(&oDstCRS, poSrcLayerCRS)); 126 2 : ret = (poCT != nullptr) && (poReversedCT != nullptr); 127 2 : if (ret) 128 : { 129 4 : reprojectedDataset->AddLayer(std::make_unique<OGRWarpedLayer>( 130 0 : poSrcLayer, /* iGeomField = */ 0, 131 2 : /*bTakeOwnership = */ false, poCT.release(), 132 4 : poReversedCT.release())); 133 : } 134 : } 135 : } 136 : 137 2 : if (ret) 138 2 : m_outputDataset.Set(std::move(reprojectedDataset)); 139 : 140 2 : return ret; 141 : } 142 : 143 : //! @endcond