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

  Program:   Visualization Toolkit
  Module:    vtkCheckerboardSplatter.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.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 vtkCheckerboardSplatter - splat points into a volume with an elliptical, Gaussian distribution
// .SECTION Description
// vtkCheckerboardSplatter is a filter that injects input points into a
// structured points (volume) dataset using a multithreaded 8-way
// checkerboard approach. It produces a scalar field of a specified type. As
// each point is injected, it "splats" or distributes values to nearby
// voxels. Data is distributed using an elliptical, Gaussian distribution
// function. The distribution function is modified using scalar values
// (expands distribution) or normals (creates ellipsoidal distribution rather
// than spherical). This algorithm is designed for scalability through
// multithreading.
//
// In general, the Gaussian distribution function f(x) around a given
// splat point p is given by
//
//     f(x) = ScaleFactor * exp( ExponentFactor*((r/Radius)**2) )
//
// where x is the current voxel sample point; r is the distance |x-p|
// ExponentFactor <= 0.0, and ScaleFactor can be multiplied by the scalar
// value of the point p that is currently being splatted.
//
// If point normals are present (and NormalWarping is on), then the splat
// function becomes elliptical (as compared to the spherical one described
// by the previous equation). The Gaussian distribution function then
// becomes:
//
//     f(x) = ScaleFactor *
//               exp( ExponentFactor*( ((rxy/E)**2 + z**2)/R**2) )
//
// where E is a user-defined eccentricity factor that controls the elliptical
// shape of the splat; z is the distance of the current voxel sample point
// along normal N; and rxy is the distance of x in the direction
// prependicular to N.
//
// This class is typically used to convert point-valued distributions into
// a volume representation. The volume is then usually iso-surfaced or
// volume rendered to generate a visualization. It can be used to create
// surfaces from point distributions, or to create structure (i.e.,
// topology) when none exists.
//
// This class makes use of vtkSMPTools to implement a parallel, shared-memory
// implementation. Hence performance will be significantly improved if VTK is
// built with VTK_SMP_IMPLEMENTATION_TYPE set to something other than
// "Sequential" (typically TBB). For example, on a standard laptop with four
// threads it is common to see a >10x speedup as compared to the serial
// version of vtkGaussianSplatter.
//
// In summary, the algorithm operates by dividing the volume into a 3D
// checkerboard, where the squares of the checkerboard overlay voxels in the
// volume. The checkerboard overlay is designed as a function of the splat
// footprint, so that when splatting occurs in a group (or color) of
// checkerboard squares, the splat operation will not cause write contention
// as the splatting proceeds in parallel. There are eight colors in this
// checkerboard (like an octree) and parallel splatting occurs simultaneously
// in one of the eight colors (e.g., octants). A single splat operation
// (across the given 3D footprint) may also be parallelized if the splat is
// large enough.

// .SECTION Caveats
// The input to this filter is of type vtkPointSet. Currently only real types
// (e.g., float, double) are supported as input, but this could easily be
// extended to other types. The output type is limited to real types as well.
//
// Some voxels may never receive a contribution during the splatting process.
// The final value of these points can be specified with the "NullValue"
// instance variable. Note that NullValue is also the initial value of the
// output voxel values and will affect the accumulation process.
//
// While this class is very similar to vtkGaussianSplatter, it does produce
// slightly different output in most cases (due to the way the footprint is
// computed).

// .SECTION See Also
// vtkShepardMethod vtkGaussianSplatter

#ifndef vtkCheckerboardSplatter_h
#define vtkCheckerboardSplatter_h

#include "vtkImagingHybridModule.h" // For export macro
#include "vtkImageAlgorithm.h"

#define VTK_ACCUMULATION_MODE_MIN 0
#define VTK_ACCUMULATION_MODE_MAX 1
#define VTK_ACCUMULATION_MODE_SUM 2

class vtkDoubleArray;
class vtkCompositeDataSet;

class VTKIMAGINGHYBRID_EXPORT vtkCheckerboardSplatter : public vtkImageAlgorithm
{
public:
  vtkTypeMacro(vtkCheckerboardSplatter,vtkImageAlgorithm);
  void PrintSelf(ostream& os, vtkIndent indent);

  // Description:
  // Construct object with dimensions=(50,50,50); automatic computation of
  // bounds; a Footprint of 2; a Radius of 0; an exponent factor of -5; and normal and
  // scalar warping enabled; and Capping enabled.
  static vtkCheckerboardSplatter *New();

