/*=auto=========================================================================

  Portions (c) Copyright 2005 Brigham and Women's Hospital (BWH) All Rights Reserved.

  See Doc/copyright/copyright.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Program:   3D Slicer
  Module:    $RCSfile: vtkSeedTracts.h,v $
  Date:      $Date: 2007/02/20 20:46:20 $
  Version:   $Revision: 1.12 $

=========================================================================auto=*/
///  vtkSeedTracts - 
/// 
//
/// Individual streamlines can be started at a point, or 
/// many can be started inside a region of interest.
//

#ifndef __vtkSeedTracts_h
#define __vtkSeedTracts_h

#include "vtkObject.h"
#include "vtkObjectFactory.h"

#include "vtkTeemConfigure.h"

#include "vtkImageData.h"
#include "vtkTransform.h"
#include "vtkCollection.h"
#include "vtkShortArray.h"

#include "vtkHyperStreamline.h"
#include "vtkHyperStreamlineDTMRI.h"
#include "vtkHyperStreamlineTeem.h"
#include "vtkPreciseHyperStreamlinePoints.h"

#define USE_VTK_HYPERSTREAMLINE 0
#define USE_VTK_HYPERSTREAMLINE_POINTS 1
#define USE_VTK_PRECISE_HYPERSTREAMLINE_POINTS 2
#define USE_VTK_HYPERSTREAMLINE_TEEM 3

class VTK_Teem_EXPORT vtkSeedTracts : public vtkObject
{
 public:
  static vtkSeedTracts *New();
  vtkTypeMacro(vtkSeedTracts,vtkObject);

  /// Description
  /// Start a streamline from each voxel which has the value InputROIValue
  /// in the InputROI volume.  Streamlines are added to the vtkCollection
  /// this->Streamlines.
  void SeedStreamlinesInROI();
  
  /// Description
  /// Start a streamline from each voxel which has the values stored in
  /// the vtkShortArray InputMultipleROIValues
  /// in the InputROI volume.  Streamlines are added to the vtkCollection
  /// this->Streamlines.
  void SeedStreamlinesInROIWithMultipleValues();

  /// Description
  /// Start a streamline from each voxel in ROI, keep those paths
  /// that pass through ROI2.
  void SeedStreamlinesFromROIIntersectWithROI2();

 /// Description
 /// Store all the streamlines in one vtkPolyData and
 /// transform the points to be in RAS. It takes
 /// special care of transforming the tensor
 void TransformStreamlinesToRASAndAppendToPolyData(vtkPolyData *outFibers);

  /// Description
  /// Start a streamline from the input point.
  /// The point should be in the world coordinates of the scene.
  void SeedStreamlineFromPoint(double x, double y, double z);

  /// Description
  /// Input tensor field in which to seed streamlines
  vtkSetObjectMacro(InputTensorField, vtkImageData);
  vtkGetObjectMacro(InputTensorField, vtkImageData);

  /// Description
  /// Streamlines will be started at locations with this value in the InputROI.
  /// The value must be greater than 0. A 0 value is not allowed because it
  /// would allow users to accidentally start streamlines outside of their
  /// ROI.
  vtkSetClampMacro(InputROIValue, int, 1, VTK_SHORT_MAX);
  vtkGetMacro(InputROIValue, int);
  vtkSetClampMacro(InputROI2Value, int, 1, VTK_SHORT_MAX);
  vtkGetMacro(InputROI2Value, int);

  /// Description
  /// Streamlines will be started at locations with these values in the InputROI.
  /// The value must be greater than 0. A 0 value is not allowed because it
  /// would allow users to accidentally start streamlines outside of their
  /// ROI.
  vtkSetObjectMacro(InputMultipleROIValues,vtkShortArray);
  vtkGetObjectMacro(InputMultipleROIValues,vtkShortArray);

  /// Description
  /// Input ROI volume describing where to start streamlines
  vtkSetObjectMacro(InputROI, vtkImageData);
  vtkGetObjectMacro(InputROI, vtkImageData);

  /// Description
  /// Input ROI volume to select streamlines (those that begin
  /// within InputROI and pass through InputROI2
  /// will be displayed).
  vtkSetObjectMacro(InputROI2, vtkImageData);
  vtkGetObjectMacro(InputROI2, vtkImageData);

