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