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

  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 vtkContourSegmentationFilter - Segments an image given a contour
// .SECTION Description 
// The class takes a contour and an image data as input and segments the
// image data by extruding the contour along a specified direction
//
// .SECTION Parameters and Usage
// At least two inputs must be specified. The contour and the image data to
// be segmented. Note that the class operates as an in-place filter on
// the image data. The extrusion direction can be optionally specified via
// SetStencilAxes(). The class may be used in two ways:
//
// 1. When the contour is drawn on one of the axis aligned planes, the 
// orientation may be conveniently inferred from the bounds of the contour
// polydata. You could use the filter as
// 
// \code
// filter->SetInput(image);                
// filter->SetImage(image);                
// filter->SetSegmentationExtentToImageExtent();
// filter->SetContourPolydata(contourPolyData);
// filter->ObtainOrientationFromContourPolyDataOn();
// filter->Update();
// \endcode
// 
// 2. When the contour is drawn on an arbitrary plane, say using a 
// vtkImagePlaneWidget, (which internally uses a vtkImageReslice to slice 
// oblique planes through the volume, you could draw contours on the oblique 
// plane and segment using the extrusion perpendicular to the plane as the 
// boundary. You would use the filter as:
// 
// \code 
// filter->SetImage(image);                // Image data to segment
// filter->SetInput(reslice->GetOutput()); // slice on which contour is drawn
// filter->SetSegmentationExtentToImageExtent();
// filter->SetContourPolydata(contourPolyData);
// filter->SetStencilAxes(reslice->GetResliceAxes());
// filter->ObtainOrientationFromContourPolyDataOff();
// filter->Update();
// \endcode
//
// In fact, you could always use the second method and set 
// ObtainOrientationFromContourPolyDataOff() by default, and pass in the 
// appropriate direction cosines, whether the contour lies on the axis aligned 
// planes or not. (Sometimes its just convenient to not care where the contour is
// drawn if you have only axis aligned image widgets).
//
// The boolean SegmentInside decides whether the segmentation is inside or outside
// the contour. SetReplaceValue() can be used to specify a replace value for 
// pixels segmented away. GetNumberOfPixelsReplaced() tells you the number of 
// pixels segmented away (removed).
//
// 3. Slice by slice segmentation:
// <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
// instead of \c SetSegmentationExtentToImageExtent()
// 
// .SECTION See Also
// vtkStencilProjectionImageFilter, vtkContourStatistics,
// vtkContourToImageStencil
//
#ifndef __vtkContourSegmentationFilter_h
#define __vtkContourSegmentationFilter_h

//#define VTK_VV_CONTOUR_SEGMENTATION_DEBUG 

#include "vtkImageInPlaceFilter.h"
#include "vtkSmartPointer.h" //

