BoundarySegment.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2016 Imperial College London
5  * Copyright 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_BoundarySegment_H
21 #define MIRTK_BoundarySegment_H
22 
23 #include "mirtk/Object.h"
24 #include "mirtk/Array.h"
25 #include "mirtk/Vector.h"
26 #include "mirtk/Point.h"
27 #include "mirtk/UnorderedMap.h"
28 
29 #include "vtkSmartPointer.h"
30 #include "vtkPolyData.h"
31 
32 
33 namespace mirtk {
34 
35 
36 /**
37  * Closed boundary segment of surface mesh
38  *
39  * A boundary segment is a closed line strip defined by an ordered list of point
40  * indices with an edge between each consecutive pair of points. The boundary
41  * loop is closed by the edge connecting the last point with the first point.
42  * A surface mesh may have any number of boundary segments, including no boundary
43  * at all in case of a closed genus-0 surface mesh which is topologically
44  * equivalent to a sphere. This class represents a single boundary segment.
45  */
46 class BoundarySegment : public Object
47 {
48  mirtkObjectMacro(BoundarySegment);
49 
50  // ---------------------------------------------------------------------------
51  // Types
52 
53  /// Type of surface point ID to boundary segment point index map
54  typedef UnorderedMap<int, int> PointIdToIndexMap;
55 
56  // ---------------------------------------------------------------------------
57  // Attributes
58 
59  /// Surface mesh which this boundary segment belongs to
60  mirtkReadOnlyAttributeMacro(vtkSmartPointer<vtkPolyData>, Surface);
61 
62  /// IDs of boundary segment points
63  mirtkReadOnlyAttributeMacro(Array<int>, PointIds);
64 
65  /// Pre-computed map from surface point ID to boundary segment point index
66  mirtkAttributeMacro(PointIdToIndexMap, Index);
67 
68  /// Indices of selected points
69  mirtkAttributeMacro(Array<int>, Selection);
70 
71  /// Pre-computed boundary segment edge lengths
72  Vector _EdgeLengths;
73 
74  /// Length of boundary segment
75  double _Length;
76 
77  /// Copy attributes of this class from another instance
78  void CopyAttributes(const BoundarySegment &);
79 
80  // ---------------------------------------------------------------------------
81  // Construction/Destruction
82 
83 public:
84 
85  /// Default constructor
87 
88  /// Constructor
89  ///
90  /// \param[in] surface Surface mesh.
91  /// \param[in] ptIds Ordered list of IDs of surface points making up this
92  /// boundary segment.
93  BoundarySegment(vtkPolyData *surface, const Array<int> &ptIds);
94 
95  /// Copy constructor
97 
98  /// Assignment operator
100 
101  /// Destructor
102  virtual ~BoundarySegment();
103 
104  // ---------------------------------------------------------------------------
105  // Initialization
106 
107  /// Pre-compute map of surface point ID to boundary segment point index
108  void InitializeIndex();
109 
110  // Pre-compute edge lengths and total length
111  void InitializeLengths();
112 
113  /// Compute edge lengths
114  Vector ComputeEdgeLengths() const;
115 
116  /// Compute length of boundary segment
117  double ComputeLength() const;
118 
119  // ---------------------------------------------------------------------------
120  // Boundary points
121 
122  /// Number of boundary segment points
123  int NumberOfPoints() const;
124 
125  /// Get boundary segment point index in range [0, N)
126  int IndexModuloNumberOfPoints(int i) const;
127 
128  /// Get surface point ID of i-th boundary segment point
129  ///
130  /// \param[in] i Index of boundary segment point.
131  ///
132  /// \returns Surface point ID of i-th boundary segment point.
133  int PointId(int i) const;
134 
135  /// Get boundary segment point coordinates
136  ///
137  /// \param[in] i Index of boundary segment point.
138  /// \param[out] p Coordinates of i-th boundary segment point.
139  void GetPoint(int i, double p[3]) const;
140 
141  /// Set boundary segment point coordinates
142  ///
143  /// \param[in] i Index of boundary segment point.
144  /// \param[in] p New coordinates of i-th boundary segment point.
145  void SetPoint(int i, const double p[3]);
146 
147  /// Get boundary segment point coordinates
148  ///
149  /// \param[in] i Index of boundary segment point.
150  ///
151  /// \returns Coordinates of i-th boundary segment point.
152  class Point Point(int i) const;
153 
154  /// Set boundary segment point coordinates
155  ///
156  /// \param[in] i Index of boundary segment point.
157  /// \param[in] p New coordinates of i-th boundary segment point.
158  void Point(int i, const class Point &p);
159 
160  /// Find surface point in boundary segment
161  ///
162  /// \param[in] ptId Surface point ID.
163  ///
164  /// \returns Boundary segment point index or -1 if segment does not contain this point.
165  int Find(int ptId) const;
166 
167  /// Find closest boundary point
168  ///
169  /// \param[in] x Point coordinates.
170  /// \param[in] dist2 Squared distance of closest boundary point.
171  ///
172  /// \returns Index of closest boundary segment point.
173  int FindClosestPoint(const class Point &x, double *dist2 = nullptr) const;
174 
175  /// Whether this boundary segment contains a given surface point
176  ///
177  /// \param[in] ptId Surface point ID.
178  ///
179  /// \returns Whether surface point ID is part of this boundary segment.
180  bool Contains(int ptId) const;
181 
182  // ---------------------------------------------------------------------------
183  // Boundary edges
184 
185  /// Get total length of boundary segment
186  double Length() const;
187 
188  /// Get lengths of boundary segment edges
189  Vector EdgeLengths() const;
190 
191  /// Length of boundary segment edge
192  ///
193  /// \param[in] i Index of first boundary segment point.
194  /// \param[in] di Index increment +1 or -1, i.e., traversal direction.
195  ///
196  /// \returns Boundary segment edge lengths.
197  double EdgeLength(int i, int di = +1) const;
198 
199  // ---------------------------------------------------------------------------
200  // Selected points
201 
202  /// Reserve space for n selected points
203  ///
204  /// \param[in] n Number of points to be selected.
205  void ReserveSelection(int n);
206 
207  /// Remove the i-th selected point
208  ///
209  /// \param[in] i Selected point index.
210  void RemoveSelection(int i);
211 
212  /// Deselect all points
213  void ClearSelection();
214 
215  /// Add i-th boundary segment point to selection
216  ///
217  /// \param[in] i Boundary segment point index.
218  void SelectPoint(int i);
219 
220  /// Remove i-th boundary segment point from selection
221  ///
222  /// \param[in] i Boundary segment point index.
223  void DeselectPoint(int i);
224 
225  /// Number of selected curve points
226  int NumberOfSelectedPoints() const;
227 
228  /// Get boundary segment point index of i-th selected boundary point
229  ///
230  /// \param[in] i Index of selected point.
231  ///
232  /// \return Index of corresponding boundary segment point.
233  int SelectedPointIndex(int i) const;
234 
235  /// Get surface point ID of i-th selected boundary point
236  ///
237  /// \param[in] i Index of selected point.
238  ///
239  /// \return Index of corresponding surface point.
240  int SelectedPointId(int i) const;
241 
242  /// Get selected boundary segment point coordinates
243  ///
244  /// \param[in] i Index of selected boundary segment point.
245  /// \param[out] p Coordinates of i-th selected boundary segment point.
246  void GetSelectedPoint(int i, double p[3]) const;
247 
248  /// Get selected boundary segment point coordinates
249  ///
250  /// \param[in] i Index of selected boundary segment point.
251  ///
252  /// \returns Coordinates of i-th selected boundary segment point.
253  class Point SelectedPoint(int i) const;
254 
255  /// Check if boundary segment point is selected
256  ///
257  /// \param[in] i Index of boundary segment point.
258  /// The index is taken modulo the number of boundary
259  /// points and negative values count from the end of
260  /// the list of boundary points.
261  ///
262  /// \return Whether boundary segment point is selected.
263  bool IsSelected(int i) const;
264 
265 };
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 // Inline definitions
269 ////////////////////////////////////////////////////////////////////////////////
270 
271 // =============================================================================
272 // Initialization
273 // =============================================================================
274 
275 // -----------------------------------------------------------------------------
276 inline double BoundarySegment::ComputeLength() const
277 {
278  if (_EdgeLengths) return _EdgeLengths.Sum();
279  return ComputeEdgeLengths().Sum();
280 }
281 
282 // =============================================================================
283 // Boundary points
284 // =============================================================================
285 
286 // -----------------------------------------------------------------------------
288 {
289  return static_cast<int>(_PointIds.size());
290 }
291 
292 // -----------------------------------------------------------------------------
294 {
295  const int n = NumberOfPoints();
296  if (i < 0) i = (i + 1) % n + n - 1;
297  else if (i >= n) i = i % n;
298  return i;
299 }
300 
301 // -----------------------------------------------------------------------------
302 inline int BoundarySegment::PointId(int i) const
303 {
305  return _PointIds[i];
306 }
307 
308 // -----------------------------------------------------------------------------
309 inline void BoundarySegment::GetPoint(int i, double p[3]) const
310 {
312  _Surface->GetPoint(static_cast<vtkIdType>(PointId(i)), p);
313 }
314 
315 // -----------------------------------------------------------------------------
316 inline void BoundarySegment::SetPoint(int i, const double p[3])
317 {
319  _Surface->GetPoints()->SetPoint(static_cast<vtkIdType>(PointId(i)), const_cast<double *>(p));
320 }
321 
322 // -----------------------------------------------------------------------------
323 inline Point BoundarySegment::Point(int i) const
324 {
325  double p[3];
326  GetPoint(i, p);
327  return p;
328 }
329 
330 // -----------------------------------------------------------------------------
331 inline void BoundarySegment::Point(int i, const class Point &p)
332 {
333  SetPoint(i, p);
334 }
335 
336 // -----------------------------------------------------------------------------
337 inline bool BoundarySegment::Contains(int ptId) const
338 {
339  return Find(ptId) != -1;
340 }
341 
342 // =============================================================================
343 // Boundary edges
344 // =============================================================================
345 
346 // -----------------------------------------------------------------------------
347 inline double BoundarySegment::Length() const
348 {
349  if (_Length > 0.) return _Length;
350  return ComputeLength();
351 }
352 
353 // -----------------------------------------------------------------------------
355 {
356  if (_EdgeLengths) return _EdgeLengths;
357  return ComputeEdgeLengths();
358 }
359 
360 // -----------------------------------------------------------------------------
361 inline double BoundarySegment::EdgeLength(int i, int di) const
362 {
363  if (_EdgeLengths) {
364  return _EdgeLengths(IndexModuloNumberOfPoints(di < 0 ? i-1 : i));
365  } else {
366  return Point(i).Distance(Point(i + di));
367  }
368 }
369 
370 // =============================================================================
371 // Selected points
372 // =============================================================================
373 
374 // -----------------------------------------------------------------------------
376 {
377  return static_cast<int>(_Selection.size());
378 }
379 
380 // -----------------------------------------------------------------------------
381 inline int BoundarySegment::SelectedPointIndex(int i) const
382 {
383  return _Selection[i];
384 }
385 
386 // -----------------------------------------------------------------------------
387 inline int BoundarySegment::SelectedPointId(int i) const
388 {
389  return _PointIds[_Selection[i]];
390 }
391 
392 // -----------------------------------------------------------------------------
393 inline void BoundarySegment::GetSelectedPoint(int i, double p[3]) const
394 {
395  GetPoint(_Selection[i], p);
396 }
397 
398 // -----------------------------------------------------------------------------
400 {
401  return Point(_Selection[i]);
402 }
403 
404 // -----------------------------------------------------------------------------
405 inline bool BoundarySegment::IsSelected(int i) const
406 {
407  for (auto it = _Selection.begin(); it != _Selection.end(); ++it) {
408  if (*it == i) return true;
409  }
410  return false;
411 }
412 
413 
414 } // namespace mirtk
415 
416 #endif // MIRTK_BoundarySegment_H
double Length() const
Get total length of boundary segment.
class Point Point(int i) const
class Point SelectedPoint(int i) const
void ReserveSelection(int n)
double Sum() const
Returns sum of a vector components.
Definition: Vector.h:772
void ClearSelection()
Deselect all points.
Vector ComputeEdgeLengths() const
Compute edge lengths.
Definition: IOConfig.h:41
void GetSelectedPoint(int i, double p[3]) const
int IndexModuloNumberOfPoints(int i) const
Get boundary segment point index in range [0, N)
bool Contains(int ptId) const
BoundarySegment()
Default constructor.
void SetPoint(int i, const double p[3])
virtual ~BoundarySegment()
Destructor.
int NumberOfSelectedPoints() const
Number of selected curve points.
void GetPoint(int i, double p[3]) const
BoundarySegment & operator=(const BoundarySegment &)
Assignment operator.
int SelectedPointId(int i) const
int FindClosestPoint(const class Point &x, double *dist2=nullptr) const
int Find(int ptId) const
void RemoveSelection(int i)
double EdgeLength(int i, int di=+1) const
int SelectedPointIndex(int i) const
void InitializeIndex()
Pre-compute map of surface point ID to boundary segment point index.
double ComputeLength() const
Compute length of boundary segment.
double Distance() const
Distance from origin.
Definition: Point.h:823
bool IsSelected(int i) const
void DeselectPoint(int i)
Vector EdgeLengths() const
Get lengths of boundary segment edges.
int NumberOfPoints() const
Number of boundary segment points.
int PointId(int i) const