CASToR  2.0
Tomographic Reconstruction (PET/SPECT/CT)
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iProjectorIncrementalSiddon.cc
Go to the documentation of this file.
1 /*
2 This file is part of CASToR.
3 
4  CASToR is free software: you can redistribute it and/or modify it under the
5  terms of the GNU General Public License as published by the Free Software
6  Foundation, either version 3 of the License, or (at your option) any later
7  version.
8 
9  CASToR is distributed in the hope that it will be useful, but WITHOUT ANY
10  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  details.
13 
14  You should have received a copy of the GNU General Public License along with
15  CASToR (in file GNU_GPL.TXT). If not, see <http://www.gnu.org/licenses/>.
16 
17 Copyright 2017-2018 all CASToR contributors listed below:
18 
19  --> current contributors: Thibaut MERLIN, Simon STUTE, Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Mael MILLARDET
20  --> past contributors: Valentin VIELZEUF
21 
22 This is CASToR version 2.0.
23 */
24 
32 #include "sOutputManager.hh"
33 
34 // =====================================================================
35 // ---------------------------------------------------------------------
36 // ---------------------------------------------------------------------
37 // =====================================================================
38 
40 {
41  // This projector is compatible with SPECT attenuation correction because
42  // all voxels contributing to a given line are ordered from point 1 (focal)
43  // to point 2 (scanner). Note that there can be some aliasing problem with
44  // this incremental method, but which will depend on the voxel size and number.
45  // However, these problems are quite negligible and pretty uncommon. So we still
46  // say that this projector is compatible.
48  // This projector is compatible with compression as it works only with the
49  // cartesian coordinates of 2 end points of a line
51 }
52 
53 // =====================================================================
54 // ---------------------------------------------------------------------
55 // ---------------------------------------------------------------------
56 // =====================================================================
57 
59 {
60 }
61 
62 // =====================================================================
63 // ---------------------------------------------------------------------
64 // ---------------------------------------------------------------------
65 // =====================================================================
66 
67 int iProjectorIncrementalSiddon::ReadConfigurationFile(const string& a_configurationFile)
68 {
69  // No options for incremental siddon
70  ;
71  // Normal end
72  return 0;
73 }
74 
75 // =====================================================================
76 // ---------------------------------------------------------------------
77 // ---------------------------------------------------------------------
78 // =====================================================================
79 
80 int iProjectorIncrementalSiddon::ReadOptionsList(const string& a_optionsList)
81 {
82  // No options for incremental siddon
83  ;
84  // Normal end
85  return 0;
86 }
87 
88 // =====================================================================
89 // ---------------------------------------------------------------------
90 // ---------------------------------------------------------------------
91 // =====================================================================
92 
94 {
95  cout << "This projector is a simple line projector that computes the exact path length of a line through the voxels." << endl;
96  cout << "It is basically an incremental version of the original algorithm proposed by R. L. Siddon (see the classicSiddon projector)." << endl;
97  cout << "It is implemented from the following published paper:" << endl;
98  cout << "F. Jacobs et al, \"A fast algorithm to calculate the exact radiological path through a pixel or voxel space\", J. Comput. Inf. Technol., vol. 6, pp. 89-94, 1998." << endl;
99 }
100 
101 // =====================================================================
102 // ---------------------------------------------------------------------
103 // ---------------------------------------------------------------------
104 // =====================================================================
105 
107 {
108  // Nothing to check for this projector
109  ;
110  // Normal end
111  return 0;
112 }
113 
114 // =====================================================================
115 // ---------------------------------------------------------------------
116 // ---------------------------------------------------------------------
117 // =====================================================================
118 
120 {
121  // Verbose
122  if (m_verbose>=2) Cout("iProjectorIncrementalSiddon::InitializeSpecific() -> Use incremental Siddon projector" << endl);
123  // Normal end
124  return 0;
125 }
126 
127 // =====================================================================
128 // ---------------------------------------------------------------------
129 // ---------------------------------------------------------------------
130 // =====================================================================
131 
133 {
134  // Find the maximum number of voxels along a given dimension
135  INTNB max_nb_voxels_in_dimension = mp_ImageDimensionsAndQuantification->GetNbVoxX();
136  if (mp_ImageDimensionsAndQuantification->GetNbVoxY()>max_nb_voxels_in_dimension) max_nb_voxels_in_dimension = mp_ImageDimensionsAndQuantification->GetNbVoxY();
137  if (mp_ImageDimensionsAndQuantification->GetNbVoxZ()>max_nb_voxels_in_dimension) max_nb_voxels_in_dimension = mp_ImageDimensionsAndQuantification->GetNbVoxZ();
138  // We should have at most 4 voxels in a given plane, so multiply by 4
139  // (note: this is not true however it ensures no overflow and is already quite optimized for RAM usage !)
140  max_nb_voxels_in_dimension *= 4;
141  // Return the value
142  return max_nb_voxels_in_dimension;
143 }
144 
145 // =====================================================================
146 // ---------------------------------------------------------------------
147 // ---------------------------------------------------------------------
148 // =====================================================================
149 
150 int iProjectorIncrementalSiddon::ProjectWithoutTOF(int a_direction, oProjectionLine* ap_ProjectionLine )
151 {
152  #ifdef CASTOR_DEBUG
153  if (!m_initialized)
154  {
155  Cerr("***** iProjectorIncrementalSiddon::ProjectWithoutTOF() -> Called while not initialized !" << endl);
156  Exit(EXIT_DEBUG);
157  }
158  #endif
159 
160  #ifdef CASTOR_VERBOSE
161  if (m_verbose>=10)
162  {
163  string direction = "";
164  if (a_direction==FORWARD) direction = "forward";
165  else direction = "backward";
166  Cout("iProjectorIncrementalSiddon::Project without TOF -> Project line '" << ap_ProjectionLine << "' in " << direction << " direction" << endl);
167  }
168  #endif
169 
170  // Get event positions
171  FLTNB* event1Float = ap_ProjectionLine->GetPosition1();
172  FLTNB* event2Float = ap_ProjectionLine->GetPosition2();
173  HPFLTNB event1[3] = { event1Float[0], event1Float[1], event1Float[2] };
174  HPFLTNB event2[3] = { event2Float[0], event2Float[1], event2Float[2] };
175 
176  // **************************************
177  // STEP 1: LOR length calculation
178  // **************************************
179  HPFLTNB length_LOR = ap_ProjectionLine->GetLength();
180 
181  // **************************************
182  // STEP 2: Compute entrance voxel indexes
183  // **************************************
184  HPFLTNB alphaFirst[] = { 0.0, 0.0, 0.0 };
185  HPFLTNB alphaLast[] = { 0.0, 0.0, 0.0 };
186 
187  HPFLTNB alphaMin = 0.0f, alphaMax = 1.0f;
188  HPFLTNB delta_pos[] = {
189  event2[ 0 ] - event1[ 0 ],
190  event2[ 1 ] - event1[ 1 ],
191  event2[ 2 ] - event1[ 2 ]
192  };
193 
194  // Computation of alphaMin et alphaMax values (entrance and exit point of the ray)
195  for( int i = 0; i < 3; ++i )
196  {
197  if( delta_pos[ i ] != 0.0 )
198  {
199  alphaFirst[i] = (-mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
200  alphaLast[i] = ( mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
201  alphaMin = (std::max)(alphaMin,(std::min)(alphaFirst[i],alphaLast[i]));
202  alphaMax = (std::min)(alphaMax,(std::max)(alphaFirst[i],alphaLast[i]));
203  }
204  }
205 
206  // if alphaMax is less than or equal to alphaMin no intersection
207  // and return an empty buffer
208  if( alphaMax <= alphaMin ) return 0;
209 
210  // Now we have to find the indices of the particular plane
211  // (iMin,iMax), (jMin,jMax), (kMin,kMax)
212  int iMin = 0, iMax = 0;
213  int jMin = 0, jMax = 0;
214  int kMin = 0, kMax = 0;
215 
216  // For the X-axis
217  if( delta_pos[ 0 ] > 0.0f )
218  {
219  iMin = ::ceil( ( mp_nbVox[ 0 ] + 1 ) - ( mp_halfFOV[ 0 ] - alphaMin * delta_pos[ 0 ] - event1[ 0 ] ) / mp_sizeVox[0] );
220  iMax = ::floor( 1 + ( event1[ 0 ] + alphaMax * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] );
221  }
222  else if( delta_pos[ 0 ] < 0.0f )
223  {
224  iMin = ::ceil( ( mp_nbVox[ 0 ] + 1 ) - ( mp_halfFOV[ 0 ] - alphaMax * delta_pos[ 0 ] - event1[ 0 ] ) / mp_sizeVox[0] );
225  iMax = ::floor( 1 + ( event1[ 0 ] + alphaMin * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] );
226  }
227  if( delta_pos[ 0 ] == 0 )
228  {
229  iMin = 1, iMax = 0;
230  }
231 
232  // For the Y-axis
233  if( delta_pos[ 1 ] > 0 )
234  {
235  jMin = ::ceil( ( mp_nbVox[ 1 ] + 1 ) - ( mp_halfFOV[ 1 ] - alphaMin * delta_pos[ 1 ] - event1[ 1 ] ) / mp_sizeVox[1] );
236  jMax = ::floor( 1 + ( event1[ 1 ] + alphaMax * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] );
237  }
238  else if( delta_pos[ 1 ] < 0 )
239  {
240  jMin = ::ceil( ( mp_nbVox[ 1 ] + 1 ) - ( mp_halfFOV[ 1 ] - alphaMax * delta_pos[ 1 ] - event1[ 1 ] ) / mp_sizeVox[1] );
241  jMax = ::floor( 1 + ( event1[ 1 ] + alphaMin * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] );
242  }
243  else if( delta_pos[ 1 ] == 0 )
244  {
245  jMin = 1, jMax = 0;
246  }
247 
248  // For the Z-axis
249  if( delta_pos[ 2 ] > 0 )
250  {
251  kMin = ::ceil( ( mp_nbVox[ 2 ] + 1 ) - ( mp_halfFOV[ 2 ] - alphaMin * delta_pos[ 2 ] - event1[ 2 ] ) / mp_sizeVox[2] );
252  kMax = ::floor( 1 + ( event1[ 2 ] + alphaMax * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] );
253  }
254  else if( delta_pos[ 2 ] < 0 )
255  {
256  kMin = ::ceil( ( mp_nbVox[ 2 ] + 1 ) - ( mp_halfFOV[ 2 ] - alphaMax * delta_pos[ 2 ] - event1[ 2 ] ) / mp_sizeVox[2] );
257  kMax = ::floor( 1 + ( event1[ 2 ] + alphaMin * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] );
258  }
259  else if( delta_pos[ 2 ] == 0 )
260  {
261  kMin = 1, kMax = 0;
262  }
263 
264  // Computing the last term n number of intersection
265  INTNB n = ( iMax - iMin + 1 ) + ( jMax - jMin + 1 )
266  + ( kMax - kMin + 1 );
267 
268  // Array storing the first alpha in X, Y and Z
269  HPFLTNB alpha_XYZ[ 3 ] = { 1.0f, 1.0f, 1.0f };
270 
271  // Computing the first alpha in X
272  if( delta_pos[ 0 ] > 0 )
273  alpha_XYZ[ 0 ] = ( ( (-mp_halfFOV[ 0 ]) + ( iMin - 1 ) * mp_sizeVox[0] ) - event1[ 0 ] ) / delta_pos[ 0 ];
274  else if( delta_pos[ 0 ] < 0 )
275  alpha_XYZ[ 0 ] = ( ( (-mp_halfFOV[ 0 ]) + ( iMax - 1 ) * mp_sizeVox[0] ) - event1[ 0 ] ) / delta_pos[ 0 ];
276 
277  // Computing the first alpha in Y
278  if( delta_pos[ 1 ] > 0 )
279  alpha_XYZ[ 1 ] = ( ( (-mp_halfFOV[ 1 ]) + ( jMin - 1 ) * mp_sizeVox[1] ) - event1[ 1 ] ) / delta_pos[ 1 ];
280  else if( delta_pos[ 1 ] < 0 )
281  alpha_XYZ[ 1 ] = ( ( (-mp_halfFOV[ 1 ]) + ( jMax - 1 ) * mp_sizeVox[1] ) - event1[ 1 ] ) / delta_pos[ 1 ];
282 
283  // Computing the first alpha in Z
284  if( delta_pos[ 2 ] > 0 )
285  alpha_XYZ[ 2 ] = ( ( (-mp_halfFOV[ 2 ]) + ( kMin - 1 ) * mp_sizeVox[2] ) - event1[ 2 ] ) / delta_pos[ 2 ];
286  else if( delta_pos[ 2 ] < 0 )
287  alpha_XYZ[ 2 ] = ( ( (-mp_halfFOV[ 2 ]) + ( kMax - 1 ) * mp_sizeVox[2] ) - event1[ 2 ] ) / delta_pos[ 2 ];
288 
289  // Computing the alpha updating
290  HPFLTNB alpha_u[ 3 ] = {
291  mp_sizeVox[0] / std::fabs( delta_pos[ 0 ] ),
292  mp_sizeVox[1] / std::fabs( delta_pos[ 1 ] ),
293  mp_sizeVox[2] / std::fabs( delta_pos[ 2 ] )
294  };
295 
296  // Computing the index updating
297  INTNB index_u[ 3 ] = {
298  (delta_pos[ 0 ] < 0) ? -1 : 1,
299  (delta_pos[ 1 ] < 0) ? -1 : 1,
300  (delta_pos[ 2 ] < 0) ? -1 : 1
301  };
302 
303  // Check which alpha is the min/max and increment
304  if( alpha_XYZ[ 0 ] == alphaMin ) alpha_XYZ[ 0 ] += alpha_u[ 0 ];
305  if( alpha_XYZ[ 1 ] == alphaMin ) alpha_XYZ[ 1 ] += alpha_u[ 1 ];
306  if( alpha_XYZ[ 2 ] == alphaMin ) alpha_XYZ[ 2 ] += alpha_u[ 2 ];
307 
308  // Computing the minimum value in the alpha_XYZ buffer
309  HPFLTNB const min_alpha_XYZ = (std::min)( alpha_XYZ[ 0 ],
310  (std::min)( alpha_XYZ[ 1 ], alpha_XYZ[ 2 ] ) );
311 
312  // Computing the first index of intersection
313  HPFLTNB const alphaMid = ( min_alpha_XYZ + alphaMin ) / 2.0f;
314  INTNB index_ijk[ 3 ] = {
315  1 + (int)( ( event1[ 0 ] + alphaMid * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] ),
316  1 + (int)( ( event1[ 1 ] + alphaMid * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] ),
317  1 + (int)( ( event1[ 2 ] + alphaMid * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] )
318  };
319 
320  INTNB const w = mp_nbVox[ 0 ];
321  INTNB const wh = w * mp_nbVox[ 1 ];
322 
323  // Loop over the number of plane to cross
324  HPFLTNB alpha_c = alphaMin;
325  FLTNB coeff = 0.0f;
326  INTNB numVox = 0;
327 
328  for( int nP = 0; nP < n - 1; ++nP )
329  {
330  if( ( alpha_XYZ[ 0 ] <= alpha_XYZ[ 1 ] )
331  && ( alpha_XYZ[ 0 ] <= alpha_XYZ[ 2 ] ) )
332  {
333  // Storing values
334  if( ( alpha_XYZ[ 0 ] >= alphaMin )
335  && ( index_ijk[ 0 ] - 1 >= 0 )
336  && ( index_ijk[ 0 ] - 1 <= mp_nbVox[ 0 ] - 1 )
337  && ( index_ijk[ 1 ] - 1 >= 0 )
338  && ( index_ijk[ 1 ] - 1 <= mp_nbVox[ 1 ] - 1 )
339  && ( index_ijk[ 2 ] - 1 >= 0 )
340  && ( index_ijk[ 2 ] - 1 <= mp_nbVox[ 2 ] - 1 ) )
341  {
342  coeff = ( alpha_XYZ[ 0 ] - alpha_c ) * length_LOR;
343  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
344  // if this voxel is masked, do nothing
345  if (!m_hasMask || mp_mask[numVox]) ap_ProjectionLine->AddVoxel(a_direction, numVox, coeff);
346  }
347  // Increment values
348  alpha_c = alpha_XYZ[ 0 ];
349  alpha_XYZ[ 0 ] += alpha_u[ 0 ];
350  index_ijk[ 0 ] += index_u[ 0 ];
351  }
352  else if( ( alpha_XYZ[ 1 ] < alpha_XYZ[ 0 ] )
353  && ( alpha_XYZ[ 1 ] <= alpha_XYZ[ 2 ] ) )
354  {
355  // Storing values
356  if( ( alpha_XYZ[ 1 ] >= alphaMin )
357  && ( index_ijk[ 0 ] - 1 >= 0 )
358  && ( index_ijk[ 0 ] - 1 <= mp_nbVox[ 0 ] - 1 )
359  && ( index_ijk[ 1 ] - 1 >= 0 )
360  && ( index_ijk[ 1 ] - 1 <= mp_nbVox[ 1 ] - 1 )
361  && ( index_ijk[ 2 ] - 1 >= 0 )
362  && ( index_ijk[ 2 ] - 1 <= mp_nbVox[ 2 ] - 1 ) )
363  {
364  coeff = ( alpha_XYZ[ 1 ] - alpha_c ) * length_LOR;
365  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
366  // if this voxel is masked, do nothing
367  if (!m_hasMask || mp_mask[numVox]) ap_ProjectionLine->AddVoxel(a_direction, numVox, coeff);
368  }
369  // Increment values
370  alpha_c = alpha_XYZ[ 1 ];
371  alpha_XYZ[ 1 ] += alpha_u[ 1 ];
372  index_ijk[ 1 ] += index_u[ 1 ];
373  }
374  else if( ( alpha_XYZ[ 2 ] < alpha_XYZ[ 0 ] )
375  && ( alpha_XYZ[ 2 ] < alpha_XYZ[ 1 ] ) )
376  {
377  // Storing values
378  if( ( alpha_XYZ[ 2 ] >= alphaMin )
379  && ( index_ijk[ 0 ] - 1 >= 0 )
380  && ( index_ijk[ 0 ] - 1 <= mp_nbVox[ 0 ] - 1 )
381  && ( index_ijk[ 1 ] - 1 >= 0 )
382  && ( index_ijk[ 1 ] - 1 <= mp_nbVox[ 1 ] - 1 )
383  && ( index_ijk[ 2 ] - 1 >= 0 )
384  && ( index_ijk[ 2 ] - 1 <= mp_nbVox[ 2 ] - 1 ) )
385  {
386  coeff = ( alpha_XYZ[ 2 ] - alpha_c ) * length_LOR;
387  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
388  // if this voxel is masked, do nothing
389  if (!m_hasMask || mp_mask[numVox]) ap_ProjectionLine->AddVoxel(a_direction, numVox, coeff);
390  }
391  // Increment values
392  alpha_c = alpha_XYZ[ 2 ];
393  alpha_XYZ[ 2 ] += alpha_u[ 2 ];
394  index_ijk[ 2 ] += index_u[ 2 ];
395  }
396  }
397 
398  return 0;
399 }
400 
401 // =====================================================================
402 // ---------------------------------------------------------------------
403 // ---------------------------------------------------------------------
404 // =====================================================================
405 
406 int iProjectorIncrementalSiddon::ProjectWithTOFPos(int a_direction, oProjectionLine* ap_ProjectionLine)
407 {
408  #ifdef CASTOR_DEBUG
409  if (!m_initialized)
410  {
411  Cerr("***** iProjectorIncrementalSiddon::ProjectWithTOFPos() -> Called while not initialized !" << endl);
412  Exit(EXIT_DEBUG);
413  }
414  #endif
415 
416  #ifdef CASTOR_VERBOSE
417  if (m_verbose>=10)
418  {
419  string direction = "";
420  if (a_direction==FORWARD) direction = "forward";
421  else direction = "backward";
422  Cout("iProjectorIncrementalSiddon::Project with TOF position -> Project line '" << ap_ProjectionLine << "' in " << direction << " direction" << endl);
423  }
424  #endif
425 
426  // Simpler way now, hopefully it works
427  FLTNB* event1Float = ap_ProjectionLine->GetPosition1();
428  FLTNB* event2Float = ap_ProjectionLine->GetPosition2();
429  HPFLTNB event1[3] = { event1Float[0], event1Float[1], event1Float[2] };
430  HPFLTNB event2[3] = { event2Float[0], event2Float[1], event2Float[2] };
431 
432  // **************************************
433  // STEP 1: LOR length calculation
434  // **************************************
435  HPFLTNB length_LOR = ap_ProjectionLine->GetLength();
436 
437  // **************************************
438  // STEP 2: Compute entrance voxel indexes
439  // **************************************
440  HPFLTNB alphaFirst[] = { 0.0, 0.0, 0.0 };
441  HPFLTNB alphaLast[] = { 0.0, 0.0, 0.0 };
442 
443  HPFLTNB alphaMin = 0.0f, alphaMax = 1.0f;
444  HPFLTNB delta_pos[] = {
445  event2[ 0 ] - event1[ 0 ],
446  event2[ 1 ] - event1[ 1 ],
447  event2[ 2 ] - event1[ 2 ]
448  };
449 
450  // Get TOF info
451  HPFLTNB tof_resolutionT = ap_ProjectionLine->GetTOFResolution();
452  HPFLTNB tof_measurement = ap_ProjectionLine->GetTOFMeasurement();
453 
454  // TOF spatial standard deviation and truncation
455  HPFLTNB tof_sigma = tof_resolutionT * SPEED_OF_LIGHT * 0.5 / TWO_SQRT_TWO_LN_2;
456  HPFLTNB tof_sigma_sqrt2 = sqrt(2.)*tof_sigma;
457  HPFLTNB tof_half_span = tof_sigma * m_TOFnbSigmas;
458 
459  // convert delta time into delta length
460  HPFLTNB tof_delta = tof_measurement * SPEED_OF_LIGHT * 0.5;
461 
462  // distance between the first event1 and the center of the Gaussian distribution along the LOR
463  HPFLTNB lor_tof_center = length_LOR * 0.5 + tof_delta;
464 
465  // index along each axis of the first voxel falling inside the truncated Gaussian distribution
466  HPFLTNB tof_edge_low[] = {0,0,0};
467  // index along each axis of the last voxel falling inside the truncated Gaussian distribution
468  HPFLTNB tof_edge_high[] = {0,0,0};
469  HPFLTNB tof_center;
470  INTNB tof_index_low[] = {0,0,0};
471  INTNB tof_index_high[] = {0,0,0};
472 
473  // low/high voxel edges (in absolute coordinates) for truncated TOF
474  for (int ax=0;ax<3;ax++)
475  {
476  // absolute coordinate along each axis of the center of the TOF distribution
477  tof_center = event1[ax] + lor_tof_center * delta_pos[ax] / length_LOR;
478 
479  // absolute coordinate along each axis of the lowest voxel edge spanned by the TOF distribution, limited by the lowest FOV edge
480  tof_edge_low[ax] = tof_center - tof_half_span * fabs(delta_pos[ax]) / length_LOR;
481  tof_index_low[ax] = max( (INTNB)::floor( (tof_edge_low[ax] - (-mp_halfFOV[ax])) / mp_sizeVox[ax] ), (INTNB)0);
482  // if low TOF edge above the highest FOV edge, return empty line
483  if (tof_index_low[ax]>mp_nbVox[ax]-1) return 0;
484  tof_edge_low[ax] = (HPFLTNB)tof_index_low[ax] * mp_sizeVox[ax] - mp_halfFOV[ax];
485 
486  // absolute coordinate along each axis of the highest voxel edge spanned by the TOF distribution, limited by the highest FOV edge
487  tof_edge_high[ax] = tof_center + tof_half_span * fabs(delta_pos[ax]) / length_LOR;
488  tof_index_high[ax] = min( (INTNB)::floor( (tof_edge_high[ax] - (-mp_halfFOV[ax])) / mp_sizeVox[ax] ), mp_nbVox[ax]-1);
489  // if high TOF edge below the lowest FOV edge, return empty line
490  if (tof_index_high[ax]<0) return 0;
491  tof_edge_high[ax] = (HPFLTNB)(tof_index_high[ax]+1) * mp_sizeVox[ax] - mp_halfFOV[ax];
492  }
493 
494  // Computation of alphaMin et alphaMax values (entrance and exit point of the ray)
495  for( int i = 0; i < 3; ++i )
496  {
497  if( delta_pos[ i ] != 0.0 )
498  {
499  alphaFirst[i] = (-mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
500  alphaLast[i] = ( mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
501  alphaMin = (std::max)(alphaMin,(std::min)(alphaFirst[i],alphaLast[i]));
502  alphaMax = (std::min)(alphaMax,(std::max)(alphaFirst[i],alphaLast[i]));
503  }
504  }
505 
506  // if alphaMax is less than or equal to alphaMin no intersection
507  // and return an empty buffer
508  if( alphaMax <= alphaMin ) return 0;
509 
510  // Now we have to find the indices of the particular plane
511  // (iMin,iMax), (jMin,jMax), (kMin,kMax)
512  int iMin = 0, iMax = 0;
513  int jMin = 0, jMax = 0;
514  int kMin = 0, kMax = 0;
515 
516  // For the X-axis
517  if( delta_pos[ 0 ] > 0.0f )
518  {
519  iMin = ::ceil( ( mp_nbVox[ 0 ] + 1 ) - ( mp_halfFOV[ 0 ] - alphaMin * delta_pos[ 0 ] - event1[ 0 ] ) / mp_sizeVox[0] );
520  iMax = ::floor( 1 + ( event1[ 0 ] + alphaMax * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] );
521  }
522  else if( delta_pos[ 0 ] < 0.0f )
523  {
524  iMin = ::ceil( ( mp_nbVox[ 0 ] + 1 ) - ( mp_halfFOV[ 0 ] - alphaMax * delta_pos[ 0 ] - event1[ 0 ] ) / mp_sizeVox[0] );
525  iMax = ::floor( 1 + ( event1[ 0 ] + alphaMin * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] );
526  }
527  if( delta_pos[ 0 ] == 0 )
528  {
529  iMin = 1, iMax = 0;
530  }
531 
532  // For the Y-axis
533  if( delta_pos[ 1 ] > 0 )
534  {
535  jMin = ::ceil( ( mp_nbVox[ 1 ] + 1 ) - ( mp_halfFOV[ 1 ] - alphaMin * delta_pos[ 1 ] - event1[ 1 ] ) / mp_sizeVox[1] );
536  jMax = ::floor( 1 + ( event1[ 1 ] + alphaMax * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] );
537  }
538  else if( delta_pos[ 1 ] < 0 )
539  {
540  jMin = ::ceil( ( mp_nbVox[ 1 ] + 1 ) - ( mp_halfFOV[ 1 ] - alphaMax * delta_pos[ 1 ] - event1[ 1 ] ) / mp_sizeVox[1] );
541  jMax = ::floor( 1 + ( event1[ 1 ] + alphaMin * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] );
542  }
543  else if( delta_pos[ 1 ] == 0 )
544  {
545  jMin = 1, jMax = 0;
546  }
547 
548  // For the Z-axis
549  if( delta_pos[ 2 ] > 0 )
550  {
551  kMin = ::ceil( ( mp_nbVox[ 2 ] + 1 ) - ( mp_halfFOV[ 2 ] - alphaMin * delta_pos[ 2 ] - event1[ 2 ] ) / mp_sizeVox[2] );
552  kMax = ::floor( 1 + ( event1[ 2 ] + alphaMax * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] );
553  }
554  else if( delta_pos[ 2 ] < 0 )
555  {
556  kMin = ::ceil( ( mp_nbVox[ 2 ] + 1 ) - ( mp_halfFOV[ 2 ] - alphaMax * delta_pos[ 2 ] - event1[ 2 ] ) / mp_sizeVox[2] );
557  kMax = ::floor( 1 + ( event1[ 2 ] + alphaMin * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] );
558  }
559  else if( delta_pos[ 2 ] == 0 )
560  {
561  kMin = 1, kMax = 0;
562  }
563 
564  // Computing the last term n number of intersection
565  INTNB n = ( iMax - iMin + 1 ) + ( jMax - jMin + 1 )
566  + ( kMax - kMin + 1 );
567 
568  // Array storing the first alpha in X, Y and Z
569  HPFLTNB alpha_XYZ[ 3 ] = { 1.0f, 1.0f, 1.0f };
570 
571  // Computing the first alpha in X
572  if( delta_pos[ 0 ] > 0 )
573  alpha_XYZ[ 0 ] = ( ( (-mp_halfFOV[ 0 ]) + ( iMin - 1 ) * mp_sizeVox[0] ) - event1[ 0 ] ) / delta_pos[ 0 ];
574  else if( delta_pos[ 0 ] < 0 )
575  alpha_XYZ[ 0 ] = ( ( (-mp_halfFOV[ 0 ]) + ( iMax - 1 ) * mp_sizeVox[0] ) - event1[ 0 ] ) / delta_pos[ 0 ];
576 
577  // Computing the first alpha in Y
578  if( delta_pos[ 1 ] > 0 )
579  alpha_XYZ[ 1 ] = ( ( (-mp_halfFOV[ 1 ]) + ( jMin - 1 ) * mp_sizeVox[1] ) - event1[ 1 ] ) / delta_pos[ 1 ];
580  else if( delta_pos[ 1 ] < 0 )
581  alpha_XYZ[ 1 ] = ( ( (-mp_halfFOV[ 1 ]) + ( jMax - 1 ) * mp_sizeVox[1] ) - event1[ 1 ] ) / delta_pos[ 1 ];
582 
583  // Computing the first alpha in Z
584  if( delta_pos[ 2 ] > 0 )
585  alpha_XYZ[ 2 ] = ( ( (-mp_halfFOV[ 2 ]) + ( kMin - 1 ) * mp_sizeVox[2] ) - event1[ 2 ] ) / delta_pos[ 2 ];
586  else if( delta_pos[ 2 ] < 0 )
587  alpha_XYZ[ 2 ] = ( ( (-mp_halfFOV[ 2 ]) + ( kMax - 1 ) * mp_sizeVox[2] ) - event1[ 2 ] ) / delta_pos[ 2 ];
588 
589  // Computing the alpha updating
590  HPFLTNB alpha_u[ 3 ] = {
591  mp_sizeVox[0] / std::fabs( delta_pos[ 0 ] ),
592  mp_sizeVox[1] / std::fabs( delta_pos[ 1 ] ),
593  mp_sizeVox[2] / std::fabs( delta_pos[ 2 ] )
594  };
595 
596  // Computing the index updating
597  INTNB index_u[ 3 ] = {
598  (delta_pos[ 0 ] < 0) ? -1 : 1,
599  (delta_pos[ 1 ] < 0) ? -1 : 1,
600  (delta_pos[ 2 ] < 0) ? -1 : 1
601  };
602 
603  // Check which alpha is the min/max and increment
604  if( alpha_XYZ[ 0 ] == alphaMin ) alpha_XYZ[ 0 ] += alpha_u[ 0 ];
605  if( alpha_XYZ[ 1 ] == alphaMin ) alpha_XYZ[ 1 ] += alpha_u[ 1 ];
606  if( alpha_XYZ[ 2 ] == alphaMin ) alpha_XYZ[ 2 ] += alpha_u[ 2 ];
607 
608  // Computing the minimum value in the alpha_XYZ buffer
609  HPFLTNB const min_alpha_XYZ = (std::min)( alpha_XYZ[ 0 ], (std::min)( alpha_XYZ[ 1 ], alpha_XYZ[ 2 ] ) );
610 
611  // Computing the first index of intersection
612  HPFLTNB const alphaMid = ( min_alpha_XYZ + alphaMin ) / 2.0f;
613  INTNB index_ijk[ 3 ] = {
614  1 + (INTNB)( ( event1[ 0 ] + alphaMid * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] ),
615  1 + (INTNB)( ( event1[ 1 ] + alphaMid * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] ),
616  1 + (INTNB)( ( event1[ 2 ] + alphaMid * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] )
617  };
618 
619  INTNB const w = mp_nbVox[ 0 ];
620  INTNB const wh = w * mp_nbVox[ 1 ];
621 
622  // tof : erf of first voxel edge - Gaussian center
623  HPFLTNB previous_edge_erf = 0.;
624  HPFLTNB next_edge_erf = 0.;
625  bool previous_edge_erf_initialized = false;
626 
627  // Loop over the number of plane to cross
628  HPFLTNB alpha_c = alphaMin;
629  FLTNB coeff = 0.0f;
630  INTNB numVox = 0;
631  for( int nP = 0; nP < n - 1; ++nP )
632  {
633  if( ( alpha_XYZ[ 0 ] <= alpha_XYZ[ 1 ] )
634  && ( alpha_XYZ[ 0 ] <= alpha_XYZ[ 2 ] ) )
635  {
636  // Storing values
637  if( ( alpha_XYZ[ 0 ] >= alphaMin )
638  && ( index_ijk[ 0 ] - 1 >= tof_index_low[0] )
639  && ( index_ijk[ 0 ] - 1 <= tof_index_high[0] )
640  && ( index_ijk[ 1 ] - 1 >= tof_index_low[1] )
641  && ( index_ijk[ 1 ] - 1 <= tof_index_high[1] )
642  && ( index_ijk[ 2 ] - 1 >= tof_index_low[2] )
643  && ( index_ijk[ 2 ] - 1 <= tof_index_high[2] ) )
644  {
645  // initialize if not initialized yet
646  if (!previous_edge_erf_initialized)
647  {
648  previous_edge_erf = erf( (length_LOR *alpha_c - lor_tof_center) / tof_sigma_sqrt2 );
649  previous_edge_erf_initialized = true;
650  }
651 
652  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
653 
654  // tof : erf of next voxel edge - Gaussian center
655  next_edge_erf = erf( (length_LOR * alpha_XYZ[ 0 ] - lor_tof_center) / tof_sigma_sqrt2 );
656  // integration of the Gaussian is done on the LOR portion matching the whole current voxel along X axis
657  coeff = 0.5 * std::fabs(previous_edge_erf - next_edge_erf) ;
658  // keeping record of the previous edge, so as to save 1 erf computation
659  previous_edge_erf = next_edge_erf;
660 
661  if (!m_hasMask || mp_mask[numVox]) ap_ProjectionLine->AddVoxelInTOFBin(a_direction, 0, numVox, coeff);
662  }
663 
664  // Increment values
665  alpha_c = alpha_XYZ[ 0 ];
666  alpha_XYZ[ 0 ] += alpha_u[ 0 ];
667  index_ijk[ 0 ] += index_u[ 0 ];
668  }
669  else if( ( alpha_XYZ[ 1 ] < alpha_XYZ[ 0 ] )
670  && ( alpha_XYZ[ 1 ] <= alpha_XYZ[ 2 ] ) )
671  {
672  // Storing values
673  if( ( alpha_XYZ[ 1 ] >= alphaMin )
674  && ( index_ijk[ 0 ] - 1 >= tof_index_low[0] )
675  && ( index_ijk[ 0 ] - 1 <= tof_index_high[0] )
676  && ( index_ijk[ 1 ] - 1 >= tof_index_low[1] )
677  && ( index_ijk[ 1 ] - 1 <= tof_index_high[1] )
678  && ( index_ijk[ 2 ] - 1 >= tof_index_low[2] )
679  && ( index_ijk[ 2 ] - 1 <= tof_index_high[2] ) )
680  {
681  // initialize if not initialized yet
682  if (!previous_edge_erf_initialized)
683  {
684  previous_edge_erf = erf( (length_LOR *alpha_c - lor_tof_center) / tof_sigma_sqrt2 );
685  previous_edge_erf_initialized = true;
686  }
687 
688  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
689 
690  // tof : erf of next voxel edge - Gaussian center
691  next_edge_erf = erf( (length_LOR * alpha_XYZ[ 1 ] - lor_tof_center) / tof_sigma_sqrt2 );
692  // integration of the Gaussian is done on the LOR portion matching the whole current voxel along X axis
693  coeff = 0.5 * std::fabs(previous_edge_erf - next_edge_erf) ;
694  // keeping record of the previous edge, so as to save 1 erf computation
695  previous_edge_erf = next_edge_erf;
696 
697  // if the voxel is not masked
698  if (!m_hasMask || mp_mask[numVox]) ap_ProjectionLine->AddVoxelInTOFBin(a_direction, 0, numVox, coeff);
699  }
700 
701  // Increment values
702  alpha_c = alpha_XYZ[ 1 ];
703  alpha_XYZ[ 1 ] += alpha_u[ 1 ];
704  index_ijk[ 1 ] += index_u[ 1 ];
705  }
706  else if( ( alpha_XYZ[ 2 ] < alpha_XYZ[ 0 ] )
707  && ( alpha_XYZ[ 2 ] < alpha_XYZ[ 1 ] ) )
708  {
709  // Storing values
710  if( ( alpha_XYZ[ 2 ] >= alphaMin )
711  && ( index_ijk[ 0 ] - 1 >= tof_index_low[0] )
712  && ( index_ijk[ 0 ] - 1 <= tof_index_high[0] )
713  && ( index_ijk[ 1 ] - 1 >= tof_index_low[1] )
714  && ( index_ijk[ 1 ] - 1 <= tof_index_high[1] )
715  && ( index_ijk[ 2 ] - 1 >= tof_index_low[2] )
716  && ( index_ijk[ 2 ] - 1 <= tof_index_high[2] ) )
717  {
718  // initialize if not initialized yet
719  if (!previous_edge_erf_initialized)
720  {
721  previous_edge_erf = erf( (length_LOR *alpha_c - lor_tof_center) / tof_sigma_sqrt2 );
722  previous_edge_erf_initialized = true;
723  }
724 
725  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
726 
727  // tof : erf of next voxel edge - Gaussian center
728  next_edge_erf = erf( (length_LOR * alpha_XYZ[ 2 ] - lor_tof_center) / tof_sigma_sqrt2 );
729  // integration of the Gaussian is done on the LOR portion matching the whole current voxel along X axis
730  coeff = 0.5 * std::fabs(previous_edge_erf - next_edge_erf) ;
731  // keeping record of the previous edge, so as to save 1 erf computation
732  previous_edge_erf = next_edge_erf;
733 
734  // if the voxel is not masked
735  if (!m_hasMask || mp_mask[numVox]) ap_ProjectionLine->AddVoxelInTOFBin(a_direction, 0, numVox, coeff);
736  }
737 
738  // Increment values
739  alpha_c = alpha_XYZ[ 2 ];
740  alpha_XYZ[ 2 ] += alpha_u[ 2 ];
741  index_ijk[ 2 ] += index_u[ 2 ];
742  }
743  }
744 
745  return 0;
746 }
747 
748 // =====================================================================
749 // ---------------------------------------------------------------------
750 // ---------------------------------------------------------------------
751 // =====================================================================
752 
753 int iProjectorIncrementalSiddon::ProjectWithTOFBin(int a_direction, oProjectionLine* ap_ProjectionLine)
754 {
755  #ifdef CASTOR_DEBUG
756  if (!m_initialized)
757  {
758  Cerr("***** iProjectorIncrementalSiddon::ProjectWithTOFBin() -> Called while not initialized !" << endl);
759  Exit(EXIT_DEBUG);
760  }
761  #endif
762 
763  #ifdef CASTOR_VERBOSE
764  if (m_verbose>=10)
765  {
766  string direction = "";
767  if (a_direction==FORWARD) direction = "forward";
768  else direction = "backward";
769  Cout("iProjectorIncrementalSiddon::Project with TOF bins -> Project line '" << ap_ProjectionLine << "' in " << direction << " direction" << endl);
770  }
771  #endif
772 
773  // Simpler way now, hopefully it works
774  FLTNB* event1Float = ap_ProjectionLine->GetPosition1();
775  FLTNB* event2Float = ap_ProjectionLine->GetPosition2();
776  HPFLTNB event1[3] = { event1Float[0], event1Float[1], event1Float[2] };
777  HPFLTNB event2[3] = { event2Float[0], event2Float[1], event2Float[2] };
778 
779  // **************************************
780  // STEP 1: LOR length calculation
781  // **************************************
782  HPFLTNB length_LOR = ap_ProjectionLine->GetLength();
783  HPFLTNB length_LOR_half = length_LOR * 0.5;
784 
785  // **************************************
786  // STEP 2: Compute entrance voxel indexes
787  // **************************************
788  HPFLTNB alphaFirst[] = { 0.0, 0.0, 0.0 };
789  HPFLTNB alphaLast[] = { 0.0, 0.0, 0.0 };
790 
791  HPFLTNB alphaMin = 0.0f, alphaMax = 1.0f;
792  HPFLTNB delta_pos[] = {
793  event2[ 0 ] - event1[ 0 ],
794  event2[ 1 ] - event1[ 1 ],
795  event2[ 2 ] - event1[ 2 ]
796  };
797 
798  // Get TOF info
799  // TOF temporal resolution (FWHM)
800  HPFLTNB tof_resolutionT = ap_ProjectionLine->GetTOFResolution();
801  // TOF bin temporal size
802  HPFLTNB tof_bin_sizeT = ap_ProjectionLine->GetTOFBinSize();
803  INTNB tof_nb_bins = ap_ProjectionLine->GetNbTOFBins();
804  INTNB tof_half_nb_bins = tof_nb_bins/2;
805 
806  // TOF spatial standard deviation (simple TOF Gaussian, not convolved with the TOF bin width, maybe TODO)
807  HPFLTNB tof_sigma = tof_resolutionT * SPEED_OF_LIGHT * 0.5 / TWO_SQRT_TWO_LN_2;
808  //HPFLTNB tof_sigma_sqrt2 = sqrt(2.)*tof_sigma;
809  HPFLTNB tof_half_span = tof_sigma * m_TOFnbSigmas;
810 
811  // normalized Gaussian (integral=1) : precomputation of the coefficient that multiplies the exponential
812  HPFLTNB gaussian_norm_coef = INV_SQRT_2_PI * 1./tof_sigma;
813 
814  // spatial size of the TOF bin in mm
815  HPFLTNB tof_bin_size = tof_bin_sizeT * SPEED_OF_LIGHT * 0.5;
816 
817  // minimum and maximum TOF bins
818  INTNB tof_bin_last = tof_half_nb_bins;
819  INTNB tof_bin_first = -tof_half_nb_bins;
820 
821  // distance between the first event1 and the center of the Gaussian distribution of the first TOF bin along the LOR
822  //HPFLTNB tof_bin_center_first = length_LOR * 0.5 + tof_bin_first * tof_bin_size;
823  // distance between the first event1 and the center of the Gaussian distribution of the current TOF bin along the LOR
824  HPFLTNB lor_tof_center = 0.;
825  // normalization coefficient used for making the sum of TOF bin coefficients for a voxel equal the nonTOF voxel coefficient
826  HPFLTNB tof_norm_coef = 0.;
827 
828  // tof help variables
829  //HPFLTNB previous_edge_erf, next_edge_erf;
830  HPFLTNB tof_weight;
831 
832  // Computation of alphaMin et alphaMax values (entrance and exit point of the ray)
833  for( int i = 0; i < 3; ++i )
834  {
835  if( delta_pos[ i ] != 0.0 )
836  {
837  alphaFirst[i] = (-mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
838  alphaLast[i] = ( mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
839  alphaMin = (std::max)(alphaMin,(std::min)(alphaFirst[i],alphaLast[i]));
840  alphaMax = (std::min)(alphaMax,(std::max)(alphaFirst[i],alphaLast[i]));
841  }
842  }
843 
844  // if alphaMax is less than or equal to alphaMin no intersection
845  // and return an empty buffer
846  if( alphaMax <= alphaMin ) return 0;
847 
848  // temporary storage for TOF bins Gaussian integrals over the current voxel
849  // allocated after potential returns
850  HPFLTNB* tof_weights_temp = new HPFLTNB[tof_nb_bins];
851  for (INTNB tof_bin=0; tof_bin<tof_nb_bins; tof_bin++) tof_weights_temp[tof_bin] = 0.;
852 
853  // Now we have to find the indices of the particular plane
854  // (iMin,iMax), (jMin,jMax), (kMin,kMax)
855  int iMin = 0, iMax = 0;
856  int jMin = 0, jMax = 0;
857  int kMin = 0, kMax = 0;
858 
859  // For the X-axis
860  if( delta_pos[ 0 ] > 0.0f )
861  {
862  iMin = ::ceil( ( mp_nbVox[ 0 ] + 1 ) - ( mp_halfFOV[ 0 ] - alphaMin * delta_pos[ 0 ] - event1[ 0 ] ) / mp_sizeVox[0] );
863  iMax = ::floor( 1 + ( event1[ 0 ] + alphaMax * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] );
864  }
865  else if( delta_pos[ 0 ] < 0.0f )
866  {
867  iMin = ::ceil( ( mp_nbVox[ 0 ] + 1 ) - ( mp_halfFOV[ 0 ] - alphaMax * delta_pos[ 0 ] - event1[ 0 ] ) / mp_sizeVox[0] );
868  iMax = ::floor( 1 + ( event1[ 0 ] + alphaMin * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] );
869  }
870  if( delta_pos[ 0 ] == 0 )
871  {
872  iMin = 1, iMax = 0;
873  }
874 
875  // For the Y-axis
876  if( delta_pos[ 1 ] > 0 )
877  {
878  jMin = ::ceil( ( mp_nbVox[ 1 ] + 1 ) - ( mp_halfFOV[ 1 ] - alphaMin * delta_pos[ 1 ] - event1[ 1 ] ) / mp_sizeVox[1] );
879  jMax = ::floor( 1 + ( event1[ 1 ] + alphaMax * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] );
880  }
881  else if( delta_pos[ 1 ] < 0 )
882  {
883  jMin = ::ceil( ( mp_nbVox[ 1 ] + 1 ) - ( mp_halfFOV[ 1 ] - alphaMax * delta_pos[ 1 ] - event1[ 1 ] ) / mp_sizeVox[1] );
884  jMax = ::floor( 1 + ( event1[ 1 ] + alphaMin * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] );
885  }
886  else if( delta_pos[ 1 ] == 0 )
887  {
888  jMin = 1, jMax = 0;
889  }
890 
891  // For the Z-axis
892  if( delta_pos[ 2 ] > 0 )
893  {
894  kMin = ::ceil( ( mp_nbVox[ 2 ] + 1 ) - ( mp_halfFOV[ 2 ] - alphaMin * delta_pos[ 2 ] - event1[ 2 ] ) / mp_sizeVox[2] );
895  kMax = ::floor( 1 + ( event1[ 2 ] + alphaMax * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] );
896  }
897  else if( delta_pos[ 2 ] < 0 )
898  {
899  kMin = ::ceil( ( mp_nbVox[ 2 ] + 1 ) - ( mp_halfFOV[ 2 ] - alphaMax * delta_pos[ 2 ] - event1[ 2 ] ) / mp_sizeVox[2] );
900  kMax = ::floor( 1 + ( event1[ 2 ] + alphaMin * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] );
901  }
902  else if( delta_pos[ 2 ] == 0 )
903  {
904  kMin = 1, kMax = 0;
905  }
906 
907  // Computing the last term n number of intersection
908  INTNB n = ( iMax - iMin + 1 ) + ( jMax - jMin + 1 )
909  + ( kMax - kMin + 1 );
910 
911  // Array storing the first alpha in X, Y and Z
912  HPFLTNB alpha_XYZ[ 3 ] = { 1.0f, 1.0f, 1.0f };
913 
914  // Computing the first alpha in X
915  if( delta_pos[ 0 ] > 0 )
916  alpha_XYZ[ 0 ] = ( ( (-mp_halfFOV[ 0 ]) + ( iMin - 1 ) * mp_sizeVox[0] ) - event1[ 0 ] ) / delta_pos[ 0 ];
917  else if( delta_pos[ 0 ] < 0 )
918  alpha_XYZ[ 0 ] = ( ( (-mp_halfFOV[ 0 ]) + ( iMax - 1 ) * mp_sizeVox[0] ) - event1[ 0 ] ) / delta_pos[ 0 ];
919 
920  // Computing the first alpha in Y
921  if( delta_pos[ 1 ] > 0 )
922  alpha_XYZ[ 1 ] = ( ( (-mp_halfFOV[ 1 ]) + ( jMin - 1 ) * mp_sizeVox[1] ) - event1[ 1 ] ) / delta_pos[ 1 ];
923  else if( delta_pos[ 1 ] < 0 )
924  alpha_XYZ[ 1 ] = ( ( (-mp_halfFOV[ 1 ]) + ( jMax - 1 ) * mp_sizeVox[1] ) - event1[ 1 ] ) / delta_pos[ 1 ];
925 
926  // Computing the first alpha in Z
927  if( delta_pos[ 2 ] > 0 )
928  alpha_XYZ[ 2 ] = ( ( (-mp_halfFOV[ 2 ]) + ( kMin - 1 ) * mp_sizeVox[2] ) - event1[ 2 ] ) / delta_pos[ 2 ];
929  else if( delta_pos[ 2 ] < 0 )
930  alpha_XYZ[ 2 ] = ( ( (-mp_halfFOV[ 2 ]) + ( kMax - 1 ) * mp_sizeVox[2] ) - event1[ 2 ] ) / delta_pos[ 2 ];
931 
932  // Computing the alpha updating
933  HPFLTNB alpha_u[ 3 ] = {
934  mp_sizeVox[0] / std::fabs( delta_pos[ 0 ] ),
935  mp_sizeVox[1] / std::fabs( delta_pos[ 1 ] ),
936  mp_sizeVox[2] / std::fabs( delta_pos[ 2 ] )
937  };
938 
939  // Computing the index updating
940  INTNB index_u[ 3 ] = {
941  (delta_pos[ 0 ] < 0) ? -1 : 1,
942  (delta_pos[ 1 ] < 0) ? -1 : 1,
943  (delta_pos[ 2 ] < 0) ? -1 : 1
944  };
945 
946  // Check which alpha is the min/max and increment
947  if( alpha_XYZ[ 0 ] == alphaMin ) alpha_XYZ[ 0 ] += alpha_u[ 0 ];
948  if( alpha_XYZ[ 1 ] == alphaMin ) alpha_XYZ[ 1 ] += alpha_u[ 1 ];
949  if( alpha_XYZ[ 2 ] == alphaMin ) alpha_XYZ[ 2 ] += alpha_u[ 2 ];
950 
951  // Computing the minimum value in the alpha_XYZ buffer
952  HPFLTNB const min_alpha_XYZ = (std::min)( alpha_XYZ[ 0 ], (std::min)( alpha_XYZ[ 1 ], alpha_XYZ[ 2 ] ) );
953 
954  // Computing the first index of intersection
955  HPFLTNB const alphaMid = ( min_alpha_XYZ + alphaMin ) / 2.0f;
956  INTNB index_ijk[ 3 ] = {
957  1 + (INTNB)( ( event1[ 0 ] + alphaMid * delta_pos[ 0 ] - (-mp_halfFOV[ 0 ]) ) / mp_sizeVox[0] ),
958  1 + (INTNB)( ( event1[ 1 ] + alphaMid * delta_pos[ 1 ] - (-mp_halfFOV[ 1 ]) ) / mp_sizeVox[1] ),
959  1 + (INTNB)( ( event1[ 2 ] + alphaMid * delta_pos[ 2 ] - (-mp_halfFOV[ 2 ]) ) / mp_sizeVox[2] )
960  };
961 
962  INTNB const w = mp_nbVox[ 0 ];
963  INTNB const wh = w * mp_nbVox[ 1 ];
964 
965  // Loop over the number of plane to cross
966  HPFLTNB alpha_c = alphaMin;
967  FLTNB coeff = 0.0f;
968  INTNB numVox = 0;
969  INTNB tof_bin_first_for_voxel = 0, tof_bin_last_for_voxel = 0;
970  for( int nP = 0; nP < n - 1; ++nP )
971  {
972  if( ( alpha_XYZ[ 0 ] <= alpha_XYZ[ 1 ] )
973  && ( alpha_XYZ[ 0 ] <= alpha_XYZ[ 2 ] ) )
974  {
975  // Storing values
976  if( ( alpha_XYZ[ 0 ] >= alphaMin )
977  && ( index_ijk[ 0 ] - 1 >= 0 )
978  && ( index_ijk[ 0 ] - 1 <= mp_nbVox[ 0 ] - 1 )
979  && ( index_ijk[ 1 ] - 1 >= 0 )
980  && ( index_ijk[ 1 ] - 1 <= mp_nbVox[ 1 ] - 1 )
981  && ( index_ijk[ 2 ] - 1 >= 0 )
982  && ( index_ijk[ 2 ] - 1 <= mp_nbVox[ 2 ] - 1 ) )
983  {
984  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
985 
986  // if this voxel is masked, do nothing
987  if (!m_hasMask || mp_mask[numVox])
988  {
989  coeff = ( alpha_XYZ[ 0 ] - alpha_c ) * length_LOR;
990 
991  // Compute the first and the last relevant TOF bin for this voxel
992  tof_bin_first_for_voxel = max(tof_bin_first , (INTNB)(trunc( (alpha_c * length_LOR - tof_half_span - length_LOR_half ) / tof_bin_size )));
993  tof_bin_last_for_voxel = min(tof_bin_last , (INTNB)(trunc( (alpha_XYZ[ 0 ] * length_LOR + tof_half_span - length_LOR_half) / tof_bin_size )));
994  lor_tof_center = length_LOR_half + tof_bin_first_for_voxel * tof_bin_size;
995 
996  // if min/max TOF bins for this voxel do not fall into the total available TOF bins range, skip
997  if(tof_bin_first_for_voxel>tof_bin_last || tof_bin_last_for_voxel<tof_bin_first) continue;
998 
999  // shift tof bin indices from -/+ to 0:nbBins range
1000  tof_bin_first_for_voxel += tof_half_nb_bins;
1001  tof_bin_last_for_voxel += tof_half_nb_bins;
1002 
1003  // first compute the normalization for TOF bin coefficients for the current voxel (simple sum)
1004  tof_norm_coef = 0.;
1005  for (INTNB tof_bin=tof_bin_first_for_voxel; tof_bin<=tof_bin_last_for_voxel; tof_bin++)
1006  {
1007  // erf ( voxel edge projected onto the LOR - TOF bin center along the LOR )
1008  //previous_edge_erf = erf( (length_LOR * alpha_c - lor_tof_center) / tof_sigma_sqrt2 );
1009  //next_edge_erf = erf( (length_LOR * alpha_XYZ[ 0 ] - lor_tof_center) / tof_sigma_sqrt2 );
1010  //tof_weight = 0.5 * fabs(previous_edge_erf - next_edge_erf);
1011  // approximation of the integration of the Gaussian over the voxel
1012  // TOF coefficient = value of the Gaussian at voxel center (projected onto the LOR) * voxel size (projected onto the LOR)
1013  HPFLTNB temp = (( alpha_XYZ[ 0 ] + alpha_c ) * 0.5 * length_LOR - lor_tof_center) / tof_sigma;
1014  tof_weight = exp(- 0.5 * temp * temp ) * gaussian_norm_coef * coeff;
1015  // add the weight to the sum for normalization
1016  tof_norm_coef += tof_weight;
1017  // save the weight temporarily
1018  tof_weights_temp[tof_bin] = tof_weight;
1019  // update TOF center along the LOR for the next TOF bin
1020  lor_tof_center += tof_bin_size;
1021  }
1022 
1023  // compute the final TOF bin coefficients for the current voxel
1024  if (tof_norm_coef>0.)
1025  {
1026  // first normalize TOF bin coefficients
1027  for (INTNB tof_bin=tof_bin_first_for_voxel; tof_bin<=tof_bin_last_for_voxel; tof_bin++)
1028  {
1029  tof_weights_temp[tof_bin] /= tof_norm_coef;
1030  }
1031  // then write all TOF bins for the current voxel
1032  ap_ProjectionLine->AddVoxelAllTOFBins(a_direction, numVox, coeff, tof_weights_temp, tof_bin_first_for_voxel, tof_bin_last_for_voxel);
1033  }
1034  }
1035  }
1036  // Increment values
1037  alpha_c = alpha_XYZ[ 0 ];
1038  alpha_XYZ[ 0 ] += alpha_u[ 0 ];
1039  index_ijk[ 0 ] += index_u[ 0 ];
1040  }
1041  else if( ( alpha_XYZ[ 1 ] < alpha_XYZ[ 0 ] )
1042  && ( alpha_XYZ[ 1 ] <= alpha_XYZ[ 2 ] ) )
1043  {
1044  // Storing values
1045  if( ( alpha_XYZ[ 1 ] >= alphaMin )
1046  && ( index_ijk[ 0 ] - 1 >= 0 )
1047  && ( index_ijk[ 0 ] - 1 <= mp_nbVox[ 0 ] - 1 )
1048  && ( index_ijk[ 1 ] - 1 >= 0 )
1049  && ( index_ijk[ 1 ] - 1 <= mp_nbVox[ 1 ] - 1 )
1050  && ( index_ijk[ 2 ] - 1 >= 0 )
1051  && ( index_ijk[ 2 ] - 1 <= mp_nbVox[ 2 ] - 1 ) )
1052  {
1053  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
1054 
1055  // if this voxel is masked, do nothing
1056  if (!m_hasMask || mp_mask[numVox])
1057  {
1058  coeff = ( alpha_XYZ[ 1 ] - alpha_c ) * length_LOR;
1059 
1060  // Compute the first and the last relevant TOF bin for this voxel
1061  tof_bin_first_for_voxel = max(tof_bin_first , (INTNB)(trunc( (alpha_c * length_LOR - tof_half_span - length_LOR_half ) / tof_bin_size )));
1062  tof_bin_last_for_voxel = min(tof_bin_last , (INTNB)(trunc( (alpha_XYZ[ 1 ] * length_LOR + tof_half_span - length_LOR_half) / tof_bin_size )));
1063  lor_tof_center = length_LOR_half + tof_bin_first_for_voxel * tof_bin_size;
1064 
1065  // if min/max TOF bins for this voxel do not fall into the total available TOF bins range, skip
1066  if(tof_bin_first_for_voxel>tof_bin_last || tof_bin_last_for_voxel<tof_bin_first) continue;
1067 
1068  // shift tof bin indices from -/+ to 0:nbBins range
1069  tof_bin_first_for_voxel += tof_half_nb_bins;
1070  tof_bin_last_for_voxel += tof_half_nb_bins;
1071 
1072  // first compute the normalization for TOF bin coefficients for the current voxel (simple sum)
1073  tof_norm_coef = 0.;
1074  for (INTNB tof_bin=tof_bin_first_for_voxel; tof_bin<=tof_bin_last_for_voxel; tof_bin++)
1075  {
1076  // erf ( voxel edge projected onto the LOR - TOF bin center along the LOR )
1077  //previous_edge_erf = erf( (length_LOR * alpha_c - lor_tof_center) / tof_sigma_sqrt2 );
1078  //next_edge_erf = erf( (length_LOR * alpha_XYZ[ 1 ] - lor_tof_center) / tof_sigma_sqrt2 );
1079  //tof_weight = 0.5 * fabs(previous_edge_erf - next_edge_erf);
1080  // approximation of the integration of the Gaussian over the voxel
1081  // TOF coefficient = value of the Gaussian at voxel center (projected onto the LOR) * voxel size (projected onto the LOR)
1082  HPFLTNB temp = (( alpha_XYZ[ 1 ] + alpha_c ) * 0.5 * length_LOR - lor_tof_center) / tof_sigma;
1083  tof_weight = exp(- 0.5 * temp * temp ) * gaussian_norm_coef * coeff;
1084  // add the weight to the sum for normalization
1085  tof_norm_coef += tof_weight;
1086  // save the weight temporarily
1087  tof_weights_temp[tof_bin] = tof_weight;
1088  // update TOF center along the LOR for the next TOF bin
1089  lor_tof_center += tof_bin_size;
1090  }
1091 
1092  // compute the final TOF bin coefficients for the current voxel
1093  if (tof_norm_coef>0.)
1094  {
1095  // first normalize TOF bin coefficients
1096  for (INTNB tof_bin=tof_bin_first_for_voxel; tof_bin<=tof_bin_last_for_voxel; tof_bin++)
1097  {
1098  tof_weights_temp[tof_bin] /= tof_norm_coef;
1099  }
1100  // then write all TOF bins for the current voxel
1101  ap_ProjectionLine->AddVoxelAllTOFBins(a_direction, numVox, coeff, tof_weights_temp, tof_bin_first_for_voxel, tof_bin_last_for_voxel);
1102  }
1103  }
1104  }
1105 
1106  // Increment values
1107  alpha_c = alpha_XYZ[ 1 ];
1108  alpha_XYZ[ 1 ] += alpha_u[ 1 ];
1109  index_ijk[ 1 ] += index_u[ 1 ];
1110  }
1111  else if( ( alpha_XYZ[ 2 ] < alpha_XYZ[ 0 ] )
1112  && ( alpha_XYZ[ 2 ] < alpha_XYZ[ 1 ] ) )
1113  {
1114  // Storing values
1115  if( ( alpha_XYZ[ 2 ] >= alphaMin )
1116  && ( index_ijk[ 0 ] - 1 >= 0 )
1117  && ( index_ijk[ 0 ] - 1 <= mp_nbVox[ 0 ] - 1 )
1118  && ( index_ijk[ 1 ] - 1 >= 0 )
1119  && ( index_ijk[ 1 ] - 1 <= mp_nbVox[ 1 ] - 1 )
1120  && ( index_ijk[ 2 ] - 1 >= 0 )
1121  && ( index_ijk[ 2 ] - 1 <= mp_nbVox[ 2 ] - 1 ) )
1122  {
1123  numVox = ( index_ijk[ 0 ] - 1 ) + ( ( index_ijk[ 1 ] - 1 ) ) * w + ( ( index_ijk[ 2 ] - 1 ) ) * wh;
1124 
1125  // if this voxel is masked, do nothing
1126  if (!m_hasMask || mp_mask[numVox])
1127  {
1128  coeff = ( alpha_XYZ[ 2 ] - alpha_c ) * length_LOR;
1129 
1130  // Compute the first and the last relevant TOF bin for this voxel
1131  tof_bin_first_for_voxel = max(tof_bin_first , (INTNB)(trunc( (alpha_c * length_LOR - tof_half_span - length_LOR_half ) / tof_bin_size )));
1132  tof_bin_last_for_voxel = min(tof_bin_last , (INTNB)(trunc( (alpha_XYZ[ 2 ] * length_LOR + tof_half_span - length_LOR_half) / tof_bin_size )));
1133  lor_tof_center = length_LOR_half + tof_bin_first_for_voxel * tof_bin_size;
1134 
1135  // if min/max TOF bins for this voxel do not fall into the total available TOF bins range, skip
1136  if(tof_bin_first_for_voxel>tof_bin_last || tof_bin_last_for_voxel<tof_bin_first) continue;
1137 
1138  // shift tof bin indices from -/+ to 0:nbBins range
1139  tof_bin_first_for_voxel += tof_half_nb_bins;
1140  tof_bin_last_for_voxel += tof_half_nb_bins;
1141 
1142  // first compute the normalization for TOF bin coefficients for the current voxel (simple sum)
1143  tof_norm_coef = 0.;
1144  for (INTNB tof_bin=tof_bin_first_for_voxel; tof_bin<=tof_bin_last_for_voxel; tof_bin++)
1145  {
1146  // erf ( voxel edge projected onto the LOR - TOF bin center along the LOR )
1147  //previous_edge_erf = erf( (length_LOR * alpha_c - lor_tof_center) / tof_sigma_sqrt2 );
1148  //next_edge_erf = erf( (length_LOR * alpha_XYZ[ 2 ] - lor_tof_center) / tof_sigma_sqrt2 );
1149  //tof_weight = 0.5 * fabs(previous_edge_erf - next_edge_erf);
1150  // approximation of the integration of the Gaussian over the voxel
1151  // TOF coefficient = value of the Gaussian at voxel center (projected onto the LOR) * voxel size (projected onto the LOR)
1152  HPFLTNB temp = (( alpha_XYZ[ 2 ] + alpha_c ) * 0.5 * length_LOR - lor_tof_center) / tof_sigma;
1153  tof_weight = exp(- 0.5 * temp * temp ) * gaussian_norm_coef * coeff;
1154  // add the weight to the sum for normalization
1155  tof_norm_coef += tof_weight;
1156  // save the weight temporarily
1157  tof_weights_temp[tof_bin] = tof_weight;
1158  // update TOF center along the LOR for the next TOF bin
1159  lor_tof_center += tof_bin_size;
1160  }
1161 
1162  // compute the final TOF bin coefficients for the current voxel
1163  if (tof_norm_coef>0.)
1164  {
1165  // first normalize TOF bin coefficients
1166  for (INTNB tof_bin=tof_bin_first_for_voxel; tof_bin<=tof_bin_last_for_voxel; tof_bin++)
1167  {
1168  tof_weights_temp[tof_bin] /= tof_norm_coef;
1169  }
1170  // then write all TOF bins for the current voxel
1171  ap_ProjectionLine->AddVoxelAllTOFBins(a_direction, numVox, coeff, tof_weights_temp, tof_bin_first_for_voxel, tof_bin_last_for_voxel);
1172  }
1173  }
1174  }
1175 
1176  // Increment values
1177  alpha_c = alpha_XYZ[ 2 ];
1178  alpha_XYZ[ 2 ] += alpha_u[ 2 ];
1179  index_ijk[ 2 ] += index_u[ 2 ];
1180  }
1181  }
1182 
1183  delete[] tof_weights_temp;
1184 
1185  return 0;
1186 }
1187 
1188 // =====================================================================
1189 // ---------------------------------------------------------------------
1190 // ---------------------------------------------------------------------
1191 // =====================================================================
bool m_compatibleWithSPECTAttenuationCorrection
Definition: vProjector.hh:355
FLTNB mp_sizeVox[3]
Definition: vProjector.hh:338
~iProjectorIncrementalSiddon()
The destructor of iProjectorIncrementalSiddon.
INTNB mp_nbVox[3]
Definition: vProjector.hh:339
#define FLTNB
Definition: gVariables.hh:81
void AddVoxelAllTOFBins(int a_direction, INTNB a_voxelIndex, FLTNB a_voxelWeight, HPFLTNB *a_tofWeights, INTNB a_tofBinFirst, INTNB a_tofBinLast)
Add a voxel contribution to the line for all relevant TOF bins.
#define TWO_SQRT_TWO_LN_2
Definition: gVariables.hh:100
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
Definition: vProjector.hh:344
void ShowHelpSpecific()
A function used to show help about the child module.
#define HPFLTNB
Definition: gVariables.hh:83
This class is designed to generically described any on-the-fly projector.
Definition: vProjector.hh:76
FLTNB GetTOFMeasurement()
This function is used to get the TOF measurement.
Declaration of class iProjectorIncrementalSiddon.
FLTNB GetLength()
This function is used to get the length of the line.
void Exit(int code)
FLTNB GetTOFResolution()
This function is used to get the TOF resolution.
#define Cerr(MESSAGE)
FLTNB * GetPosition1()
This function is used to get the pointer to the mp_position1 (3-values tab).
bool m_initialized
Definition: vProjector.hh:364
bool * mp_mask
Definition: vProjector.hh:365
void AddVoxel(int a_direction, INTNB a_voxelIndice, FLTNB a_voxelWeight)
This function is used to add a voxel contribution to the line, assuming TOF bin 0 (i...
int ReadConfigurationFile(const string &a_configurationFile)
A function used to read options from a configuration file.
int ProjectWithTOFPos(int a_direction, oProjectionLine *ap_ProjectionLine)
A function to project with TOF continuous information.
iProjectorIncrementalSiddon()
The constructor of iProjectorIncrementalSiddon.
INTNB EstimateMaxNumberOfVoxelsPerLine()
This function is used to compute and provide an estimate of the maximum number of voxels that could c...
int InitializeSpecific()
This function is used to initialize specific stuff to the child projector.
bool m_hasMask
Definition: vProjector.hh:366
FLTNB m_TOFnbSigmas
Definition: vProjector.hh:349
#define INTNB
Definition: gVariables.hh:92
This class is designed to manage and store system matrix elements associated to a vEvent...
int ProjectWithoutTOF(int a_direction, oProjectionLine *ap_ProjectionLine)
A function to project without TOF.
Declaration of class sOutputManager.
int ProjectWithTOFBin(int a_direction, oProjectionLine *ap_ProjectionLine)
A function to project with TOF binned information.
int GetNbTOFBins()
This function is used to get the number of TOF bins in use.
FLTNB mp_halfFOV[3]
Definition: vProjector.hh:341
#define EXIT_DEBUG
Definition: gVariables.hh:97
#define SPEED_OF_LIGHT
Definition: gVariables.hh:106
FLTNB * GetPosition2()
This function is used to get the pointer to the mp_position2 (3-values tab).
int ReadOptionsList(const string &a_optionsList)
A function used to read options from a list of options.
INTNB GetNbVoxX()
Get the number of voxels along the X axis.
FLTNB GetTOFBinSize()
This function is used to get the size in ps of a TOF bin.
#define INV_SQRT_2_PI
Definition: gVariables.hh:103
INTNB GetNbVoxZ()
Get the number of voxels along the Z axis.
#define FORWARD
#define Cout(MESSAGE)
bool m_compatibleWithCompression
Definition: vProjector.hh:358
void AddVoxelInTOFBin(int a_direction, int a_TOFBin, INTNB a_voxelIndice, FLTNB a_voxelWeight)
This function is used to add a voxel contribution to the line and provided TOF bin.
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child projector.
INTNB GetNbVoxY()
Get the number of voxels along the Y axis.