OpenWalnut  1.5.0dev
WThreadedTrackingFunction.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 <limits>
26 #include <string>
27 #include <vector>
28 
29 #include "../common/WLimits.h"
30 #include "WThreadedTrackingFunction.h"
31 
32 namespace wtracking
33 {
34  bool WTrackingUtility::followToNextVoxel( DataSetPtr dataset, JobType& job, DirFunc const& dirFunc )
35  {
36  // TODO(reichenbach): Give those WAsserts correct strings incase they occur
37  WAssert( dataset->getGrid(), "" );
38  Grid3DPtr g = std::dynamic_pointer_cast< WGridRegular3D >( dataset->getGrid() );
39  WAssert( g, "" );
40  WAssert( g->encloses( job.first ), "" );
41 
42  // find matching direction
43  WVector3d dir = dirFunc( dataset, job );
44 
45  if( fabs( length( dir ) - 1.0 ) > TRACKING_EPS )
46  {
47  return false;
48  }
49 
50  // find t such that job.first() + t * dir is a point on the boundary of the current voxel
51  double t = getDistanceToBoundary( g, job.first, dir );
52  WAssert( !wlimits::isInf( t ) && !wlimits::isNaN( t ), "Warning in WTrackingUtility::followToNextVoxel NaN's or INF's occured" );
53  WAssert( t > 0.0, "" );
54  WAssert( onBoundary( g, job.first + dir * t ), "" );
55 
56  if( !g->encloses( job.first + dir * t ) )
57  {
58  return false;
59  }
60 
61  // increase t, so that job.first() + t * dir does not lie on any boundary anymore
62  // ( so we can find the corresponding voxel without ambiguities )
63  // ( this also means the resulting new position will never be in the same
64  // voxel as the starting position )
65  int i = 0;
66  while( onBoundary( g, job.first + dir * t ) && i < 50 )
67  {
68  t += TRACKING_EPS;
69  if( !g->encloses( job.first + dir * t ) )
70  {
71  return false;
72  }
73  ++i;
74  }
75  if( i == 50 )
76  {
77  return false;
78  }
79 
80  // set the new position
81  job.first += t * dir;
82  job.second = dir;
83  return true;
84  }
85 
87  {
88  WVector3d v = pos - grid->getOrigin();
89  double p;
90  double z;
91  WVector3d d = grid->getDirectionX();
92  d = normalize( d );
93  double c = dot( d, v ) / grid->getOffsetX() + 0.5;
94  p = c >= 0.0 ? modf( c, &z ) : 1.0 + modf( c, &z );
95  if( fabs( p ) < TRACKING_EPS || fabs( p - 1 ) < TRACKING_EPS )
96  {
97  return true;
98  }
99  d = grid->getDirectionY();
100  d = normalize( d );
101  c = dot( d, v ) / grid->getOffsetY() + 0.5;
102  p = c >= 0.0 ? modf( c, &z ) : 1.0 + modf( c, &z );
103  if( fabs( p ) < TRACKING_EPS || fabs( p - 1 ) < TRACKING_EPS )
104  {
105  return true;
106  }
107  d = grid->getDirectionZ();
108  d = normalize( d );
109  c = dot( d, v ) / grid->getOffsetZ() + 0.5;
110  p = c >= 0.0 ? modf( c, &z ) : 1.0 + modf( c, &z );
111  if( fabs( p ) < TRACKING_EPS || fabs( p - 1 ) < TRACKING_EPS )
112  {
113  return true;
114  }
115  return false;
116  }
117 
119  {
120  // the input pos is at least TRACKING_EPS away from the boundary
121  // so distance calculations don't get screwed
122  WAssert( !onBoundary( grid, pos ), "" );
123 
124  double dist = std::numeric_limits< double >::infinity();
125 
126  WVector3d v = pos - grid->getOrigin();
127  WVector3d p;
128  double z;
129  WVector3d o( grid->getOffsetX(), grid->getOffsetY(), grid->getOffsetZ() );
130  WVector3d s[ 3 ] = { grid->getDirectionX() / o[ 0 ], grid->getDirectionY() / o[ 1 ], grid->getDirectionZ() / o[ 2 ] };
131  double c = dot( s[ 0 ], v ) / o[ 0 ] + 0.5;
132  p[ 0 ] = c >= 0.0 ? modf( c, &z ) : 1.0 + modf( c, &z );
133  c = dot( s[ 1 ], v ) / o[ 1 ] + 0.5;
134  p[ 1 ] = c >= 0.0 ? modf( c, &z ) : 1.0 + modf( c, &z );
135  c = dot( s[ 2 ], v ) / o[ 2 ] + 0.5;
136  p[ 2 ] = c >= 0.0 ? modf( c, &z ) : 1.0 + modf( c, &z );
137  WVector3d d( dot( dir, s[ 0 ] ), dot( dir, s[ 1 ] ), dot( dir, s[ 2 ] ) );
138 
139  double t;
140  for( int i = 0; i < 3; ++i )
141  {
142  WAssert( -TRACKING_EPS < p[ i ] && p[ i ] < o[ i ] + TRACKING_EPS, "" );
143  for( double j = 0.0; j <= 1.0; j += 1.0 )
144  {
145  if( fabs( d[ i ] ) > TRACKING_EPS )
146  {
147  t = ( j - p[ i ] ) * o[ i ] / d[ i ];
148  if( t > 0.0 && t < dist )
149  {
150  dist = t;
151  }
152  }
153  }
154  }
155  // distance absolute must be at least TRACKING_EPS!
156  WAssert( dist >= TRACKING_EPS, "" );
157  return dist;
158  }
159 
160  //////////////////////////////////////////////////////////////////////////////////////////
161 
163  NextPositionFunc nextFunc,
164  FiberVisitorFunc fiberVst, PointVisitorFunc pointVst,
165  std::size_t seedPositions, std::size_t seedsPerPos,
166  std::vector< int > v0, std::vector< int > v1 )
167  : Base( dataset ),
168  m_grid( std::dynamic_pointer_cast< GridType >( dataset->getGrid() ) ),
169  m_directionFunc( dirFunc ),
170  m_nextPosFunc( nextFunc ),
171  m_fiberVisitor( fiberVst ),
172  m_pointVisitor( pointVst ),
173  m_maxPoints(),
174  m_currentIndex()
175  {
176  // dataset != 0 is tested by the base constructor
177  if( !m_grid )
178  {
179  throw WException( std::string( "Cannot find WGridRegular3D. Are you sure the dataset has the correct grid type?" ) );
180  }
181 
182  m_maxPoints = static_cast< std::size_t >( 5 * pow( static_cast< double >( m_grid->size() ), 1.0 / 3.0 ) );
183 
184  m_currentIndex.getWriteTicket()->get() = IndexType( m_grid, v0, v1, seedPositions, seedsPerPos );
185  }
186 
188  {
189  }
190 
192  {
194  if( t->get().done() )
195  {
196  return false;
197  }
198  else
199  {
200  job = t->get().job();
201  ++t->get();
202  return true;
203  }
204  }
205 
207  {
208  WVector3d e = m_directionFunc( input, job );
209  JobType j = job;
210  j.second = e;
211 
212  std::vector< WVector3d > fiber;
213  if( fabs( length( e ) - 1.0 ) > TRACKING_EPS )
214  {
215  if( m_fiberVisitor )
216  {
217  m_fiberVisitor( fiber );
218  }
219  return;
220  }
221 
222  fiber.push_back( j.first );
223  if( m_pointVisitor )
224  {
225  m_pointVisitor( j.first );
226  }
227 
228  // forward integration
229  for( std::size_t k = 0; k < m_maxPoints; ++k )
230  {
231  if( fabs( length( j.second ) - 1.0 ) > TRACKING_EPS )
232  {
233  break;
234  }
235  if( !m_nextPosFunc( input, j, m_directionFunc ) )
236  {
237  break;
238  }
239  fiber.push_back( j.first );
240  if( m_pointVisitor )
241  {
242  m_pointVisitor( j.first );
243  }
244  }
245 
246  // backward integration
247  std::reverse( fiber.begin(), fiber.end() );
248  j = job;
249  j.second = e * -1.0;
250  for( std::size_t k = 0; k < m_maxPoints; ++k )
251  {
252  if( fabs( length( j.second ) - 1.0 ) > TRACKING_EPS )
253  {
254  break;
255  }
256  if( !m_nextPosFunc( input, j, m_directionFunc ) )
257  {
258  break;
259  }
260  fiber.push_back( j.first );
261  if( m_pointVisitor )
262  {
263  m_pointVisitor( j.first );
264  }
265  }
266 
267  // output result
268  if( m_fiberVisitor )
269  {
270  m_fiberVisitor( fiber );
271  }
272  }
273 
275  : m_grid(),
276  m_done( true )
277  {
278  }
279 
280  WThreadedTrackingFunction::IndexType::IndexType( GridPtr grid, std::vector< int > const& v0,
281  std::vector< int > const& v1, std::size_t seedPositions,
282  std::size_t seedsPerPosition )
283  : m_grid( grid ),
284  m_done( false )
285  {
286  if( v0.size() != 3 )
287  {
288  m_min[ 0 ] = m_min[ 1 ] = m_min[ 2 ] = seedPositions;
289  }
290  else
291  {
292  WAssert( v0[ 0 ] >= 1 && static_cast< std::size_t >( v0[ 0 ] ) < m_grid->getNbCoordsX() - 1, "" );
293  WAssert( v0[ 1 ] >= 1 && static_cast< std::size_t >( v0[ 1 ] ) < m_grid->getNbCoordsY() - 1, "" );
294  WAssert( v0[ 2 ] >= 1 && static_cast< std::size_t >( v0[ 2 ] ) < m_grid->getNbCoordsZ() - 1, "" );
295  for( int i = 0; i < 3; ++i )
296  {
297  m_min[ i ] = v0[ i ] * seedPositions;
298  }
299  }
300  if( v1.size() != 3 )
301  {
302  m_max[ 0 ] = ( m_grid->getNbCoordsX() - 1 ) * seedPositions;
303  m_max[ 1 ] = ( m_grid->getNbCoordsY() - 1 ) * seedPositions;
304  m_max[ 2 ] = ( m_grid->getNbCoordsZ() - 1 ) * seedPositions;
305  }
306  else
307  {
308  WAssert( v1[ 0 ] > v0[ 0 ] && static_cast< std::size_t >( v1[ 0 ] ) < grid->getNbCoordsX(), "" );
309  WAssert( v1[ 1 ] > v0[ 1 ] && static_cast< std::size_t >( v1[ 1 ] ) < grid->getNbCoordsY(), "" );
310  WAssert( v1[ 2 ] > v0[ 2 ] && static_cast< std::size_t >( v1[ 2 ] ) < grid->getNbCoordsZ(), "" );
311  for( int i = 0; i < 3; ++i )
312  {
313  m_max[ i ] = v1[ i ] * seedPositions;
314  }
315  }
316  m_offset = 1.0 / seedPositions;
317  m_min[ 3 ] = 0;
318  m_max[ 3 ] = seedsPerPosition;
319  m_pos[ 0 ] = m_min[ 0 ];
320  m_pos[ 1 ] = m_min[ 1 ];
321  m_pos[ 2 ] = m_min[ 2 ];
322  m_pos[ 3 ] = 0;
323  }
324 
326  {
327  if( !m_done )
328  {
329  for( int i = 3; i > -1; --i )
330  {
331  ++m_pos[ i ];
332  if( m_pos[ i ] == m_max[ i ] )
333  {
334  m_pos[ i ] = m_min[ i ];
335  m_done = i == 0;
336  }
337  else
338  {
339  break;
340  };
341  }
342  }
343  return *this;
344  }
345 
347  {
348  return m_done;
349  }
350 
352  {
353  JobType job;
354  job.second = WVector3d( 0.0, 0.0, 0.0 );
355  job.first = m_grid->getOrigin() + m_grid->getDirectionX() * ( m_offset * ( 0.5 + m_pos[ 0 ] ) - 0.5 )
356  + m_grid->getDirectionY() * ( m_offset * ( 0.5 + m_pos[ 1 ] ) - 0.5 )
357  + m_grid->getDirectionZ() * ( m_offset * ( 0.5 + m_pos[ 2 ] ) - 0.5 );
358  return job;
359  }
360 
361 } // namespace wtracking
Basic exception handler.
Definition: WException.h:39
A grid that has parallelepiped cells which all have the same proportion.
std::shared_ptr< WSharedObjectTicketWrite< T > > WriteTicket
Type for write tickets.
Definition: WSharedObject.h:70
A threaded functor base class for producer-consumer-style multithreaded computation.
Definition: WThreadedJobs.h:51
boost::array< std::size_t, 4 > m_max
the maximum position in the seed space
boost::array< std::size_t, 4 > m_min
the minimum position in the seed space
bool done()
Check if there aren't any more seed positions.
double m_offset
the relative (to the size of a voxel) distance between seeds
IndexType & operator++()
Increase the index by one, effectively generating the next seed position.
boost::array< std::size_t, 4 > m_pos
the position in the seed space
WTrackingUtility::JobType JobType
the job type
WTrackingUtility::DataSetPtr DataSetPtr
a pointer to a dataset
std::shared_ptr< GridType > GridPtr
a pointer to the grid
FiberVisitorFunc m_fiberVisitor
the fiber visitor
std::size_t m_maxPoints
the maximum number of points per forward/backward integration of a fiber
boost::function< void(std::vector< WVector3d > const &) > FiberVisitorFunc
a visitor function for fibers
WThreadedTrackingFunction(DataSetPtr dataset, DirFunc dirFunc, NextPositionFunc nextFunc, FiberVisitorFunc fiberVst, PointVisitorFunc pointVst, std::size_t seedPositions=1, std::size_t seedsPerPos=1, std::vector< int > v0=std::vector< int >(), std::vector< int > v1=std::vector< int >())
Constructor.
WTrackingUtility::DirFunc DirFunc
the direction calculation function
boost::function< bool(DataSetPtr, JobType &, DirFunc const &) > NextPositionFunc
the path integration function
NextPositionFunc m_nextPosFunc
a function that calculates the next position
boost::function< void(WVector3d const &) > PointVisitorFunc
a visitor function type for points
WSharedObject< IndexType > m_currentIndex
the current index/seed position
virtual void compute(DataSetPtr input, JobType const &job)
The calculation per job.
DirFunc m_directionFunc
a function that returns the next direction
virtual bool getJob(JobType &job)
The job generator.
PointVisitorFunc m_pointVisitor
the point visitor
static bool onBoundary(Grid3DPtr grid, WVector3d const &pos)
Check if a point is on the boundary of the given grid, where boundary means a distance less then TRAC...
std::pair< WVector3d, WVector3d > JobType
define a job type for tracking algorithms
static bool followToNextVoxel(DataSetPtr dataset, JobType &job, DirFunc const &dirFunc)
A function that follows a direction until leaving the current voxel.
std::shared_ptr< WGridRegular3D > Grid3DPtr
a pointer to a regular 3d grid
std::shared_ptr< DataSetType const > DataSetPtr
a pointer to a dataset
static double getDistanceToBoundary(Grid3DPtr grid, WVector3d const &pos, WVector3d const &dir)
Calculate the distance from a given position to the nearest voxel boundary on the ray from the positi...
boost::function< WVector3d(DataSetPtr, JobType const &) > DirFunc
a function that calculates a direction to continue tracking
bool isInf(T value)
Determines if a number is considered as infinity or not.
Definition: WLimits.h:101
bool isNaN(T value)
Determines if a number is considered as NaN (aka Not a Number) or not.
Definition: WLimits.h:96
forward declaration