/*=========================================================================

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.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.

=========================================================================*/
// .NAME vtkStencilProjectionImageFilter - Projects a stencil onto an image
// .SECTION Description
// The class takes as input a vtkImageStencilData and a vtkImageData. It 
// extrudes the stencil along a specified direction into the image and 
// segments the data within (or outside) the stencil.
//
// .SECTION Parameters and usage
// <p>1) The two inputs to the class are the stencil and the image data. 
// The extrusion is specified by a 4x4 matrix via the \c SetStencilAxes() method.
// The first column of the matrix specifies the x-axis vector (the fourth 
// element must be set to zero), the second column specifies the y-axis, and 
// the third column the z-axis.  The fourth column is the origin of the axes
// (the fourth element must be set to one).   
// The stencil may be segmented inside or outside using \c SegmentInsideOff()
// The scalar value with which pixels segmented away must be replaced is
// set via \c SetReplaceValue().
// The number of pixels replaced is returned via \c GetNumberOfPixelsReplaced()
// <p>2) A code fragment where you might have contours drawn on an image widget, 
// let's say the vtkImagePlaneWidget and wanted to achieve a segmentation via an 
// extrusion along the normal to that plane would look like this:
// \code
// filter->SetInput(imageData);
// filter->SetResliceAxes(imagePlaneWidget->GetReslice()->GetResliceAxes());
// filter->Update();
// \endcode
// Note that this is an inplace filter. (The methods GetReslice in the 
//  above code fragment don't really exist, but you know what to pass in).
// <p>3) Slice by slice segmentation: The default behaviour of the widget is to 
// segment via an extrusion of the contour. In other words, the contour is 
// extruded along its normal or the normal to the stencil axes, (if specified). 
// Sometimes, what you may want is slice by slice segmentation or segmentation 
// or segmentation restricted to a slab. To facilitate this, the filter allows 
// you to restrict the segmentation via a set of extents. As an example, if you
// were to do slice by slice segmentation on slice 10 of a coronal widget, 
// you'd set these extents as
// \code
// SetSegmentationExtent( image->GetExtent()[0], image->GetExtent[1],
//                   10, 10, image->GetExtent[4], image->GetExtent()[5] );
// \endcode
//
// .SECTION Bugs
// When the image data has unequal origins ie xorigin, yorigin and zorigin are
// not equal, projection along a non-axis aligned stencil axes is incorrect. I 
// need to fix the bug.
// 
// .SECTION See Also
// vtkContourToImageStencil vtkContourStatistics vtkContourSegmentationFilter
//
#ifndef __vtkStencilProjectionImageFilter_h
#define __vtkStencilProjectionImageFilter_h

#include "vtkImageInPlaceFilter.h"

class vtkImageData;
class vtkImageStencilData;
class vtkMatrix4x4;
class vtkCamera;

class VTK_EXPORT vtkStencilProjectionImageFilter : public vtkImageInPlaceFilter
{
public:
  // Description:
  // Constructs with initial values of zero.
  static vtkStencilProjectionImageFilter *New();

  vtkTypeRevisionMacro(vtkStencilProjectionImageFilter,vtkImageInPlaceFilter);
  void PrintSelf(ostream& os, vtkIndent indent);

  // Description:
  // Set the contour polydata
  virtual void SetStencil( vtkImageStencilData *stencilData );
  vtkImageStencilData *GetStencil();

  // Description:
  // Get number of pixels classified as "inside" after the segmentation
  vtkGetMacro( NumberOfPixelsReplaced, int );
  
  // Description:
  // Turn SegmentInside to Off if you want to preserve the regions
  // outside the contour. By default the regions inside the contour are 
  // preserved and everything else is set to ReplaceValue.
  vtkSetMacro( SegmentInside, int );
  vtkGetMacro( SegmentInside, int );
  vtkBooleanMacro( SegmentInside, int );
  
  // Description:
  // The default behaviour of the widget is to segment via an extrusion of the
  // contour. In other words, the contour is extruded along its normal or the
  // normal to the stencil axes, (if specified). Sometimes, what you may want
  // is slice by slice segmentation or segmentation restricted to a slab. To
  // facilitate this, the filter allows you to restrict the segmentation  
  // via a set of extents. As an example, if you were to do slice by slice 
  // segmentation on slice 10 of a coronal widget, you'd set these extents as
  //   \code
  //   SetSegmentationExtent( image->GetExtent()[0], image->GetExtent[1],
  //                   10, 10, image->GetExtent[4], image->GetExtent()[5] );
  //   \endcode
  vtkSetVector6Macro(SegmentationExtent, int );
  vtkGetVector6Macro(SegmentationExtent, int );

