OpenWalnut  1.4.0
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  * Sets the main direction of the cluster
184  *
185  * \param mainDirection the cluster's main direction
186  */
187  void setMainDirection( osg::Vec3 mainDirection );
188 
189  /**
190  * Gets the main direction of the cluster ( if set )
191  *
192  * \return the cluster's main direction
193  */
194  osg::Vec3 getMainDirection() const;
195 
196  /**
197  * The name of this transferable. This is useful information for the users.
198  *
199  * \return the name.
200  */
201  virtual const std::string getName() const;
202 
203  /**
204  *
205  * The description of this transferable. This is useful information for the users.
206  *
207  * \return A description
208  */
209  virtual const std::string getDescription() const;
210 
211  /**
212  * \param other The other fiber which should be compared
213  * \return true If both clusters having same fibers IN SAME ORDER!
214  */
215  bool operator==( const WFiberCluster& other ) const;
216 
217  /**
218  * The opposite of the operator==
219  *
220  * \param other The other fiber which should be compared
221  * \return false If both clusters having same fibers IN SAME ORDER!
222  */
223  bool operator!=( const WFiberCluster& other ) const;
224 
225  /**
226  * Copy assignment operator which does NOT copy the mutex's!!!
227  *
228  * \param other The instance to copy.
229  *
230  * \return itself
231  */
233  {
234  WTransferable::operator=( other );
236  m_fibs = other.m_fibs;
237  m_color = other.m_color;
238  m_centerLineCreationLock = new boost::shared_mutex();
239  m_longestLineCreationLock = new boost::shared_mutex();
240  // copy them only if they exist
241  if( other.m_centerLine )
242  {
243  m_centerLine = boost::shared_ptr< WFiber >( new WFiber( *other.m_centerLine.get() ) );
244  }
245  if( other.m_longestLine )
246  {
247  m_longestLine = boost::shared_ptr< WFiber >( new WFiber( *other.m_longestLine.get() ) );
248  }
249  return *this;
250  }
251 
252  // TODO(math): The only reason why we store here a Reference to the fiber
253  // dataset is, we need it in the WMVoxelizer module as well as the clustering
254  // information. Since we don't have the possibility of multiple
255  // InputConnectors we must agglomerate those into one object. Please remove this.
256  // \cond Suppress_Doxygen
257  void setDataSetReference( boost::shared_ptr< const WDataSetFiberVector > fibs );
258  boost::shared_ptr< const WDataSetFiberVector > getDataSetReference() const;
259  // \endcond
260 
261  /**
262  * Returns a prototype instantiated with the true type of the deriving class.
263  *
264  * \return the prototype.
265  */
266  static boost::shared_ptr< WPrototyped > getPrototype();
267 
268  /**
269  * Returns the center line of this cluster. The centerline gets calculated during the first call of this method.
270  *
271  * \return Reference to the center line
272  */
273  boost::shared_ptr< WFiber > getCenterLine() const;
274 
275  /**
276  * Returns the center line of this cluster. The longest line gets calculated during the first call if this method.
277  *
278  * \return Reference to the longest line
279  */
280  boost::shared_ptr< WFiber > getLongestLine() const;
281 
282  /**
283  * Makes the hard work to compute the center line.
284  */
285  void generateCenterLine() const;
286 
287  /**
288  * Makes the hard work to find the longest line.
289  */
290  void generateLongestLine() const;
291 
292  /**
293  * Recomputes on every call the axis aligned bounding box incorporating all tracts in this cluster.
294  *
295  * \return AABB as WBoundingBox.
296  */
298 
299 protected:
300  /**
301  * Prototype for this dataset
302  */
303  static boost::shared_ptr< WPrototyped > m_prototype;
304 
305  /**
306  * Alings all fibers within the given dataset to be in one main direction. But Alignment only may swap the ordering of the fibers
307  * but not the positions or something similar. We need this only for the centerline generation.
308  *
309  * \param fibs The dataset
310  */
311  void unifyDirection( boost::shared_ptr< WDataSetFiberVector > fibs ) const;
312 
313 private:
314  /**
315  * The centerline may be shortened due to the averaging of outliers. To
316  * nevertheless color almost the whole bundle surface we need a surface
317  * parameterization (given via the centerline) upto the endings of the
318  * bundle. Therefore the centerline is stepwise elongated with the last
319  * known direction, until no perpendicular plane intersects any of the
320  * tracts inside of the bundle.
321  */
322  void elongateCenterLine() const;
323 
324  /**
325  * All indices in this set are members of this cluster
326  */
328 
329  // TODO(math): The only reason why we store here a Reference to the fiber
330  // dataset is, we need it in the WMVoxelizer module as well as the clustering
331  // information. Since we don't have the possibility of multiple
332  // InputConnectors we must agglomerate those into one object. Please remove this.
333  /**
334  * Reference to the real fibers of the brain this cluster belongs to.
335  */
336  boost::shared_ptr< const WDataSetFiberVector > m_fibs;
337 
338  /**
339  * Color which is used to paint the members of this cluster.
340  */
341  WColor m_color;
342 
343  /**
344  * The cluster's main direction
345  */
346  osg::Vec3 m_mainDirection;
347 
348  /**
349  * Lock the modification in the m_centerLine mutable. The lock is stored as pointer to avoid copy construction problems.
350  */
351  boost::shared_mutex* m_centerLineCreationLock;
352 
353  /**
354  * Lock the modification in the m_longestLine mutable. The lock is stored as pointer to avoid copy construction problems.
355  */
356  boost::shared_mutex* m_longestLineCreationLock;
357 
358  /**
359  * Average fiber for this cluster representing the main direction and curvature of this cluster.
360  *
361  * \note This member is mutable as it needs to be modified during a const getter.
362  */
363  mutable boost::shared_ptr< WFiber > m_centerLine;
364 
365  /**
366  * The longest fiber in the dataset.
367  *
368  * \note This member is mutable as it needs to be modified during a const getter.
369  */
370  mutable boost::shared_ptr< WFiber > m_longestLine;
371 };
372 
373 inline bool WFiberCluster::empty() const
374 {
375  return m_memberIndices.empty();
376 }
377 
378 inline void WFiberCluster::sort()
379 {
380  m_memberIndices.sort();
381 }
382 
383 inline size_t WFiberCluster::size() const
384 {
385  return m_memberIndices.size();
386 }
387 
388 inline void WFiberCluster::clear()
389 {
390  m_memberIndices.clear();
391 }
392 
393 inline void WFiberCluster::setColor( WColor color )
394 {
395  m_color = color;
396 }
397 
398 inline WColor WFiberCluster::getColor() const
399 {
400  return m_color;
401 }
402 
403 inline void WFiberCluster::setMainDirection( osg::Vec3 mainDirection )
404 {
405  m_mainDirection = mainDirection;
406 }
407 
408 inline osg::Vec3 WFiberCluster::getMainDirection() const
409 {
410  return m_mainDirection;
411 }
412 
413 inline const std::string WFiberCluster::getName() const
414 {
415  return "FiberCluster";
416 }
417 
418 inline const std::string WFiberCluster::getDescription() const
419 {
420  return "A collection of indices for fibers representing a fiber cluster";
421 }
422 
423 inline bool WFiberCluster::operator==( const WFiberCluster& other ) const
424 {
425  return m_memberIndices == other.m_memberIndices;
426 }
427 
428 inline bool WFiberCluster::operator!=( const WFiberCluster& other ) const
429 {
430  return m_memberIndices != other.m_memberIndices;
431 }
432 
434 {
435  return m_memberIndices;
436 }
437 
439 {
440  m_memberIndices = indices;
441 }
442 
443 inline std::ostream& operator<<( std::ostream& os, const WFiberCluster& c )
444 {
445  using string_utils::operator<<;
446  return os << c.getIndices();
447 }
448 
449 #endif // WFIBERCLUSTER_H