
#ifndef __vtkITKBSplineTransform_h
#define __vtkITKBSplineTransform_h

#include "vtkWarpTransform.h"
#include "vtkDoubleArray.h"

#include "itkBSplineDeformableTransform.h"
#include "itkAffineTransform.h"

#include "vtkITK.h"

class vtkITKBSplineTransformHelper;

// A BSpline transform.
//
// See the ITK BSplineTransform documentation for details on the
// underlying functionality and dependencies of this class.

class VTK_ITK_EXPORT vtkITKBSplineTransform : public vtkWarpTransform
{
public:
  //BTX
  typedef itk::AffineTransform<double,3> BulkTransformType;
  //ETX
  static vtkITKBSplineTransform *New();
  vtkTypeRevisionMacro( vtkITKBSplineTransform, vtkWarpTransform );
  virtual void PrintSelf( ostream& os, vtkIndent indent );

  vtkAbstractTransform* MakeTransform();

  // SetOrder MUST be called first before other set functions.
  void SetSplineOrder( unsigned int );

  unsigned int GetSplineOrder() const;

  // The origin of the B-spline grid must be set at one grid position
  // away from the origin of the desired output image.
  void SetGridOrigin( const double origin[3] );

  // The spacing between grid nodes.
  void SetGridSpacing( const double spacing[3] );

  // Number of grid nodes in each dimension.
  //
  // Note that there need to
  // be extra nodes "outside" the valid input region.  The number of
  // such extra nodes depends on the order of the BSpline; for a cubic
  // (order 3) BSpline, there needs to be 3 extra nodes in each
  // dimension.
  void SetGridSize( const unsigned int size[3] );

  // See the documentation of SetParameters(double[]).
  void SetParameters( vtkDoubleArray& param );

  // Set the BSpline parameters.
  //
  // There should be this->GetNumberOfParameters() parameters in this
  // vector.  The parameters can be thought of as the required
  // displacement each node in each dimension.
  //
  // Suppose the grid (set by SetGridSize) is LxNxM.  Then, the first
  // LxNxM values represent the x-displacement, the next LxNxM values
  // represent the y-displacement, and finally, the last LxNxM values
  // represent the z-displacement.  For each space dimension, the
  // LxNxM values are the values at the corresponding grid points,
  // vectorized by traversing the grid in the x-dimension first, then
  // the y-dimension, and finally the z-dimension.  That is, if
  // param[17] is for grid node (1,2,3), then param[18] is for grid
  // node (2,2,3).
  //
  // The parameter values in \a param are copied, and hence can be
  // released after this call.
  //
  void SetParameters( const double* param );

  // The number of elements in the parameter vector.
  //
  // See SetParameters(double[]).
  unsigned int GetNumberOfParameters() const;

  const double* GetParameters() const;


  // Set the fixed parameters.
  //
  // These are the grid spacing, the grid origin, etc.
  void SetFixedParameters( const double* param, unsigned N );

  // The number of fixed parameters.
  unsigned int GetNumberOfFixedParameters() const;

  // Return a pointer to the fixed parameter array.
  //
  // This is a pointer to internal data; the class still owns it.
  const double* GetFixedParameters() const;

  // BulkTransform should be in the ITK coordinate system, which is LPS.
  void SetBulkTransform( const double linear[3][3], const double offset[3] );
  void GetBulkTransform( double linear[3][3], double offset[3] );
  //BTX
  BulkTransformType const* GetBulkTransform() const;
  //ETX

  // Sets whether a LPS->RAS conversion should be done.
  //
  // When the BSpline is created, it is assumed to be in an LPS
  // coordinate system, as is typical for ITK BSplines.  If this
  // switch is set to \c true, then this class will assume that the
  // input and output points are in an RAS coordinate system, and will
  // first convert them to LPS, call the ITK BSpline, and convert the
  // result back to RAS.
  //
  // By default, this switch is is FALSE.  Thus, by default, this
  // class will behave exactly like the wrapped ITK BSpline.
  void SetSwitchCoordinateSystem( bool v );

  bool GetSwitchCoordinateSystem() const;

  //BTX
  itk::Transform<double,3,3>::Pointer GetITKTransform() const;
  //ETX

protected:
  vtkITKBSplineTransform();
  virtual ~vtkITKBSplineTransform();

  void ForwardTransformPoint( const float in[3], float out[3] );
  void ForwardTransformPoint( const double in[3], double out[3] );

  void ForwardTransformDerivative( const float in[3], float out[3],
                                   float derivative[3][3] );
  void ForwardTransformDerivative( const double in[3], double out[3],
                                   double derivative[3][3] );

  void InverseTransformPoint( const float in[3], float out[3] );

  void InverseTransformPoint( const double in[3], double out[3] );

  void InverseTransformDerivative( const float in[3], float out[3],
                                   float derivative[3][3] );
  void InverseTransformDerivative( const double in[3], double out[3],
                                   double derivative[3][3] );

private:
  vtkITKBSplineTransformHelper* Helper;
};

#endif