  // Description:
  // Outside value. The pixels outside the scalar stencil are set to this value
  // It defaults to 0. Although the representation here is double, it will be 
  // casted to the appropriate datatype.
  vtkSetMacro( ReplaceValue, double );
  vtkGetMacro( ReplaceValue, double );

  // Description:
  // This method is used to set up the axes for the stencil. The stencil itself
  // is just a 2D mask. The StencilAxes is used to define the orientation along
  // which the stencil is supposed to lie so that you can bore a hole along
  // that direction to achieve a segmentation of the image data. The
  // orientation is specified via a 4x4 matrix (much like vtkImageReslice).
  // <p>The first column of the matrix specifies the x-axis 
  // vector (the fourth element must be set to zero), the second
  // column specifies the y-axis, and the third column the
  // z-axis.  The fourth column is the origin of the
  // axes (the fourth element must be set to one).  
  virtual void SetStencilAxes(vtkMatrix4x4*);
  vtkGetObjectMacro(StencilAxes, vtkMatrix4x4);

  vtkSetMacro( VolumetricProjection, int );
  vtkGetMacro( VolumetricProjection, int );
  vtkBooleanMacro( VolumetricProjection, int );

  // Description:
  // Set the camera. In the case of volumetric projection, the projection
  // direction is inferred from the camera. If the camera uses parallel 
  // projection, the stencil (which is assumed to lie on the focal plane) 
  // is extruded along the projection direction to obtain an in-place
  // segmentation of the data. For perspective projection, the stencil is
  // extruded according to the perspective transformation, as defined by
  // the set camera.
  virtual void SetCamera( vtkCamera * camera );
  vtkGetObjectMacro( Camera, vtkCamera );

  // Description:
  // Set the composite projection transform matrix. Needed only for 
  // perspective transformations.
  virtual void SetCompositeProjectionTransformMatrix( vtkMatrix4x4 * );
  vtkGetObjectMacro( CompositeProjectionTransformMatrix, vtkMatrix4x4 );

  // Description:
  // Used INTERNALLY by the filter to determine of the projection of a point 
  // onto its stencil, lies within the stencil. The stencil lies along the 
  // direction as specified via SetStencilAxes().
  int CheckIfPointProjectionIsWithinStencil(double p[3]);

  // Description:
  // Used INTERNALLY by the filter to persepective project a point on the
  // focal plane. The passed argument contains the world location and 
  // upon return contains the world location of that point when projected
  // on the focal plane
  void PerspectiveProjectPointOnFocalPlane( double p[4] );

  // Description:
  // Used INTERNALLY by the filter to get the extents that are the intersection 
  // of inExtent and SegmentationExtent (set by the user) and return the result
  // in outExtent. 
  // Returns 0 if they don't intersect.
  int IntersectWithSegmentationExtent( int inExtent[6], int outExtent[6] );

protected:
  vtkStencilProjectionImageFilter();
  ~vtkStencilProjectionImageFilter();

  virtual int RequestData(vtkInformation* request,
                          vtkInformationVector** inputVector,
                          vtkInformationVector* outputVector);
  virtual int FillInputPortInformation(int port, vtkInformation *info);
  virtual int RequestUpdateExtent (vtkInformation *, vtkInformationVector **, 
                                                     vtkInformationVector *);

  // Description:
  // Contours can be projected fast along the axis directions.
  // Checks the values of the direction cosines to see if they are along the 
  // axis aligned directions (within a certain tolerance). 
  int CheckIfAxisAlignedDirection() const;

  vtkMatrix4x4           *StencilAxes;
  int                    NumberOfPixelsReplaced;
  int                    SegmentInside;
  double                 ReplaceValue;
  int                    SegmentationExtent[6];
  
private:
  vtkStencilProjectionImageFilter(const vtkStencilProjectionImageFilter&);  // Not implemented.
  void operator=(const vtkStencilProjectionImageFilter&);  // Not implemented.

  // Description:
  // Temporary storage variables
  vtkImageStencilData    *Stencil;
  vtkCamera              *Camera;
  vtkMatrix4x4           *CompositeProjectionTransformMatrix;
  vtkMatrix4x4           *InverseCompositeProjectionTransformMatrix;
  double                 StencilSpacing[3];
  int                    StencilExtent[6];
  double                 StencilOrigin[3];
  double                 FocalDepth;
  int                    VolumetricProjection;
};

#endif

