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