  /// Description
  /// Transformation used in seeding streamlines.  Their start
  /// points are specified in the coordinate system of the ROI volume.
  /// Transform the ijk coordinates of the ROI to world coordinates.
  vtkSetObjectMacro(ROIToWorld, vtkTransform);
  vtkGetObjectMacro(ROIToWorld, vtkTransform);

  /// Description
  /// Transformation used in seeding streamlines.  This is for the 
  /// second ROI volume.
  vtkSetObjectMacro(ROI2ToWorld, vtkTransform);
  vtkGetObjectMacro(ROI2ToWorld, vtkTransform);

  /// Description
  /// Transformation used in seeding streamlines.  Their start
  /// points are specified in the coordinate system of the ROI volume.
  /// Transform world coordinates into scaled ijk of the tensor field.
  vtkSetObjectMacro(WorldToTensorScaledIJK, vtkTransform);
  vtkGetObjectMacro(WorldToTensorScaledIJK, vtkTransform);

  /// 
  /// Example usage is as follows:
  /// 1) If tensors are to be saved in a coordinate system
  ///    that is not IJK (array-based), and the whole volume is
  ///    being rotated, each tensor needs also to be rotated.
  ///    First find the matrix that positions your tensor volume.
  ///    This is how the entire volume is positioned, not 
  ///    the matrix that positions an arbitrary reformatted slice.
  /// 2) Remove scaling and translation from this matrix; we
  ///    just need to rotate each tensor.
  /// 3) Set TensorRotationMatrix to this rotation matrix.
  //
  /// TO DO: slicer3 clean up matrix vs transform in these classes
  vtkSetObjectMacro(TensorRotationMatrix, vtkMatrix4x4);
  vtkGetObjectMacro(TensorRotationMatrix, vtkMatrix4x4);

  /// Description
  /// Whether to seed once in each voxel or isotropically 
  /// (evenly on a IsotropicSeedingResolution resolution grid)
  vtkSetMacro(IsotropicSeeding,int)
  vtkGetMacro(IsotropicSeeding,int)
  vtkBooleanMacro(IsotropicSeeding,int)

  /// Description
  /// If IsotropicSeeding is true, seed in the ROI at this resolution. 
  vtkSetMacro(IsotropicSeedingResolution,double)
  vtkGetMacro(IsotropicSeedingResolution,double)

  /// 
  /// Whether to randomly jitter seed points. 
  /// (They stay within same grid cube or voxel.)
  vtkSetMacro(RandomGrid,int)
  vtkGetMacro(RandomGrid,int)
  vtkBooleanMacro(RandomGrid,int)

  /// Description
  /// List of the output vtkHyperStreamlines (or subclasses)
  vtkSetObjectMacro(Streamlines, vtkCollection);
  vtkGetObjectMacro(Streamlines, vtkCollection);

  /// Description
  /// Type of vtkHyperStreamline subclass to create.
  /// Use standard VTK class.
  void UseVtkHyperStreamline()
    {
      this->TypeOfHyperStreamline=USE_VTK_HYPERSTREAMLINE;
    }

  /// Description
  /// Type of vtkHyperStreamline subclass to create.
  /// Use our subclass that returns points on the streamline.
  void UseVtkHyperStreamlinePoints()
    {
      this->TypeOfHyperStreamline=USE_VTK_HYPERSTREAMLINE_POINTS;
    }

  /// Description
  /// Type of vtkHyperStreamline subclass to create.
  /// Use our subclass that returns points on the streamline
  /// and interpolates using BSplines.
  void UseVtkPreciseHyperStreamlinePoints()
    {
      this->TypeOfHyperStreamline=USE_VTK_PRECISE_HYPERSTREAMLINE_POINTS;
    }

  /// Description
  /// Type of vtkHyperStreamline subclass to create.
  /// Use teem streamlines.
  void UseVtkHyperStreamlineTeem()
    {
      this->TypeOfHyperStreamline=USE_VTK_HYPERSTREAMLINE_TEEM;
    }

