1 : /******************************************************************************
2 : *
3 : * Project: Virtual GDAL Datasets
4 : * Purpose: Implementation of a sourced raster band that derives its raster
5 : * by applying an algorithm (GDALDerivedPixelFunc) to the sources.
6 : * Author: Pete Nagy
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2005 Vexcel Corp.
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : *****************************************************************************/
29 :
30 : #include "vrtdataset.h"
31 : #include "cpl_minixml.h"
32 : #include "cpl_string.h"
33 :
34 : /************************************************************************/
35 : /* ==================================================================== */
36 : /* VRTDerivedRasterBand */
37 : /* ==================================================================== */
38 : /************************************************************************/
39 :
40 : static int nFunctions = 0;
41 : static GDALDerivedPixelFunc *papfnPixelFunctions = NULL;
42 : static char **papszNames = NULL;
43 :
44 : /************************************************************************/
45 : /* VRTDerivedRasterBand() */
46 : /************************************************************************/
47 :
48 0 : VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDS, int nBand)
49 0 : : VRTSourcedRasterBand( poDS, nBand )
50 :
51 : {
52 0 : this->pszFuncName = NULL;
53 0 : this->eSourceTransferType = GDT_Unknown;
54 0 : }
55 :
56 : /************************************************************************/
57 : /* VRTDerivedRasterBand() */
58 : /************************************************************************/
59 :
60 0 : VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDS, int nBand,
61 : GDALDataType eType,
62 : int nXSize, int nYSize)
63 0 : : VRTSourcedRasterBand(poDS, nBand, eType, nXSize, nYSize)
64 :
65 : {
66 0 : this->pszFuncName = NULL;
67 0 : this->eSourceTransferType = GDT_Unknown;
68 0 : }
69 :
70 : /************************************************************************/
71 : /* ~VRTDerivedRasterBand() */
72 : /************************************************************************/
73 :
74 0 : VRTDerivedRasterBand::~VRTDerivedRasterBand()
75 :
76 : {
77 0 : if (this->pszFuncName != NULL) {
78 0 : CPLFree(this->pszFuncName);
79 0 : this->pszFuncName = NULL;
80 : }
81 0 : }
82 :
83 : /************************************************************************/
84 : /* AddPixelFunction() */
85 : /************************************************************************/
86 :
87 : /**
88 : * This adds a pixel function to the global list of available pixel
89 : * functions for derived bands. Pixel functions must be registered
90 : * in this way before a derived band tries to access data.
91 : *
92 : * Derived bands are stored with only the name of the pixel function
93 : * that it will apply, and if a pixel function matching the name is not
94 : * found the IRasterIO() call will do nothing.
95 : *
96 : * @param pszFuncName Name used to access pixel function
97 : * @param pfnNewFunction Pixel function associated with name. An
98 : * existing pixel function registered with the same name will be
99 : * replaced with the new one.
100 : *
101 : * @return CE_None, invalid (NULL) parameters are currently ignored.
102 : */
103 0 : CPLErr CPL_STDCALL GDALAddDerivedBandPixelFunc
104 : (const char *pszFuncName, GDALDerivedPixelFunc pfnNewFunction)
105 : {
106 : int ii;
107 :
108 : /* ---- Init ---- */
109 0 : if ((pszFuncName == NULL) || (pfnNewFunction == NULL)) {
110 0 : return CE_None;
111 : }
112 :
113 : /* ---- Check for match with fn already on list, and replace ---- */
114 0 : for (ii = 0; ii < nFunctions; ii++) {
115 0 : if (strcmp(pszFuncName, papszNames[ii]) == 0) {
116 0 : papfnPixelFunctions[ii] = pfnNewFunction;
117 0 : return CE_None;
118 : }
119 : }
120 :
121 : /* ---- Increment pixel function counter and add name/fn to lists ---- */
122 0 : nFunctions++;
123 :
124 : papfnPixelFunctions = (GDALDerivedPixelFunc *)
125 0 : CPLRealloc(papfnPixelFunctions, sizeof(void*) * nFunctions);
126 0 : papfnPixelFunctions[nFunctions - 1] = pfnNewFunction;
127 :
128 : papszNames = (char **)
129 0 : CPLRealloc(papszNames, sizeof(void*) * nFunctions);
130 0 : papszNames[nFunctions - 1] = (char *)pszFuncName;
131 :
132 0 : return CE_None;
133 : }
134 : /**
135 : * This adds a pixel function to the global list of available pixel
136 : * functions for derived bands.
137 : *
138 : * This is the same as the c function GDALAddDerivedBandPixelFunc()
139 : *
140 : * @param pszFuncName Name used to access pixel function
141 : * @param pfnNewFunction Pixel function associated with name. An
142 : * existing pixel function registered with the same name will be
143 : * replaced with the new one.
144 : *
145 : * @return CE_None, invalid (NULL) parameters are currently ignored.
146 : */
147 0 : CPLErr VRTDerivedRasterBand::AddPixelFunction
148 : (const char *pszFuncName, GDALDerivedPixelFunc pfnNewFunction)
149 : {
150 0 : return GDALAddDerivedBandPixelFunc(pszFuncName, pfnNewFunction);
151 : }
152 :
153 : /************************************************************************/
154 : /* GetPixelFunction() */
155 : /************************************************************************/
156 :
157 : /**
158 : * Get a pixel function previously registered using the global
159 : * AddPixelFunction.
160 : *
161 : * @param pszFuncName The name associated with the pixel function.
162 : *
163 : * @return A derived band pixel function, or NULL if none have been
164 : * registered for pszFuncName.
165 : */
166 0 : GDALDerivedPixelFunc VRTDerivedRasterBand::GetPixelFunction
167 : (const char *pszFuncName)
168 : {
169 : int ii;
170 :
171 : /* ---- Init ---- */
172 0 : if ((pszFuncName == NULL) || (pszFuncName[0] == '\0')) return NULL;
173 :
174 : /* ---- Check for match with fn added with AddPixelFunction ---- */
175 0 : for (ii = 0; ii < nFunctions; ii++) {
176 0 : if (strcmp(pszFuncName, papszNames[ii]) == 0) {
177 0 : return papfnPixelFunctions[ii];
178 : }
179 : }
180 :
181 0 : return NULL;
182 : }
183 :
184 : /************************************************************************/
185 : /* SetPixelFunctionName() */
186 : /************************************************************************/
187 :
188 : /**
189 : * Set the pixel function name to be applied to this derived band. The
190 : * name should match a pixel function registered using AddPixelFunction.
191 : *
192 : * @param pszFuncName Name of pixel function to be applied to this derived
193 : * band.
194 : */
195 0 : void VRTDerivedRasterBand::SetPixelFunctionName(const char *pszFuncName)
196 : {
197 0 : this->pszFuncName = CPLStrdup( pszFuncName );
198 0 : }
199 :
200 : /************************************************************************/
201 : /* SetSourceTransferType() */
202 : /************************************************************************/
203 :
204 : /**
205 : * Set the transfer type to be used to obtain pixel information from
206 : * all of the sources. If unset, the transfer type used will be the
207 : * same as the derived band data type. This makes it possible, for
208 : * example, to pass CFloat32 source pixels to the pixel function, even
209 : * if the pixel function generates a raster for a derived band that
210 : * is of type Byte.
211 : *
212 : * @param eDataType Data type to use to obtain pixel information from
213 : * the sources to be passed to the derived band pixel function.
214 : */
215 0 : void VRTDerivedRasterBand::SetSourceTransferType(GDALDataType eDataType)
216 : {
217 0 : this->eSourceTransferType = eDataType;
218 0 : }
219 :
220 : /************************************************************************/
221 : /* IRasterIO() */
222 : /************************************************************************/
223 :
224 : /**
225 : * Read/write a region of image data for this band.
226 : *
227 : * Each of the sources for this derived band will be read and passed to
228 : * the derived band pixel function. The pixel function is responsible
229 : * for applying whatever algorithm is necessary to generate this band's
230 : * pixels from the sources.
231 : *
232 : * The sources will be read using the transfer type specified for sources
233 : * using SetSourceTransferType(). If no transfer type has been set for
234 : * this derived band, the band's data type will be used as the transfer type.
235 : *
236 : * @see gdalrasterband
237 : *
238 : * @param eRWFlag Either GF_Read to read a region of data, or GT_Write to
239 : * write a region of data.
240 : *
241 : * @param nXOff The pixel offset to the top left corner of the region
242 : * of the band to be accessed. This would be zero to start from the left side.
243 : *
244 : * @param nYOff The line offset to the top left corner of the region
245 : * of the band to be accessed. This would be zero to start from the top.
246 : *
247 : * @param nXSize The width of the region of the band to be accessed in pixels.
248 : *
249 : * @param nYSize The height of the region of the band to be accessed in lines.
250 : *
251 : * @param pData The buffer into which the data should be read, or from which
252 : * it should be written. This buffer must contain at least nBufXSize *
253 : * nBufYSize words of type eBufType. It is organized in left to right,
254 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
255 : * and nLineSpace parameters.
256 : *
257 : * @param nBufXSize The width of the buffer image into which the desired
258 : * region is to be read, or from which it is to be written.
259 : *
260 : * @param nBufYSize The height of the buffer image into which the desired
261 : * region is to be read, or from which it is to be written.
262 : *
263 : * @param eBufType The type of the pixel values in the pData data buffer. The
264 : * pixel values will automatically be translated to/from the GDALRasterBand
265 : * data type as needed.
266 : *
267 : * @param nPixelSpace The byte offset from the start of one pixel value in
268 : * pData to the start of the next pixel value within a scanline. If defaulted
269 : * (0) the size of the datatype eBufType is used.
270 : *
271 : * @param nLineSpace The byte offset from the start of one scanline in
272 : * pData to the start of the next. If defaulted the size of the datatype
273 : * eBufType * nBufXSize is used.
274 : *
275 : * @return CE_Failure if the access fails, otherwise CE_None.
276 : */
277 0 : CPLErr VRTDerivedRasterBand::IRasterIO(GDALRWFlag eRWFlag,
278 : int nXOff, int nYOff, int nXSize,
279 : int nYSize, void * pData, int nBufXSize,
280 : int nBufYSize, GDALDataType eBufType,
281 : int nPixelSpace, int nLineSpace )
282 : {
283 : GDALDerivedPixelFunc pfnPixelFunc;
284 : void **pBuffers;
285 0 : CPLErr eErr = CE_None;
286 : int iSource, ii, typesize, sourcesize;
287 : GDALDataType eSrcType;
288 :
289 0 : if( eRWFlag == GF_Write )
290 : {
291 : CPLError( CE_Failure, CPLE_AppDefined,
292 0 : "Writing through VRTSourcedRasterBand is not supported." );
293 0 : return CE_Failure;
294 : }
295 :
296 0 : typesize = GDALGetDataTypeSize(eBufType) / 8;
297 0 : if (GDALGetDataTypeSize(eBufType) % 8 > 0) typesize++;
298 0 : eSrcType = this->eSourceTransferType;
299 0 : if ((eSrcType == GDT_Unknown) || (eSrcType >= GDT_TypeCount)) {
300 0 : eSrcType = eBufType;
301 : }
302 0 : sourcesize = GDALGetDataTypeSize(eSrcType) / 8;
303 :
304 : /* -------------------------------------------------------------------- */
305 : /* Initialize the buffer to some background value. Use the */
306 : /* nodata value if available. */
307 : /* -------------------------------------------------------------------- */
308 0 : if ( nPixelSpace == typesize &&
309 : (!bNoDataValueSet || dfNoDataValue == 0) ) {
310 0 : memset( pData, 0, nBufXSize * nBufYSize * nPixelSpace );
311 : }
312 0 : else if ( !bEqualAreas || bNoDataValueSet )
313 : {
314 0 : double dfWriteValue = 0.0;
315 : int iLine;
316 :
317 0 : if( bNoDataValueSet )
318 0 : dfWriteValue = dfNoDataValue;
319 :
320 0 : for( iLine = 0; iLine < nBufYSize; iLine++ )
321 : {
322 : GDALCopyWords( &dfWriteValue, GDT_Float64, 0,
323 : ((GByte *)pData) + nLineSpace * iLine,
324 0 : eBufType, nPixelSpace, nBufXSize );
325 : }
326 : }
327 :
328 : /* -------------------------------------------------------------------- */
329 : /* Do we have overviews that would be appropriate to satisfy */
330 : /* this request? */
331 : /* -------------------------------------------------------------------- */
332 0 : if( (nBufXSize < nXSize || nBufYSize < nYSize)
333 0 : && GetOverviewCount() > 0 )
334 : {
335 0 : if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
336 : pData, nBufXSize, nBufYSize,
337 : eBufType, nPixelSpace, nLineSpace ) == CE_None )
338 0 : return CE_None;
339 : }
340 :
341 : /* ---- Get pixel function for band ---- */
342 0 : pfnPixelFunc = VRTDerivedRasterBand::GetPixelFunction(this->pszFuncName);
343 0 : if (pfnPixelFunc == NULL) {
344 : CPLError( CE_Failure, CPLE_IllegalArg,
345 : "VRTDerivedRasterBand::IRasterIO:" \
346 : "Derived band pixel function '%s' not registered.\n",
347 0 : this->pszFuncName);
348 0 : return CE_Failure;
349 : }
350 :
351 : /* TODO: It would be nice to use a MallocBlock function for each
352 : individual buffer that would recycle blocks of memory from a
353 : cache by reassigning blocks that are nearly the same size.
354 : A corresponding FreeBlock might only truly free if the total size
355 : of freed blocks gets to be too great of a percentage of the size
356 : of the allocated blocks. */
357 :
358 : /* ---- Get buffers for each source ---- */
359 0 : pBuffers = (void **) CPLMalloc(sizeof(void *) * nSources);
360 0 : for (iSource = 0; iSource < nSources; iSource++) {
361 0 : pBuffers[iSource] = (void *)
362 0 : malloc(sourcesize * nBufXSize * nBufYSize);
363 0 : if (pBuffers[iSource] == NULL) {
364 0 : for (ii = 0; ii < iSource; ii++) {
365 0 : free(pBuffers[iSource]);
366 : }
367 : CPLError( CE_Failure, CPLE_OutOfMemory,
368 : "VRTDerivedRasterBand::IRasterIO:" \
369 : "Out of memory allocating %d bytes.\n",
370 0 : nPixelSpace * nBufXSize * nBufYSize);
371 0 : return CE_Failure;
372 : }
373 : }
374 :
375 : /* ---- Load values for sources into packed buffers ---- */
376 0 : for(iSource = 0; iSource < nSources; iSource++) {
377 0 : eErr = ((VRTSource *)papoSources[iSource])->RasterIO
378 : (nXOff, nYOff, nXSize, nYSize,
379 : pBuffers[iSource], nBufXSize, nBufYSize,
380 : eSrcType, GDALGetDataTypeSize( eSrcType ) / 8,
381 0 : (GDALGetDataTypeSize( eSrcType ) / 8) * nBufXSize);
382 : }
383 :
384 : /* ---- Apply pixel function ---- */
385 0 : if (eErr == CE_None) {
386 : eErr = pfnPixelFunc((void **)pBuffers, nSources,
387 : pData, nBufXSize, nBufYSize,
388 0 : eSrcType, eBufType, nPixelSpace, nLineSpace);
389 : }
390 :
391 : /* ---- Release buffers ---- */
392 0 : for (iSource = 0; iSource < nSources; iSource++) {
393 0 : free(pBuffers[iSource]);
394 : }
395 0 : CPLFree(pBuffers);
396 :
397 0 : return eErr;
398 : }
399 :
400 : /************************************************************************/
401 : /* XMLInit() */
402 : /************************************************************************/
403 :
404 0 : CPLErr VRTDerivedRasterBand::XMLInit(CPLXMLNode *psTree,
405 : const char *pszVRTPath)
406 :
407 : {
408 : CPLErr eErr;
409 : const char *pszTypeName;
410 :
411 0 : eErr = VRTSourcedRasterBand::XMLInit( psTree, pszVRTPath );
412 0 : if( eErr != CE_None )
413 0 : return eErr;
414 :
415 : /* ---- Read derived pixel function type ---- */
416 : this->SetPixelFunctionName
417 0 : (CPLGetXMLValue(psTree, "PixelFunctionType", NULL));
418 :
419 : /* ---- Read optional source transfer data type ---- */
420 0 : pszTypeName = CPLGetXMLValue(psTree, "SourceTransferType", NULL);
421 0 : if (pszTypeName != NULL) {
422 0 : this->eSourceTransferType = GDALGetDataTypeByName(pszTypeName);
423 : }
424 :
425 0 : return CE_None;
426 : }
427 :
428 : /************************************************************************/
429 : /* SerializeToXML() */
430 : /************************************************************************/
431 :
432 0 : CPLXMLNode *VRTDerivedRasterBand::SerializeToXML(const char *pszVRTPath)
433 : {
434 : CPLXMLNode *psTree;
435 :
436 0 : psTree = VRTSourcedRasterBand::SerializeToXML( pszVRTPath );
437 :
438 : /* -------------------------------------------------------------------- */
439 : /* Set subclass. */
440 : /* -------------------------------------------------------------------- */
441 : CPLCreateXMLNode(
442 : CPLCreateXMLNode( psTree, CXT_Attribute, "subClass" ),
443 0 : CXT_Text, "VRTDerivedRasterBand" );
444 :
445 : /* ---- Encode DerivedBand-specific fields ---- */
446 0 : if( pszFuncName != NULL && strlen(pszFuncName) > 0 )
447 0 : CPLSetXMLValue(psTree, "PixelFunctionType", this->pszFuncName);
448 0 : if( this->eSourceTransferType != GDT_Unknown)
449 : CPLSetXMLValue(psTree, "SourceTransferType",
450 0 : GDALGetDataTypeName(this->eSourceTransferType));
451 :
452 0 : return psTree;
453 : }
454 :
|