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_pam.h" 14 : #include "derivedlist.h" 15 : 16 : class DerivedDataset final : public VRTDataset 17 : { 18 : public: 19 : DerivedDataset(int nXSize, int nYSize); 20 : 21 34 : ~DerivedDataset() 22 17 : { 23 34 : } 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 76096 : int DerivedDataset::Identify(GDALOpenInfo *poOpenInfo) 37 : { 38 : /* Try to open original dataset */ 39 152183 : CPLString filename(poOpenInfo->pszFilename); 40 : 41 : /* DERIVED_SUBDATASET should be first domain */ 42 76094 : const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:"); 43 : 44 76087 : if (dsds_pos != 0) 45 : { 46 : /* Unable to Open in this case */ 47 76057 : return FALSE; 48 : } 49 : 50 30 : return TRUE; 51 : } 52 : 53 21 : GDALDataset *DerivedDataset::Open(GDALOpenInfo *poOpenInfo) 54 : { 55 : /* Try to open original dataset */ 56 42 : CPLString filename(poOpenInfo->pszFilename); 57 : 58 : /* DERIVED_SUBDATASET should be first domain */ 59 21 : const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:"); 60 21 : const size_t nPrefixLen = strlen("DERIVED_SUBDATASET:"); 61 : 62 21 : if (dsds_pos != 0) 63 : { 64 : /* Unable to Open in this case */ 65 0 : return nullptr; 66 : } 67 : 68 : /* Next, we need to now which derived dataset to compute */ 69 21 : const size_t alg_pos = filename.find(":", nPrefixLen + 1); 70 21 : if (alg_pos == std::string::npos) 71 : { 72 : /* Unable to Open if we do not find the name of the derived dataset */ 73 1 : return nullptr; 74 : } 75 : 76 40 : CPLString odDerivedName = filename.substr(nPrefixLen, alg_pos - nPrefixLen); 77 : 78 20 : CPLDebug("DerivedDataset::Open", "Derived dataset requested: %s", 79 : odDerivedName.c_str()); 80 : 81 40 : CPLString pixelFunctionName = ""; 82 20 : bool datasetFound = false; 83 : 84 20 : unsigned int nbSupportedDerivedDS(0); 85 20 : GDALDataType type = GDT_Float64; 86 : 87 : const DerivedDatasetDescription *poDDSDesc = 88 20 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS); 89 : 90 160 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS; 91 : ++derivedId) 92 : { 93 140 : if (odDerivedName == poDDSDesc[derivedId].pszDatasetName) 94 : { 95 19 : datasetFound = true; 96 19 : pixelFunctionName = poDDSDesc[derivedId].pszPixelFunction; 97 : type = 98 19 : GDALGetDataTypeByName(poDDSDesc[derivedId].pszOutputPixelType); 99 : } 100 : } 101 : 102 20 : if (!datasetFound) 103 : { 104 1 : return nullptr; 105 : } 106 : 107 : CPLString odFilename = 108 38 : filename.substr(alg_pos + 1, filename.size() - alg_pos); 109 : 110 19 : GDALDataset *poTmpDS = (GDALDataset *)GDALOpen(odFilename, GA_ReadOnly); 111 : 112 19 : if (poTmpDS == nullptr) 113 1 : return nullptr; 114 : 115 18 : int nbBands = poTmpDS->GetRasterCount(); 116 : 117 18 : if (nbBands == 0) 118 : { 119 1 : GDALClose(poTmpDS); 120 1 : return nullptr; 121 : } 122 : 123 17 : int nRows = poTmpDS->GetRasterYSize(); 124 17 : int nCols = poTmpDS->GetRasterXSize(); 125 : 126 17 : DerivedDataset *poDS = new DerivedDataset(nCols, nRows); 127 : 128 : // Transfer metadata 129 17 : poDS->SetMetadata(poTmpDS->GetMetadata()); 130 : 131 17 : char **papszRPC = poTmpDS->GetMetadata("RPC"); 132 17 : if (papszRPC) 133 : { 134 1 : poDS->SetMetadata(papszRPC, "RPC"); 135 : } 136 : 137 : // Transfer projection 138 17 : poDS->SetProjection(poTmpDS->GetProjectionRef()); 139 : 140 : // Transfer geotransform 141 : double padfTransform[6]; 142 17 : CPLErr transformOk = poTmpDS->GetGeoTransform(padfTransform); 143 : 144 17 : if (transformOk == CE_None) 145 : { 146 9 : poDS->SetGeoTransform(padfTransform); 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 17 : GDALClose(poTmpDS); 170 : 171 : // If dataset is a real file, initialize overview manager 172 : VSIStatBufL sStat; 173 17 : if (VSIStatL(odFilename, &sStat) == 0) 174 : { 175 34 : CPLString path = CPLGetPath(odFilename); 176 34 : CPLString ovrFileName = "DERIVED_DATASET_" + odDerivedName + "_" + 177 34 : CPLGetFilename(odFilename); 178 34 : CPLString ovrFilePath = CPLFormFilename(path, ovrFileName, nullptr); 179 : 180 17 : poDS->oOvManager.Initialize(poDS, ovrFilePath); 181 : } 182 : 183 17 : return poDS; 184 : } 185 : 186 1595 : void GDALRegister_Derived() 187 : { 188 1595 : if (GDALGetDriverByName("DERIVED") != nullptr) 189 302 : return; 190 : 191 1293 : GDALDriver *poDriver = new GDALDriver(); 192 : 193 1293 : poDriver->SetDescription("DERIVED"); 194 : #ifdef GDAL_DCAP_RASTER 195 1293 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 196 : #endif 197 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 198 1293 : "Derived datasets using VRT pixel functions"); 199 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 200 1293 : "drivers/raster/derived.html"); 201 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "NO"); 202 : 203 1293 : poDriver->pfnOpen = DerivedDataset::Open; 204 1293 : poDriver->pfnIdentify = DerivedDataset::Identify; 205 : 206 1293 : GetGDALDriverManager()->RegisterDriver(poDriver); 207 : }