1 //*******************************************************************
2 // Copyright (C) 2000 ImageLinks Inc.
3 //
4 // License:  LGPL
5 //
6 // See LICENSE.txt file in the top level directory for more details.
7 //
8 // Author: Garrett Potts
9 //
10 //*************************************************************************
11 // $Id: ossimScaleFilter.cpp 21631 2012-09-06 18:10:55Z dburken $
12 #include <ossim/imaging/ossimScaleFilter.h>
13 #include <ossim/imaging/ossimFilter.h>
14 #include <ossim/imaging/ossimImageGeometry.h>
15 #include <ossim/imaging/ossimDiscreteConvolutionKernel.h>
16 #include <ossim/imaging/ossimImageDataFactory.h>
17 #include <ossim/projection/ossimProjectionFactoryRegistry.h>
18 #include <ossim/projection/ossimMapProjection.h>
19 #include <ossim/base/ossimKeywordNames.h>
20 
21 using namespace std;
22 
23 RTTI_DEF1(ossimScaleFilter, "ossimScaleFilter", ossimImageSourceFilter);
24 
25 //**************************************************************************************************
ossimScaleFilter()26 ossimScaleFilter::ossimScaleFilter()
27    :ossimImageSourceFilter(),
28     m_BlankTile(NULL),
29     m_Tile(NULL),
30     m_MinifyFilter(NULL),
31     m_MagnifyFilter(NULL),
32     m_MinifyFilterType(ossimScaleFilter_NEAREST_NEIGHBOR),
33     m_MagnifyFilterType(ossimScaleFilter_NEAREST_NEIGHBOR),
34     m_ScaleFactor(1.0, 1.0),
35     m_InverseScaleFactor(1.0, 1.0),
36     m_TileSize(64, 64),
37     m_BlurFactor(1.0)
38 {
39    m_InputRect.makeNan();
40    m_MinifyFilter  = new ossimNearestNeighborFilter();
41    m_MagnifyFilter = new ossimNearestNeighborFilter();
42 }
43 
44 //**************************************************************************************************
ossimScaleFilter(ossimImageSource * inputSource,const ossimDpt & scaleFactor)45 ossimScaleFilter::ossimScaleFilter(ossimImageSource* inputSource,
46                                    const ossimDpt& scaleFactor)
47    :ossimImageSourceFilter(inputSource),
48     m_BlankTile(NULL),
49     m_Tile(NULL),
50     m_MinifyFilter(NULL),
51     m_MagnifyFilter(NULL),
52     m_MinifyFilterType(ossimScaleFilter_NEAREST_NEIGHBOR),
53     m_MagnifyFilterType(ossimScaleFilter_NEAREST_NEIGHBOR),
54     m_ScaleFactor(scaleFactor),
55     m_TileSize(64, 64),
56     m_BlurFactor(1.0)
57 {
58    m_InputRect.makeNan();
59    m_MinifyFilter  = new ossimNearestNeighborFilter();
60    m_MagnifyFilter = new ossimNearestNeighborFilter();
61 }
62 
63 //**************************************************************************************************
~ossimScaleFilter()64 ossimScaleFilter::~ossimScaleFilter()
65 {
66    if(m_MinifyFilter)
67    {
68       delete m_MinifyFilter;
69       m_MinifyFilter = NULL;
70    }
71 
72    if(m_MagnifyFilter)
73    {
74       delete m_MagnifyFilter;
75       m_MagnifyFilter = NULL;
76    }
77 }
78 
79 //**************************************************************************************************
getTile(const ossimIrect & tileRect,ossim_uint32 resLevel)80 ossimRefPtr<ossimImageData> ossimScaleFilter::getTile(
81    const ossimIrect& tileRect, ossim_uint32 resLevel)
82 {
83 
84    if((!isSourceEnabled())||
85       (!theInputConnection)||
86       ((m_ScaleFactor.x == 1.0)&&
87        (m_ScaleFactor.y == 1.0)&&
88        (m_BlurFactor == 1.0)))
89    {
90       return ossimImageSourceFilter::getTile(tileRect, resLevel);
91    }
92    if(!m_Tile.valid())
93    {
94       allocate();
95    }
96 
97    if(!m_Tile)
98    {
99       return ossimImageSourceFilter::getTile(tileRect, resLevel);
100    }
101 
102    m_Tile->makeBlank();
103 
104 
105    ossimIrect imageRect = tileRect*m_InverseScaleFactor;
106 
107    m_Tile->setImageRectangle(tileRect);
108    m_BlankTile->setImageRectangle(tileRect);
109 
110 
111    double xSupport;
112    double ySupport;
113 
114    getSupport(xSupport, ySupport);
115 
116    ossimIpt deltaPt;
117    deltaPt.x = (ossim_int32)ceil(xSupport);
118    deltaPt.y = (ossim_int32)ceil(ySupport);
119 
120    imageRect = ossimIrect(imageRect.ul().x - (deltaPt.x),
121                           imageRect.ul().y - (deltaPt.y),
122                           imageRect.lr().x + (deltaPt.x),
123                           imageRect.lr().y + (deltaPt.y));
124 
125 
126    runFilter(imageRect, tileRect);
127 
128    m_Tile->validate();
129 
130    return m_Tile;
131 }
132 
133 //**************************************************************************************************
runFilter(const ossimIrect & imageRect,const ossimIrect & viewRect)134 void ossimScaleFilter::runFilter(const ossimIrect& imageRect,
135                                  const ossimIrect& viewRect)
136 {
137    switch(m_Tile->getScalarType())
138    {
139       case OSSIM_UINT8:
140       {
141          runFilterTemplate((ossim_uint8)0,
142                            imageRect,
143                            viewRect);
144          break;
145       }
146       case OSSIM_USHORT11:
147       case OSSIM_USHORT12:
148       case OSSIM_USHORT13:
149       case OSSIM_USHORT14:
150       case OSSIM_USHORT15:
151       case OSSIM_UINT16:
152       {
153          runFilterTemplate((ossim_uint16)0,
154                            imageRect,
155                            viewRect);
156          break;
157       }
158       case OSSIM_SINT16:
159       {
160          runFilterTemplate((ossim_sint16)0,
161                            imageRect,
162                            viewRect);
163          break;
164       }
165       case OSSIM_UINT32:
166       {
167          runFilterTemplate((ossim_uint32)0,
168                            imageRect,
169                            viewRect);
170          break;
171       }
172       case OSSIM_DOUBLE:
173       case OSSIM_NORMALIZED_DOUBLE:
174       {
175          runFilterTemplate((ossim_float64)0,
176                            imageRect,
177                            viewRect);
178          break;
179       }
180       case OSSIM_FLOAT:
181       case OSSIM_NORMALIZED_FLOAT:
182       {
183          runFilterTemplate((ossim_float32)0,
184                            imageRect,
185                            viewRect);
186          break;
187       }
188       default:
189          break;
190    }
191 }
192 
193 //**************************************************************************************************
194 template <class T>
runFilterTemplate(T dummy,const ossimIrect & imageRect,const ossimIrect & viewRect)195 void ossimScaleFilter::runFilterTemplate(T dummy,
196                                          const ossimIrect& imageRect,
197                                          const ossimIrect& viewRect)
198 {
199    ossimRefPtr<ossimImageData> inputData =
200       theInputConnection->getTile(imageRect);
201 
202    if(!inputData.valid()   ||
203       !inputData->getBuf() ||
204       (inputData->getDataObjectStatus() == OSSIM_EMPTY))
205    {
206       return;
207    }
208 
209    ossim_int32 h = imageRect.height();
210    ossimRefPtr<ossimImageData> tempData =
211       ossimImageDataFactory::instance()->create(NULL,
212                                                 inputData->getScalarType(),
213                                                 inputData->getNumberOfBands(),
214                                                 viewRect.width(),
215                                                 h);
216    tempData->setOrigin(ossimIpt(viewRect.ul().x,
217                                 imageRect.ul().y));
218 
219    tempData->initialize();
220 
221    if((m_ScaleFactor.x != 1.0)||
222       (m_BlurFactor != 1.0))
223    {
224       runHorizontalFilterTemplate(dummy,
225                                   inputData,
226                                   tempData);
227       tempData->validate();
228    }
229    else
230    {
231       tempData->loadTile(inputData.get());
232    }
233 
234    if((m_ScaleFactor.y != 1.0)||
235       (m_BlurFactor != 1.0))
236    {
237       runVerticalFilterTemplate(dummy,
238                                 tempData,
239                                 m_Tile);
240    }
241    else
242    {
243       m_Tile->loadTile(tempData.get());
244    }
245 
246    m_Tile->validate();
247 }
248 
249 //**************************************************************************************************
getBoundingRect(ossim_uint32 resLevel) const250 ossimIrect ossimScaleFilter::getBoundingRect(ossim_uint32 resLevel)const
251 {
252    ossimIrect result = ossimImageSourceFilter::getBoundingRect(resLevel);
253 
254    if(!result.hasNans())
255    {
256       result *= m_ScaleFactor;
257    }
258 
259    return result;
260 }
261 
262 //**************************************************************************************************
setFilterType(ossimScaleFilterType filterType)263 void ossimScaleFilter::setFilterType(ossimScaleFilterType filterType)
264 {
265    setFilterType(filterType, filterType);
266 }
267 
268 
269 //**************************************************************************************************
setFilterType(ossimScaleFilterType minifyFilterType,ossimScaleFilterType magnifyFilterType)270 void ossimScaleFilter::setFilterType(ossimScaleFilterType minifyFilterType,
271                                      ossimScaleFilterType magnifyFilterType)
272 {
273    if(m_MinifyFilter)
274    {
275       delete m_MinifyFilter;
276       m_MinifyFilter = NULL;
277    }
278    if(m_MagnifyFilter)
279    {
280       delete m_MagnifyFilter;
281       m_MagnifyFilter = NULL;
282    }
283 
284    m_MinifyFilterType  = minifyFilterType;
285    m_MagnifyFilterType = magnifyFilterType;
286 
287    m_MinifyFilter  = createNewFilter(minifyFilterType, m_MinifyFilterType);
288    m_MagnifyFilter = createNewFilter(magnifyFilterType, m_MagnifyFilterType);
289 }
290 
291 //**************************************************************************************************
createNewFilter(ossimScaleFilterType filterType,ossimScaleFilterType & result)292 ossimFilter* ossimScaleFilter::createNewFilter(ossimScaleFilterType filterType,
293                                                ossimScaleFilterType& result)
294 {
295    switch(filterType)
296    {
297    case ossimScaleFilter_NEAREST_NEIGHBOR:
298    {
299       return new ossimNearestNeighborFilter();
300    }
301    case ossimScaleFilter_BOX:
302    {
303       return new ossimBoxFilter();
304    }
305    case ossimScaleFilter_GAUSSIAN:
306    {
307       return new ossimGaussianFilter();
308    }
309    case ossimScaleFilter_CUBIC:
310    {
311       return new ossimCubicFilter();
312    }
313    case ossimScaleFilter_HANNING:
314    {
315       return new ossimHanningFilter();
316    }
317    case ossimScaleFilter_HAMMING:
318    {
319       return new ossimHammingFilter();
320    }
321    case ossimScaleFilter_LANCZOS:
322    {
323       return new ossimLanczosFilter();
324    }
325    case ossimScaleFilter_CATROM:
326    {
327       return new ossimCatromFilter();
328    }
329    case ossimScaleFilter_MITCHELL:
330    {
331       return new ossimMitchellFilter();
332    }
333    case ossimScaleFilter_BLACKMAN:
334    {
335       return new ossimBlackmanFilter();
336    }
337    case ossimScaleFilter_BLACKMAN_SINC:
338    {
339       return new ossimBlackmanSincFilter();
340    }
341    case ossimScaleFilter_BLACKMAN_BESSEL:
342    {
343       return new ossimBlackmanBesselFilter();
344    }
345    case ossimScaleFilter_QUADRATIC:
346    {
347       return new ossimQuadraticFilter();
348    }
349    case ossimScaleFilter_TRIANGLE:
350    {
351       return new ossimTriangleFilter();
352    }
353    case ossimScaleFilter_HERMITE:
354    {
355       return new ossimHermiteFilter();
356    }
357 
358    }
359 
360    result = ossimScaleFilter_NEAREST_NEIGHBOR;
361    return new ossimNearestNeighborFilter();
362 }
363 
364 //**************************************************************************************************
setScaleFactor(const ossimDpt & scale)365 void ossimScaleFilter::setScaleFactor(const ossimDpt& scale)
366 {
367    m_ScaleFactor = scale;
368    if(fabs(m_ScaleFactor.x) <= FLT_EPSILON)
369    {
370       m_ScaleFactor.x = 1.0;
371    }
372    if(fabs(m_ScaleFactor.y) <= FLT_EPSILON)
373    {
374       m_ScaleFactor.y = 1.0;
375    }
376 
377    m_InverseScaleFactor.x = 1.0/m_ScaleFactor.x;
378    m_InverseScaleFactor.y = 1.0/m_ScaleFactor.y;
379 
380    // A change in the scale factor implies a change to the image geometry. If one has been created
381    // it needs to be modified:
382    updateGeometry();
383 }
384 
385 
386 //**************************************************************************************************
runHorizontalFilterTemplate(T,const ossimRefPtr<ossimImageData> & input,ossimRefPtr<ossimImageData> & output)387 template <class T> void ossimScaleFilter::runHorizontalFilterTemplate(
388    T /* dummy */,
389    const ossimRefPtr<ossimImageData>& input,
390    ossimRefPtr<ossimImageData>& output)
391 {
392    ossimIrect viewRect  = output->getImageRectangle();
393    ossimIrect imageRect = input->getImageRectangle();
394    ossim_int32 vw = viewRect.width();
395    ossim_int32 vh = viewRect.height();
396    ossim_int32 iw = imageRect.width();
397    ossimIpt origin(viewRect.ul());
398    ossimIpt imageOrigin(imageRect.ul());
399    ossimIpt inputUl = m_InputRect.ul();
400    ossimIpt inputLr = m_InputRect.lr();
401 
402    double scale = 0.0;
403    double support = 0.0;
404    ossim_int32 x = 0;
405    ossim_int32 y = 0;
406    ossim_int32 start = 0;
407    ossim_int32 stop  = 0;
408    ossim_int32 kernelIdx = 0;
409    const ossimFilter* filter = getHorizontalFilter();
410    ossim_float64 center = 0.0;
411    ossim_int32 bandIdx = 0;
412    ossim_int32 numberOfBands = m_Tile->getNumberOfBands();
413 
414    scale = m_BlurFactor*ossim::max(1.0/m_ScaleFactor.x, 1.0);
415 
416    support=scale*filter->getSupport();
417    if (support <= 0.5)
418    {
419       support = 0.5 + FLT_EPSILON;
420       scale = 1.0;
421    }
422    scale=1.0/scale;
423    for(bandIdx = 0; bandIdx < numberOfBands; ++bandIdx)
424    {
425       T* imageBuf = (T*)input->getBuf(bandIdx);
426       T* viewBuf  = (T*)output->getBuf(bandIdx);
427       T np        = (T)input->getNullPix(bandIdx);
428       T outNp     = (T)output->getNullPix(bandIdx);
429       T outMinPix = (T)output->getMinPix(bandIdx);
430       T outMaxPix = (T)output->getMaxPix(bandIdx);
431 
432       for(x = 0; x < vw; ++x)
433       {
434          center=(origin.x + x+ .5)/m_ScaleFactor.x;
435          start=ossim::max((ossim_int32)ossim::round<int>(center-support), (ossim_int32)inputUl.x);
436          stop=ossim::min((ossim_int32)ossim::round<int>(center+support), (ossim_int32)inputLr.x);
437          ossim_int32 delta = stop-start;
438          if (delta <= 0)
439          {
440             break;
441          }
442          vector<double> kernel(delta);
443          double density=0.0;
444 
445          for(kernelIdx = 0; kernelIdx < delta; ++kernelIdx)
446          {
447             double t = scale*(start + kernelIdx -
448                               center + .5);
449             kernel[kernelIdx] = filter->filter(t,
450                                                filter->getSupport());
451             density += kernel[kernelIdx];
452          }
453          if ((density != 0.0) && (density != 1.0))
454          {
455             /*
456               Normalize.
457             */
458             density=1.0/density;
459             for (kernelIdx=0; kernelIdx < delta; kernelIdx++)
460                kernel[kernelIdx]*=density;
461          }
462          ossim_int32 offset       = start  - imageOrigin.x;
463 
464          T* xptr         = imageBuf + offset;
465          T* xCenterptr   = imageBuf + offset;
466          T* outptr       = viewBuf  + x;
467 
468          for(y = 0; y < vh; ++y)
469          {
470             double result = 0.0;
471             density = 0.0;
472             if((*xCenterptr) == np)
473             {
474                *outptr = outNp;
475             }
476             else
477             {
478                for(kernelIdx = 0; kernelIdx < (int)kernel.size(); ++kernelIdx)
479                {
480                   if((*xptr != np)&&
481                      (kernel[kernelIdx] != 0.0))
482                   {
483                      result  += ((double)(*(xptr+kernelIdx))*kernel[kernelIdx]);
484                      density += kernel[kernelIdx];
485                   }
486                }
487                if(density != 0.0)
488                {
489                   result /= density;
490 
491                   if(result < outMinPix) result = outMinPix;
492                   if(result > outMaxPix) result = outMaxPix;
493 
494                   *outptr = (T)result;
495                }
496                else
497                {
498                   *outptr = outNp;
499                }
500             }
501             xCenterptr += iw;
502             xptr   += iw;
503             outptr += vw;
504          }
505       }
506    }
507 }
508 
509 //**************************************************************************************************
runVerticalFilterTemplate(T,const ossimRefPtr<ossimImageData> & input,ossimRefPtr<ossimImageData> & output)510 template <class T> void ossimScaleFilter::runVerticalFilterTemplate(
511    T /* dummy */,
512    const ossimRefPtr<ossimImageData>& input,
513    ossimRefPtr<ossimImageData>& output)
514 {
515    ossimIrect viewRect  = output->getImageRectangle();
516    ossimIrect imageRect = input->getImageRectangle();
517    ossim_int32 vw = viewRect.width();
518    ossim_int32 vh = viewRect.height();
519    ossim_int32 iw = imageRect.width();
520    ossimIpt origin(viewRect.ul());
521    ossimIpt imageOrigin(imageRect.ul());
522    ossimIpt inputUl = m_InputRect.ul();
523    ossimIpt inputLr = m_InputRect.lr();
524    double scale = 0.0;
525    double support = 0.0;
526    ossim_int32 x = 0;
527    ossim_int32 y = 0;
528    ossim_int32 start = 0;
529    ossim_int32 stop  = 0;
530    ossim_int32 kernelIdx = 0;
531    const ossimFilter* filter = getVerticalFilter();
532    ossim_float64 center = 0.0;
533    ossim_int32 bandIdx = 0;
534    ossim_int32 numberOfBands = m_Tile->getNumberOfBands();
535 
536    scale = m_BlurFactor*ossim::max(1.0/m_ScaleFactor.y, 1.0);
537 
538    support=scale*filter->getSupport();
539    if (support <= 0.5)
540    {
541       support = .5 + FLT_EPSILON;
542       scale = 1.0;
543    }
544    scale=1.0/scale;
545 
546    for(bandIdx = 0; bandIdx < numberOfBands; ++bandIdx)
547    {
548       T* imageBuf = (T*)input->getBuf(bandIdx);
549       T* viewBuf  = (T*)output->getBuf(bandIdx);
550       T np        = (T)input->getNullPix(bandIdx);
551       T outNp     = (T)output->getNullPix(bandIdx);
552       T outMinPix = (T)output->getMinPix(bandIdx);
553       T outMaxPix = (T)output->getMaxPix(bandIdx);
554 
555       for(y = 0; y < vh; ++y)
556       {
557          center=(double) ((y + origin.y+0.5)/m_ScaleFactor.y);
558          start=ossim::max((ossim_int32)ossim::round<int>(center-support), (ossim_int32)inputUl.y);
559          stop=ossim::min((ossim_int32)ossim::round<int>(center+support), (ossim_int32)inputLr.y);
560          ossim_int32 delta = stop-start;
561          if (delta <= 0)
562          {
563             break;
564          }
565          vector<double> kernel(delta);
566          double density = 0.0;
567          for(kernelIdx = 0; kernelIdx < delta; ++kernelIdx)
568          {
569             kernel[kernelIdx] = filter->filter(scale*(start + kernelIdx - center + .5),
570                                                filter->getSupport());
571             density += kernel[kernelIdx];
572          }
573          if ((density != 0.0) && (density != 1.0))
574          {
575             /*
576               Normalize.
577             */
578             density=1.0/density;
579             for (kernelIdx=0; kernelIdx < delta; kernelIdx++)
580                kernel[kernelIdx]*=density;
581          }
582 
583          ossim_int32 offset       = ((start  - imageOrigin.y)*iw);
584          ossim_int32 offsetCenter = ((((ossim_int32)center) - imageOrigin.y)*iw);
585 
586          for(x = 0; x < vw; ++x)
587          {
588             T* yptr         = imageBuf + offset       + x;
589             T* yCenterptr   = imageBuf + offsetCenter + x;
590             double result = 0.0;
591             density = 0.0;
592 
593             if((*yCenterptr) == np)
594             {
595                *viewBuf = outNp;
596             }
597             else
598             {
599                for(kernelIdx = 0; kernelIdx < delta; ++kernelIdx)
600                {
601                   if((*yptr != np)&&
602                      (kernel[kernelIdx] != 0.0))
603                   {
604                      result  += ((*yptr)*kernel[kernelIdx]);
605                      density += kernel[kernelIdx];
606                   }
607                   yptr += iw;
608                }
609                if(density != 0.0)
610                {
611                   result /= density;
612 
613                   if(result < outMinPix) result = outMinPix;
614                   if(result > outMaxPix) result = outMaxPix;
615 
616                   *viewBuf = (T)result;
617                }
618                else
619                {
620                   *viewBuf = outNp;
621                }
622             }
623             ++viewBuf;
624          }
625       }
626    }
627 }
628 
629 //**************************************************************************************************
initialize()630 void ossimScaleFilter::initialize()
631 {
632    ossimImageSourceFilter::initialize();
633 
634    // Force an allocate next getTile.
635    m_Tile = NULL;
636    m_BlankTile = NULL;
637    m_InputRect.makeNan();
638 }
639 
640 //**************************************************************************************************
allocate()641 void ossimScaleFilter::allocate()
642 {
643    m_Tile      = NULL;
644    m_BlankTile = NULL;
645    m_InputRect.makeNan();
646 
647    if(theInputConnection&&isSourceEnabled())
648    {
649       m_Tile      = ossimImageDataFactory::instance()->create(this, this);
650       m_BlankTile = ossimImageDataFactory::instance()->create(this, this);
651 
652       m_Tile->initialize();
653 
654       m_InputRect = theInputConnection->getBoundingRect();
655    }
656 }
657 
658 //**************************************************************************************************
659 // Returns a pointer reference to the active image geometry at this filter. The input source
660 // geometry is modified, so we need to maintain our own geometry object as a data member.
661 //**************************************************************************************************
getImageGeometry()662 ossimRefPtr<ossimImageGeometry> ossimScaleFilter::getImageGeometry()
663 {
664    // Have we already defined our own geometry? Return it if so:
665    if (m_ScaledGeometry.valid()) return m_ScaledGeometry;
666 
667    // Otherwise we'll need to establish a geometry based on the input connection:
668    if(theInputConnection)
669    {
670       // Fetch the map projection of the input image if it exists:
671       ossimRefPtr<ossimImageGeometry> inputGeom = theInputConnection->getImageGeometry();
672 
673       // If trivial case of identity scale, just pass along the input connection's geometry:
674       if ((m_ScaleFactor.x == 1.0) && (m_ScaleFactor.y == 1.0))
675          return inputGeom;
676 
677       // Need to create a copy of the input geom and modify it as our own, then pass that:
678       if ( inputGeom.valid() )
679       {
680          m_ScaledGeometry = new ossimImageGeometry(*inputGeom);
681          updateGeometry();
682 
683          // Return the modified geometry:
684          return m_ScaledGeometry;
685       }
686    }
687 
688    // No geometry defined, return NULL pointer:
689    return ossimRefPtr<ossimImageGeometry>();
690 }
691 
692 //**************************************************************************************************
scaleRect(const ossimIrect input,const ossimDpt & scaleFactor) const693 ossimIrect ossimScaleFilter::scaleRect(const ossimIrect input,
694                                        const ossimDpt& scaleFactor)const
695 {
696    ossimIpt origin(ossim::round<int>(input.ul().x*scaleFactor.x),
697                    ossim::round<int>(input.ul().y*scaleFactor.y));
698    ossim_int32 w = ossim::round<int>(input.width()*scaleFactor.x);
699    ossim_int32 h = ossim::round<int>(input.height()*scaleFactor.y);
700 
701    if(w < 1) w = 1;
702    if(h < 1) h = 1;
703 
704    return ossimIrect(origin.x,
705                      origin.y,
706                      origin.x + (w-1),
707                      origin.y + (h-1));
708 }
709 
710 //**************************************************************************************************
getFilterTypeAsString(ossimScaleFilterType type) const711 ossimString ossimScaleFilter::getFilterTypeAsString(ossimScaleFilterType type)const
712 {
713    switch(type)
714    {
715    case ossimScaleFilter_NEAREST_NEIGHBOR:
716    {
717       return "nearest_neighbor";
718    }
719    case ossimScaleFilter_BOX:
720    {
721       return "box";
722    }
723    case ossimScaleFilter_GAUSSIAN:
724    {
725       return "gaussian";
726    }
727    case ossimScaleFilter_CUBIC:
728    {
729       return "cubic";
730    }
731    case ossimScaleFilter_HANNING:
732    {
733       return "hanning";
734    }
735    case ossimScaleFilter_HAMMING:
736    {
737       return "hamming";
738    }
739    case ossimScaleFilter_LANCZOS:
740    {
741       return "lanczos";
742    }
743    case ossimScaleFilter_MITCHELL:
744    {
745       return "mitchell";
746    }
747    case ossimScaleFilter_CATROM:
748    {
749       return "catrom";
750    }
751    case ossimScaleFilter_BLACKMAN:
752    {
753       return "blackman";
754    }
755    case ossimScaleFilter_BLACKMAN_SINC:
756    {
757       return "blackman_sinc";
758    }
759    case ossimScaleFilter_BLACKMAN_BESSEL:
760    {
761       return "blackman_bessel";
762    }
763    case ossimScaleFilter_QUADRATIC:
764    {
765       return "quadratic";
766    }
767    case ossimScaleFilter_TRIANGLE:
768    {
769       return "triangle";
770    }
771    case ossimScaleFilter_HERMITE:
772    {
773       return "hermite";
774    }
775    }
776 
777    return "nearest_neighbor";
778 }
779 
780 //**************************************************************************************************
getFilterType(const ossimString & type) const781 ossimScaleFilter::ossimScaleFilterType ossimScaleFilter::getFilterType(const ossimString& type)const
782 {
783    ossimString typeUpper = type;
784    typeUpper = typeUpper.upcase();
785 
786    if(typeUpper.contains("BOX"))
787    {
788       return ossimScaleFilter_BOX;
789    }
790    else if(typeUpper.contains("NEAREST_NEIGHBOR"))
791    {
792       return ossimScaleFilter_NEAREST_NEIGHBOR;
793    }
794    else if(typeUpper.contains("GAUSSIAN"))
795    {
796       return ossimScaleFilter_GAUSSIAN;
797    }
798    else if(typeUpper.contains("HANNING"))
799    {
800       return ossimScaleFilter_HANNING;
801    }
802    else if(typeUpper.contains("HAMMING"))
803    {
804       return ossimScaleFilter_HAMMING;
805    }
806    else if(typeUpper.contains("LANCZOS"))
807    {
808       return ossimScaleFilter_LANCZOS;
809    }
810    else if(typeUpper.contains("MITCHELL"))
811    {
812       return ossimScaleFilter_MITCHELL;
813    }
814    else if(typeUpper.contains("CATROM"))
815    {
816       return ossimScaleFilter_CATROM;
817    }
818    else if(typeUpper.contains("CUBIC"))
819    {
820       return ossimScaleFilter_CUBIC;
821    }
822    else if(typeUpper.contains("BLACKMAN_BESSEL"))
823    {
824       return ossimScaleFilter_BLACKMAN_BESSEL;
825    }
826    else if(typeUpper.contains("BLACKMAN_SINC"))
827    {
828       return ossimScaleFilter_BLACKMAN_SINC;
829    }
830    else if(typeUpper.contains("BLACKMAN"))
831    {
832       return ossimScaleFilter_BLACKMAN;
833    }
834    else if(typeUpper.contains("QUADRATIC"))
835    {
836       return ossimScaleFilter_QUADRATIC;
837    }
838    else if(typeUpper.contains("TRIANGLE"))
839    {
840       return ossimScaleFilter_TRIANGLE;
841    }
842    else if(typeUpper.contains("HERMITE"))
843    {
844       return ossimScaleFilter_HERMITE;
845    }
846 
847    return ossimScaleFilter_NEAREST_NEIGHBOR;
848 }
849 
850 //**************************************************************************************************
getSupport(double & x,double & y)851 void ossimScaleFilter::getSupport(double& x, double& y)
852 {
853    const ossimFilter* horizontalFilter = getHorizontalFilter();
854    const ossimFilter* verticalFilter   = getVerticalFilter();
855 
856    x = m_BlurFactor*ossim::max(1.0/m_ScaleFactor.x, 1.0)*
857        horizontalFilter->getSupport();
858    y = m_BlurFactor*ossim::max(1.0/m_ScaleFactor.y, 1.0)*
859        verticalFilter->getSupport();
860 }
861 
862 //**************************************************************************************************
getHorizontalFilter() const863 const ossimFilter* ossimScaleFilter::getHorizontalFilter()const
864 {
865    if(m_ScaleFactor.x < 1)
866    {
867       return m_MinifyFilter;
868    }
869 
870    return m_MagnifyFilter;
871 }
872 
873 //**************************************************************************************************
getVerticalFilter() const874 const ossimFilter* ossimScaleFilter::getVerticalFilter()const
875 {
876    if(m_ScaleFactor.y < 1)
877    {
878       return m_MinifyFilter;
879    }
880 
881    return m_MagnifyFilter;
882 }
883 
884 
885 
886 //**************************************************************************************************
saveState(ossimKeywordlist & kwl,const char * prefix) const887 bool ossimScaleFilter::saveState(ossimKeywordlist& kwl, const char* prefix)const
888 {
889    kwl.add(prefix,
890            ossimKeywordNames::SCALE_X_KW,
891            m_ScaleFactor.x,
892            true);
893    kwl.add(prefix,
894            ossimKeywordNames::SCALE_Y_KW,
895            m_ScaleFactor.y,
896            true);
897    kwl.add(prefix,
898            "minify_type",
899            getFilterTypeAsString(m_MinifyFilterType),
900            true);
901    kwl.add(prefix,
902            "magnify_type",
903            getFilterTypeAsString(m_MagnifyFilterType),
904            true);
905 
906    return ossimImageSourceFilter::saveState(kwl, prefix);
907 }
908 
909 //**************************************************************************************************
loadState(const ossimKeywordlist & kwl,const char * prefix)910 bool ossimScaleFilter::loadState(const ossimKeywordlist& kwl,
911                                  const char* prefix)
912 {
913    ossimString scalex  = kwl.find(prefix,
914                                  ossimKeywordNames::SCALE_X_KW);
915    ossimString scaley  = kwl.find(prefix,
916                                   ossimKeywordNames::SCALE_Y_KW);
917    ossimString minify  = kwl.find(prefix,
918                                   "minify_type");
919    ossimString magnify = kwl.find(prefix,
920                                   "magnify_type");
921 
922    m_ScaleFactor.x = scalex.toDouble();
923    m_ScaleFactor.y = scaley.toDouble();
924 
925    if(fabs(m_ScaleFactor.x) <= FLT_EPSILON)
926    {
927       m_ScaleFactor.x = 1.0;
928    }
929    if(fabs(m_ScaleFactor.y) <= FLT_EPSILON)
930    {
931       m_ScaleFactor.y = 1.0;
932    }
933 
934    m_InverseScaleFactor.x = 1.0/m_ScaleFactor.x;
935    m_InverseScaleFactor.y = 1.0/m_ScaleFactor.y;
936 
937    setFilterType(getFilterType(minify),
938                  getFilterType(magnify));
939 
940    // A change in the scale factor implies a change to the image geometry. If one has been created
941    // it needs to be modified:
942    updateGeometry();
943 
944    return ossimImageSourceFilter::loadState(kwl, prefix);
945 }
946 
947 //**************************************************************************************************
948 //! If this object is maintaining an ossimImageGeometry, this method needs to be called after
949 //! a scale change so that the geometry's projection is modified accordingly.
950 //**************************************************************************************************
updateGeometry()951 void ossimScaleFilter::updateGeometry()
952 {
953    if (m_ScaledGeometry.valid())
954    {
955       // Modify the image geometry's projection with the scale factor before returning geom:
956       ossimProjection* proj = m_ScaledGeometry->getProjection();
957       ossimMapProjection* mapProj = PTR_CAST(ossimMapProjection, proj);
958       if(mapProj)
959          mapProj->applyScale(m_InverseScaleFactor, true);
960    }
961 }
962