  // Description:
  // Set / get the dimensions of the sampling structured point set. Higher
  // values produce better results but may be much slower.
  void SetSampleDimensions(int i, int j, int k);
  void SetSampleDimensions(int dim[3]);
  vtkGetVectorMacro(SampleDimensions,int,3);

  // Description:
  // Set / get the (xmin,xmax, ymin,ymax, zmin,zmax) bounding box in which
  // the sampling is performed. If any of the (min,max) bounds values are
  // min >= max, then the bounds will be computed automatically from the input
  // data. Otherwise, the user-specified bounds will be used.
  vtkSetVector6Macro(ModelBounds,double);
  vtkGetVectorMacro(ModelBounds,double,6);

  // Description:
  // Control the footprint size of the splat in terms of propagation across a
  // voxel neighborhood. The Footprint value simply indicates the number of
  // neigboring voxels in the i-j-k directions to extend the splat. A value
  // of zero means that only the voxel containing the splat point is
  // affected. A value of one means the immediate neighbors touching the
  // affected voxel are affected as well. Larger numbers increase the splat
  // footprint and significantly increase processing time. Note that the
  // footprint is always 3D rectangular.
  vtkSetClampMacro(Footprint,int,0,VTK_INT_MAX);
  vtkGetMacro(Footprint,int);

  // Description:
  // Set / get the radius variable that controls the Gaussian exponential
  // function (see equation above). If set to zero, it is automatically set
  // to the radius of the circumsphere bounding a single voxel. (By default,
  // the Radius is set to zero and is automatically computed.)
  vtkSetClampMacro(Radius,double,0.0,VTK_DOUBLE_MAX);
  vtkGetMacro(Radius,double);

  // Description:
  // Multiply Gaussian splat distribution by this value. If ScalarWarping
  // is on, then the Scalar value will be multiplied by the ScaleFactor
  // times the Gaussian function.
  vtkSetClampMacro(ScaleFactor,double,0.0,VTK_DOUBLE_MAX);
  vtkGetMacro(ScaleFactor,double);

  // Description:
  // Set / get the sharpness of decay of the splats. This is the exponent
  // constant in the Gaussian equation described above. Normally this is a
  // negative value.
  vtkSetMacro(ExponentFactor,double);
  vtkGetMacro(ExponentFactor,double);

  // Description:
  // Turn on/off the scaling of splats by scalar value.
  vtkSetMacro(ScalarWarping,int);
  vtkGetMacro(ScalarWarping,int);
  vtkBooleanMacro(ScalarWarping,int);

  // Description:
  // Turn on/off the generation of elliptical splats. If normal warping is
  // on, then the input normals affect the distribution of the splat. This
  // boolean is used in combination with the Eccentricity ivar.
  vtkSetMacro(NormalWarping,int);
  vtkGetMacro(NormalWarping,int);
  vtkBooleanMacro(NormalWarping,int);

  // Description:
  // Control the shape of elliptical splatting. Eccentricity is the ratio
  // of the major axis (aligned along normal) to the minor (axes) aligned
  // along other two axes. So Eccentricity > 1 creates needles with the
  // long axis in the direction of the normal; Eccentricity<1 creates
  // pancakes perpendicular to the normal vector.
  vtkSetClampMacro(Eccentricity,double,0.001,VTK_DOUBLE_MAX);
  vtkGetMacro(Eccentricity,double);

  // Description:
  // Specify the scalar accumulation mode. This mode expresses how scalar
  // values are combined when splats overlap one another. The Max mode acts
  // like a set union operation and is the most commonly used; the Min mode
  // acts like a set intersection, and the sum is just weird (and can
  // potentially cause accumulation overflow in extreme cases). Note that the
  // NullValue must be set consistent with the accumulation operation.
  vtkSetClampMacro(AccumulationMode,int,
                   VTK_ACCUMULATION_MODE_MIN,VTK_ACCUMULATION_MODE_SUM);
  vtkGetMacro(AccumulationMode,int);
  void SetAccumulationModeToMin()
    {this->SetAccumulationMode(VTK_ACCUMULATION_MODE_MIN);}
  void SetAccumulationModeToMax()
    {this->SetAccumulationMode(VTK_ACCUMULATION_MODE_MAX);}
  void SetAccumulationModeToSum()
    {this->SetAccumulationMode(VTK_ACCUMULATION_MODE_SUM);}
  const char *GetAccumulationModeAsString();

