Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: Implementation of derived subdatasets 5 : * Author: Julien Michel <julien dot michel at cnes dot fr> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2016 Julien Michel <julien dot michel at cnes dot fr> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : *****************************************************************************/ 12 : #include "../vrt/vrtdataset.h" 13 : #include "gdal_frmts.h" 14 : #include "gdal_pam.h" 15 : #include "gdal_priv.h" 16 : #include "derivedlist.h" 17 : 18 34 : class DerivedDataset final : public VRTDataset 19 : { 20 : public: 21 : DerivedDataset(int nXSize, int nYSize); 22 : 23 : ~DerivedDataset() override; 24 : 25 : static int Identify(GDALOpenInfo *); 26 : static GDALDataset *Open(GDALOpenInfo *); 27 : }; 28 : 29 17 : DerivedDataset::DerivedDataset(int nXSize, int nYSize) 30 17 : : VRTDataset(nXSize, nYSize) 31 : { 32 17 : poDriver = nullptr; 33 17 : SetWritable(FALSE); 34 17 : } 35 : 36 : DerivedDataset::~DerivedDataset() = default; 37 : 38 89295 : int DerivedDataset::Identify(GDALOpenInfo *poOpenInfo) 39 : { 40 : /* Try to open original dataset */ 41 178586 : CPLString filename(poOpenInfo->pszFilename); 42 : 43 : /* DERIVED_SUBDATASET should be first domain */ 44 89301 : const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:"); 45 : 46 89291 : if (dsds_pos != 0) 47 : { 48 : /* Unable to Open in this case */ 49 89270 : return FALSE; 50 : } 51 : 52 21 : return TRUE; 53 : } 54 : 55 21 : GDALDataset *DerivedDataset::Open(GDALOpenInfo *poOpenInfo) 56 : { 57 : /* Try to open original dataset */ 58 42 : CPLString filename(poOpenInfo->pszFilename); 59 : 60 : /* DERIVED_SUBDATASET should be first domain */ 61 21 : const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:"); 62 21 : const size_t nPrefixLen = strlen("DERIVED_SUBDATASET:"); 63 : 64 21 : if (dsds_pos != 0) 65 : { 66 : /* Unable to Open in this case */ 67 0 : return nullptr; 68 : } 69 : 70 : /* Next, we need to now which derived dataset to compute */ 71 21 : const size_t alg_pos = filename.find(":", nPrefixLen + 1); 72 21 : if (alg_pos == std::string::npos) 73 : { 74 : /* Unable to Open if we do not find the name of the derived dataset */ 75 1 : return nullptr; 76 : } 77 : 78 40 : CPLString odDerivedName = filename.substr(nPrefixLen, alg_pos - nPrefixLen); 79 : 80 20 : CPLDebug("DerivedDataset::Open", "Derived dataset requested: %s", 81 : odDerivedName.c_str()); 82 : 83 40 : CPLString pixelFunctionName = ""; 84 20 : bool datasetFound = false; 85 : 86 20 : unsigned int nbSupportedDerivedDS(0); 87 20 : GDALDataType type = GDT_Float64; 88 : 89 : const DerivedDatasetDescription *poDDSDesc = 90 20 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS); 91 : 92 160 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS; 93 : ++derivedId) 94 : { 95 140 : if (odDerivedName == poDDSDesc[derivedId].pszDatasetName) 96 : { 97 19 : datasetFound = true; 98 19 : pixelFunctionName = poDDSDesc[derivedId].pszPixelFunction; 99 : type = 100 19 : GDALGetDataTypeByName(poDDSDesc[derivedId].pszOutputPixelType); 101 : } 102 : } 103 : 104 20 : if (!datasetFound) 105 : { 106 1 : return nullptr; 107 : } 108 : 109 : CPLString odFilename = 110 38 : filename.substr(alg_pos + 1, filename.size() - alg_pos); 111 : 112 : auto poTmpDS = std::unique_ptr<GDALDataset>( 113 38 : GDALDataset::Open(odFilename, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR)); 114 : 115 19 : if (poTmpDS == nullptr) 116 1 : return nullptr; 117 : 118 18 : int nbBands = poTmpDS->GetRasterCount(); 119 : 120 18 : if (nbBands == 0) 121 : { 122 1 : return nullptr; 123 : } 124 : 125 17 : int nRows = poTmpDS->GetRasterYSize(); 126 17 : int nCols = poTmpDS->GetRasterXSize(); 127 : 128 17 : DerivedDataset *poDS = new DerivedDataset(nCols, nRows); 129 : 130 : // Transfer metadata 131 17 : poDS->SetMetadata(poTmpDS->GetMetadata()); 132 : 133 17 : char **papszRPC = poTmpDS->GetMetadata("RPC"); 134 17 : if (papszRPC) 135 : { 136 1 : poDS->SetMetadata(papszRPC, "RPC"); 137 : } 138 : 139 : // Transfer projection 140 17 : poDS->SetProjection(poTmpDS->GetProjectionRef()); 141 : 142 : // Transfer geotransform 143 17 : GDALGeoTransform gt; 144 17 : if (poTmpDS->GetGeoTransform(gt) == CE_None) 145 : { 146 9 : poDS->SetGeoTransform(gt); 147 : } 148 : 149 : // Transfer GCPs 150 17 : const char *gcpProjection = poTmpDS->GetGCPProjection(); 151 17 : int nbGcps = poTmpDS->GetGCPCount(); 152 17 : poDS->SetGCPs(nbGcps, poTmpDS->GetGCPs(), gcpProjection); 153 : 154 : // Map bands 155 34 : for (int nBand = 1; nBand <= nbBands; ++nBand) 156 : { 157 : VRTDerivedRasterBand *poBand = 158 17 : new VRTDerivedRasterBand(poDS, nBand, type, nCols, nRows); 159 17 : poDS->SetBand(nBand, poBand); 160 : 161 17 : poBand->SetPixelFunctionName(pixelFunctionName); 162 17 : poBand->SetSourceTransferType( 163 : poTmpDS->GetRasterBand(nBand)->GetRasterDataType()); 164 : 165 17 : poBand->AddComplexSource(odFilename, nBand, 0, 0, nCols, nRows, 0, 0, 166 : nCols, nRows); 167 : } 168 : 169 : // If dataset is a real file, initialize overview manager 170 : VSIStatBufL sStat; 171 17 : if (VSIStatL(odFilename, &sStat) == 0) 172 : { 173 34 : CPLString path = CPLGetPathSafe(odFilename); 174 34 : CPLString ovrFileName = "DERIVED_DATASET_" + odDerivedName + "_" + 175 34 : CPLGetFilename(odFilename); 176 34 : CPLString ovrFilePath = CPLFormFilenameSafe(path, ovrFileName, nullptr); 177 : 178 17 : poDS->oOvManager.Initialize(poDS, ovrFilePath); 179 : } 180 : 181 17 : return poDS; 182 : } 183 : 184 2033 : void GDALRegister_Derived() 185 : { 186 2033 : if (GDALGetDriverByName("DERIVED") != nullptr) 187 283 : return; 188 : 189 1750 : GDALDriver *poDriver = new GDALDriver(); 190 : 191 1750 : poDriver->SetDescription("DERIVED"); 192 : #ifdef GDAL_DCAP_RASTER 193 1750 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 194 : #endif 195 1750 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 196 1750 : "Derived datasets using VRT pixel functions"); 197 1750 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 198 1750 : "drivers/raster/derived.html"); 199 1750 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "NO"); 200 : 201 1750 : poDriver->pfnOpen = DerivedDataset::Open; 202 1750 : poDriver->pfnIdentify = DerivedDataset::Identify; 203 : 204 1750 : GetGDALDriverManager()->RegisterDriver(poDriver); 205 : }