/*========================================================================= Program: Visualization Toolkit Module: vtkGaussianSplatter.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. =========================================================================*/ /** * @class vtkGaussianSplatter * @brief splat points into a volume with an elliptical, Gaussian distribution * * vtkGaussianSplatter is a filter that injects input points into a * structured points (volume) dataset. 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). * * 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 points 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. * * @warning * The input to this filter is any dataset type. This filter can be used * to resample any form of data, i.e., the input data need not be * unstructured. * * @warning * 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. * * @warning * This class has been threaded with vtkSMPTools. Using TBB or other * non-sequential type (set in the CMake variable * VTK_SMP_IMPLEMENTATION_TYPE) may improve performance significantly. * * @sa * vtkShepardMethod vtkCheckerboardSplatter */ #ifndef vtkGaussianSplatter_h #define vtkGaussianSplatter_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 vtkGaussianSplatterAlgorithm; class VTKIMAGINGHYBRID_EXPORT vtkGaussianSplatter : public vtkImageAlgorithm { public: vtkTypeMacro(vtkGaussianSplatter,vtkImageAlgorithm); void PrintSelf(ostream& os, vtkIndent indent) override; /** * Construct object with dimensions=(50,50,50); automatic computation of * bounds; a splat radius of 0.1; an exponent factor of -5; and normal and * scalar warping turned on. */ static vtkGaussianSplatter *New(); //@{ /** * Set / get the dimensions of the sampling structured point set. Higher * values produce better results but are much slower. */ void SetSampleDimensions(int i, int j, int k); void SetSampleDimensions(int dim[3]); vtkGetVectorMacro(SampleDimensions,int,3); //@} //@{ /** * 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); //@} //@{ /** * Set / get the radius of propagation of the splat. This value is expressed * as a percentage of the length of the longest side of the sampling * volume. Smaller numbers greatly reduce execution time. */ vtkSetClampMacro(Radius,double,0.0,1.0); vtkGetMacro(Radius,double); //@} //@{ /** * 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); //@} //@{ /** * Set / get the sharpness of decay of the splats. This is the * exponent constant in the Gaussian equation. Normally this is * a negative value. */ vtkSetMacro(ExponentFactor,double); vtkGetMacro(ExponentFactor,double); //@} //@{ /** * 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); //@} //@{ /** * 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); //@} //@{ /** * Turn on/off the scaling of splats by scalar value. */ vtkSetMacro(ScalarWarping,int); vtkGetMacro(ScalarWarping,int); vtkBooleanMacro(ScalarWarping,int); //@} //@{ /** * 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); //@} //@{ /** * Specify the cap value to use. (This instance variable only has effect * if the ivar Capping is on.) */ vtkSetMacro(CapValue,double); vtkGetMacro(CapValue,double); //@} //@{ /** * Specify the scalar accumulation mode. This mode expresses how scalar * values are combined when splats are overlapped. 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. */ 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(); //@} //@{ /** * Set the Null value for output points not receiving a contribution from the * input points. (This is the initial value of the voxel samples.) */ vtkSetMacro(NullValue,double); vtkGetMacro(NullValue,double); //@} //@{ /** * 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); void ComputeModelBounds(vtkCompositeDataSet *input, vtkImageData *output, vtkInformation *outInfo); //@} //@{ /** * Provide access to templated helper class. Note that SamplePoint() method * is public here because some compilers don't handle friend functions * properly. */ friend class vtkGaussianSplatterAlgorithm; double SamplePoint(double x[3]) //for compilers who can't handle this {return (this->*Sample)(x);} void SetScalar(int idx, double dist2, double *sPtr) { double v = (this->*SampleFactor)(this->S) * exp(static_cast (this->ExponentFactor*(dist2)/(this->Radius2))); //@} if ( ! this->Visited[idx] ) { this->Visited[idx] = 1; *sPtr = v; } else { switch (this->AccumulationMode) { case VTK_ACCUMULATION_MODE_MIN: if ( *sPtr > v ) { *sPtr = v; } break; case VTK_ACCUMULATION_MODE_MAX: if ( *sPtr < v ) { *sPtr = v; } break; case VTK_ACCUMULATION_MODE_SUM: *sPtr += v; break; } }//not first visit } protected: vtkGaussianSplatter(); ~vtkGaussianSplatter() override {} int FillInputPortInformation(int port, vtkInformation* info) override; int RequestInformation (vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override; void Cap(vtkDoubleArray *s); int SampleDimensions[3]; // dimensions of volume to splat into double Radius; // maximum distance splat propagates (as fraction 0->1) double ExponentFactor; // scale exponent of gaussian function double ModelBounds[6]; // bounding box of splatting dimensions 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 Gaussian(double x[3]); double EccentricGaussian(double x[3]); double ScalarSampling(double s) {return this->ScaleFactor * s;} double PositionSampling(double) {return this->ScaleFactor;} private: double Radius2; double (vtkGaussianSplatter::*Sample)(double x[3]); double (vtkGaussianSplatter::*SampleFactor)(double s); char *Visited; double Eccentricity2; double *P; double *N; double S; double Origin[3]; double Spacing[3]; double SplatDistance[3]; double NullValue; private: vtkGaussianSplatter(const vtkGaussianSplatter&) = delete; void operator=(const vtkGaussianSplatter&) = delete; }; #endif