OpenWalnut  1.3.1
WFiberCluster.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WFIBERCLUSTER_H
26 #define WFIBERCLUSTER_H
27 
28 #include <list>
29 #include <string>
30 #include <vector>
31 
32 #include <boost/shared_ptr.hpp>
33 #include <boost/thread.hpp>
34 
35 #include "../../common/WColor.h"
36 #include "../../common/WTransferable.h"
37 #include "../WDataSetFiberVector.h"
38 
39 
40 /**
41  * Represents a cluster of indices of a WDataSetFiberVector.
42  */
43 class WFiberCluster: public WTransferable // NOLINT
44 {
45 friend class WFiberClusterTest;
46 public:
47  /**
48  * Shared pointer abbreviation.
49  */
50  typedef boost::shared_ptr< WFiberCluster > SPtr;
51 
52  /**
53  * Const shared pointer abbreviation.
54  */
55  typedef boost::shared_ptr< const WFiberCluster > ConstSPtr;
56 
57  /**
58  * This is the list of indices of fibers.
59  */
60  typedef std::list< size_t > IndexList;
61 
62  /**
63  * Const iterator on the index list.
64  */
65  typedef IndexList::const_iterator IndexListConstIterator;
66 
67  /**
68  * Constructs an cluster with one fiber and a reference to the fiber dataset
69  * to compute the intercluster distance.
70  *
71  * \param index The index of the first fiber belonging to this cluster
72  */
73  explicit WFiberCluster( size_t index );
74 
75  /**
76  * Constructs a cluster with the specified set of indices and the given color.
77  *
78  * \param indices the indices initially used for this clustering
79  * \param color the color of this cluster
80  */
81  WFiberCluster( const IndexList& indices, const WColor& color = WColor() );
82 
83  /**
84  * Constructs a clustering with the given set of indices. The indexlist is generated using the given iterators. It copies the elements in
85  * [indicesBegin,indicesEnd).
86  *
87  * \param indicesBegin begin iterator in the predefined index set
88  * \param indicesEnd end iterator in the predefined index set
89  * \param color the color of this cluster
90  */
92  IndexListConstIterator indicesEnd, const WColor& color = WColor() );
93 
94  /**
95  * Copies the specified \ref WFiberCluster Instance. The copy does not contain a valid centerline or longest line.
96  *
97  * \param other the other instance to clone.
98  */
99  WFiberCluster( const WFiberCluster& other );
100 
101  /**
102  * Constructs an empty cluster.
103  */
104  WFiberCluster();
105 
106  /**
107  * Destructs. Frees used locks/mutex.
108  */
109  virtual ~WFiberCluster();
110 
111  /**
112  * Returns true if there are no fibers in that cluster, false otherwise.
113  *
114  * \return true if empty
115  */
116  bool empty() const;
117 
118  /**
119  * Merge the fibers of the other cluster with the fibers of this cluster.
120  * Afterwards the other cluster is empty.
121  *
122  * \param other The other WFiberCluster which should merged into this one
123  */
124  void merge( WFiberCluster &other ); // NOLINT
125 
126  /**
127  * Copy the elements denoted by the two iterators to this cluster. In contrast to the other merge() methods, this will not clean the source
128  * list.
129  *
130  * \param indicesBegin begin iterator in the predefined index set
131  * \param indicesEnd end iterator in the predefined index set
132  */
133  void merge( IndexListConstIterator indicesBegin, IndexListConstIterator indicesEnd );
134 
135  /**
136  * Returns a const reference of all indices inside this cluster
137  *
138  * \return the index list
139  */
140  const IndexList& getIndices() const;
141 
142  /**
143  * Reset the indices belonging to that cluster
144  *
145  * \param indices list of indices
146  */
147  void setIndices( const IndexList& indices );
148 
149  /**
150  * Sort the indices of fibers associated with this cluster in ascending
151  * order.
152  */
153  void sort();
154 
155  /**
156  * \return Number of fibers associated with this cluster.
157  */
158  size_t size() const;
159 
160  /**
161  * Make this cluster empty. Note: The real fibers from fiber dataset are
162  * not deleted.
163  */
164  void clear();
165 
166  /**
167  * Sets the color of which all fibers of this clusters should be painted
168  * with.
169  *
170  * \param color The color for all fibers of this cluster.
171  */
172  void setColor( WColor color );
173 
174  /**
175  * Gets the color of which all fibers of this clusters should be painted
176  * with.
177  *
178  * \return cluster color.
179  */
180  WColor getColor() const;
181 
182  /**
183  * The name of this transferable. This is useful information for the users.
184  *
185  * \return the name.
186  */
187  virtual const std::string getName() const;
188 
189  /**
190  *
191  * The description of this transferable. This is useful information for the users.
192  *
193  * \return A description
194  */
195  virtual const std::string getDescription() const;
196 
197  /**
198  * \param other The other fiber which should be compared
199  * \return true If both clusters having same fibers IN SAME ORDER!
200  */
201  bool operator==( const WFiberCluster& other ) const;
202 
203  /**
204  * The opposite of the operator==
205  *
206  * \param other The other fiber which should be compared
207  * \return false If both clusters having same fibers IN SAME ORDER!
208  */
209  bool operator!=( const WFiberCluster& other ) const;
210 
211  /**
212  * Copy assignment operator which does NOT copy the mutex's!!!
213  *
214  * \param other The instance to copy.
215  *
216  * \return itself
217  */
219  {
220  WTransferable::operator=( other );
222  m_fibs = other.m_fibs;
223  m_color = other.m_color;
224  m_centerLineCreationLock = new boost::shared_mutex();
225  m_longestLineCreationLock = new boost::shared_mutex();
226  // copy them only if they exist
227  if( other.m_centerLine )
228  {
229  m_centerLine = boost::shared_ptr< WFiber >( new WFiber( *other.m_centerLine.get() ) );
230  }
231  if( other.m_longestLine )
232  {
233  m_longestLine = boost::shared_ptr< WFiber >( new WFiber( *other.m_longestLine.get() ) );
234  }
235  return *this;
236  }
237 
238  // TODO(math): The only reason why we store here a Reference to the fiber
239  // dataset is, we need it in the WMVoxelizer module as well as the clustering
240  // information. Since we don't have the possibility of multiple
241  // InputConnectors we must agglomerate those into one object. Please remove this.
242  // \cond Suppress_Doxygen
243  void setDataSetReference( boost::shared_ptr< const WDataSetFiberVector > fibs );
244  boost::shared_ptr< const WDataSetFiberVector > getDataSetReference() const;
245  // \endcond
246 
247  /**
248  * Returns a prototype instantiated with the true type of the deriving class.
249  *
250  * \return the prototype.
251  */
252  static boost::shared_ptr< WPrototyped > getPrototype();
253 
254  /**
255  * Returns the center line of this cluster. The centerline gets calculated during the first call of this method.
256  *
257  * \return Reference to the center line
258  */
259  boost::shared_ptr< WFiber > getCenterLine() const;
260 
261  /**
262  * Returns the center line of this cluster. The longest line gets calculated during the first call if this method.
263  *
264  * \return Reference to the longest line
265  */
266  boost::shared_ptr< WFiber > getLongestLine() const;
267 
268  /**
269  * Makes the hard work to compute the center line.
270  */
271  void generateCenterLine() const;
272 
273  /**
274  * Makes the hard work to find the longest line.
275  */
276  void generateLongestLine() const;
277 
278  /**
279  * Recomputes on every call the axis aligned bounding box incorporating all tracts in this cluster.
280  *
281  * \return AABB as WBoundingBox.
282  */
284 
285 protected:
286  /**
287  * Prototype for this dataset
288  */
289  static boost::shared_ptr< WPrototyped > m_prototype;
290 
291  /**
292  * Alings all fibers within the given dataset to be in one main direction. But Alignment only may swap the ordering of the fibers
293  * but not the positions or something similar. We need this only for the centerline generation.
294  *
295  * \param fibs The dataset
296  */
297  void unifyDirection( boost::shared_ptr< WDataSetFiberVector > fibs ) const;
298 
299 private:
300  /**
301  * The centerline may be shortened due to the averaging of outliers. To
302  * nevertheless color almost the whole bundle surface we need a surface
303  * parameterization (given via the centerline) upto the endings of the
304  * bundle. Therefore the centerline is stepwise elongated with the last
305  * known direction, until no perpendicular plane intersects any of the
306  * tracts inside of the bundle.
307  */
308  void elongateCenterLine() const;
309 
310  /**
311  * All indices in this set are members of this cluster
312  */
314 
315  // TODO(math): The only reason why we store here a Reference to the fiber
316  // dataset is, we need it in the WMVoxelizer module as well as the clustering
317  // information. Since we don't have the possibility of multiple
318  // InputConnectors we must agglomerate those into one object. Please remove this.
319  /**
320  * Reference to the real fibers of the brain this cluster belongs to.
321  */
322  boost::shared_ptr< const WDataSetFiberVector > m_fibs;
323 
324  /**
325  * Color which is used to paint the members of this cluster.
326  */
327  WColor m_color;
328 
329  /**
330  * Lock the modification in the m_centerLine mutable. The lock is stored as pointer to avoid copy construction problems.
331  */
332  boost::shared_mutex* m_centerLineCreationLock;
333 
334  /**
335  * Lock the modification in the m_longestLine mutable. The lock is stored as pointer to avoid copy construction problems.
336  */
337  boost::shared_mutex* m_longestLineCreationLock;
338 
339  /**
340  * Average fiber for this cluster representing the main direction and curvature of this cluster.
341  *
342  * \note This member is mutable as it needs to be modified during a const getter.
343  */
344  mutable boost::shared_ptr< WFiber > m_centerLine;
345 
346  /**
347  * The longest fiber in the dataset.
348  *
349  * \note This member is mutable as it needs to be modified during a const getter.
350  */
351  mutable boost::shared_ptr< WFiber > m_longestLine;
352 };
353 
354 inline bool WFiberCluster::empty() const
355 {
356  return m_memberIndices.empty();
357 }
358 
359 inline void WFiberCluster::sort()
360 {
361  m_memberIndices.sort();
362 }
363 
364 inline size_t WFiberCluster::size() const
365 {
366  return m_memberIndices.size();
367 }
368 
369 inline void WFiberCluster::clear()
370 {
371  m_memberIndices.clear();
372 }
373 
374 inline void WFiberCluster::setColor( WColor color )
375 {
376  m_color = color;
377 }
378 
379 inline WColor WFiberCluster::getColor() const
380 {
381  return m_color;
382 }
383 
384 inline const std::string WFiberCluster::getName() const
385 {
386  return "FiberCluster";
387 }
388 
389 inline const std::string WFiberCluster::getDescription() const
390 {
391  return "A collection of indices for fibers representing a fiber cluster";
392 }
393 
394 inline bool WFiberCluster::operator==( const WFiberCluster& other ) const
395 {
396  return m_memberIndices == other.m_memberIndices;
397 }
398 
399 inline bool WFiberCluster::operator!=( const WFiberCluster& other ) const
400 {
401  return m_memberIndices != other.m_memberIndices;
402 }
403 
405 {
406  return m_memberIndices;
407 }
408 
410 {
411  m_memberIndices = indices;
412 }
413 
414 inline std::ostream& operator<<( std::ostream& os, const WFiberCluster& c )
415 {
416  using string_utils::operator<<;
417  return os << c.getIndices();
418 }
419 
420 #endif // WFIBERCLUSTER_H