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

  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 vtkContourStatistics - compute area, perimeter min, max, mean, 
// standard deviation, number of pixels in a closed contour.
// 
// .SECTION Description
// vtkContourStatistics compute area, perimeter min, max, mean, 
// standard deviation, number of pixels in a closed contour. 
//
// .SECTION Inputs
// The contour is assumed to be represented by vtkPolyData, (a closed 
// vtkPolyline). The polydata must contain 1 cell and at least 3 points.   
// 
// Optionally, an image data may also be set. The contour must have been drawn
// somewhere within this volume. If the image data has been set, you may also
// obtain the min, max, mean, variance etc of pixels within the contour. 
// This computation is done only if the contour is along one of the axis 
// aligned planes. Arbitrarily oriented planes aren't supported.
//
// .SECTION Parameters and usage
// There are 3 ways to use this class.
// 
// 1. To get the area perimeter etc...
// 
// \code
// myContourStats->SetInput(myvtkPolyline);
// myContourStats->GetArea(); 
// \endcode
//
// 2. To additionally get the statistics within the contour
// 
// \code
// myContourStats->SetImageData(myvtkImageData);
// if (!myContourStats->GetStatisticsComputeFailed())
//   {
//   myContourStats->GetMean();
//   }
// else
//   {
//   std::cout << myContourStats->GetStatisticsComputeFailedHow();
//   }
// \endcode
//
// 3. 
// With default settings, the slice the position of the contour is obtained from
// its co-ordinates. Optionally the contour statistics (min, max, mean) etc may 
// be computed on a different slice other than the one the contour lies on. 
// This may be useful in a image viewer application, where you would draw the 
// contour on a certain slice and then sift through slices and expect the 
// contour statistics to be automatically re-evaluated on this slice, without 
// having to redraw the contour on this slice. To do that, you would add the 
// lines
// 
// \code
// myContourStats->ObtainSliceFromContourPolyDataOff();
// myContourStats->SetSlice(20);
// if (!myContourStats->GetStatisticsComputeFailed())
//   {
//   myContourStats->GetMean();
//   }
// \endcode
//    
// .SECTION Caveats
//   The contour must lie within the image data (if set). The Slice if set must
// lie within the extents of the image data along that dimension.
//   The computation of the statistics is generally quiet. No exceptions are 
// thrown. The \c GetStatisticsComputeFailed() indicates if the computation of 
// contour statistics on the image was successful. 
// \c GetStatisticsComputeFailedHow() gives a meaningful message about why it 
// failed. Note that this only indicates if the image dependent statistics
// failed and not the area/perimeter information.
// 
// .SECTION See Also
// vtkTriangleFilter

#ifndef __vtkContourStatistics_h
#define __vtkContourStatistics_h

#include "vtkPolyDataAlgorithm.h"

