OpenWalnut  1.5.0dev
WFiberCluster.cpp
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 #include <algorithm>
26 #include <list>
27 #include <memory>
28 #include <string>
29 #include <vector>
30 
31 
32 #include "../../common/WLimits.h"
33 #include "../../common/WTransferable.h"
34 #include "../../common/math/WMath.h"
35 #include "../../common/math/WPlane.h"
36 #include "../WDataSetFiberVector.h"
37 #include "WFiberCluster.h"
38 
39 // The prototype as singleton. Created during first getPrototype() call
40 std::shared_ptr< WPrototyped > WFiberCluster::m_prototype = std::shared_ptr< WPrototyped >();
41 
43  : WTransferable(),
44  m_centerLineCreationLock( new std::shared_mutex() ),
45  m_longestLineCreationLock( new std::shared_mutex() )
46 {
47 }
48 
50  : WTransferable(),
51  m_centerLineCreationLock( new std::shared_mutex() ),
52  m_longestLineCreationLock( new std::shared_mutex() )
53 {
54  m_memberIndices.push_back( index );
55 }
56 
57 WFiberCluster::WFiberCluster( const WFiberCluster::IndexList& indices, const WColor& color, std::string const& annotation )
58  : WTransferable(),
59  m_memberIndices( indices ),
60  m_color( color ),
61  m_annotation( annotation ),
62  m_centerLineCreationLock( new std::shared_mutex() ),
63  m_longestLineCreationLock( new std::shared_mutex() )
64 {
65  // init
66 }
67 
70  const WColor& color,
71  std::string const& annotation )
72  : WTransferable(),
73  m_color( color ),
74  m_annotation( annotation ),
75  m_centerLineCreationLock( new std::shared_mutex() ),
76  m_longestLineCreationLock( new std::shared_mutex() )
77 {
78  // now copy the index list
79  std::copy( indicesBegin, indicesEnd, m_memberIndices.begin() );
80 }
81 
83  : WTransferable( other ),
84  m_memberIndices( other.m_memberIndices ),
85  m_fibs( other.m_fibs ),
86  m_color( other.m_color ),
87  m_annotation( other.m_annotation ),
88  m_centerLineCreationLock( new std::shared_mutex() ), // do not copy the mutex as both instances of WFiberCluster can be modifed at the
89  // same time
90  m_longestLineCreationLock( new std::shared_mutex() ),
91  m_centerLine(), // << we can't ensure that the centerline and longest line are initialized yet, but we want a deep copy
92  m_longestLine()
93 {
94  // copy them only if they exist
95  if( other.m_centerLine )
96  {
97  m_centerLine = std::shared_ptr< WFiber >( new WFiber( *other.m_centerLine.get() ) );
98  }
99  if( other.m_longestLine )
100  {
101  m_longestLine = std::shared_ptr< WFiber >( new WFiber( *other.m_longestLine.get() ) );
102  }
103 }
104 
106 {
109 }
110 
111 void WFiberCluster::merge( WFiberCluster& other ) // NOLINT
112 {
113  WFiberCluster::IndexList::const_iterator cit = other.m_memberIndices.begin();
114  for( ; cit != other.m_memberIndices.end(); ++cit )
115  {
116  m_memberIndices.push_back( *cit );
117  }
118  // make sure that those indices aren't occuring anywhere else
119  other.m_centerLine.reset(); // they are not valid anymore
120  other.m_longestLine.reset();
121  other.clear();
122 }
123 
126 {
127  // now copy the index list
128  m_memberIndices.insert( m_memberIndices.end(), indicesBegin, indicesEnd );
129 }
130 
131 // NODOXYGEN
132 // \cond Suppress_Doxygen
133 void WFiberCluster::setDataSetReference( std::shared_ptr< const WDataSetFiberVector > fibs )
134 {
135  m_fibs = fibs;
136 }
137 
138 std::shared_ptr< const WDataSetFiberVector > WFiberCluster::getDataSetReference() const
139 {
140  return m_fibs;
141 }
142 // TODO(math): The only reason why we store here a Reference to the fiber
143 // dataset is, we need it in the WMVoxelizer module as well as the clustering
144 // information. Since we don't have the possibility of multiple
145 // InputConnectors we must agglomerate those into one object. Please remove this.
146 // \endcond
147 
148 std::shared_ptr< WPrototyped > WFiberCluster::getPrototype()
149 {
150  if( !m_prototype )
151  {
152  m_prototype = std::shared_ptr< WPrototyped >( new WFiberCluster() );
153  }
154  return m_prototype;
155 }
156 
158 {
159  // ensure nobody changes the mutable m_centerline
160  std::unique_lock< std::shared_mutex > lock = std::unique_lock< std::shared_mutex >( *m_centerLineCreationLock );
161  // has the line been calculated while we waited?
162  if( m_centerLine )
163  {
164  lock.unlock();
165  return;
166  }
167 
168  // make copies of the fibers
169  std::shared_ptr< WDataSetFiberVector > fibs( new WDataSetFiberVector() );
170  size_t avgFiberSize = 0;
171  for( WFiberCluster::IndexList::const_iterator cit = m_memberIndices.begin(); cit != m_memberIndices.end(); ++cit )
172  {
173  fibs->push_back( m_fibs->at( *cit ) );
174  avgFiberSize += fibs->back().size();
175  }
176  avgFiberSize /= fibs->size();
177 
178  unifyDirection( fibs );
179 
180  for( WDataSetFiberVector::iterator cit = fibs->begin(); cit != fibs->end(); ++cit )
181  {
182  cit->resampleByNumberOfPoints( avgFiberSize );
183  }
184 
185  m_centerLine = std::shared_ptr< WFiber >( new WFiber() );
186  m_centerLine->reserve( avgFiberSize );
187  for( size_t i = 0; i < avgFiberSize; ++i )
188  {
189  WPosition avgPosition( 0, 0, 0 );
190  for( WDataSetFiberVector::const_iterator cit = fibs->begin(); cit != fibs->end(); ++cit )
191  {
192  avgPosition += cit->at( i );
193  }
194  avgPosition /= static_cast< double >( fibs->size() );
195  m_centerLine->push_back( avgPosition );
196  }
197 
199  lock.unlock();
200 }
201 
203 {
204  // ensure nobody changes the mutable m_longestline
205  std::unique_lock< std::shared_mutex > lock = std::unique_lock< std::shared_mutex >( *m_longestLineCreationLock );
206  // has the line been calculated while we waited?
207  if( m_longestLine )
208  {
209  lock.unlock();
210  return;
211  }
212 
213  m_longestLine = std::shared_ptr< WFiber >( new WFiber() );
214 
215  // empty datasets can be ignored
216  if( m_fibs->size() == 0 )
217  {
218  return;
219  }
220 
221  size_t longest = 0;
222  size_t longestID = 0;
223  for( size_t cit = 0; cit < m_fibs->size(); ++cit )
224  {
225  if( m_fibs->at( cit ).size() > longest )
226  {
227  longest = m_fibs->at( cit ).size();
228  longestID = cit;
229  }
230  }
231 
232  for( WFiber::const_iterator cit = m_fibs->at( longestID ).begin(); cit != m_fibs->at( longestID ).end(); ++cit )
233  {
234  m_longestLine->push_back( *cit );
235  }
236 
237  lock.unlock();
238 }
239 
241 {
242  // first ending of the centerline
243  assert( m_centerLine->size() > 1 );
244  WFiber cL( *m_centerLine );
245  WPlane p( cL[0] - cL[1], cL[0] + ( cL[0] - cL[1] ) );
246  std::shared_ptr< WPosition > cutPoint( new WPosition( 0, 0, 0 ) );
247  bool intersectionFound = true;
248 
249  // in the beginning all fibers participate
250  std::shared_ptr< WDataSetFiberVector > fibs( new WDataSetFiberVector() );
251  for( WFiberCluster::IndexList::const_iterator cit = m_memberIndices.begin(); cit != m_memberIndices.end(); ++cit )
252  {
253  fibs->push_back( m_fibs->at( *cit ) );
254  }
255 
256  while( intersectionFound )
257  {
258  intersectionFound = false;
259  size_t intersectingFibers = 0;
260 // WPosition avg( 0, 0, 0 );
261  for( WDataSetFiberVector::iterator cit = fibs->begin(); cit != fibs->end(); )
262  {
263  if( intersectPlaneLineNearCP( p, *cit, cutPoint ) )
264  {
265  if( length( *cutPoint - p.getPosition() ) < 20 )
266  {
267 // avg += *cutPoint;
268  intersectingFibers++;
269  intersectionFound = true;
270  ++cit;
271  }
272  else
273  {
274  cit = fibs->erase( cit );
275  }
276  }
277  else
278  {
279  cit = fibs->erase( cit );
280  }
281  }
282  if( intersectingFibers > 10 )
283  {
284  cL.insert( cL.begin(), cL[0] + ( cL[0] - cL[1] ) );
285  p.resetPosition( cL[0] + ( cL[0] - cL[1] ) );
286 // avg[0] /= static_cast< double >( intersectingFibers );
287 // avg[1] /= static_cast< double >( intersectingFibers );
288 // avg[2] /= static_cast< double >( intersectingFibers );
289 // cL.insert( cL.begin(), 0.995 * ( cL[0] + ( cL[0] - cL[1] ) ) + 0.005 * avg );
290 // p.resetPosition( cL[0] + ( cL[0] - cL[1] ) );
291 // p.setNormal( ( cL[0] - cL[1] ) );
292  }
293  else // no intersections found => abort
294  {
295  break;
296  }
297  }
298  // second ending of the centerline
299  std::shared_ptr< WDataSetFiberVector > fobs( new WDataSetFiberVector() );
300  for( WFiberCluster::IndexList::const_iterator cit = m_memberIndices.begin(); cit != m_memberIndices.end(); ++cit )
301  {
302  fobs->push_back( m_fibs->at( *cit ) );
303  }
304 
305  // try to discard other lines from other end
306 
307  WPlane q( cL.back() - cL[ cL.size() - 2 ], cL.back() + ( cL.back() - cL[ cL.size() - 2 ] ) );
308  intersectionFound = true;
309  while( intersectionFound )
310  {
311  intersectionFound = false;
312  size_t intersectingFibers = 0;
313 // WPosition avg( 0, 0, 0 );
314  for( WDataSetFiberVector::iterator cit = fobs->begin(); cit != fobs->end(); )
315  {
316  if( intersectPlaneLineNearCP( q, *cit, cutPoint ) )
317  {
318  if( length( *cutPoint - q.getPosition() ) < 20 )
319  {
320 // avg += *cutPoint;
321  intersectingFibers++;
322  intersectionFound = true;
323  ++cit;
324  }
325  else
326  {
327  cit = fobs->erase( cit );
328  }
329  }
330  else
331  {
332  cit = fobs->erase( cit );
333  }
334  }
335  if( intersectingFibers > 10 )
336  {
337  cL.push_back( cL.back() + ( cL.back() - cL[ cL.size() - 2 ] ) );
338  q.resetPosition( cL.back() + ( cL.back() - cL[ cL.size() - 2 ] ) );
339 // avg[0] /= static_cast< double >( intersectingFibers );
340 // avg[1] /= static_cast< double >( intersectingFibers );
341 // avg[2] /= static_cast< double >( intersectingFibers );
342 // cL.push_back( 0.995 * ( cL.back() + ( cL.back() - cL[ cL.size() - 2 ] ) ) + 0.005 * avg );
343 // q.resetPosition( cL.back() + ( cL.back() - cL[ cL.size() - 2 ] ) );
344 // q.setNormal( cL.back() - cL[ cL.size() - 2 ] );
345  }
346  else // no intersections found => abort
347  {
348  break;
349  }
350  }
351  *m_centerLine = cL;
352 }
353 
354 void WFiberCluster::unifyDirection( std::shared_ptr< WDataSetFiberVector > fibs ) const
355 {
356  if( fibs->size() < 2 )
357  {
358  return;
359  }
360 
361  assert( !( fibs->at( 0 ).empty() ) && "WFiberCluster.unifyDirection: Empty fiber processed.. aborting" );
362 
363  // first fiber defines direction
364  const WFiber& firstFib = fibs->front();
365  const WPosition start = firstFib.front();
366  const WPosition m1 = firstFib.at( firstFib.size() * 1.0 / 3.0 );
367  const WPosition m2 = firstFib.at( firstFib.size() * 2.0 / 3.0 );
368  const WPosition end = firstFib.back();
369 
370  for( WDataSetFiberVector::iterator cit = fibs->begin() + 1; cit != fibs->end(); ++cit )
371  {
372  const WFiber& other = *cit;
373  double distance = length2( start - other.front() ) +
374  length2( m1 - other.at( other.size() * 1.0 / 3.0 ) ) +
375  length2( m2 - other.at( other.size() * 2.0 / 3.0 ) ) +
376  length2( end - other.back() );
377  double inverseDistance = length2( start - other.back() ) +
378  length2( m1 - other.at( other.size() * 2.0 / 3.0 ) ) +
379  length2( m2 - other.at( other.size() * 1.0 / 3.0 ) ) +
380  length2( end - other.front() );
381  distance /= 4.0;
382  inverseDistance /= 4.0;
383  if( inverseDistance < distance )
384  {
385  cit->reverseOrder();
386  }
387  }
388 }
389 
390 std::shared_ptr< WFiber > WFiberCluster::getCenterLine() const
391 {
392  if( !m_centerLine )
393  {
395  }
396  return m_centerLine;
397 }
398 
399 std::shared_ptr< WFiber > WFiberCluster::getLongestLine() const
400 {
401  if( !m_longestLine )
402  {
404  }
405  return m_longestLine;
406 }
407 
409 {
410  WBoundingBox result;
411  for( WFiberCluster::IndexList::const_iterator cit = m_memberIndices.begin(); cit != m_memberIndices.end(); ++cit )
412  {
413  result.expandBy( computeBoundingBox( m_fibs->at( *cit ) ) );
414  }
415  return result;
416 }
void expandBy(const WBoundingBoxImpl< VT > &bb)
Expands this bounding box to include the given bounding box.
Definition: WBoundingBox.h:240
Represents a simple set of WFibers.
Represents a cluster of indices of a WDataSetFiberVector.
Definition: WFiberCluster.h:45
std::shared_ptr< WFiber > m_centerLine
Average fiber for this cluster representing the main direction and curvature of this cluster.
std::shared_ptr< WFiber > m_longestLine
The longest fiber in the dataset.
IndexList m_memberIndices
All indices in this set are members of this cluster.
void elongateCenterLine() const
The centerline may be shortened due to the averaging of outliers.
static std::shared_ptr< WPrototyped > m_prototype
Prototype for this dataset.
void clear()
Make this cluster empty.
IndexList::const_iterator IndexListConstIterator
Const iterator on the index list.
Definition: WFiberCluster.h:66
virtual ~WFiberCluster()
Destructs.
std::shared_ptr< WFiber > getCenterLine() const
Returns the center line of this cluster.
std::list< size_t > IndexList
This is the list of indices of fibers.
Definition: WFiberCluster.h:61
void generateLongestLine() const
Makes the hard work to find the longest line.
std::shared_ptr< WFiber > getLongestLine() const
Returns the center line of this cluster.
std::shared_ptr< const WDataSetFiberVector > m_fibs
Reference to the real fibers of the brain this cluster belongs to.
static std::shared_ptr< WPrototyped > getPrototype()
Returns a prototype instantiated with the true type of the deriving class.
void merge(WFiberCluster &other)
Merge the fibers of the other cluster with the fibers of this cluster.
WFiberCluster()
Constructs an empty cluster.
void unifyDirection(std::shared_ptr< WDataSetFiberVector > fibs) const
Alings all fibers within the given dataset to be in one main direction.
void generateCenterLine() const
Makes the hard work to compute the center line.
std::shared_mutex * m_centerLineCreationLock
Lock the modification in the m_centerLine mutable.
std::shared_mutex * m_longestLineCreationLock
Lock the modification in the m_longestLine mutable.
WBoundingBox getBoundingBox() const
Recomputes on every call the axis aligned bounding box incorporating all tracts in this cluster.
Represents a neural pathway.
Definition: WFiber.h:40
vector_type::iterator iterator
Compares to std::vector type.
Definition: WMixinVector.h:92
size_type size() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:267
void push_back(const value_type &value)
Wrapper around std::vector member function.
Definition: WMixinVector.h:457
const_reference back() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:537
const_reference front() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:557
iterator insert(iterator where, const value_type &value)
Wrapper around std::vector member function.
Definition: WMixinVector.h:503
const_iterator begin() const
Wrapper around std::vector member function.
Definition: WMixinVector.h:307
const_reference at(size_type index) const
Wrapper around std::vector member function.
Definition: WMixinVector.h:413
vector_type::const_iterator const_iterator
Compares to std::vector type.
Definition: WMixinVector.h:87
Represents a plane with a normal vector and a position in space.
Definition: WPlane.h:39
const WPosition & getPosition() const
Returns a point in that plane.
Definition: WPlane.h:166
void resetPosition(WPosition newPos)
Reset the position of the plane, normal remains the same.
Definition: WPlane.cpp:61
This only is a 3d double vector.
Class building the interface for classes that might be transferred using WModuleConnector.
Definition: WTransferable.h:38