1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkMultiObjectMassProperties.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   vtkMultiObjectMassProperties
17  * @brief   compute volume and area of objects in a polygonal mesh
18  *
19  * vtkMultiObjectMassProperties estimates the volume and the surface area of
20  * a polygonal mesh. Multiple, valid closed objects may be represented, and
21  * each object is assumed to be defined as a polyhedron defined by polygonal
22  * faces (i.e., the faces do not have to be triangles). The algorithm
23  * computes the total volume and area, as well as per object values which are
24  * placed in data arrays. Note that an object is valid only if it is manifold
25  * and closed (i.e., each edge is used exactly two times by two different
26  * polygons). Invalid objects are processed but may produce inaccurate
27  * results. Inconsistent polygon ordering is also allowed.
28  *
29  * The algorithm is composed of two basic parts. First a connected traversal
30  * is performed to identify objects, detect whether the objects are valid,
31  * and ensure that the composing polygons are ordered consistently. Next, in
32  * threaded execution, a parallel process of computing areas and volumes is
33  * performed. It is possible to skip the first part if the SkipValidityCheck
34  * is enabled, AND a vtkIdTypeArray data array named "ObjectIds" is
35  * associated with the polygon input (i.e., cell data) that enumerates which
36  * object every polygon belongs to (i.e., indictaes that it is a boundary
37  * polygon of a specified object).
38  *
39  * The algorithm implemented here is inspired by this paper:
40  * http://chenlab.ece.cornell.edu/Publication/Cha/icip01_Cha.pdf. Also see
41  * the Stackflow entry: https://stackoverflow.com/questions/1406029/
42  * how-to-calculate-the-volume-of-a-3d-mesh-object-the-surface-of-which-is-made-up.
43  * The general assumption here is that the model is of closed surface.  Also,
44  * this approach requires triangulating the polygons so triangle meshes are
45  * processed much faster. Finally, the volume and area calculations are done
46  * in paraellel (threaded) after a connectivity pass is made (used to
47  * identify objects and verify that they are manifold and closed).
48  *
49  * The output contains six additional data arrays. The arrays
50  * "ObjectValidity", "ObjectVolumes" and "ObjectAreas" are placed in the
51  * output field data.  These are arrays which indicate which objects are
52  * valid; the volume of each object; and the surface area of each
53  * object. Three additional arrays are placed in the output cell data, and
54  * indicate, on a per polygons basis, which object the polygon bounds
55  * "ObjectIds"; the polygon area "Areas"; and the contribution of volume
56  * "Volumes".  Additionally, the TotalVolume and TotalArea is available after
57  * the filter executes (i.e., the sum of the ObjectVolumes and ObjectAreas
58  * arrays).
59  *
60  * Per object validity, as mentioned previously, is reported in the
61  * ObjectValidity array. However another variable, AllValid, is set after
62  * filter execution which indicates whether all objects are valid (!=0) or
63  * not. This information can be used as a shortcut in case you want to skip
64  * validity checking on an object-by-object basis.
65  *
66  * @warning
67  * This filter operates on the polygonal data contained in the input
68  * vtkPolyData. Other types (verts, lines, triangle strips) are ignored and
69  * not passed to the output. The input polys and points, as well as
70  * associated point and cell data, are passed through to the output.
71  *
72  * @warning
73  * This filter is similar to vtkMassProperties. However vtkMassProperties
74  * operates on triangle meshes and assumes only a single, closed, properly
75  * oriented surface is represented. vtkMultiObjectMassProperties performs
76  * additional topological and connectivity operations to identify separate
77  * objects, and confirms that they are manifold. It also accommodates
78  * inconsistent ordering.
79  *
80  * @warning
81  * This class has been threaded with vtkSMPTools. Using TBB or other
82  * non-sequential type (set in the CMake variable
83  * VTK_SMP_IMPLEMENTATION_TYPE) may improve performance significantly.
84  *
85  * @sa
86  * vtkMassProperties
87 */
88 
89 #ifndef vtkMultiObjectMassProperties_h
90 #define vtkMultiObjectMassProperties_h
91 
92 #include "vtkFiltersCoreModule.h" // For export macro
93 #include "vtkPolyDataAlgorithm.h"
94 
95 class vtkDoubleArray;
96 class vtkUnsignedCharArray;
97 class vtkIdTypeArray;
98 
99 class VTKFILTERSCORE_EXPORT vtkMultiObjectMassProperties : public vtkPolyDataAlgorithm
100 {
101 public:
102   //@{
103   /**
104    * Standard methods for construction, type and printing.
105    */
106   static vtkMultiObjectMassProperties *New();
107   vtkTypeMacro(vtkMultiObjectMassProperties,vtkPolyDataAlgorithm);
108   void PrintSelf(ostream& os, vtkIndent indent) override;
109   //@}
110 
111   //@{
112   /**
113    * Indicate whether to skip the validity check (the first part of the
114    * algorithm). By default this is off; however even if enabled validity
115    * skipping will only occur if a vtkIdTypeArray named "ObjectIds" is also
116    * provided on input to the filter.
117    */
118   vtkSetMacro(SkipValidityCheck,vtkTypeBool);
119   vtkGetMacro(SkipValidityCheck,vtkTypeBool);
120   vtkBooleanMacro(SkipValidityCheck,vtkTypeBool);
121   //@}
122 
123   /**
124    * Return the number of objects identified. This is valid only after the
125    * filter executes. Check the ObjectValidity array which indicates which of
126    * these identified objects are valid. Invalid objects may have incorrect
127    * volume and area values.
128    */
GetNumberOfObjects()129   vtkIdType GetNumberOfObjects()
130     {return this->NumberOfObjects;}
131 
132   /**
133    * Return whether all objects are valid or not. This is valid only after the
134    * filter executes.
135    */
GetAllValid()136   vtkTypeBool GetAllValid()
137     {return this->AllValid;}
138 
139   /**
140    * Return the summed volume of all objects. This is valid only after the
141    * filter executes.
142    */
GetTotalVolume()143   double GetTotalVolume()
144     {return this->TotalVolume;}
145 
146   /**
147    * Return the summed area of all objects. This is valid only after the
148    * filter executes.
149    */
GetTotalArea()150   double GetTotalArea()
151     {return this->TotalArea;}
152 
153 protected:
154   vtkMultiObjectMassProperties();
155   ~vtkMultiObjectMassProperties() override;
156 
157   int RequestData(vtkInformation* request,
158                   vtkInformationVector** inputVector,
159                   vtkInformationVector* outputVector) override;
160 
161   // Data members supporting API
162   vtkTypeBool SkipValidityCheck;
163   vtkTypeBool AllValid;
164   double  TotalVolume;
165   double  TotalArea;
166 
167   // Internal data members supporting algorithm execution
168   vtkIdType NumberOfObjects; //number of objects identified
169   vtkIdTypeArray *ObjectIds; //for each input polygon, the object id that the polygon is in
170 
171   vtkUnsignedCharArray *ObjectValidity; //is it a valid object?
172   vtkDoubleArray *ObjectVolumes; //what is the object volume (if valid)?
173   vtkDoubleArray *ObjectAreas; //what is the total object area?
174 
175   vtkIdList *CellNeighbors; //avoid repetitive new/delete
176   vtkIdList *Wave; //processing wave
177   vtkIdList *Wave2;
178 
179   // Connected traversal to identify objects
180   void TraverseAndMark (vtkPolyData *output, vtkIdType *objectIds,
181                         vtkDataArray *valid, unsigned char *orient);
182 
183 private:
184   vtkMultiObjectMassProperties(const vtkMultiObjectMassProperties&) = delete;
185   void operator=(const vtkMultiObjectMassProperties&) = delete;
186 };
187 
188 #endif
189