class vtkImageData;
class vtkIntArray;  
class vtkImageStencilData;

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

  vtkTypeRevisionMacro(vtkContourStatistics,vtkPolyDataAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent);

  // Description:
  // Set the image data.. used to compute min max std etc
  virtual void SetImageData( vtkImageData *imageData );
  vtkGetObjectMacro(  ImageData, vtkImageData );

  // Description:
  // Compute and return the area.
  double GetArea() {this->Update(); return this->Area;}

  // Description:
  // Compute and return the area.
  double GetPerimeter() {this->Update(); return this->Perimeter;}

  // Description:
  // Get the contour orientation
  vtkGetMacro( ContourOrientation, int );

  // Description:
  // Get min/max/standard deviation/ mean / number of pixels
  // within the contour
  vtkGetMacro( Mean                   , double );
  vtkGetMacro( Minimum                , double );
  vtkGetMacro( Maximum                , double );
  vtkGetMacro( StandardDeviation      , double );
  vtkGetMacro( NumberOfPixelsInContour, int );
  
  // Description:
  // A value of 1 after an Update means that the computation
  // of min/max/standard deviation/mean/number of pixels 
  // failed. If it succeeded, it is 0. The GetStatisticsComputeFailedHow()
  // gives you a meaningful message on how it failed.
  vtkGetMacro( StatisticsComputeFailed, int );
  vtkGetStringMacro( StatisticsComputeFailedHow );
  
  // Description:
  // The class optionally allows you to evaluate the contour statistics on a 
  // different slice using the same polydata representation. To do this,
  // you must have ObtainSliceFromContourPolyDataOff() and set the slice
  // the contour is on. If the contour is on the axial plane,
  // specify the Z slice number. If it is on the Sagittal plane, specify
  // the X slice number. If on the coronal plane, specify the Y slice number.
  // The contour statistics will be evaluated on this slice. 
  //    The slice number should be within the extents of the image data set as
  // input via SetImageData or the min/max statistics will not be computed.
  //    If you have ObtainSliceFromContourPolyDataOn(), the slice is 
  // obtained from the contour polydata.
  vtkSetMacro( Slice, int );
  vtkGetMacro( Slice, int );
  vtkSetMacro( ObtainSliceFromContourPolyData, int );
  vtkGetMacro( ObtainSliceFromContourPolyData, int );
  vtkBooleanMacro( ObtainSliceFromContourPolyData, int );

  // Description:
  // Get the MTime
  unsigned long GetMTime();

 protected:
  vtkContourStatistics();
  ~vtkContourStatistics();

  virtual int RequestData(vtkInformation* request,
                          vtkInformationVector** inputVector,
                          vtkInformationVector* outputVector);

  // Description:
  // Compute the perimeter of the contour. If more than 1 contour
  // is specified, the perimeter is the sum of their perimeters
  double ComputePerimeter( const vtkPolyData* ) const;

  // Description:
  // Compute the Area of the contour. Assumes 1 cell. 
  double ComputeArea( const vtkPolyData* );

  // Description:
  // Compute the min/max/std/mean/ number of pixels statistics. The vtkPolyData
  // passed in must have at least one cell, which must be a vtkPolyLine. The 
  // ImageData must be single component data. If no image data pixels are found
  // to lie within the contour, the min, max, mean, StandardDeviation and 
  // NumberOfPixelsInContour are set to 0.
  // If the statistics were not computed due to incorrect extents, degenerate
  // polydata etc.. the StatisticsComputeFailed ivar is set to 1. Otherwise it
  // is 0.
  void ComputeMinMaxStatistics( const vtkPolyData* );
  
  double  Area;
  double  Perimeter;
  double  Minimum;
  double  Maximum;
  double  StandardDeviation;
  double  Mean;
  int     NumberOfPixelsInContour;
  int     StatisticsComputeFailed;
  char *  StatisticsComputeFailedHow;
  int     Slice;
  
  vtkTimeStamp ExecuteTime;

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

  int ContourOrientation;
  int ObtainSliceFromContourPolyData;

  // Description:
  // To be used internally to give meaningful failure messages
  vtkSetStringMacro( StatisticsComputeFailedHow );
  
private:
  vtkContourStatistics(const vtkContourStatistics&);  // Not implemented.
  void operator=(const vtkContourStatistics&);  // Not implemented.

  // Description:
  // Reorient the polyline along the XY plane. See the .cxx for a detailed
  // description
  int ReorientPolyline( const vtkPolyData *polyIn, vtkPolyData *polyOut);
  
  // Description:
  // Iterate over the image and glean statistics if it is within the stencil
  // Returns 1 on failure, 0 on success. See the .cxx for detailed description
  int ComputeStatisticsWithinStencil( vtkImageData *image, 
                                       vtkImageStencilData *stencil);

  // Description:
  // The rationale for maintaining these times is this:
  // The Area and the Perimeter do not need to rebuilt unless the polydata or 
  // the input image data change. Simply changing the slice number will not 
  // affect the shape of the contour. However the min-max stats will need to 
  // be recomputed in that case. 
  //      In effect, an update will be triggered if the input image data or the
  // polydata or the slice number changes. However the area/perimeter will 
  // not be recomputed unless the contour polydata changes. 
  unsigned long LastAreaBuildTime;
  unsigned long StatisticsBuildTime;
};

#endif