  // Description:
  // Set what type of scalar data this source should generate. Only double
  // and float types are supported currently due to precision requirements
  // during accumulation. By default, float scalars are produced.
  vtkSetMacro(OutputScalarType,int);
  vtkGetMacro(OutputScalarType,int);
  void SetOutputScalarTypeToDouble()
    {this->SetOutputScalarType(VTK_DOUBLE);}
  void SetOutputScalarTypeToFloat()
    {this->SetOutputScalarType(VTK_FLOAT);}

  // Description:
  // Turn on/off the capping of the outer boundary of the volume
  // to a specified cap value. This can be used to close surfaces
  // (after iso-surfacing) and create other effects.
  vtkSetMacro(Capping,int);
  vtkGetMacro(Capping,int);
  vtkBooleanMacro(Capping,int);

  // Description:
  // Specify the cap value to use. (This instance variable only has effect
  // if the ivar Capping is on.)
  vtkSetMacro(CapValue,double);
  vtkGetMacro(CapValue,double);

  // Description:
  // Set the Null value for output points not receiving a contribution from
  // the input points. (This is the initial value of the voxel samples, by
  // default it is set to zero.) Note that the value should be consistent
  // with the output dataset type. The NullValue also provides the initial
  // value on which the accumulations process operates.
  vtkSetMacro(NullValue,double);
  vtkGetMacro(NullValue,double);

  // Description:
  // Set/Get the maximum dimension of the checkerboard (i.e., the number of
  // squares in any of the i, j, or k directions). This number also impacts
  // the granularity of the parallel threading (since each checker square is
  // processed separaely). Because of the internal addressing, the maximum
  // dimension is limited to 255 (maximum value of an unsigned char).
  vtkSetClampMacro(MaximumDimension,int,0,255);
  vtkGetMacro(MaximumDimension,int);

  // Description:
  // Set/get the crossover point expressed in footprint size where the
  // splatting operation is parallelized (through vtkSMPTools). By default
  // the parallel crossover point is for splat footprints of size two or
  // greater (i.e., at footprint=2 then splat is 5x5x5 and parallel splatting
  // occurs). This is really meant for experimental purposes.
  vtkSetClampMacro(ParallelSplatCrossover,int,0,255);
  vtkGetMacro(ParallelSplatCrossover,int);

  // Description:
  // Compute the size of the sample bounding box automatically from the
  // input data. This is an internal helper function.
  void ComputeModelBounds(vtkDataSet *input, vtkImageData *output,
                          vtkInformation *outInfo);

protected:
  vtkCheckerboardSplatter();
  ~vtkCheckerboardSplatter() {}

  virtual int FillInputPortInformation(int port, vtkInformation* info);
  virtual int RequestInformation (vtkInformation *,
                                  vtkInformationVector **,
                                  vtkInformationVector *);
  virtual int RequestData(vtkInformation *,
                          vtkInformationVector **,
                          vtkInformationVector *);

  int OutputScalarType; //the type of output scalars
  int SampleDimensions[3]; // dimensions of volume to splat into
  double Radius; // Radius factor in the Gaussian exponential function
  int Footprint; // maximum distance splat propagates (in voxels 0->Dim)
  double ExponentFactor; // scale exponent of gaussian function
  double ModelBounds[6]; // bounding box of splatting dimensions
  double Origin[3], Spacing[3]; // output geometry
  int NormalWarping; // on/off warping of splat via normal
  double Eccentricity;// elliptic distortion due to normals
  int ScalarWarping; // on/off warping of splat via scalar
  double ScaleFactor; // splat size influenced by scale factor
  int Capping; // Cap side of volume to close surfaces
  double CapValue; // value to use for capping
  int AccumulationMode; // how to combine scalar values
  double NullValue; // initial value of voxels
  unsigned char MaximumDimension; // max resolution of checkerboard
  int ParallelSplatCrossover; //the point at which parallel splatting occurs

private:
  vtkCheckerboardSplatter(const vtkCheckerboardSplatter&);  // Not implemented.
  void operator=(const vtkCheckerboardSplatter&);  // Not implemented.
};

#endif
