text: /*=========================================================================
  
    Program:   Visualization Toolkit
    Module:    vtkImageSpatialAlgorithm.cxx
  
    Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
    All rights reserved.
    See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
  
       This software is distributed WITHOUT ANY WARRANTY; without even
       the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
       PURPOSE.  See the above copyright notice for more information.
  
  =========================================================================*/
  #include "vtkImageSpatialAlgorithm.h"
  
  #include "vtkDataArray.h"
  #include "vtkImageData.h"
  #include "vtkInformation.h"
  #include "vtkInformationVector.h"
  #include "vtkObjectFactory.h"
  #include "vtkPointData.h"
  #include "vtkStreamingDemandDrivenPipeline.h"
  
  #include <math.h>
  
  vtkCxxRevisionMacro(vtkImageSpatialAlgorithm, "1.3");
  vtkStandardNewMacro(vtkImageSpatialAlgorithm);
  
  //----------------------------------------------------------------------------
  // Construct an instance of vtkImageSpatialAlgorithm fitler.
  vtkImageSpatialAlgorithm::vtkImageSpatialAlgorithm()
  {
    this->KernelSize[0] = this->KernelSize[1] = this->KernelSize[2] = 1;
    this->KernelMiddle[0] = this->KernelMiddle[1] = this->KernelMiddle[2] = 0;
    this->HandleBoundaries = 1;
  }
  
  
  //----------------------------------------------------------------------------
  void vtkImageSpatialAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
  {  
    this->Superclass::PrintSelf(os, indent);
    
    int idx;
  
    os << indent << "KernelSize: (" << this->KernelSize[0];
    for (idx = 1; idx < 3; ++idx)
      {
      os << ", " << this->KernelSize[idx];
      }
    os << ").\n";
  
    os << indent << "KernelMiddle: (" << this->KernelMiddle[0];
    for (idx = 1; idx < 3; ++idx)
      {
      os << ", " << this->KernelMiddle[idx];
      }
    os << ").\n";
  
  }
  
  //----------------------------------------------------------------------------
  int vtkImageSpatialAlgorithm::RequestInformation (
    vtkInformation *vtkNotUsed(request),
    vtkInformationVector **inputVector,
    vtkInformationVector *outputVector)
  {
    vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
    vtkInformation *outInfo = outputVector->GetInformationObject(0);
    
    // Take this opportunity to override the defaults. 
    int extent[6];
    inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
    this->ComputeOutputWholeExtent(extent, this->HandleBoundaries);
    outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent, 6);
  
    return 1;
  }
  
  //----------------------------------------------------------------------------
  // A helper method to compute output image extent
  void vtkImageSpatialAlgorithm::ComputeOutputWholeExtent(int extent[6], 
                                                          int handleBoundaries)
  {
    int idx;
  
    if ( ! handleBoundaries)
      {
      // Make extent a little smaller because of the kernel size.
      for (idx = 0; idx < 3; ++idx)
        {
        extent[idx*2] += this->KernelMiddle[idx];
        extent[idx*2+1] -= (this->KernelSize[idx]-1) - this->KernelMiddle[idx];
        }
      }
    
  }
  
  //----------------------------------------------------------------------------
  // This method computes the extent of the input region necessary to generate
  // an output region.  Before this method is called "region" should have the 
  // extent of the output region.  After this method finishes, "region" should 
  // have the extent of the required input region.
  int vtkImageSpatialAlgorithm::RequestUpdateExtent(
    vtkInformation *vtkNotUsed(request),
    vtkInformationVector **inputVector,
    vtkInformationVector *outputVector)
  {
    int wholeExtent[6], extent[6], inExtent[6];
    
    vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
    vtkInformation *outInfo = outputVector->GetInformationObject(0);
  
    inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), wholeExtent);
    outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inExtent);
  
    this->InternalRequestUpdateExtent(extent, inExtent, wholeExtent);
  
    inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), extent, 6);
  
    return 1;
  }
  
  //----------------------------------------------------------------------------
  void vtkImageSpatialAlgorithm::InternalRequestUpdateExtent(int *extent,
                                                             int *inExtent,
                                                             int *wholeExtent)
  {
    int idx;
    for (idx = 0; idx < 3; ++idx)
      {
      // Magnify by strides
      extent[idx*2] = inExtent[idx*2];
      extent[idx*2+1] = inExtent[idx*2+1];
  
      // Expand to get inRegion Extent
      extent[idx*2] -= this->KernelMiddle[idx];
      extent[idx*2+1] += (this->KernelSize[idx]-1) - this->KernelMiddle[idx];
      
      // If the expanded region is out of the IMAGE Extent (grow min)
      if (extent[idx*2] < wholeExtent[idx*2])
        {
        if (this->HandleBoundaries)
          {
          // shrink the required region extent
          extent[idx*2] = wholeExtent[idx*2];
          }
        else
          {
          vtkWarningMacro(<< "Required region is out of the image extent.");
          }
        }
      // If the expanded region is out of the IMAGE Extent (shrink max)      
      if (extent[idx*2+1] > wholeExtent[idx*2+1])
        {
        if (this->HandleBoundaries)
          {
          // shrink the required region extent
          extent[idx*2+1] = wholeExtent[idx*2+1];
          }
        else
          {
          vtkWarningMacro(<< "Required region is out of the image extent.");
          }
        }
      }
  }
  