1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkCheckerboardSplatter.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /**
16  * @class   vtkCheckerboardSplatter
17  * @brief   splat points into a volume with an elliptical, Gaussian distribution
18  *
19  * vtkCheckerboardSplatter is a filter that injects input points into a
20  * structured points (volume) dataset using a multithreaded 8-way
21  * checkerboard approach. It produces a scalar field of a specified type. As
22  * each point is injected, it "splats" or distributes values to nearby
23  * voxels. Data is distributed using an elliptical, Gaussian distribution
24  * function. The distribution function is modified using scalar values
25  * (expands distribution) or normals (creates ellipsoidal distribution rather
26  * than spherical). This algorithm is designed for scalability through
27  * multithreading.
28  *
29  * In general, the Gaussian distribution function f(x) around a given
30  * splat point p is given by
31  *
32  *     f(x) = ScaleFactor * exp( ExponentFactor*((r/Radius)**2) )
33  *
34  * where x is the current voxel sample point; r is the distance |x-p|
35  * ExponentFactor <= 0.0, and ScaleFactor can be multiplied by the scalar
36  * value of the point p that is currently being splatted.
37  *
38  * If point normals are present (and NormalWarping is on), then the splat
39  * function becomes elliptical (as compared to the spherical one described
40  * by the previous equation). The Gaussian distribution function then
41  * becomes:
42  *
43  *     f(x) = ScaleFactor *
44  *               exp( ExponentFactor*( ((rxy/E)**2 + z**2)/R**2) )
45  *
46  * where E is a user-defined eccentricity factor that controls the elliptical
47  * shape of the splat; z is the distance of the current voxel sample point
48  * along normal N; and rxy is the distance of x in the direction
49  * prependicular to N.
50  *
51  * This class is typically used to convert point-valued distributions into
52  * a volume representation. The volume is then usually iso-surfaced or
53  * volume rendered to generate a visualization. It can be used to create
54  * surfaces from point distributions, or to create structure (i.e.,
55  * topology) when none exists.
56  *
57  * This class makes use of vtkSMPTools to implement a parallel, shared-memory
58  * implementation. Hence performance will be significantly improved if VTK is
59  * built with VTK_SMP_IMPLEMENTATION_TYPE set to something other than
60  * "Sequential" (typically TBB). For example, on a standard laptop with four
61  * threads it is common to see a >10x speedup as compared to the serial
62  * version of vtkGaussianSplatter.
63  *
64  * In summary, the algorithm operates by dividing the volume into a 3D
65  * checkerboard, where the squares of the checkerboard overlay voxels in the
66  * volume. The checkerboard overlay is designed as a function of the splat
67  * footprint, so that when splatting occurs in a group (or color) of
68  * checkerboard squares, the splat operation will not cause write contention
69  * as the splatting proceeds in parallel. There are eight colors in this
70  * checkerboard (like an octree) and parallel splatting occurs simultaneously
71  * in one of the eight colors (e.g., octants). A single splat operation
72  * (across the given 3D footprint) may also be parallelized if the splat is
73  * large enough.
74  *
75  * @warning
76  * The input to this filter is of type vtkPointSet. Currently only real types
77  * (e.g., float, double) are supported as input, but this could easily be
78  * extended to other types. The output type is limited to real types as well.
79  *
80  * @warning
81  * Some voxels may never receive a contribution during the splatting process.
82  * The final value of these points can be specified with the "NullValue"
83  * instance variable. Note that NullValue is also the initial value of the
84  * output voxel values and will affect the accumulation process.
85  *
86  * @warning
87  * While this class is very similar to vtkGaussianSplatter, it does produce
88  * slightly different output in most cases (due to the way the footprint is
89  * computed).
90  *
91  * @sa
92  * vtkShepardMethod vtkGaussianSplatter
93  */
94 
95 #ifndef vtkCheckerboardSplatter_h
96 #define vtkCheckerboardSplatter_h
97 
98 #include "vtkImageAlgorithm.h"
99 #include "vtkImagingHybridModule.h" // For export macro
100 
101 #define VTK_ACCUMULATION_MODE_MIN 0
102 #define VTK_ACCUMULATION_MODE_MAX 1
103 #define VTK_ACCUMULATION_MODE_SUM 2
104 
105 class vtkDoubleArray;
106 class vtkCompositeDataSet;
107 
108 class VTKIMAGINGHYBRID_EXPORT vtkCheckerboardSplatter : public vtkImageAlgorithm
109 {
110 public:
111   vtkTypeMacro(vtkCheckerboardSplatter, vtkImageAlgorithm);
112   void PrintSelf(ostream& os, vtkIndent indent) override;
113 
114   /**
115    * Construct object with dimensions=(50,50,50); automatic computation of
116    * bounds; a Footprint of 2; a Radius of 0; an exponent factor of -5; and normal and
117    * scalar warping enabled; and Capping enabled.
118    */
119   static vtkCheckerboardSplatter* New();
120 
121   ///@{
122   /**
123    * Set / get the dimensions of the sampling structured point set. Higher
124    * values produce better results but may be much slower.
125    */
126   void SetSampleDimensions(int i, int j, int k);
127   void SetSampleDimensions(int dim[3]);
128   vtkGetVectorMacro(SampleDimensions, int, 3);
129   ///@}
130 
131   ///@{
132   /**
133    * Set / get the (xmin,xmax, ymin,ymax, zmin,zmax) bounding box in which
134    * the sampling is performed. If any of the (min,max) bounds values are
135    * min >= max, then the bounds will be computed automatically from the input
136    * data. Otherwise, the user-specified bounds will be used.
137    */
138   vtkSetVector6Macro(ModelBounds, double);
139   vtkGetVectorMacro(ModelBounds, double, 6);
140   ///@}
141 
142   ///@{
143   /**
144    * Control the footprint size of the splat in terms of propagation across a
145    * voxel neighborhood. The Footprint value simply indicates the number of
146    * neighboring voxels in the i-j-k directions to extend the splat. A value
147    * of zero means that only the voxel containing the splat point is
148    * affected. A value of one means the immediate neighbors touching the
149    * affected voxel are affected as well. Larger numbers increase the splat
150    * footprint and significantly increase processing time. Note that the
151    * footprint is always 3D rectangular.
152    */
153   vtkSetClampMacro(Footprint, int, 0, VTK_INT_MAX);
154   vtkGetMacro(Footprint, int);
155   ///@}
156 
157   ///@{
158   /**
159    * Set / get the radius variable that controls the Gaussian exponential
160    * function (see equation above). If set to zero, it is automatically set
161    * to the radius of the circumsphere bounding a single voxel. (By default,
162    * the Radius is set to zero and is automatically computed.)
163    */
164   vtkSetClampMacro(Radius, double, 0.0, VTK_DOUBLE_MAX);
165   vtkGetMacro(Radius, double);
166   ///@}
167 
168   ///@{
169   /**
170    * Multiply Gaussian splat distribution by this value. If ScalarWarping
171    * is on, then the Scalar value will be multiplied by the ScaleFactor
172    * times the Gaussian function.
173    */
174   vtkSetClampMacro(ScaleFactor, double, 0.0, VTK_DOUBLE_MAX);
175   vtkGetMacro(ScaleFactor, double);
176   ///@}
177 
178   ///@{
179   /**
180    * Set / get the sharpness of decay of the splats. This is the exponent
181    * constant in the Gaussian equation described above. Normally this is a
182    * negative value.
183    */
184   vtkSetMacro(ExponentFactor, double);
185   vtkGetMacro(ExponentFactor, double);
186   ///@}
187 
188   ///@{
189   /**
190    * Turn on/off the scaling of splats by scalar value.
191    */
192   vtkSetMacro(ScalarWarping, vtkTypeBool);
193   vtkGetMacro(ScalarWarping, vtkTypeBool);
194   vtkBooleanMacro(ScalarWarping, vtkTypeBool);
195   ///@}
196 
197   ///@{
198   /**
199    * Turn on/off the generation of elliptical splats. If normal warping is
200    * on, then the input normals affect the distribution of the splat. This
201    * boolean is used in combination with the Eccentricity ivar.
202    */
203   vtkSetMacro(NormalWarping, vtkTypeBool);
204   vtkGetMacro(NormalWarping, vtkTypeBool);
205   vtkBooleanMacro(NormalWarping, vtkTypeBool);
206   ///@}
207 
208   ///@{
209   /**
210    * Control the shape of elliptical splatting. Eccentricity is the ratio
211    * of the major axis (aligned along normal) to the minor (axes) aligned
212    * along other two axes. So Eccentricity > 1 creates needles with the
213    * long axis in the direction of the normal; Eccentricity<1 creates
214    * pancakes perpendicular to the normal vector.
215    */
216   vtkSetClampMacro(Eccentricity, double, 0.001, VTK_DOUBLE_MAX);
217   vtkGetMacro(Eccentricity, double);
218   ///@}
219 
220   ///@{
221   /**
222    * Specify the scalar accumulation mode. This mode expresses how scalar
223    * values are combined when splats overlap one another. The Max mode acts
224    * like a set union operation and is the most commonly used; the Min mode
225    * acts like a set intersection, and the sum is just weird (and can
226    * potentially cause accumulation overflow in extreme cases). Note that the
227    * NullValue must be set consistent with the accumulation operation.
228    */
229   vtkSetClampMacro(AccumulationMode, int, VTK_ACCUMULATION_MODE_MIN, VTK_ACCUMULATION_MODE_SUM);
230   vtkGetMacro(AccumulationMode, int);
SetAccumulationModeToMin()231   void SetAccumulationModeToMin() { this->SetAccumulationMode(VTK_ACCUMULATION_MODE_MIN); }
SetAccumulationModeToMax()232   void SetAccumulationModeToMax() { this->SetAccumulationMode(VTK_ACCUMULATION_MODE_MAX); }
SetAccumulationModeToSum()233   void SetAccumulationModeToSum() { this->SetAccumulationMode(VTK_ACCUMULATION_MODE_SUM); }
234   const char* GetAccumulationModeAsString();
235   ///@}
236 
237   ///@{
238   /**
239    * Set what type of scalar data this source should generate. Only double
240    * and float types are supported currently due to precision requirements
241    * during accumulation. By default, float scalars are produced.
242    */
243   vtkSetMacro(OutputScalarType, int);
244   vtkGetMacro(OutputScalarType, int);
SetOutputScalarTypeToDouble()245   void SetOutputScalarTypeToDouble() { this->SetOutputScalarType(VTK_DOUBLE); }
SetOutputScalarTypeToFloat()246   void SetOutputScalarTypeToFloat() { this->SetOutputScalarType(VTK_FLOAT); }
247   ///@}
248 
249   ///@{
250   /**
251    * Turn on/off the capping of the outer boundary of the volume
252    * to a specified cap value. This can be used to close surfaces
253    * (after iso-surfacing) and create other effects.
254    */
255   vtkSetMacro(Capping, vtkTypeBool);
256   vtkGetMacro(Capping, vtkTypeBool);
257   vtkBooleanMacro(Capping, vtkTypeBool);
258   ///@}
259 
260   ///@{
261   /**
262    * Specify the cap value to use. (This instance variable only has effect
263    * if the ivar Capping is on.)
264    */
265   vtkSetMacro(CapValue, double);
266   vtkGetMacro(CapValue, double);
267   ///@}
268 
269   ///@{
270   /**
271    * Set the Null value for output points not receiving a contribution from
272    * the input points. (This is the initial value of the voxel samples, by
273    * default it is set to zero.) Note that the value should be consistent
274    * with the output dataset type. The NullValue also provides the initial
275    * value on which the accumulations process operates.
276    */
277   vtkSetMacro(NullValue, double);
278   vtkGetMacro(NullValue, double);
279   ///@}
280 
281   ///@{
282   /**
283    * Set/Get the maximum dimension of the checkerboard (i.e., the number of
284    * squares in any of the i, j, or k directions). This number also impacts
285    * the granularity of the parallel threading (since each checker square is
286    * processed separaely). Because of the internal addressing, the maximum
287    * dimension is limited to 255 (maximum value of an unsigned char).
288    */
289   vtkSetClampMacro(MaximumDimension, int, 0, 255);
290   vtkGetMacro(MaximumDimension, int);
291   ///@}
292 
293   ///@{
294   /**
295    * Set/get the crossover point expressed in footprint size where the
296    * splatting operation is parallelized (through vtkSMPTools). By default
297    * the parallel crossover point is for splat footprints of size two or
298    * greater (i.e., at footprint=2 then splat is 5x5x5 and parallel splatting
299    * occurs). This is really meant for experimental purposes.
300    */
301   vtkSetClampMacro(ParallelSplatCrossover, int, 0, 255);
302   vtkGetMacro(ParallelSplatCrossover, int);
303   ///@}
304 
305   /**
306    * Compute the size of the sample bounding box automatically from the
307    * input data. This is an internal helper function.
308    */
309   void ComputeModelBounds(vtkDataSet* input, vtkImageData* output, vtkInformation* outInfo);
310 
311 protected:
312   vtkCheckerboardSplatter();
313   ~vtkCheckerboardSplatter() override = default;
314 
315   int FillInputPortInformation(int port, vtkInformation* info) override;
316   int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
317   int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override;
318 
319   int OutputScalarType;           // the type of output scalars
320   int SampleDimensions[3];        // dimensions of volume to splat into
321   double Radius;                  // Radius factor in the Gaussian exponential function
322   int Footprint;                  // maximum distance splat propagates (in voxels 0->Dim)
323   double ExponentFactor;          // scale exponent of gaussian function
324   double ModelBounds[6];          // bounding box of splatting dimensions
325   double Origin[3], Spacing[3];   // output geometry
326   vtkTypeBool NormalWarping;      // on/off warping of splat via normal
327   double Eccentricity;            // elliptic distortion due to normals
328   vtkTypeBool ScalarWarping;      // on/off warping of splat via scalar
329   double ScaleFactor;             // splat size influenced by scale factor
330   vtkTypeBool Capping;            // Cap side of volume to close surfaces
331   double CapValue;                // value to use for capping
332   int AccumulationMode;           // how to combine scalar values
333   double NullValue;               // initial value of voxels
334   unsigned char MaximumDimension; // max resolution of checkerboard
335   int ParallelSplatCrossover;     // the point at which parallel splatting occurs
336 
337 private:
338   vtkCheckerboardSplatter(const vtkCheckerboardSplatter&) = delete;
339   void operator=(const vtkCheckerboardSplatter&) = delete;
340 };
341 
342 #endif
343