class vtkImageData;
class vtkImageStencilData;
class vtkPolyData;
class vtkMatrix4x4;
class vtkCamera;
class vtkRenderer;

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

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

  // Description:
  // Set the contour polydata
  virtual void SetContourPolyData( vtkPolyData *polyData );
  vtkPolyData *GetContourPolyData();

  // Description:
  // Get number of pixels classified as "inside" after the segmentation
  vtkGetMacro( NumberOfPixelsReplaced, int );
  
  // Description:
  // Default On
  vtkSetMacro( ObtainOrientationFromContourPolyData, int );
  vtkGetMacro( ObtainOrientationFromContourPolyData, int );
  vtkBooleanMacro( ObtainOrientationFromContourPolyData, int );

  // 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
  // the normal to 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);

  // Description:
  // Outside value. The pixels outside the scalar stencil are set to this value
  // It defaults to the minimum representable value for the ScalarType of the
  // image. Although the representation here is double, it will be casted to 
  // the appropriate datatype.
  vtkSetMacro( ReplaceValue, double );
  vtkGetMacro( ReplaceValue, double );
  
  // 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 to 
  // 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:
  // Set the image to be segmented. (Usually the same as the one the contour is
  // drawn on). Defaults to the one specified using SetInput(), if none is 
  // specified. Usually you would not want to use this method unless the image
  // data that you are drawing the contour on is different from the one which 
  // you are trying to segment. For instance in the case of a ImagePlaneWidget,
  // the contour is drawn on a resliced image. The ImageData to be segmented is
  // the input to the vtkImageReslice.
  virtual void SetImage( vtkImageData * );
  vtkImageData* GetImage();

  // Description:
  // Convenience method that set the segmentation extent to the image extents.
  // In other words, if a contour is drawn, the entire image segmented using an
  // extrusion of the contour along its normal. This is the default. You should
  // have set the input image data prior to using this method.
  void SetSegmentationExtentToImageExtent();

  // Description:
  // See vtkStencilProjectionImageFilter for details
  vtkSetMacro( VolumetricProjection, int );
  vtkGetMacro( VolumetricProjection, int );
  vtkBooleanMacro( VolumetricProjection, int );

  // Description:
  // See vtkStencilProjectionImageFilter for details
  virtual void SetCamera( vtkCamera * );
  vtkGetObjectMacro( Camera, vtkCamera );

  // Description:
  // See vtkStencilProjectionImageFilter for details
  virtual void SetCompositeProjectionTransformMatrix( vtkMatrix4x4 * );
  vtkGetObjectMacro( CompositeProjectionTransformMatrix, vtkMatrix4x4 );

  // Description:
  // Set the renderer. The camera, CompositeProjectionTransformMatrix are
  // obtained from the renderer. 
  virtual void SetRenderer( vtkRenderer * );
  vtkGetObjectMacro( Renderer, vtkRenderer );

#ifdef VTK_VV_CONTOUR_SEGMENTATION_DEBUG 
  // Description:
  // The method exists for DEBUG purposes only. It spews out the rasterized 
  // stencil in the form of a mask to a PNG file. The mask will be as large
  // as the contour bounds and will have the shape of the contour. 
  static void WriteRasterizedContourToPNGFile( vtkImageStencilData *,
                                               const char *filename );
#endif 

protected:
  vtkContourSegmentationFilter();
  ~vtkContourSegmentationFilter();

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

  // Description:
  // Reorient the polyline along the XY plane. See the .cxx for a detailed
  // description
  int ReorientPolyline( const vtkPolyData *polyIn, vtkPolyData *polyOut,
                        const vtkImageData *image);
  
  virtual vtkSmartPointer< vtkImageData >AllocateContourRegionImageData( 
                   vtkImageData *inputImageData, const vtkPolyData *pd );

  vtkSmartPointer< vtkImageStencilData >
    RasterizePolyline( vtkPolyData *poly,  vtkImageData *contourRegionImageData);

  // Description:
  // Given a vtkPolyData, this function uses the matrix inverse to pre-multiply and
  // transform the polydata "in" to polydata "out".
  static void TransformPolyData( const vtkMatrix4x4 *, 
                         const vtkPolyData *in, vtkPolyData *out );
  
  int                     NumberOfPixelsReplaced;
  int                     ObtainOrientationFromContourPolyData;
  vtkMatrix4x4            *StencilAxes;
  double                  ReplaceValue;
  int                     SegmentInside;
  int                     SegmentationExtent[6];
  int                     VolumetricProjection;
  vtkRenderer            *Renderer;
  vtkCamera              *Camera;
  vtkMatrix4x4           *CompositeProjectionTransformMatrix;
  
private:
  vtkContourSegmentationFilter(const vtkContourSegmentationFilter&);  // Not implemented.
  void operator=(const vtkContourSegmentationFilter&);  // Not implemented.

  // Description:
  // Number indicates the axis the contour perpendicular to 
//BTX
  enum ContourPlane 
  {
    X = 0,
    Y = 1,
    Z = 2,
    NonOrthogonal = 3
  };
//ETX

  int ContourOrientation;

  unsigned long LastBuildTime;
};

#endif

