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 34 : class DerivedDataset final : public VRTDataset 17 : { 18 : public: 19 : DerivedDataset(int nXSize, int nYSize); 20 : 21 : ~DerivedDataset(); 22 : 23 : static int Identify(GDALOpenInfo *); 24 : static GDALDataset *Open(GDALOpenInfo *); 25 : }; 26 : 27 17 : DerivedDataset::DerivedDataset(int nXSize, int nYSize) 28 17 : : VRTDataset(nXSize, nYSize) 29 : { 30 17 : poDriver = nullptr; 31 17 : SetWritable(FALSE); 32 17 : } 33 : 34 : DerivedDataset::~DerivedDataset() = default; 35 : 36 85665 : int DerivedDataset::Identify(GDALOpenInfo *poOpenInfo) 37 : { 38 : /* Try to open original dataset */ 39 171314 : CPLString filename(poOpenInfo->pszFilename); 40 : 41 : /* DERIVED_SUBDATASET should be first domain */ 42 85662 : const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:"); 43 : 44 85649 : if (dsds_pos != 0) 45 : { 46 : /* Unable to Open in this case */ 47 85620 : return FALSE; 48 : } 49 : 50 29 : 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 : auto poTmpDS = std::unique_ptr<GDALDataset>( 111 38 : GDALDataset::Open(odFilename, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR)); 112 : 113 19 : if (poTmpDS == nullptr) 114 1 : return nullptr; 115 : 116 18 : int nbBands = poTmpDS->GetRasterCount(); 117 : 118 18 : if (nbBands == 0) 119 : { 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 17 : GDALGeoTransform gt; 142 17 : if (poTmpDS->GetGeoTransform(gt) == CE_None) 143 : { 144 9 : poDS->SetGeoTransform(gt); 145 : } 146 : 147 : // Transfer GCPs 148 17 : const char *gcpProjection = poTmpDS->GetGCPProjection(); 149 17 : int nbGcps = poTmpDS->GetGCPCount(); 150 17 : poDS->SetGCPs(nbGcps, poTmpDS->GetGCPs(), gcpProjection); 151 : 152 : // Map bands 153 34 : for (int nBand = 1; nBand <= nbBands; ++nBand) 154 : { 155 : VRTDerivedRasterBand *poBand = 156 17 : new VRTDerivedRasterBand(poDS, nBand, type, nCols, nRows); 157 17 : poDS->SetBand(nBand, poBand); 158 : 159 17 : poBand->SetPixelFunctionName(pixelFunctionName); 160 17 : poBand->SetSourceTransferType( 161 : poTmpDS->GetRasterBand(nBand)->GetRasterDataType()); 162 : 163 17 : poBand->AddComplexSource(odFilename, nBand, 0, 0, nCols, nRows, 0, 0, 164 : nCols, nRows); 165 : } 166 : 167 : // If dataset is a real file, initialize overview manager 168 : VSIStatBufL sStat; 169 17 : if (VSIStatL(odFilename, &sStat) == 0) 170 : { 171 34 : CPLString path = CPLGetPathSafe(odFilename); 172 34 : CPLString ovrFileName = "DERIVED_DATASET_" + odDerivedName + "_" + 173 34 : CPLGetFilename(odFilename); 174 34 : CPLString ovrFilePath = CPLFormFilenameSafe(path, ovrFileName, nullptr); 175 : 176 17 : poDS->oOvManager.Initialize(poDS, ovrFilePath); 177 : } 178 : 179 17 : return poDS; 180 : } 181 : 182 1928 : void GDALRegister_Derived() 183 : { 184 1928 : if (GDALGetDriverByName("DERIVED") != nullptr) 185 282 : return; 186 : 187 1646 : GDALDriver *poDriver = new GDALDriver(); 188 : 189 1646 : poDriver->SetDescription("DERIVED"); 190 : #ifdef GDAL_DCAP_RASTER 191 1646 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); 192 : #endif 193 1646 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 194 1646 : "Derived datasets using VRT pixel functions"); 195 1646 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 196 1646 : "drivers/raster/derived.html"); 197 1646 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "NO"); 198 : 199 1646 : poDriver->pfnOpen = DerivedDataset::Open; 200 1646 : poDriver->pfnIdentify = DerivedDataset::Identify; 201 : 202 1646 : GetGDALDriverManager()->RegisterDriver(poDriver); 203 : }