EdgeTable.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_EdgeTable_H
21 #define MIRTK_EdgeTable_H
22 
23 #include "mirtk/SparseMatrix.h"
24 
25 #include "mirtk/Memory.h"
26 #include "mirtk/Parallel.h"
27 
28 #include "vtkSmartPointer.h"
29 #include "vtkDataSet.h"
30 
31 
32 namespace mirtk {
33 
34 
35 /**
36  * Edge table / adjacency matrix
37  *
38  * This class represents the adjacency matrix of point set nodes. It provides
39  * efficient access to the set of nodes adjacent to a given point. The non-zero
40  * entries stored in the sparse matrix are the one-based edge IDs such that
41  * sparse matrix entries are non-zero. To efficiently iterate all edges or a
42  * subset of these, use the thread-safe EdgeIterator.
43  */
44 class EdgeTable : public GenericSparseMatrix<int>
45 {
46  mirtkObjectMacro(EdgeTable);
47 
48  /// Pointer to data set which this edge table was computed from
49  mirtkReadOnlyAttributeMacro(vtkSmartPointer<vtkDataSet>, Mesh);
50 
51  /// Number of undirected edges
52  mirtkReadOnlyAttributeMacro(int, NumberOfEdges);
53 
54  /// Copy attributes of this class from another instance
55  void CopyAttributes(const EdgeTable &);
56 
57 public:
58 
59  /// Construct edge table for given dataset
60  EdgeTable(vtkDataSet * = nullptr);
61 
62  /// Copy constructor
63  EdgeTable(const EdgeTable &);
64 
65  /// Assignment operator
66  EdgeTable &operator =(const EdgeTable &);
67 
68  /// Destructor
69  virtual ~EdgeTable();
70 
71  /// Initialize edge table from given dataset
72  void Initialize(vtkDataSet *);
73 
74  /// Clear edge table
75  virtual void Clear();
76 
77  /// Number of nodes
78  int NumberOfPoints() const;
79 
80  /// Determine whether two nodes are connected by an edge
81  template <class IdType1, class IdType2>
82  bool IsEdge(IdType1, IdType2) const;
83 
84  /// Get ID of undirected edge connecting two nodes
85  ///
86  /// \return Zero-based edge ID or -1 if edge does not exist.
87  template <class IdType1, class IdType2>
88  int EdgeId(IdType1, IdType2) const;
89 
90  /// Get IDs of edge nodes (ptId1 < ptId2)
91  template <class EdgeIdType, class IdType1, class IdType2>
92  bool GetEdge(EdgeIdType, IdType1 &ptId1, IdType2 &ptId2) const;
93 
94  /// Get number of adjacent points
95  template <class IdType>
96  int NumberOfAdjacentPoints(IdType) const;
97 
98  /// Get maximum number of adjacent points
99  int MaxNumberOfAdjacentPoints() const;
100 
101  /// Access list of adjacent nodes (thread-safe)
102  void GetAdjacentPoints(int, int &, const int *&) const;
103 
104  /// Get start and end pointer into list of adjacent nodes (thread-safe)
105  void GetAdjacentPoints(int, const int *&, const int *&) const;
106 };
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 // Inline definitions
110 ////////////////////////////////////////////////////////////////////////////////
111 
112 // -----------------------------------------------------------------------------
113 inline int EdgeTable::NumberOfPoints() const
114 {
115  return Rows();
116 }
117 
118 // -----------------------------------------------------------------------------
119 template <class IdType1, class IdType2>
120 inline bool EdgeTable::IsEdge(IdType1 ptId1, IdType2 ptId2) const
121 {
122  return static_cast<bool>(Get(static_cast<int>(ptId1), static_cast<int>(ptId2)));
123 }
124 
125 // -----------------------------------------------------------------------------
126 template <class IdType1, class IdType2>
127 inline int EdgeTable::EdgeId(IdType1 ptId1, IdType2 ptId2) const
128 {
129  return Get(static_cast<int>(ptId1), static_cast<int>(ptId2)) - 1;
130 }
131 
132 // -----------------------------------------------------------------------------
133 template <class EdgeIdType, class IdType1, class IdType2>
134 inline bool EdgeTable::GetEdge(EdgeIdType edgeId, IdType1 &ptId1, IdType2 &ptId2) const
135 {
136  const int eid = static_cast<int>(edgeId) + 1;
137  if (eid <= 0) return false;
138 
139  int i, j;
140  const int *row = _Row;
141  const int *col = _Col;
142  if (_Layout == CRS) swap(row, col);
143 
144  const IdType2 npoints = static_cast<IdType2>(NumberOfPoints());
145  for (ptId2 = 0; ptId2 < npoints; ++ptId2) {
146  for (i = col[ptId2], j = col[ptId2 + 1]; i < j; ++i) {
147  ptId1 = static_cast<IdType1>(row[i]);
148  if (_Data[i] == eid) return true;
149  if (ptId1 > ptId2) break;
150  }
151  }
152 
153  ptId1 = static_cast<IdType1>(-1);
154  ptId2 = static_cast<IdType2>(-1);
155  return false;
156 }
157 
158 // -----------------------------------------------------------------------------
159 template <class IdType>
160 inline int EdgeTable::NumberOfAdjacentPoints(IdType ptId) const
161 {
162  if (_Layout == CCS) {
163  return _Col[ptId+1] - _Col[ptId];
164  } else {
165  return _Row[ptId+1] - _Row[ptId];
166  }
167 }
168 
169 // -----------------------------------------------------------------------------
170 inline void EdgeTable::GetAdjacentPoints(int ptId, int &numAdjPts, const int *&adjPtIds) const
171 {
172  if (_Layout == CCS) {
173  numAdjPts = _Col[ptId+1] - _Col[ptId];
174  adjPtIds = _Row + _Col[ptId];
175  } else {
176  numAdjPts = _Row[ptId+1] - _Row[ptId];
177  adjPtIds = _Col + _Row[ptId];
178  }
179 }
180 
181 // -----------------------------------------------------------------------------
182 inline void EdgeTable::GetAdjacentPoints(int ptId, const int *&begin, const int *&end) const
183 {
184  if (_Layout == CCS) {
185  begin = _Row + _Col[ptId];
186  end = _Row + _Col[ptId + 1];
187  } else {
188  begin = _Col + _Row[ptId];
189  end = _Col + _Row[ptId + 1];
190  }
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 // EdgeIterator
195 ////////////////////////////////////////////////////////////////////////////////
196 
197 /**
198  * Thread-safe helper class for iteration of edges
199  */
201 {
202  const EdgeTable &_Table;
203  int _EdgeId;
204  int _EndId;
205  const int *_PointId1;
206  const int *_ListEnd;
207  int _PointId2;
208 
209 public:
210 
211  /// Constructor
212  EdgeIterator(const EdgeTable &table)
213  :
214  _Table(table), _EdgeId(-1), _EndId(-1),
215  _PointId1(NULL), _ListEnd(NULL), _PointId2(-1)
216  {}
217 
218  /// Constructor
219  EdgeIterator(const EdgeTable &table, int begin, int end = -1)
220  :
221  EdgeIterator(table)
222  {
223  InitTraversal(begin, end);
224  }
225 
226  /// Initialize traversal of edges
227  ///
228  /// @param[in] begin ID of first edge to iterate.
229  /// @param[in] end ID one behind last edge to iterate. If negative,
230  /// all edges from @p begin until the end are iterated.
231  ///
232  /// @bug Not sure if this functions works correctly for begin > 0, cf.,
233  /// AverageEdgeLength implementation.
234  inline void InitTraversal(int begin = 0, int end = -1)
235  {
236  _EdgeId = begin;
237  _EndId = ((end < 0 || end > _Table.NumberOfEdges()) ? _Table.NumberOfEdges() : end);
238  if (_EndId > _EdgeId) {
239  for (_PointId2 = 0; _PointId2 < _Table.NumberOfPoints(); ++_PointId2) {
240  _Table.GetAdjacentPoints(_PointId2, _PointId1, _ListEnd);
241  while (_PointId1 != _ListEnd) {
242  if (*_PointId1 > _PointId2) {
243  _PointId1 = _ListEnd;
244  break;
245  }
246  if (begin == 0) break;
247  ++_PointId1, --begin;
248  }
249  if (begin == 0 && _PointId1 != _ListEnd) break;
250  }
251  } else {
252  _PointId1 = _ListEnd = NULL;
253  _PointId2 = -1;
254  }
255  }
256 
257  /// Initialize traversal of edges in range
258  template <class IdType>
259  inline void InitTraversal(const blocked_range<IdType> &re)
260  {
261  InitTraversal(static_cast<int>(re.begin()), static_cast<int>(re.end()));
262  }
263 
264  /// Get next edge
265  ///
266  /// @param[out] ptId1 ID of first edge point.
267  /// @param[out] ptId2 ID of second edge point.
268  ///
269  /// @return ID of undirected edge (ptId1, ptId2) or -1 if end reached
270  template <class IdType>
271  int GetNextEdge(IdType &ptId1, IdType &ptId2)
272  {
273  if (_EdgeId >= _EndId) return -1;
274  ptId1 = static_cast<IdType>(*_PointId1);
275  ptId2 = static_cast<IdType>(_PointId2);
276  int edgeId = _EdgeId;
277  if (++_EdgeId < _EndId) {
278  if (++_PointId1 == _ListEnd || (*_PointId1) > _PointId2) {
279  do {
280  _Table.GetAdjacentPoints(++_PointId2, _PointId1, _ListEnd);
281  } while (_PointId1 == _ListEnd || (*_PointId1) > _PointId2);
282  }
283  }
284  return edgeId;
285  }
286 };
287 
288 
289 } // namespace mirtk
290 
291 #endif // MIRTK_EdgeTable_H
int GetNextEdge(IdType &ptId1, IdType &ptId2)
Definition: EdgeTable.h:271
bool IsEdge(IdType1, IdType2) const
Determine whether two nodes are connected by an edge.
Definition: EdgeTable.h:120
bool GetEdge(EdgeIdType, IdType1 &ptId1, IdType2 &ptId2) const
Get IDs of edge nodes (ptId1 < ptId2)
Definition: EdgeTable.h:134
int NumberOfEdges(vtkDataSet *, const EdgeTable *=nullptr)
Number of edges.
One-dimensional range.
Definition: Parallel.h:155
int MaxNumberOfAdjacentPoints() const
Get maximum number of adjacent points.
Definition: IOConfig.h:41
EntryType Get(int, int=-1) const
Get value.
void InitTraversal(int begin=0, int end=-1)
Definition: EdgeTable.h:234
int NumberOfPoints() const
Number of nodes.
Definition: EdgeTable.h:113
virtual void Clear()
Clear edge table.
EntryType * _Data
Non-zero entries.
Definition: SparseMatrix.h:104
virtual ~EdgeTable()
Destructor.
void GetAdjacentPoints(int, int &, const int *&) const
Access list of adjacent nodes (thread-safe)
Definition: EdgeTable.h:170
void InitTraversal(const blocked_range< IdType > &re)
Initialize traversal of edges in range.
Definition: EdgeTable.h:259
EdgeIterator(const EdgeTable &table, int begin, int end=-1)
Constructor.
Definition: EdgeTable.h:219
int EdgeId(IdType1, IdType2) const
Definition: EdgeTable.h:127
void Initialize(vtkDataSet *)
Initialize edge table from given dataset.
int NumberOfAdjacentPoints(IdType) const
Get number of adjacent points.
Definition: EdgeTable.h:160
EdgeIterator(const EdgeTable &table)
Constructor.
Definition: EdgeTable.h:212
EdgeTable & operator=(const EdgeTable &)
Assignment operator.
EdgeTable(vtkDataSet *=nullptr)
Construct edge table for given dataset.