1 : /******************************************************************************
2 : * $Id: vrtfilters.cpp 24530 2012-06-02 16:28:14Z rouault $
3 : *
4 : * Project: Virtual GDAL Datasets
5 : * Purpose: Implementation of some filter types.
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
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 : CPL_CVSID("$Id: vrtfilters.cpp 24530 2012-06-02 16:28:14Z rouault $");
35 :
36 : /************************************************************************/
37 : /* ==================================================================== */
38 : /* VRTFilteredSource */
39 : /* ==================================================================== */
40 : /************************************************************************/
41 :
42 : /************************************************************************/
43 : /* VRTFilteredSource() */
44 : /************************************************************************/
45 :
46 5 : VRTFilteredSource::VRTFilteredSource()
47 :
48 : {
49 5 : nExtraEdgePixels = 0;
50 5 : nSupportedTypesCount = 1;
51 5 : aeSupportedTypes[0] = GDT_Float32;
52 5 : }
53 :
54 : /************************************************************************/
55 : /* ~VRTFilteredSource() */
56 : /************************************************************************/
57 :
58 5 : VRTFilteredSource::~VRTFilteredSource()
59 :
60 : {
61 5 : }
62 :
63 : /************************************************************************/
64 : /* SetExtraEdgePixels() */
65 : /************************************************************************/
66 :
67 5 : void VRTFilteredSource::SetExtraEdgePixels( int nEdgePixels )
68 :
69 : {
70 5 : nExtraEdgePixels = nEdgePixels;
71 5 : }
72 :
73 : /************************************************************************/
74 : /* SetFilteringDataTypesSupported() */
75 : /************************************************************************/
76 :
77 5 : void VRTFilteredSource::SetFilteringDataTypesSupported( int nTypeCount,
78 : GDALDataType *paeTypes)
79 :
80 : {
81 5 : if( nTypeCount >
82 : (int) sizeof(sizeof(aeSupportedTypes)/sizeof(GDALDataType)) )
83 : {
84 0 : CPLAssert( FALSE );
85 : nTypeCount = (int)
86 0 : sizeof(sizeof(aeSupportedTypes)/sizeof(GDALDataType));
87 : }
88 :
89 5 : nSupportedTypesCount = nTypeCount;
90 5 : memcpy( aeSupportedTypes, paeTypes, sizeof(GDALDataType) * nTypeCount );
91 5 : }
92 :
93 : /************************************************************************/
94 : /* IsTypeSupported() */
95 : /************************************************************************/
96 :
97 440 : int VRTFilteredSource::IsTypeSupported( GDALDataType eTestType )
98 :
99 : {
100 : int i;
101 :
102 880 : for( i = 0; i < nSupportedTypesCount; i++ )
103 : {
104 440 : if( eTestType == aeSupportedTypes[i] )
105 0 : return TRUE;
106 : }
107 :
108 440 : return FALSE;
109 : }
110 :
111 : /************************************************************************/
112 : /* RasterIO() */
113 : /************************************************************************/
114 :
115 : CPLErr
116 220 : VRTFilteredSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
117 : void *pData, int nBufXSize, int nBufYSize,
118 : GDALDataType eBufType,
119 : int nPixelSpace, int nLineSpace )
120 :
121 : {
122 : /* -------------------------------------------------------------------- */
123 : /* For now we don't support filtered access to non-full */
124 : /* resolution requests. Just collect the data directly without */
125 : /* any operator. */
126 : /* -------------------------------------------------------------------- */
127 220 : if( nBufXSize != nXSize || nBufYSize != nYSize )
128 : {
129 : return VRTComplexSource::RasterIO( nXOff, nYOff, nXSize, nYSize,
130 : pData, nBufXSize, nBufYSize,
131 0 : eBufType, nPixelSpace, nLineSpace );
132 : }
133 :
134 : // The window we will actually request from the source raster band.
135 : int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
136 :
137 : // The window we will actual set _within_ the pData buffer.
138 : int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
139 :
140 220 : if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
141 : &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
142 : &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) )
143 0 : return CE_None;
144 :
145 : pData = ((GByte *)pData)
146 : + nPixelSpace * nOutXOff
147 220 : + nLineSpace * nOutYOff;
148 :
149 : /* -------------------------------------------------------------------- */
150 : /* Determine the data type we want to request. We try to match */
151 : /* the source or destination request, and if both those fail we */
152 : /* fallback to the first supported type at least as expressive */
153 : /* as the request. */
154 : /* -------------------------------------------------------------------- */
155 220 : GDALDataType eOperDataType = GDT_Unknown;
156 : int i;
157 :
158 220 : if( IsTypeSupported( eBufType ) )
159 0 : eOperDataType = eBufType;
160 :
161 220 : if( eOperDataType == GDT_Unknown
162 : && IsTypeSupported( poRasterBand->GetRasterDataType() ) )
163 0 : eOperDataType = poRasterBand->GetRasterDataType();
164 :
165 220 : if( eOperDataType == GDT_Unknown )
166 : {
167 440 : for( i = 0; i < nSupportedTypesCount; i++ )
168 : {
169 440 : if( GDALDataTypeUnion( aeSupportedTypes[i], eBufType )
170 220 : == aeSupportedTypes[i] )
171 : {
172 220 : eOperDataType = aeSupportedTypes[i];
173 : }
174 : }
175 : }
176 :
177 220 : if( eOperDataType == GDT_Unknown )
178 : {
179 0 : eOperDataType = aeSupportedTypes[0];
180 :
181 0 : for( i = 1; i < nSupportedTypesCount; i++ )
182 : {
183 0 : if( GDALGetDataTypeSize( aeSupportedTypes[i] )
184 : > GDALGetDataTypeSize( eOperDataType ) )
185 : {
186 0 : eOperDataType = aeSupportedTypes[i];
187 : }
188 : }
189 : }
190 :
191 : /* -------------------------------------------------------------------- */
192 : /* Allocate the buffer of data into which our imagery will be */
193 : /* read, with the extra edge pixels as well. This will be the */
194 : /* source data fed into the filter. */
195 : /* -------------------------------------------------------------------- */
196 : int nPixelOffset, nLineOffset;
197 220 : int nExtraXSize = nOutXSize + 2 * nExtraEdgePixels;
198 220 : int nExtraYSize = nOutYSize + 2 * nExtraEdgePixels;
199 : GByte *pabyWorkData;
200 :
201 : // FIXME? : risk of multiplication overflow
202 : pabyWorkData = (GByte *)
203 : VSICalloc( nExtraXSize * nExtraYSize,
204 220 : (GDALGetDataTypeSize(eOperDataType) / 8) );
205 :
206 220 : if( pabyWorkData == NULL )
207 : {
208 : CPLError( CE_Failure, CPLE_OutOfMemory,
209 0 : "Work buffer allocation failed." );
210 0 : return CE_Failure;
211 : }
212 :
213 220 : nPixelOffset = GDALGetDataTypeSize( eOperDataType ) / 8;
214 220 : nLineOffset = nPixelOffset * nExtraXSize;
215 :
216 : /* -------------------------------------------------------------------- */
217 : /* Allocate the output buffer if the passed in output buffer is */
218 : /* not of the same type as our working format, or if the passed */
219 : /* in buffer has an unusual organization. */
220 : /* -------------------------------------------------------------------- */
221 : GByte *pabyOutData;
222 :
223 440 : if( nPixelSpace != nPixelOffset || nLineSpace != nLineOffset
224 : || eOperDataType != eBufType )
225 : {
226 : pabyOutData = (GByte *)
227 220 : VSIMalloc3(nOutXSize, nOutYSize, nPixelOffset );
228 :
229 220 : if( pabyOutData == NULL )
230 : {
231 : CPLError( CE_Failure, CPLE_OutOfMemory,
232 0 : "Work buffer allocation failed." );
233 0 : return CE_Failure;
234 : }
235 : }
236 : else
237 0 : pabyOutData = (GByte *) pData;
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* Figure out the extended window that we want to load. Note */
241 : /* that we keep track of the file window as well as the amount */
242 : /* we will need to edge fill past the edge of the source dataset. */
243 : /* -------------------------------------------------------------------- */
244 220 : int nTopFill=0, nLeftFill=0, nRightFill=0, nBottomFill=0;
245 : int nFileXOff, nFileYOff, nFileXSize, nFileYSize;
246 :
247 220 : nFileXOff = nReqXOff - nExtraEdgePixels;
248 220 : nFileYOff = nReqYOff - nExtraEdgePixels;
249 220 : nFileXSize = nExtraXSize;
250 220 : nFileYSize = nExtraYSize;
251 :
252 220 : if( nFileXOff < 0 )
253 : {
254 220 : nLeftFill = -nFileXOff;
255 220 : nFileXOff = 0;
256 220 : nFileXSize -= nLeftFill;
257 : }
258 :
259 220 : if( nFileYOff < 0 )
260 : {
261 5 : nTopFill = -nFileYOff;
262 5 : nFileYOff = 0;
263 5 : nFileYSize -= nTopFill;
264 : }
265 :
266 220 : if( nFileXOff + nFileXSize > poRasterBand->GetXSize() )
267 : {
268 220 : nRightFill = nFileXOff + nFileXSize - poRasterBand->GetXSize();
269 220 : nFileXSize -= nRightFill;
270 : }
271 :
272 220 : if( nFileYOff + nFileYSize > poRasterBand->GetYSize() )
273 : {
274 5 : nBottomFill = nFileYOff + nFileYSize - poRasterBand->GetYSize();
275 5 : nFileYSize -= nBottomFill;
276 : }
277 :
278 : /* -------------------------------------------------------------------- */
279 : /* Load the data. */
280 : /* -------------------------------------------------------------------- */
281 : CPLErr eErr;
282 :
283 : eErr =
284 : VRTComplexSource::RasterIOInternal( nFileXOff, nFileYOff, nFileXSize, nFileYSize,
285 : pabyWorkData
286 : + nLineOffset * nTopFill
287 : + nPixelOffset * nLeftFill,
288 : nFileXSize, nFileYSize, eOperDataType,
289 220 : nPixelOffset, nLineOffset );
290 :
291 220 : if( eErr != CE_None )
292 : {
293 0 : if( pabyWorkData != pData )
294 0 : VSIFree( pabyWorkData );
295 :
296 0 : return eErr;
297 : }
298 :
299 : /* -------------------------------------------------------------------- */
300 : /* Fill in missing areas. Note that we replicate the edge */
301 : /* valid values out. We don't using "mirroring" which might be */
302 : /* more suitable for some times of filters. We also don't mark */
303 : /* these pixels as "nodata" though perhaps we should. */
304 : /* -------------------------------------------------------------------- */
305 220 : if( nLeftFill != 0 || nRightFill != 0 )
306 : {
307 870 : for( i = nTopFill; i < nExtraYSize - nBottomFill; i++ )
308 : {
309 650 : if( nLeftFill != 0 )
310 : GDALCopyWords( pabyWorkData + nPixelOffset * nLeftFill
311 : + i * nLineOffset, eOperDataType, 0,
312 : pabyWorkData + i * nLineOffset, eOperDataType,
313 650 : nPixelOffset, nLeftFill );
314 :
315 650 : if( nRightFill != 0 )
316 : GDALCopyWords( pabyWorkData + i * nLineOffset
317 : + nPixelOffset * (nExtraXSize - nRightFill - 1),
318 : eOperDataType, 0,
319 : pabyWorkData + i * nLineOffset
320 : + nPixelOffset * (nExtraXSize - nRightFill),
321 650 : eOperDataType, nPixelOffset, nRightFill );
322 : }
323 : }
324 :
325 225 : for( i = 0; i < nTopFill; i++ )
326 : {
327 : memcpy( pabyWorkData + i * nLineOffset,
328 : pabyWorkData + nTopFill * nLineOffset,
329 5 : nLineOffset );
330 : }
331 :
332 225 : for( i = nExtraYSize - nBottomFill; i < nExtraYSize; i++ )
333 : {
334 : memcpy( pabyWorkData + i * nLineOffset,
335 : pabyWorkData + (nExtraYSize - nBottomFill - 1) * nLineOffset,
336 5 : nLineOffset );
337 : }
338 :
339 : /* -------------------------------------------------------------------- */
340 : /* Filter the data. */
341 : /* -------------------------------------------------------------------- */
342 : eErr = FilterData( nOutXSize, nOutYSize, eOperDataType,
343 220 : pabyWorkData, pabyOutData );
344 :
345 220 : VSIFree( pabyWorkData );
346 220 : if( eErr != CE_None )
347 : {
348 0 : if( pabyOutData != pData )
349 0 : VSIFree( pabyOutData );
350 :
351 0 : return eErr;
352 : }
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Copy from work buffer to target buffer. */
356 : /* -------------------------------------------------------------------- */
357 220 : if( pabyOutData != pData )
358 : {
359 440 : for( i = 0; i < nOutYSize; i++ )
360 : {
361 : GDALCopyWords( pabyOutData + i * (nPixelOffset * nOutXSize),
362 : eOperDataType, nPixelOffset,
363 : ((GByte *) pData) + i * nLineSpace,
364 220 : eBufType, nPixelSpace, nOutXSize );
365 : }
366 :
367 220 : VSIFree( pabyOutData );
368 : }
369 :
370 220 : return CE_None;
371 : }
372 :
373 : /************************************************************************/
374 : /* ==================================================================== */
375 : /* VRTKernelFilteredSource */
376 : /* ==================================================================== */
377 : /************************************************************************/
378 :
379 : /************************************************************************/
380 : /* VRTKernelFilteredSource() */
381 : /************************************************************************/
382 :
383 5 : VRTKernelFilteredSource::VRTKernelFilteredSource()
384 :
385 : {
386 5 : GDALDataType aeSupTypes[] = { GDT_Float32 };
387 5 : padfKernelCoefs = NULL;
388 5 : nKernelSize = 0;
389 5 : bNormalized = FALSE;
390 :
391 5 : SetFilteringDataTypesSupported( 1, aeSupTypes );
392 5 : }
393 :
394 : /************************************************************************/
395 : /* ~VRTKernelFilteredSource() */
396 : /************************************************************************/
397 :
398 5 : VRTKernelFilteredSource::~VRTKernelFilteredSource()
399 :
400 : {
401 5 : CPLFree( padfKernelCoefs );
402 5 : }
403 :
404 : /************************************************************************/
405 : /* SetNormalized() */
406 : /************************************************************************/
407 :
408 5 : void VRTKernelFilteredSource::SetNormalized( int bNormalizedIn )
409 :
410 : {
411 5 : bNormalized = bNormalizedIn;
412 5 : }
413 :
414 : /************************************************************************/
415 : /* SetKernel() */
416 : /************************************************************************/
417 :
418 5 : CPLErr VRTKernelFilteredSource::SetKernel( int nNewKernelSize,
419 : double *padfNewCoefs )
420 :
421 : {
422 5 : if( nNewKernelSize < 1 || (nNewKernelSize % 2) != 1 )
423 : {
424 : CPLError( CE_Failure, CPLE_AppDefined,
425 : "Illegal filtering kernel size %d, must be odd positive number.",
426 0 : nNewKernelSize );
427 0 : return CE_Failure;
428 : }
429 :
430 5 : CPLFree( padfKernelCoefs );
431 5 : nKernelSize = nNewKernelSize;
432 :
433 : padfKernelCoefs = (double *)
434 5 : CPLMalloc(sizeof(double) * nKernelSize * nKernelSize );
435 : memcpy( padfKernelCoefs, padfNewCoefs,
436 5 : sizeof(double) * nKernelSize * nKernelSize );
437 :
438 5 : SetExtraEdgePixels( (nNewKernelSize - 1) / 2 );
439 :
440 5 : return CE_None;
441 : }
442 :
443 : /************************************************************************/
444 : /* FilterData() */
445 : /************************************************************************/
446 :
447 220 : CPLErr VRTKernelFilteredSource::
448 : FilterData( int nXSize, int nYSize, GDALDataType eType,
449 : GByte *pabySrcData, GByte *pabyDstData )
450 :
451 : {
452 : /* -------------------------------------------------------------------- */
453 : /* Validate data type. */
454 : /* -------------------------------------------------------------------- */
455 220 : if( eType != GDT_Float32 )
456 : {
457 : CPLError( CE_Failure, CPLE_AppDefined,
458 : "Unsupported data type (%s) in VRTKernelFilteredSource::FilterData()",
459 0 : GDALGetDataTypeName( eType ) );
460 0 : return CE_Failure;
461 : }
462 :
463 : CPLAssert( nExtraEdgePixels*2 + 1 == nKernelSize ||
464 220 : (nKernelSize == 0 && nExtraEdgePixels == 0) );
465 :
466 : /* -------------------------------------------------------------------- */
467 : /* Float32 case. */
468 : /* -------------------------------------------------------------------- */
469 220 : if( eType == GDT_Float32 )
470 : {
471 : int iX, iY;
472 :
473 : int bHasNoData;
474 220 : float fNoData = (float) poRasterBand->GetNoDataValue(&bHasNoData);
475 :
476 440 : for( iY = 0; iY < nYSize; iY++ )
477 : {
478 10620 : for( iX = 0; iX < nXSize; iX++ )
479 : {
480 10400 : int iYY, iKern = 0;
481 10400 : double dfSum = 0.0, dfKernSum = 0.0;
482 : float fResult;
483 10400 : int iIndex = (iY+nKernelSize/2 ) * (nXSize+2*nExtraEdgePixels) + iX + nKernelSize/2;
484 10400 : float fCenter = ((float *)pabySrcData)[iIndex];
485 :
486 : // Check if center srcpixel is NoData
487 20600 : if(!bHasNoData || fCenter != fNoData)
488 : {
489 40800 : for( iYY = 0; iYY < nKernelSize; iYY++ )
490 : {
491 : int i;
492 : float *pafData = ((float *)pabySrcData)
493 30600 : + (iY+iYY) * (nXSize+2*nExtraEdgePixels) + iX;
494 :
495 122400 : for( i = 0; i < nKernelSize; i++, pafData++, iKern++ )
496 : {
497 91800 : if(!bHasNoData || *pafData != fNoData)
498 : {
499 90964 : dfSum += *pafData * padfKernelCoefs[iKern];
500 90964 : dfKernSum += padfKernelCoefs[iKern];
501 : }
502 : }
503 : }
504 10200 : if( bNormalized )
505 : {
506 200 : if( dfKernSum != 0.0 )
507 200 : fResult = (float) (dfSum / dfKernSum);
508 : else
509 0 : fResult = 0.0;
510 : }
511 : else
512 10000 : fResult = (float) dfSum;
513 :
514 10200 : ((float *) pabyDstData)[iX + iY * nXSize] = fResult;
515 : }
516 : else
517 200 : ((float *) pabyDstData)[iX + iY * nXSize] = fNoData;
518 : }
519 : }
520 : }
521 :
522 220 : return CE_None;
523 : }
524 :
525 : /************************************************************************/
526 : /* XMLInit() */
527 : /************************************************************************/
528 :
529 5 : CPLErr VRTKernelFilteredSource::XMLInit( CPLXMLNode *psTree,
530 : const char *pszVRTPath )
531 :
532 : {
533 5 : CPLErr eErr = VRTFilteredSource::XMLInit( psTree, pszVRTPath );
534 : int nNewKernelSize, i, nCoefs;
535 : double *padfNewCoefs;
536 :
537 5 : if( eErr != CE_None )
538 0 : return eErr;
539 :
540 5 : nNewKernelSize = atoi(CPLGetXMLValue(psTree,"Kernel.Size","0"));
541 :
542 5 : if( nNewKernelSize == 0 )
543 0 : return CE_None;
544 :
545 : char **papszCoefItems =
546 5 : CSLTokenizeString( CPLGetXMLValue(psTree,"Kernel.Coefs","") );
547 :
548 5 : nCoefs = CSLCount(papszCoefItems);
549 :
550 5 : if( nCoefs != nNewKernelSize * nNewKernelSize )
551 : {
552 0 : CSLDestroy( papszCoefItems );
553 : CPLError( CE_Failure, CPLE_AppDefined,
554 : "Got wrong number of filter kernel coefficients (%s).\n"
555 : "Expected %d, got %d.",
556 : CPLGetXMLValue(psTree,"Kernel.Coefs",""),
557 0 : nNewKernelSize * nNewKernelSize, nCoefs );
558 0 : return CE_Failure;
559 : }
560 :
561 5 : padfNewCoefs = (double *) CPLMalloc(sizeof(double) * nCoefs);
562 :
563 50 : for( i = 0; i < nCoefs; i++ )
564 45 : padfNewCoefs[i] = atof(papszCoefItems[i]);
565 :
566 5 : eErr = SetKernel( nNewKernelSize, padfNewCoefs );
567 :
568 5 : CPLFree( padfNewCoefs );
569 5 : CSLDestroy( papszCoefItems );
570 :
571 5 : SetNormalized( atoi(CPLGetXMLValue(psTree,"Kernel.normalized","0")) );
572 :
573 5 : return eErr;
574 : }
575 :
576 : /************************************************************************/
577 : /* SerializeToXML() */
578 : /************************************************************************/
579 :
580 0 : CPLXMLNode *VRTKernelFilteredSource::SerializeToXML( const char *pszVRTPath )
581 :
582 : {
583 0 : CPLXMLNode *psSrc = VRTFilteredSource::SerializeToXML( pszVRTPath );
584 : CPLXMLNode *psKernel;
585 : char *pszKernelCoefs;
586 0 : int iCoef, nCoefCount = nKernelSize * nKernelSize;
587 :
588 0 : if( psSrc == NULL )
589 0 : return NULL;
590 :
591 0 : CPLFree( psSrc->pszValue );
592 0 : psSrc->pszValue = CPLStrdup("KernelFilteredSource" );
593 :
594 0 : if( nKernelSize == 0 )
595 0 : return psSrc;
596 :
597 0 : psKernel = CPLCreateXMLNode( psSrc, CXT_Element, "Kernel" );
598 :
599 0 : if( bNormalized )
600 : CPLCreateXMLNode(
601 : CPLCreateXMLNode( psKernel, CXT_Attribute, "normalized" ),
602 0 : CXT_Text, "1" );
603 : else
604 : CPLCreateXMLNode(
605 : CPLCreateXMLNode( psKernel, CXT_Attribute, "normalized" ),
606 0 : CXT_Text, "0" );
607 :
608 0 : pszKernelCoefs = (char *) CPLMalloc(nCoefCount * 32);
609 :
610 0 : strcpy( pszKernelCoefs, "" );
611 0 : for( iCoef = 0; iCoef < nCoefCount; iCoef++ )
612 : sprintf( pszKernelCoefs + strlen(pszKernelCoefs),
613 0 : "%.8g ", padfKernelCoefs[iCoef] );
614 :
615 0 : CPLSetXMLValue( psKernel, "Size", CPLSPrintf( "%d", nKernelSize ) );
616 0 : CPLSetXMLValue( psKernel, "Coefs", pszKernelCoefs );
617 :
618 0 : CPLFree( pszKernelCoefs );
619 :
620 0 : return psSrc;
621 : }
622 :
623 : /************************************************************************/
624 : /* VRTParseFilterSources() */
625 : /************************************************************************/
626 :
627 5 : VRTSource *VRTParseFilterSources( CPLXMLNode *psChild, const char *pszVRTPath )
628 :
629 : {
630 : VRTSource *poSrc;
631 :
632 5 : if( EQUAL(psChild->pszValue,"KernelFilteredSource") )
633 : {
634 5 : poSrc = new VRTKernelFilteredSource();
635 5 : if( poSrc->XMLInit( psChild, pszVRTPath ) == CE_None )
636 5 : return poSrc;
637 : else
638 0 : delete poSrc;
639 : }
640 :
641 0 : return NULL;
642 : }
643 :
|