SurfaceRemeshing.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2016 Imperial College London
5  * Copyright 2013-2016 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_SurfaceRemeshing_H
21 #define MIRTK_SurfaceRemeshing_H
22 
23 #include "mirtk/SurfaceFilter.h"
24 
25 #include "mirtk/Point.h"
26 #include "mirtk/OrderedSet.h"
27 #include "mirtk/PointSetExport.h"
28 
29 #include "vtkPriorityQueue.h"
30 
31 class vtkCellArray;
32 class vtkIdList;
33 class vtkPoints;
34 
35 
36 namespace mirtk {
37 
38 
39 class Transformation;
40 
41 
42 /**
43  * Adaptive local remeshing of triangulated surface mesh
44  *
45  * Park et al., A non-self-intersecting adaptive deformable surface for
46  * complex boundary extraction from volumetric images, 25, 421–440 (2001).
47  *
48  * \todo Interpolate cell data during remeshing. The current implementation only
49  * preserves and interpolates point data arrays. Cell attributes are discarded.
50  */
52 {
53  mirtkObjectMacro(SurfaceRemeshing);
54 
55  // ---------------------------------------------------------------------------
56  // Types
57 
58 public:
59 
60  /// Enumeration of cell order in which melting is performed
61  enum Order
62  {
63  INDEX, ///< Cell index
64  AREA, ///< Cell area
65  SHORTEST_EDGE ///< Length of shortest edge
66  };
67 
68  /// Name of minimum edge length point data array
69  MIRTK_PointSet_EXPORT static const char * const MIN_EDGE_LENGTH;
70 
71  /// Name of maximum edge length point data array
72  MIRTK_PointSet_EXPORT static const char * const MAX_EDGE_LENGTH;
73 
74  // ---------------------------------------------------------------------------
75  // Attributes
76 
77 protected:
78 
79  /// Surface point mask, only melting operations which do not modify points
80  /// or edges connecting two such points that have a zero mask value
81  /// are allowed when this mask is specified
82  mirtkPublicAttributeMacro(vtkSmartPointer<vtkDataArray>, PointMask);
83 
84  /// Surface cell mask, only melting operations which do not modify cells
85  /// that have a zero mask value are allowed when this mask is specified
86  mirtkPublicAttributeMacro(vtkSmartPointer<vtkDataArray>, CellMask);
87 
88  /// Shallow copy of input surface with additional internal point data
89  mirtkAttributeMacro(vtkSmartPointer<vtkPolyData>, Surface);
90 
91  /// Combined surface point mask
92  mirtkAttributeMacro(vtkSmartPointer<vtkDataArray>, Mask);
93 
94  /// Optional input transformation used to determine edge length and triangle area
96 
97  /// Indices of point data arrays with categorical data that requires
98  /// a voting scheme instead of arithmetic averaging of data values
99  mirtkAttributeMacro(OrderedSet<int>, CategoricalPointDataIndices);
100  Array<double> _CategoricalPointDataCache;
101 
102  /// Minimum angle between edge end point normals to consider the edge as
103  /// an important feature edge which is excluded from any melting operation.
104  mirtkPublicAttributeMacro(double, MinFeatureAngle);
105  double _MinFeatureAngleCos; ///< 1 - cos(_MinFeatureAngle)
106 
107  /// If edge end point normals make up an angle greater than this maximum
108  /// feature angle, the respective edge is subdivided even if the edge is
109  /// shorter than the _MaxEdgeLength if both edges resulting from splitting
110  /// the edge in half are at least _MinEdgeLength long.
111  mirtkPublicAttributeMacro(double, MaxFeatureAngle);
112  double _MaxFeatureAngleCos; ///< 1 - cos(_MaxFeatureAngle)
113 
114  /// Minimum edge length
116  double _MinEdgeLengthSquared;
117 
118  /// Maximum edge length
120  double _MaxEdgeLengthSquared;
121 
122  /// Point data array used to adapt the edge length range for each node
123  ///
124  /// The scalar point data values are rescaled linearly to [0, 1] after
125  /// clamping the point data range to the 5th and 95th percentile range.
126  /// The rescaled value is then plugged into a logistic function which
127  /// determines the linear interpolation weights of the global
128  /// _MinEdgeLength and _MaxEdgeLength range. This obtains an individual
129  /// edge length range for each point. The desired edge length range of a
130  /// given edge is then the mean of the minimum/maximum edge length of the
131  /// two end points of the edge.
132  mirtkPublicAttributeMacro(vtkSmartPointer<vtkDataArray>, AdaptiveEdgeLengthArray);
133 
134  /// Per-cell minimum edge length
135  mirtkPublicAttributeMacro(vtkSmartPointer<vtkDataArray>, MinCellEdgeLengthArray);
136 
137  /// Per-cell maximum edge length
138  mirtkPublicAttributeMacro(vtkSmartPointer<vtkDataArray>, MaxCellEdgeLengthArray);
139 
140  /// Per-node minimum edge length
141  mirtkAttributeMacro(vtkSmartPointer<vtkDataArray>, MinEdgeLengthArray);
142 
143  /// Per-node maximum edge length
144  mirtkAttributeMacro(vtkSmartPointer<vtkDataArray>, MaxEdgeLengthArray);
145 
146  /// Define in which order to process the cells in the melting pass
147  mirtkPublicAttributeMacro(Order, MeltingOrder);
148 
149  /// Priority queue used by melting pass
150  mirtkAttributeMacro(vtkSmartPointer<vtkPriorityQueue>, MeltingQueue);
151 
152  /// Whether to melt nodes with connectivity three by merging the adjacent triangles
153  mirtkPublicAttributeMacro(bool, MeltNodes);
154 
155  /// Whether to melt entire triangles if all three edges are below threshold
156  mirtkPublicAttributeMacro(bool, MeltTriangles);
157 
158  /// Invert pairs of triangles which share an edge that is longer than the maximum
159  mirtkPublicAttributeMacro(bool, InvertTrianglesSharingOneLongEdge);
160 
161  /// Invert edge of two triangles when it increases the minimum height
162  mirtkPublicAttributeMacro(bool, InvertTrianglesToIncreaseMinHeight);
163 
164  /// Whether to allow bisection of boundary edges
165  mirtkPublicAttributeMacro(bool, BisectBoundaryEdges);
166 
167  /// Number of melted nodes with connectivity 3
168  mirtkReadOnlyAttributeMacro(int, NumberOfMeltedNodes);
169 
170  /// Number of melted edges
171  mirtkReadOnlyAttributeMacro(int, NumberOfMeltedEdges);
172 
173  /// Number of melted triangles
174  mirtkReadOnlyAttributeMacro(int, NumberOfMeltedCells);
175 
176  /// Number of edge inversions
177  mirtkReadOnlyAttributeMacro(int, NumberOfInversions);
178 
179  /// Number of bisections
180  mirtkReadOnlyAttributeMacro(int, NumberOfBisections);
181 
182  /// Number of trisections
183  mirtkReadOnlyAttributeMacro(int, NumberOfTrisections);
184 
185  /// Number of quadsections
186  mirtkReadOnlyAttributeMacro(int, NumberOfQuadsections);
187 
188  /// Copy attributes of this class from another instance
189  void CopyAttributes(const SurfaceRemeshing &);
190 
191 public:
192 
193  /// Number of melting operations
194  int NumberOfMeltings() const;
195 
196  /// Number of subdivision operations
197  int NumberOfSubdivisions() const;
198 
199  /// Number of local remeshing operations
200  int NumberOfChanges() const;
201 
202  // ---------------------------------------------------------------------------
203  // Construction/Destruction
204 
205  /// Default constructor
207 
208  /// Copy constructor
210 
211  /// Assignment operator
213 
214  /// Destructor
215  virtual ~SurfaceRemeshing();
216 
217  // ---------------------------------------------------------------------------
218  // Inline auxiliary functions
219 
220 private:
221 
222  /// Get (transformed) surface point
223  void GetPoint(vtkIdType, double [3]) const;
224 
225  /// Get (transformed) surface point normal
226  void GetNormal(vtkIdType, double [3]) const;
227 
228  /// Calculate area of (transformed) triangle
229  double ComputeArea(vtkIdType) const;
230 
231  /// Get (non-transformed) edge middle point
232  void MiddlePoint(vtkIdType, vtkIdType, double [3]) const;
233 
234  /// Get (non-transformed) edge middle point
235  Point MiddlePoint(vtkIdType, vtkIdType) const;
236 
237  /// Get node connectivity
238  int NodeConnectivity(vtkIdType) const;
239 
240  /// Mark cell as deleted and remove all references to it
241  void DeleteCell(vtkIdType);
242 
243  /// Mark cells as deleted and remove all references to them
244  void DeleteCells(vtkIdList *);
245 
246  /// Replace cell point, also updating point to cell references
247  void ReplaceCellPoint(vtkIdType, vtkIdType, vtkIdType);
248 
249  /// Get neighboring triangle sharing an edge with specified triangle
250  vtkIdType GetCellEdgeNeighbor(vtkIdType, vtkIdType, vtkIdType) const;
251 
252  /// Check if point is on surface boundary
253  bool IsBoundaryPoint(vtkIdType) const;
254 
255  /// Check if edge is on surface boundary
256  bool IsBoundaryEdge(vtkIdType, vtkIdType) const;
257 
258  /// Check if cell is at surface boundary
259  bool IsBoundaryCell(vtkIdType) const;
260 
261  /// Get other vertices of cell edge neighbors
262  void GetCellPointNeighbors(vtkIdType, vtkIdType, vtkIdList *) const;
263 
264  /// Check connectivity of edge neighbors
265  ///
266  /// If other vertex of edge neighbor triangle has connectivity three,
267  /// the three triangles adjacent to it are replaced by the union of these
268  /// triangle and the melting operation can be performed. Otherwise, if
269  /// more than one node with connectivity three is found which is adjacent
270  /// to the edge corners, melting the (triangle) edge would cause degeneration
271  /// of adjacent triangles.
272  ///
273  /// @return ID of other vertex of edge neighbor or -1 if not unique or if
274  /// its connectivity prohibits a melting operation.
275  vtkIdType GetCellEdgeNeighborPoint(vtkIdType, vtkIdType, vtkIdType, bool = false);
276 
277  /// Get priority of cell during melting pass
278  double MeltingPriority(vtkIdType) const;
279 
280  /// Interpolate point attributes when subdividing edge
281  void InterpolatePointData(vtkPointData *, vtkIdType, vtkIdType, vtkIdType);
282 
283  /// Interpolate point attributes when melting triangle
284  void InterpolatePointData(vtkPointData *, vtkIdType, vtkIdList *, double *);
285 
286  /// Get squared minimum length for specified edge
287  double SquaredMinEdgeLength(vtkIdType, vtkIdType) const;
288 
289  /// Get squared maximum length for specified edge
290  double SquaredMaxEdgeLength(vtkIdType, vtkIdType) const;
291 
292  // ---------------------------------------------------------------------------
293  // Local remeshing operations
294 protected:
295 
296  /// Collapse single short edge of two adjacent triangles
297  bool MeltEdge(vtkIdType, vtkIdType, vtkIdType, vtkIdList *);
298 
299  /// Collapse entire triangle with more than one too short edges
300  bool MeltTriangle(vtkIdType, vtkIdList *);
301 
302  /// Melt edges or triangle if one or more edge is too short
303  void MeltingOfCells();
304 
305  /// Replace triangles adjacent to node with connectivity three by single triangle
306  void MeltingOfNodes();
307 
308  /// Invert triangles which share one too long edge
310 
311  /// Invert triangles when minimum height over this edge increases
313 
314  /// Bisect triangle
315  void Bisect(vtkIdType, vtkIdType, vtkIdType, vtkIdType, vtkPolyData *);
316 
317  /// Trisect triangle
318  void Trisect(vtkIdType, vtkIdType, vtkIdType, vtkIdType, vtkPolyData *);
319 
320  /// Quadsect triangle
321  void Quadsect(vtkIdType, vtkIdType, vtkIdType, vtkIdType, vtkPolyData *);
322 
323  // ---------------------------------------------------------------------------
324  // Execution
325 
326  /// Initialize filter after input and parameters are set
327  virtual void Initialize();
328 
329  /// Initialize point mask
330  void InitializeMask();
331 
332  /// Initialize edge length range for each node
334 
335  /// Perform local remeshing passes
336  virtual void Execute();
337 
338  /// Perform first pass: melt edges or triangles if one or more edges are too short
339  void Melting();
340 
341  /// Perform second pass: inversion of triangles sharing a long edge
342  void Inversion();
343 
344  /// Perform third pass: subdivide triangles with remaining long edges
345  void Subdivision();
346 
347  /// Finalize filter execution
348  virtual void Finalize();
349 
350  // ---------------------------------------------------------------------------
351  // Alternative VTK-like API
352 
353 public:
354 
355  /// Enable/disable melting of nodes with connectivity three
356  mirtkOnOffMacro(MeltNodes);
357 
358  /// Enable/disable melting of triangles when all edges are too short
359  mirtkOnOffMacro(MeltTriangles);
360 
361  /// Enable/disable inversion of triangles which share one long edge
362  mirtkOnOffMacro(InvertTrianglesSharingOneLongEdge);
363 
364  /// Enable/disable inversion of triangles when it increases minimum height
365  mirtkOnOffMacro(InvertTrianglesToIncreaseMinHeight);
366 
367  /// Enable/disable bisection of boundary edges
368  mirtkOnOffMacro(BisectBoundaryEdges);
369 
370 };
371 
372 ////////////////////////////////////////////////////////////////////////////////
373 // Inline definitions
374 ////////////////////////////////////////////////////////////////////////////////
375 
376 // -----------------------------------------------------------------------------
378 {
379  return _NumberOfMeltedNodes + _NumberOfMeltedEdges + _NumberOfMeltedCells;
380 }
381 
382 // -----------------------------------------------------------------------------
384 {
385  return _NumberOfBisections + _NumberOfTrisections + _NumberOfQuadsections;
386 }
387 
388 // -----------------------------------------------------------------------------
390 {
391  return NumberOfMeltings() + NumberOfInversions() + NumberOfSubdivisions();
392 }
393 
394 } // namespace mirtk
395 
396 #endif // MIRTK_SurfaceRemeshing_H
int NumberOfChanges() const
Number of local remeshing operations.
double MinEdgeLength(vtkSmartPointer< vtkPoints > points, const EdgeTable &edgeTable)
int NumberOfMeltings() const
Number of melting operations.
void MeltingOfNodes()
Replace triangles adjacent to node with connectivity three by single triangle.
mirtkAttributeMacro(vtkSmartPointer< vtkPolyData >, Surface)
Shallow copy of input surface with additional internal point data.
void InversionOfTrianglesToIncreaseMinHeight()
Invert triangles when minimum height over this edge increases.
void Trisect(vtkIdType, vtkIdType, vtkIdType, vtkIdType, vtkPolyData *)
Trisect triangle.
virtual ~SurfaceRemeshing()
Destructor.
void Melting()
Perform first pass: melt edges or triangles if one or more edges are too short.
double _MinFeatureAngleCos
1 - cos(_MinFeatureAngle)
void CopyAttributes(const SurfaceRemeshing &)
Copy attributes of this class from another instance.
void InitializeEdgeLengthRange()
Initialize edge length range for each node.
void InitializeMask()
Initialize point mask.
void Quadsect(vtkIdType, vtkIdType, vtkIdType, vtkIdType, vtkPolyData *)
Quadsect triangle.
void Subdivision()
Perform third pass: subdivide triangles with remaining long edges.
Definition: IOConfig.h:41
void Inversion()
Perform second pass: inversion of triangles sharing a long edge.
mirtkPublicAggregateMacro(const class Transformation, Transformation)
Optional input transformation used to determine edge length and triangle area.
double _MaxFeatureAngleCos
1 - cos(_MaxFeatureAngle)
void Bisect(vtkIdType, vtkIdType, vtkIdType, vtkIdType, vtkPolyData *)
Bisect triangle.
bool MeltEdge(vtkIdType, vtkIdType, vtkIdType, vtkIdList *)
Collapse single short edge of two adjacent triangles.
int NumberOfSubdivisions() const
Number of subdivision operations.
mirtkPublicAttributeMacro(vtkSmartPointer< vtkDataArray >, PointMask)
void MeltingOfCells()
Melt edges or triangle if one or more edge is too short.
mirtkOnOffMacro(MeltNodes)
Enable/disable melting of nodes with connectivity three.
virtual void Execute()
Perform local remeshing passes.
SurfaceRemeshing()
Default constructor.
void InversionOfTrianglesSharingOneLongEdge()
Invert triangles which share one too long edge.
static MIRTK_PointSet_EXPORT const char *const MAX_EDGE_LENGTH
Name of maximum edge length point data array.
double MaxEdgeLength(vtkSmartPointer< vtkPoints > points, const EdgeTable &edgeTable)
virtual void Initialize()
Initialize filter after input and parameters are set.
mirtkReadOnlyAttributeMacro(int, NumberOfMeltedNodes)
Number of melted nodes with connectivity 3.
Order
Enumeration of cell order in which melting is performed.
bool MeltTriangle(vtkIdType, vtkIdList *)
Collapse entire triangle with more than one too short edges.
virtual void Finalize()
Finalize filter execution.
static MIRTK_PointSet_EXPORT const char *const MIN_EDGE_LENGTH
Name of minimum edge length point data array.
SurfaceRemeshing & operator=(const SurfaceRemeshing &)
Assignment operator.