1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 Module: vtkExtractSurface.h 5 6 Copyright (c) Kitware, Inc. 7 All rights reserved. 8 See LICENSE file 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 vtkExtractSurface 17 * @brief generate zero-crossing isosurface from 18 * truncated signed distance volume 19 * 20 * 21 * This filter extracts the zero-crossing isosurface from a truncated signed 22 * distance function TSDF. The TSDF is sampled across a volume, and is 23 * extracted using a modified version of the Flying Edges (FE) algorithm for 24 * increased speed, and to support multithreading. To use the filter, an 25 * input volume should be assigned, which may have special values indicating 26 * empty and/or unseen portions of the volume. These values are equal to +/- 27 * radius value of the signed distance function, and should be consistent 28 * with any filters used to generate the input volume (e.g., 29 * vtkSignedDistance). 30 * 31 * The Flying Edges algorithm is modified to deal with the nature of the 32 * truncated, signed distance function. Being truncated, the distance 33 * function typically is not computed throughout the volume, rather the 34 * special data values "unseen" and/or "empty" maybe assigned to distant or 35 * bordering voxels. The implications of this are that this implementation 36 * may produce non-closed, non-manifold surfaces, which is what is required 37 * to extract surfaces. 38 * 39 * More specifically, voxels may exist in one of three states: 1) within the 40 * TSDF, which extends +/-Radius from a generating geometry (typically a 41 * point cloud); 2) in the empty state, in which it is known that the surface 42 * does not exist; and 3) the unseen state, where a surface may exist but not 43 * enough information is known to be certain. Such situations arise, for 44 * example, when laser scanners generate point clouds, and the propagation of 45 * the laser beam "carves" out regions where no geometry exists (thereby 46 * defining empty space). Furthermore, areas in which the beam are occluded 47 * by geometry are known as "unseen" and the boundary between empty and 48 * unseen can be processed to produced a portion of the output isosurface 49 * (this is called hole filling). 50 * 51 * @warning 52 * This class has been threaded with vtkSMPTools. Using TBB or other 53 * non-sequential type (set in the CMake variable 54 * VTK_SMP_IMPLEMENTATION_TYPE) may improve performance significantly. 55 * 56 * @warning 57 * Empty regions are expected to have a data value 58 * -(this->Radius+FLT_EPSILON). Unseen regions are expected to have a data 59 * value (this->Radius+FLT_EPSILON). Near regions have data values d such that: 60 * -(this->Radius+FLT_EPSILON) < d (this->Radius+FLT_EPSILON). 61 * 62 * @warning 63 * <pre> 64 * Notes on the implementation: 65 * 1. This is a lightly modified version of vtkFlyingEdges3D. Some design goals 66 * included minimizing the impact on the FE algorithm, and not adding extra 67 * memory requirements. 68 * 2. It presumes an isocontour value=0.0 (the zero crossing of a signed 69 * distance function). 70 * 3. The major modifications are to the edge cases. In Flying Edges, a single 71 * byte represents the case of an edge, and within that byte only 2 bits 72 * are needed (the extra six bytes are not used). Here, these unused bytes 73 * are repurposed to represent the "state" of the edge, whether it is 74 * 1) near to the TSDF; 2) in an empty state; or 3) unseen state. 75 * 4. Since these now-used bits encode extra state information, masking and 76 * related methods are modified from FE to tease apart the edge cases from 77 * the edge state. 78 * 5. Voxels with edges marked "empty" are not processed, i.e., no output 79 * triangle primitives are generated. Depending on whether hole filling is 80 * enabled, voxels with edges marked "unseen" may not be processed either. 81 * 6. As a result of #1 and #5, and the desire to keep the implementation simple, 82 * it is possible to produce output points which are not used by any output 83 * triangle. 84 *</pre> 85 * 86 * @warning 87 * This algorithm loosely follows the most excellent paper by Curless and 88 * Levoy: "A Volumetric Method for Building Complex Models from Range 89 * Images." 90 * 91 * @warning 92 * This algorithm differs from the paper cited above in an important way. The 93 * Curless & Levoy algorithm is designed to create watertight surfaces, while this 94 * modified algorithm may not do so as the generating surface is not assumed to be 95 * closed. 96 * 97 * @sa 98 * vtkSignedDistance vtkFlyingEdges3D 99 */ 100 101 #ifndef vtkExtractSurface_h 102 #define vtkExtractSurface_h 103 104 #include "vtkContourValues.h" // Passes calls through 105 #include "vtkFiltersPointsModule.h" // For export macro 106 #include "vtkPolyDataAlgorithm.h" 107 108 class vtkImageData; 109 110 class VTKFILTERSPOINTS_EXPORT vtkExtractSurface : public vtkPolyDataAlgorithm 111 { 112 public: 113 ///@{ 114 /** 115 * Standard methods for instantiating the class, providing type information, 116 * and printing. 117 */ 118 static vtkExtractSurface* New(); 119 vtkTypeMacro(vtkExtractSurface, vtkPolyDataAlgorithm); 120 void PrintSelf(ostream& os, vtkIndent indent) override; 121 ///@} 122 123 ///@{ 124 /** 125 * Specify the radius of influence of the signed distance function. Data 126 * values (which are distances) that are greater than the radius (i.e., d > 127 * Radius) are considered empty voxels; those voxel data values d < -Radius 128 * are considered unseen voxels. 129 */ 130 vtkSetClampMacro(Radius, double, 0.0, VTK_FLOAT_MAX); 131 vtkGetMacro(Radius, double); 132 ///@} 133 134 ///@{ 135 /** 136 * Enable hole filling. This generates separating surfaces between the 137 * empty and unseen portions of the volume. 138 */ 139 vtkSetMacro(HoleFilling, bool); 140 vtkGetMacro(HoleFilling, bool); 141 vtkBooleanMacro(HoleFilling, bool); 142 ///@} 143 144 ///@{ 145 /** 146 * Set/Get the computation of normals. Normal computation is fairly 147 * expensive in both time and storage. If the output data will be processed 148 * by filters that modify topology or geometry, it may be wise to turn 149 * Normals and Gradients off. 150 */ 151 vtkSetMacro(ComputeNormals, vtkTypeBool); 152 vtkGetMacro(ComputeNormals, vtkTypeBool); 153 vtkBooleanMacro(ComputeNormals, vtkTypeBool); 154 ///@} 155 156 ///@{ 157 /** 158 * Set/Get the computation of gradients. Gradient computation is fairly 159 * expensive in both time and storage. Note that if ComputeNormals is on, 160 * gradients will have to be calculated, but will not be stored in the 161 * output dataset. If the output data will be processed by filters that 162 * modify topology or geometry, it may be wise to turn Normals and 163 * Gradients off. 164 */ 165 vtkSetMacro(ComputeGradients, vtkTypeBool); 166 vtkGetMacro(ComputeGradients, vtkTypeBool); 167 vtkBooleanMacro(ComputeGradients, vtkTypeBool); 168 ///@} 169 170 protected: 171 vtkExtractSurface(); 172 ~vtkExtractSurface() override; 173 174 double Radius; 175 bool HoleFilling; 176 vtkTypeBool ComputeNormals; 177 vtkTypeBool ComputeGradients; 178 179 int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; 180 int RequestUpdateExtent(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; 181 int FillInputPortInformation(int port, vtkInformation* info) override; 182 183 private: 184 vtkExtractSurface(const vtkExtractSurface&) = delete; 185 void operator=(const vtkExtractSurface&) = delete; 186 }; 187 188 #endif 189