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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : *****************************************************************************/
28 : #include "../vrt/vrtdataset.h"
29 : #include "gdal_pam.h"
30 : #include "derivedlist.h"
31 :
32 : class DerivedDataset final : public VRTDataset
33 : {
34 : public:
35 : DerivedDataset(int nXSize, int nYSize);
36 :
37 30 : ~DerivedDataset()
38 15 : {
39 30 : }
40 :
41 : static int Identify(GDALOpenInfo *);
42 : static GDALDataset *Open(GDALOpenInfo *);
43 : };
44 :
45 15 : DerivedDataset::DerivedDataset(int nXSize, int nYSize)
46 15 : : VRTDataset(nXSize, nYSize)
47 : {
48 15 : poDriver = nullptr;
49 15 : SetWritable(FALSE);
50 15 : }
51 :
52 70948 : int DerivedDataset::Identify(GDALOpenInfo *poOpenInfo)
53 : {
54 : /* Try to open original dataset */
55 141887 : CPLString filename(poOpenInfo->pszFilename);
56 :
57 : /* DERIVED_SUBDATASET should be first domain */
58 70947 : const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:");
59 :
60 70939 : if (dsds_pos != 0)
61 : {
62 : /* Unable to Open in this case */
63 70907 : return FALSE;
64 : }
65 :
66 32 : return TRUE;
67 : }
68 :
69 19 : GDALDataset *DerivedDataset::Open(GDALOpenInfo *poOpenInfo)
70 : {
71 : /* Try to open original dataset */
72 38 : CPLString filename(poOpenInfo->pszFilename);
73 :
74 : /* DERIVED_SUBDATASET should be first domain */
75 19 : const size_t dsds_pos = filename.find("DERIVED_SUBDATASET:");
76 19 : const size_t nPrefixLen = strlen("DERIVED_SUBDATASET:");
77 :
78 19 : if (dsds_pos != 0)
79 : {
80 : /* Unable to Open in this case */
81 0 : return nullptr;
82 : }
83 :
84 : /* Next, we need to now which derived dataset to compute */
85 19 : const size_t alg_pos = filename.find(":", nPrefixLen + 1);
86 19 : if (alg_pos == std::string::npos)
87 : {
88 : /* Unable to Open if we do not find the name of the derived dataset */
89 1 : return nullptr;
90 : }
91 :
92 36 : CPLString odDerivedName = filename.substr(nPrefixLen, alg_pos - nPrefixLen);
93 :
94 18 : CPLDebug("DerivedDataset::Open", "Derived dataset requested: %s",
95 : odDerivedName.c_str());
96 :
97 36 : CPLString pixelFunctionName = "";
98 18 : bool datasetFound = false;
99 :
100 18 : unsigned int nbSupportedDerivedDS(0);
101 18 : GDALDataType type = GDT_Float64;
102 :
103 : const DerivedDatasetDescription *poDDSDesc =
104 18 : GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
105 :
106 144 : for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
107 : ++derivedId)
108 : {
109 126 : if (odDerivedName == poDDSDesc[derivedId].pszDatasetName)
110 : {
111 17 : datasetFound = true;
112 17 : pixelFunctionName = poDDSDesc[derivedId].pszPixelFunction;
113 : type =
114 17 : GDALGetDataTypeByName(poDDSDesc[derivedId].pszOutputPixelType);
115 : }
116 : }
117 :
118 18 : if (!datasetFound)
119 : {
120 1 : return nullptr;
121 : }
122 :
123 : CPLString odFilename =
124 34 : filename.substr(alg_pos + 1, filename.size() - alg_pos);
125 :
126 17 : GDALDataset *poTmpDS = (GDALDataset *)GDALOpen(odFilename, GA_ReadOnly);
127 :
128 17 : if (poTmpDS == nullptr)
129 1 : return nullptr;
130 :
131 16 : int nbBands = poTmpDS->GetRasterCount();
132 :
133 16 : if (nbBands == 0)
134 : {
135 1 : GDALClose(poTmpDS);
136 1 : return nullptr;
137 : }
138 :
139 15 : int nRows = poTmpDS->GetRasterYSize();
140 15 : int nCols = poTmpDS->GetRasterXSize();
141 :
142 15 : DerivedDataset *poDS = new DerivedDataset(nCols, nRows);
143 :
144 : // Transfer metadata
145 15 : poDS->SetMetadata(poTmpDS->GetMetadata());
146 :
147 15 : char **papszRPC = poTmpDS->GetMetadata("RPC");
148 15 : if (papszRPC)
149 : {
150 1 : poDS->SetMetadata(papszRPC, "RPC");
151 : }
152 :
153 : // Transfer projection
154 15 : poDS->SetProjection(poTmpDS->GetProjectionRef());
155 :
156 : // Transfer geotransform
157 : double padfTransform[6];
158 15 : CPLErr transformOk = poTmpDS->GetGeoTransform(padfTransform);
159 :
160 15 : if (transformOk == CE_None)
161 : {
162 7 : poDS->SetGeoTransform(padfTransform);
163 : }
164 :
165 : // Transfer GCPs
166 15 : const char *gcpProjection = poTmpDS->GetGCPProjection();
167 15 : int nbGcps = poTmpDS->GetGCPCount();
168 15 : poDS->SetGCPs(nbGcps, poTmpDS->GetGCPs(), gcpProjection);
169 :
170 : // Map bands
171 30 : for (int nBand = 1; nBand <= nbBands; ++nBand)
172 : {
173 : VRTDerivedRasterBand *poBand =
174 15 : new VRTDerivedRasterBand(poDS, nBand, type, nCols, nRows);
175 15 : poDS->SetBand(nBand, poBand);
176 :
177 15 : poBand->SetPixelFunctionName(pixelFunctionName);
178 15 : poBand->SetSourceTransferType(
179 : poTmpDS->GetRasterBand(nBand)->GetRasterDataType());
180 :
181 15 : poBand->AddComplexSource(odFilename, nBand, 0, 0, nCols, nRows, 0, 0,
182 : nCols, nRows);
183 : }
184 :
185 15 : GDALClose(poTmpDS);
186 :
187 : // If dataset is a real file, initialize overview manager
188 : VSIStatBufL sStat;
189 15 : if (VSIStatL(odFilename, &sStat) == 0)
190 : {
191 30 : CPLString path = CPLGetPath(odFilename);
192 30 : CPLString ovrFileName = "DERIVED_DATASET_" + odDerivedName + "_" +
193 30 : CPLGetFilename(odFilename);
194 30 : CPLString ovrFilePath = CPLFormFilename(path, ovrFileName, nullptr);
195 :
196 15 : poDS->oOvManager.Initialize(poDS, ovrFilePath);
197 : }
198 :
199 15 : return poDS;
200 : }
201 :
202 1512 : void GDALRegister_Derived()
203 : {
204 1512 : if (GDALGetDriverByName("DERIVED") != nullptr)
205 295 : return;
206 :
207 1217 : GDALDriver *poDriver = new GDALDriver();
208 :
209 1217 : poDriver->SetDescription("DERIVED");
210 : #ifdef GDAL_DCAP_RASTER
211 1217 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
212 : #endif
213 1217 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
214 1217 : "Derived datasets using VRT pixel functions");
215 1217 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
216 1217 : "drivers/raster/derived.html");
217 1217 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "NO");
218 :
219 1217 : poDriver->pfnOpen = DerivedDataset::Open;
220 1217 : poDriver->pfnIdentify = DerivedDataset::Identify;
221 :
222 1217 : GetGDALDriverManager()->RegisterDriver(poDriver);
223 : }
|