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