  /// Description
  /// Example objects whose settings will be used in creation
  /// of vtkHyperStreamline subclasses of that type.
  /// This is an alternative to duplicating the parameters of 
  /// these classes as parameters of this class.
  vtkSetObjectMacro(VtkHyperStreamlinePointsSettings,vtkHyperStreamlineDTMRI);
  vtkGetObjectMacro(VtkHyperStreamlinePointsSettings,vtkHyperStreamlineDTMRI);
  vtkSetObjectMacro(VtkPreciseHyperStreamlinePointsSettings,
                    vtkPreciseHyperStreamlinePoints);
  vtkGetObjectMacro(VtkPreciseHyperStreamlinePointsSettings,
                    vtkPreciseHyperStreamlinePoints);
  vtkSetObjectMacro(VtkHyperStreamlineTeemSettings,vtkHyperStreamlineTeem);
  vtkGetObjectMacro(VtkHyperStreamlineTeemSettings,vtkHyperStreamlineTeem);

 /// Description
 /// Update all tracts with current parameters.
 /// Loop through all of the hyperstreamline objects and set their
 /// parameters according to the current vtkHyperStreamline*Settings object
 /// which the user can modify. 
 void UpdateAllHyperStreamlineSettings();

  /// Description
  /// Delete all streamlines
  void DeleteAllStreamlines();

  /// Description
  /// Delete a particular streamline. Also calls method in vtkDisplayTracts
  /// to delete graphics objects for this streamline.
  void DeleteStreamline(int index);

 /// Description
 /// Minimum length in mm for a path (otherwise the path will be deleted).
 /// Currently only used in SeedAndSaveStreamlinesInROI.
 vtkGetMacro(MinimumPathLength,double);
 vtkSetMacro(MinimumPathLength,double);

 /// Description
 /// Minimum value of CL to start seeding.
 vtkGetMacro(StartingThreshold,double);
 vtkSetMacro(StartingThreshold,double);

  /// 
  /// Whether to randomly jitter seed points. 
  /// (They stay within same grid cube or voxel.)
  vtkSetMacro(UseStartingThreshold,int)
  vtkGetMacro(UseStartingThreshold,int)
  vtkBooleanMacro(UseStartingThreshold,int)

  /// 
  /// A file directory name for lines
  vtkSetStringMacro(FileDirectoryName);
  vtkGetStringMacro(FileDirectoryName);

  /// 
  /// A file name prefix in the lines file directory 
  vtkSetStringMacro(FilePrefix);
  vtkGetStringMacro(FilePrefix);

 protected:
  vtkSeedTracts();
  ~vtkSeedTracts();

  vtkHyperStreamline *CreateHyperStreamline();

  vtkCollection *Streamlines;

  vtkTransform *ROIToWorld;
  vtkTransform *ROI2ToWorld;
  vtkTransform *WorldToTensorScaledIJK;
  vtkMatrix4x4 *TensorRotationMatrix;

  int IsotropicSeeding;
  double IsotropicSeedingResolution;

  int RandomGrid;

  vtkImageData *InputTensorField;
  vtkImageData *InputROI;
  vtkImageData *InputROI2;

  int InputROIValue;
  int InputROI2Value;
  vtkShortArray *InputMultipleROIValues;
  
  double MinimumPathLength;

  int PointWithinTensorData(double *point, double *pointw);
  
  int TypeOfHyperStreamline;

  char *FileDirectoryName;

  char *FilePrefix;

  double StartingThreshold;

  int UseStartingThreshold;

  /// Here we have a representative accessible object 
  /// of each type, so that the user can modify it.
  /// We copy its settings to each new created streamline.
  vtkHyperStreamline *VtkHyperStreamlineSettings;
  vtkHyperStreamlineDTMRI *VtkHyperStreamlinePointsSettings;
  vtkPreciseHyperStreamlinePoints *VtkPreciseHyperStreamlinePointsSettings;
  vtkHyperStreamlineTeem *VtkHyperStreamlineTeemSettings;

  /// Since only integrating both directions makes sense in the application,
  /// this is the default of this class. This prevents the objects above
  /// from changing the integration direction.
  int IntegrationDirection;


  void UpdateHyperStreamlinePointsSettings( vtkHyperStreamlineDTMRI *currHSP);
  void UpdateHyperStreamlineTeemSettings( vtkHyperStreamlineTeem *currHST);

};

#endif
