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