79 cout <<
"This projector is a simple line projector that computes the exact path length of a line through the voxels." << endl;
80 cout <<
"It is implemented from the following published paper:" << endl;
81 cout <<
"R. L. Siddon, \"Fast calculation of the exact radiological path for a three-dimensional CT array\", Med. Phys., vol. 12, pp. 252-5, 1985." << endl;
82 cout <<
"All voxels are correctly ordered in the line, so this projector can be used with SPECT attenuation correction." << endl;
106 if (
m_verbose>=2)
Cout(
"iProjectorClassicSiddon::InitializeSpecific() -> Use classic Siddon projector" << endl);
124 max_nb_voxels_in_dimension *= 4;
126 return max_nb_voxels_in_dimension;
139 Cerr(
"***** iProjectorClassicSiddon::ProjectWithoutTOF() -> Called while not initialized !" << endl);
144 #ifdef CASTOR_VERBOSE
147 string direction =
"";
148 if (a_direction==
FORWARD) direction =
"forward";
149 else direction =
"backward";
150 Cout(
"iProjectorClassicSiddon::Project without TOF -> Project line '" << ap_ProjectionLine <<
"' in " << direction <<
" direction" << endl);
158 FLTNB event1[3] = { event1_position[0], event1_position[1], event1_position[2] };
159 FLTNB event2[3] = { event2_position[0], event2_position[1], event2_position[2] };
169 FLTNB alphaFirst[] = { 0.0, 0.0, 0.0 };
170 FLTNB alphaLast[] = { 0.0, 0.0, 0.0 };
172 FLTNB alphaMin = 0.0, alphaMax = 1.0;
173 FLTNB delta_pos[] = {
174 event2[ 0 ] - event1[ 0 ],
175 event2[ 1 ] - event1[ 1 ],
176 event2[ 2 ] - event1[ 2 ]
180 for(
int i = 0; i < 3; ++i )
182 if( delta_pos[ i ] != 0.0 )
184 alphaFirst[i] = (-
mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
185 alphaLast[i] = (
mp_halfFOV[i] - event1[i]) / (delta_pos[ i ]);
186 alphaMin = (std::max)(alphaMin,(std::min)(alphaFirst[i],alphaLast[i]));
187 alphaMax = (std::min)(alphaMax,(std::max)(alphaFirst[i],alphaLast[i]));
193 if( alphaMax <= alphaMin )
return 0;
197 int iMin = 0, iMax = 0;
198 int jMin = 0, jMax = 0;
199 int kMin = 0, kMax = 0;
202 if( delta_pos[ 0 ] > 0.0 )
205 iMax = ::floor( 1 + ( event1[ 0 ] + alphaMax * delta_pos[ 0 ] - (-
mp_halfFOV[ 0 ]) ) /
mp_sizeVox[0] );
207 else if( delta_pos[ 0 ] < 0.0 )
210 iMax = ::floor( 1 + ( event1[ 0 ] + alphaMin * delta_pos[ 0 ] - (-
mp_halfFOV[ 0 ]) ) /
mp_sizeVox[0] );
212 if( delta_pos[ 0 ] == 0. )
218 if( delta_pos[ 1 ] > 0. )
221 jMax = ::floor( 1 + ( event1[ 1 ] + alphaMax * delta_pos[ 1 ] - (-
mp_halfFOV[ 1 ]) ) /
mp_sizeVox[1] );
223 else if( delta_pos[ 1 ] < 0. )
226 jMax = ::floor( 1 + ( event1[ 1 ] + alphaMin * delta_pos[ 1 ] - (-
mp_halfFOV[ 1 ]) ) /
mp_sizeVox[1] );
228 else if( delta_pos[ 1 ] == 0. )
234 if( delta_pos[ 2 ] > 0. )
237 kMax = ::floor( 1 + ( event1[ 2 ] + alphaMax * delta_pos[ 2 ] - (-
mp_halfFOV[ 2 ]) ) /
mp_sizeVox[2] );
239 else if( delta_pos[ 2 ] < 0. )
242 kMax = ::floor( 1 + ( event1[ 2 ] + alphaMin * delta_pos[ 2 ] - (-
mp_halfFOV[ 2 ]) ) /
mp_sizeVox[2] );
244 else if( delta_pos[ 2 ] == 0. )
250 int n = ( iMax - iMin + 1 ) + ( jMax - jMin + 1 )
251 + ( kMax - kMin + 1 );
256 FLTNB *tmpAlpha =
new FLTNB[ mp_nbVox[ 0 ] + mp_nbVox[ 1 ] + mp_nbVox[ 2 ] + 3 ];
257 FLTNB *alphaX =
new FLTNB[ ( mp_nbVox[ 0 ] + 1 ) ];
258 FLTNB *alphaY =
new FLTNB[ ( mp_nbVox[ 1 ] + 1 ) ];
259 FLTNB *alphaZ =
new FLTNB[ ( mp_nbVox[ 2 ] + 1 ) ];
261 INTNB iElement = iMax - iMin + 1;
265 if( delta_pos[ 0 ] > 0. )
267 for(
int i = iMin; i <= iMax; ++i )
270 else if( delta_pos[ 0 ] < 0. )
272 for(
int i = iMax; i >= iMin; --i )
278 INTNB jElement = jMax - jMin + 1;
282 if( delta_pos[ 1 ] > 0. )
284 for(
int j = jMin; j <= jMax; ++j )
287 else if( delta_pos[ 1 ] < 0. )
289 for(
int j = jMax; j >= jMin; --j )
295 INTNB kElement = kMax - kMin + 1;
299 if( delta_pos[ 2 ] > 0. )
301 for(
int k = kMin; k <= kMax; ++k )
304 else if( delta_pos[ 2 ] < 0. )
306 for(
int k = kMax; k >= kMin; --k )
312 alphaX, alphaX + iElement,
316 ::memcpy( tmpAlpha, alpha, ( iElement ) *
sizeof(
FLTNB ) );
319 alphaY, alphaY + jElement,
320 tmpAlpha, tmpAlpha + iElement,
323 ::memcpy( tmpAlpha, alpha, ( iElement + jElement ) *
sizeof(
FLTNB ) );
326 alphaZ, alphaZ + kElement,
327 tmpAlpha, tmpAlpha + iElement + jElement,
339 FLTNB alphaMid = 0.0;
340 INTNB i = 0, j = 0, k = 0;
341 FLTNB *pAlpha = &alpha[ 1 ];
342 FLTNB *pAlphaPrevious = &alpha[ 0 ];
346 for(
int nP = 0; nP < n - 1; ++nP, ++pAlpha, ++pAlphaPrevious )
348 alphaMid = ( *pAlpha + *pAlphaPrevious ) * 0.5;
350 i = alphaMid * i2 + i1;
351 if( i < 1 || i > mp_nbVox[ 0 ] )
continue;
353 j = alphaMid * j2 + j1;
354 if( j < 1 || j > mp_nbVox[ 1 ] )
continue;
356 k = alphaMid * k2 + k1;
357 if( k < 1 || k > mp_nbVox[ 2 ] )
continue;
359 numVox = ( i - 1 ) + ( j - 1 ) * mp_nbVox[0] + ( k - 1 ) * mp_nbVox[0] * mp_nbVox[1];
360 coeff = length_LOR * ( *pAlpha - *pAlphaPrevious );
362 ap_ProjectionLine->
AddVoxel(a_direction, numVox, coeff);
371 #ifdef CASTOR_VERBOSE
374 Cout(
"iProjectorClassicSiddon::Project without TOF -> Exit function" << endl);
391 Cerr(
"***** iProjectorClassicSiddon::ProjectWithTOFPos() -> Called while not initialized !" << endl);
396 #ifdef CASTOR_VERBOSE
399 string direction =
"";
400 if (a_direction==
FORWARD) direction =
"forward";
401 else direction =
"backward";
402 Cout(
"iProjectorClassicSiddon::Project with TOF pos -> Project line '" << ap_ProjectionLine <<
"' in " << direction <<
" direction" << endl);
410 FLTNB event1[3] = { event1_position[0], event1_position[1], event1_position[2] };
411 FLTNB event2[3] = { event2_position[0], event2_position[1], event2_position[2] };
421 FLTNB alphaFirst[] = { 0.0, 0.0, 0.0 };
422 FLTNB alphaLast[] = { 0.0, 0.0, 0.0 };
424 FLTNB alphaMin = 0.0, alphaMax = 1.0;
425 FLTNB delta_pos[] = {
426 event2[ 0 ] - event1[ 0 ],
427 event2[ 1 ] - event1[ 1 ],
428 event2[ 2 ] - event1[ 2 ]
444 if ( fabs(tof_deltaL) > length_LOR * 0.5)
450 double lor_tof_center = length_LOR * 0.5 + tof_deltaL;
453 double tof_norm_coef = tof_sigma * sqrt(2*M_PI);
456 double tof_edge_low[] = {0,0,0};
458 double tof_edge_high[] = {0,0,0};
463 for (
int ax=0;ax<3;ax++)
466 tof_center = event1[ax] + lor_tof_center * delta_pos[ax] / length_LOR;
469 tof_edge_low[ax] = tof_center - tof_half_span * fabs(delta_pos[ax]) / length_LOR;
472 if (tof_index>
mp_nbVox[ax]-1)
return 0;
476 tof_edge_high[ax] = tof_center + tof_half_span * fabs(delta_pos[ax]) / length_LOR;
479 if (tof_index<0)
return 0;
486 for(
int i = 0; i < 3; ++i )
488 if( delta_pos[ i ] != 0.0 )
490 alphaFirst[i] = (tof_edge_low[i] - event1[i]) / (delta_pos[ i ]);
491 alphaLast[i] = (tof_edge_high[i] - event1[i]) / (delta_pos[ i ]);
492 alphaMin = (std::max)(alphaMin,(std::min)(alphaFirst[i],alphaLast[i]));
493 alphaMax = (std::min)(alphaMax,(std::max)(alphaFirst[i],alphaLast[i]));
499 if( alphaMax <= alphaMin )
return 0;
506 int iMin = 0, iMax = 0;
507 int jMin = 0, jMax = 0;
508 int kMin = 0, kMax = 0;
511 if( delta_pos[ 0 ] > 0.0 )
514 iMax = ::floor( 1 + ( event1[ 0 ] + alphaMax * delta_pos[ 0 ] - (-
mp_halfFOV[ 0 ]) ) /
mp_sizeVox[0] );
516 else if( delta_pos[ 0 ] < 0.0 )
519 iMax = ::floor( 1 + ( event1[ 0 ] + alphaMin * delta_pos[ 0 ] - (-
mp_halfFOV[ 0 ]) ) /
mp_sizeVox[0] );
521 if( delta_pos[ 0 ] == 0. )
527 if( delta_pos[ 1 ] > 0. )
530 jMax = ::floor( 1 + ( event1[ 1 ] + alphaMax * delta_pos[ 1 ] - (-
mp_halfFOV[ 1 ]) ) /
mp_sizeVox[1] );
532 else if( delta_pos[ 1 ] < 0. )
535 jMax = ::floor( 1 + ( event1[ 1 ] + alphaMin * delta_pos[ 1 ] - (-
mp_halfFOV[ 1 ]) ) /
mp_sizeVox[1] );
537 else if( delta_pos[ 1 ] == 0. )
543 if( delta_pos[ 2 ] > 0. )
546 kMax = ::floor( 1 + ( event1[ 2 ] + alphaMax * delta_pos[ 2 ] - (-
mp_halfFOV[ 2 ]) ) /
mp_sizeVox[2] );
548 else if( delta_pos[ 2 ] < 0. )
551 kMax = ::floor( 1 + ( event1[ 2 ] + alphaMin * delta_pos[ 2 ] - (-
mp_halfFOV[ 2 ]) ) /
mp_sizeVox[2] );
553 else if( delta_pos[ 2 ] == 0. )
559 int n = ( iMax - iMin + 1 ) + ( jMax - jMin + 1 )
560 + ( kMax - kMin + 1 );
565 FLTNB *tmpAlpha =
new FLTNB[ mp_nbVox[ 0 ] + mp_nbVox[ 1 ] + mp_nbVox[ 2 ] + 3 ];
566 FLTNB *alphaX =
new FLTNB[ ( mp_nbVox[ 0 ] + 1 ) ];
567 FLTNB *alphaY =
new FLTNB[ ( mp_nbVox[ 1 ] + 1 ) ];
568 FLTNB *alphaZ =
new FLTNB[ ( mp_nbVox[ 2 ] + 1 ) ];
570 INTNB iElement = iMax - iMin + 1;
574 if( delta_pos[ 0 ] > 0. )
576 for(
int i = iMin; i <= iMax; ++i )
579 else if( delta_pos[ 0 ] < 0. )
581 for(
int i = iMax; i >= iMin; --i )
587 INTNB jElement = jMax - jMin + 1;
591 if( delta_pos[ 1 ] > 0. )
593 for(
int j = jMin; j <= jMax; ++j )
596 else if( delta_pos[ 1 ] < 0. )
598 for(
int j = jMax; j >= jMin; --j )
604 INTNB kElement = kMax - kMin + 1;
608 if( delta_pos[ 2 ] > 0. )
610 for(
int k = kMin; k <= kMax; ++k )
613 else if( delta_pos[ 2 ] < 0. )
615 for(
int k = kMax; k >= kMin; --k )
621 alphaX, alphaX + iElement,
625 ::memcpy( tmpAlpha, alpha, ( iElement ) *
sizeof(
FLTNB ) );
628 alphaY, alphaY + jElement,
629 tmpAlpha, tmpAlpha + iElement,
632 ::memcpy( tmpAlpha, alpha, ( iElement + jElement ) *
sizeof(
FLTNB ) );
635 alphaZ, alphaZ + kElement,
636 tmpAlpha, tmpAlpha + iElement + jElement,
648 FLTNB alphaMid = 0.0;
649 INTNB i = 0, j = 0, k = 0;
650 FLTNB *pAlpha = &alpha[ 1 ];
651 FLTNB *pAlphaPrevious = &alpha[ 0 ];
656 FLTNB previous_edge_erf = erf( (length_LOR * (*pAlphaPrevious) - lor_tof_center)/ (sqrt(2.)*tof_sigma) );
660 for(
int nP = 0; nP < n - 1; ++nP, ++pAlpha, ++pAlphaPrevious )
662 alphaMid = ( *pAlpha + *pAlphaPrevious ) * 0.5;
664 i = alphaMid * i2 + i1;
665 if( i < 1 || i > mp_nbVox[ 0 ] )
continue;
667 j = alphaMid * j2 + j1;
668 if( j < 1 || j > mp_nbVox[ 1 ] )
continue;
670 k = alphaMid * k2 + k1;
671 if( k < 1 || k > mp_nbVox[ 2 ] )
continue;
673 numVox = ( i - 1 ) + ( j - 1 ) * mp_nbVox[0] + ( k - 1 ) * mp_nbVox[0] * mp_nbVox[1];
676 next_edge_erf = erf( (length_LOR * (*pAlpha) - lor_tof_center) / (sqrt(2.)*tof_sigma) );
678 coeff = 0.5 * fabs(previous_edge_erf - next_edge_erf) * tof_norm_coef ;
680 previous_edge_erf = next_edge_erf;
691 #ifdef CASTOR_VERBOSE
694 Cout(
"iProjectorClassicSiddon::Project without TOF -> Exit function" << endl);
708 Cerr(
"***** iProjectorClassicSiddon::ProjectWithTOFBin() -> Not yet implemented !" << endl);
void ShowHelpSpecific()
A function used to show help about the child projector.
bool m_compatibleWithSPECTAttenuationCorrection
#define TWO_SQRT_TWO_LN_2
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
This class is designed to generically described any on-the-fly projector.
FLTNB GetTOFMeasurement()
This function is used to get the TOF measurement.
FLTNB GetLength()
This function is used to get the length of the line.
int ReadOptionsList(const string &a_optionsList)
A function used to read options from a list of options.
FLTNB GetTOFResolution()
This function is used to get the TOF resolution.
iProjectorClassicSiddon()
The constructor of iProjectorClassicSiddon.
FLTNB * GetPosition1()
This function is used to get the pointer to the mp_position1 (3-values tab).
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 ProjectWithTOFBin(int a_direction, oProjectionLine *ap_ProjectionLine)
A function to project with TOF binned information.
int ProjectWithTOFPos(int a_direction, oProjectionLine *ap_ProjectionLine)
A function to project with TOF continuous information.
~iProjectorClassicSiddon()
The destructor of iProjectorClassicSiddon.
Declaration of class iProjectorClassicSiddon.
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child projector.
This class is designed to manage and store system matrix elements associated to a vEvent...
INTNB EstimateMaxNumberOfVoxelsPerLine()
This function is used to compute and provide an estimate of the maximum number of voxels that could c...
int ReadConfigurationFile(const string &a_configurationFile)
A function used to read options from a configuration file.
Declaration of class sOutputManager.
FLTNB * GetPosition2()
This function is used to get the pointer to the mp_position2 (3-values tab).
INTNB GetNbVoxX()
Get the number of voxels along the X axis.
INTNB GetNbVoxZ()
Get the number of voxels along the Z axis.
int ProjectWithoutTOF(int a_direction, oProjectionLine *ap_ProjectionLine)
A function to project without TOF.
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 InitializeSpecific()
This function is used to initialize specific stuff to the child projector.
INTNB GetNbVoxY()
Get the number of voxels along the Y axis.