CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
iScannerSPECTConv.cc
Go to the documentation of this file.
00001 
00002 /*
00003   Implementation of class iScannerSPECTConv
00004 
00005   - separators: X
00006   - doxygen: X
00007   - default initialization: X
00008   - CASTOR_DEBUG: none
00009   - CASTOR_VERBOSE: X
00010 */
00011 
00018 #include "iScannerSPECTConv.hh"
00019 #include "sOutputManager.hh"
00020 #include "sScannerManager.hh"
00021 
00022 
00023 
00024 
00025 
00026 // =====================================================================
00027 // ---------------------------------------------------------------------
00028 // ---------------------------------------------------------------------
00029 // =====================================================================
00030 /*
00031   \brief iScannerSPECTConv constructor. 
00032          Initialize the member variables to their default values.
00033 */
00034 iScannerSPECTConv::iScannerSPECTConv() : vScanner() 
00035 {
00036   // Set member variables to default values
00037   m_scannerType = 2;
00038   m_nbCrystals = -1;
00039   m_nbHeads = -1;
00040   m_nbPixelsTrans = 0;
00041   m_pixelsSizeTrans = -1.;
00042   m_gapSizeTrans = -1.;
00043 
00044   m_nbPixelsAxial = 0;
00045   m_pixelsSizeAxial = -1.;
00046   m_gapSizeAxial = -1.;
00047 
00048   m_vPixelsSizeTrans = -1.;
00049   m_vPixelsSizeAxial = -1.;
00050 
00051   m_vNbPixelsTrans = 0;
00052   m_vNbPixelsAxial = 0;
00053 
00054   mp_nbOfBins[0] = 0;
00055   mp_nbOfBins[1] = 0;
00056 
00057   m_crystalDepth = -1.;
00058 
00059   mp_focalModelTrans = NULL;
00060   mp_nbCoefModelTrans = NULL;
00061   m2p_transFocalParameters = NULL;    
00062 
00063   mp_focalModelAxial = NULL;
00064   mp_nbCoefModelAxial = NULL;
00065   m2p_axialFocalParameters = NULL;  
00066 
00067   m_nbOfProjections = 0;
00068   mp_projectionAngles = NULL;
00069   mp_radius = NULL;
00070   mp_CORtoDetectorDistance = NULL; 
00071   m_rotDirection = GEO_ROT_CW;
00072 
00073   mp_crystalCentralPositionX = NULL; 
00074   mp_crystalCentralPositionY = NULL; 
00075   mp_crystalCentralPositionZ = NULL; 
00076 
00077   mp_crystalOrientationX = NULL; 
00078   mp_crystalOrientationY = NULL; 
00079   mp_crystalOrientationZ = NULL; 
00080  
00081   mp_crystalFocalPositionX = NULL; 
00082   mp_crystalFocalPositionY = NULL; 
00083   mp_crystalFocalPositionZ = NULL; 
00084 
00085   mp_positionMatrix_ref = NULL;
00086   mp_positionMatrix_out = NULL;
00087   mp_rotationMatrix = NULL;
00088 }
00089 
00090 
00091 
00092 
00093 // =====================================================================
00094 // ---------------------------------------------------------------------
00095 // ---------------------------------------------------------------------
00096 // =====================================================================
00097 /*
00098   \brief iScannerSPECTConv destructor. 
00099 */
00100 iScannerSPECTConv::~iScannerSPECTConv() 
00101 {
00102   if( mp_focalModelTrans ) delete[] mp_focalModelTrans;
00103   if( mp_nbCoefModelTrans ) delete[] mp_nbCoefModelTrans;
00104 
00105   if( m2p_transFocalParameters )
00106   {
00107     for( int i = 0; i < m_nbHeads; ++i )
00108       delete m2p_transFocalParameters[ i ];
00109     
00110     delete[] m2p_transFocalParameters;
00111   }
00112     
00113 
00114   if( mp_focalModelAxial ) delete[] mp_focalModelAxial;
00115   if( mp_nbCoefModelAxial ) delete[] mp_nbCoefModelAxial;
00116 
00117   if( m2p_axialFocalParameters )
00118   {
00119     for( int i = 0; i < m_nbHeads; ++i )
00120       delete m2p_axialFocalParameters[ i ];
00121     
00122     delete[] m2p_axialFocalParameters;
00123   }
00124   
00125   if( mp_projectionAngles ) delete[] mp_projectionAngles;
00126   if( mp_radius ) delete[] mp_radius;
00127   if( mp_CORtoDetectorDistance ) delete[] mp_CORtoDetectorDistance; 
00128 
00129   if (mp_positionMatrix_ref) delete mp_positionMatrix_ref;
00130   if (mp_positionMatrix_out) delete mp_positionMatrix_out;
00131   if (mp_rotationMatrix) delete mp_rotationMatrix;
00132 
00133 
00134   if(mp_crystalCentralPositionX) delete mp_crystalCentralPositionX;
00135   if(mp_crystalCentralPositionY) delete mp_crystalCentralPositionY;
00136   if(mp_crystalCentralPositionZ) delete mp_crystalCentralPositionZ;
00137 
00138   if(mp_crystalOrientationX) delete mp_crystalOrientationX;
00139   if(mp_crystalOrientationY) delete mp_crystalOrientationY;
00140   if(mp_crystalOrientationZ) delete mp_crystalOrientationZ;
00141  
00142   if(mp_crystalFocalPositionX) delete mp_crystalFocalPositionX;
00143   if(mp_crystalFocalPositionY) delete mp_crystalFocalPositionY;
00144   if(mp_crystalFocalPositionZ) delete mp_crystalFocalPositionZ;
00145 }
00146 
00147 
00148 
00149 
00150 // =====================================================================
00151 // ---------------------------------------------------------------------
00152 // ---------------------------------------------------------------------
00153 // =====================================================================
00154 
00155 int iScannerSPECTConv::Instantiate(bool a_scannerFileIsLUT)
00156 {
00157   if(m_verbose>=2) Cout("iScannerSPECTConv::Instantiate ..."<< endl); 
00158     
00159   sScannerManager* p_scannerManager; 
00160   p_scannerManager = sScannerManager::GetInstance();  
00161   
00162   // Get the number of layers in the scanner
00163   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "number of detector heads", &m_nbHeads, 1, KEYWORD_MANDATORY))
00164   {
00165     Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read the number of SPECT heads !" << endl);
00166     return 1;
00167   }
00168   
00169   mp_radius = new FLTNB[m_nbHeads];
00170   
00171   // Get default radius
00172   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "scanner radius", mp_radius, m_nbHeads, KEYWORD_MANDATORY))
00173   {
00174     Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read the number of SPECT heads !" << endl);
00175     return 1;
00176   }
00177 
00178   for( int i = 0; i < m_nbHeads; i++ )
00179     if(mp_radius[i] == 0)
00180     {
00181       Cerr("***** iScannerSPECTConv::Instantiate() -> scanner radius == 0 ? really ? :) ... " << endl);
00182       return 1;
00183     } 
00184 
00185   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "trans number of pixels", &m_nbPixelsTrans, 1, KEYWORD_MANDATORY))
00186   {
00187     Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read the transaxial number of pixels !" << endl);
00188     return 1;
00189   }
00190  
00191   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "trans pixel size", &m_pixelsSizeTrans, 1, KEYWORD_MANDATORY))
00192   {
00193     Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read the transaxial pixel size !" << endl);
00194     return 1;
00195   }
00196   
00197   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "axial number of pixels", &m_nbPixelsAxial, 1, KEYWORD_MANDATORY))
00198   {
00199     Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read the axial number of pixels !" << endl);
00200     return 1;
00201   } 
00202   
00203   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "axial pixel size", &m_pixelsSizeAxial, 1, KEYWORD_MANDATORY))
00204   {
00205     Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read the axial pixel size !" << endl);
00206     return 1;
00207   } 
00208 
00209   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "detector depth", &m_crystalDepth, 1, KEYWORD_MANDATORY))
00210   {
00211     Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read detector depth !" << endl);
00212     return 1;
00213   } 
00214   
00215 
00216   string *head_name = new string[ m_nbHeads + 1 ];
00217   for( int i = 0; i < m_nbHeads; i++ )
00218   {
00219     ostringstream oss( ostringstream::out );
00220     oss << "head" << i+1;
00221     head_name[ i ] = oss.str();
00222   }
00223   head_name[ m_nbHeads ] = "eof";
00224 
00225 
00226   if(m_verbose>=2) Cout("iScannerSPECTConv::Allocating memory ..."<< endl); 
00227   
00228   // Allocating memories
00229   mp_focalModelTrans = new string[ m_nbHeads ];
00230   mp_focalModelAxial = new string[ m_nbHeads ];
00231   mp_nbCoefModelTrans = new uint8_t[ m_nbHeads ];
00232   mp_nbCoefModelAxial = new uint8_t[ m_nbHeads ];
00233   m2p_transFocalParameters = new FLTNB*[ m_nbHeads ];
00234   m2p_axialFocalParameters = new FLTNB*[ m_nbHeads ];
00235   
00236   
00237   
00238   // Read informations about SPECT head
00239   for( int i = 0; i < m_nbHeads; i++ )
00240   {
00241     if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "trans focal model", &mp_focalModelTrans[ i ], 1, KEYWORD_MANDATORY, head_name[ i ], head_name[ i + 1 ]))
00242     {
00243       Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read transaxial focal model of head " << i << " !" << endl);
00244       return 1;
00245     }
00246 
00247     if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "trans number of coef model", &mp_nbCoefModelTrans[ i ], 1, KEYWORD_MANDATORY, head_name[ i ], head_name[ i + 1 ]))
00248     {
00249       Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read transaxial number of coef model of head " << i << " !" << endl);
00250       return 1;
00251     }
00252 
00253     if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "axial focal model", &mp_focalModelAxial[ i ], 1, KEYWORD_MANDATORY, head_name[ i ], head_name[ i + 1 ]))
00254     {
00255       Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read axial focal model of head " << i << " !" << endl);
00256       return 1;
00257     }
00258     
00259     if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "axial number of coef model", &mp_nbCoefModelAxial[ i ], 1, KEYWORD_MANDATORY, head_name[ i ], head_name[ i + 1 ]))
00260     {
00261       Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read transaxial focal model of head " << i << " !" << endl);
00262       return 1;
00263     }
00264     
00265     m2p_transFocalParameters[i] = new FLTNB[mp_nbCoefModelTrans[ i ]];
00266     m2p_axialFocalParameters[i] = new FLTNB[mp_nbCoefModelAxial[ i ]]; 
00267     
00268     if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "trans parameters", m2p_transFocalParameters[i], mp_nbCoefModelTrans[ i ], KEYWORD_MANDATORY, head_name[ i ], head_name[ i + 1 ]))
00269     {
00270       Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read transaxial focal model of head " << i << " !" << endl);
00271       return 1;
00272     }
00273     
00274     if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "axial parameters", m2p_axialFocalParameters[i], mp_nbCoefModelAxial[ i ], KEYWORD_MANDATORY, head_name[ i ], head_name[ i + 1 ]))
00275     {
00276       Cerr("***** iScannerSPECTConv::Instantiate() -> An error occurred while trying to read transaxial focal model of head " << i << " !" << endl);
00277       return 1;
00278     }
00279   }
00280 
00281   // Instanciation of objects for matrix calculation
00282   mp_positionMatrix_ref = new oMatrix(3,1);
00283   mp_positionMatrix_out = new oMatrix(3,1);
00284   mp_rotationMatrix = new oMatrix(3,3);  
00285   
00286   delete[] head_name;
00287    
00288   return 0;
00289 }
00290 
00291 
00292 
00293 
00294 // =====================================================================
00295 // ---------------------------------------------------------------------
00296 // ---------------------------------------------------------------------
00297 // =====================================================================
00298 /*
00299   \fn BuildLUT
00300   \param a_scannerFileIsLUT : boolean indicating if the file describing 
00301                               the SPECT camera is a generic file (0) or custom Look-up-table (1)
00302   \brief Call the functions to generate the LUT or read the user-made LUT depending on the user choice
00303   \return 0 if success, positive value otherwise
00304 */
00305 int iScannerSPECTConv::BuildLUT(bool a_scannerFileIsLUT)
00306 {  
00307   if(m_verbose>=2) Cout("iScannerSPECTConv::BuildLUT ..."<< endl);
00308   
00309   // Initialize nb_crystals
00310   if(mp_nbOfBins[0] == 0 && mp_nbOfBins[1] == 0) // number of bins not initialized in the datafile, then we read the number of crystals from the geom file
00311   {
00312     if(m_nbPixelsTrans==0 || m_nbPixelsAxial==0)
00313     {
00314      Cerr("***** iScannerSPECTConv::BuildLUT() -> Error, transaxial or axial number of pixels in the geometric file should be >0 !" << endl);
00315      return 1;
00316     }
00317     
00318     m_nbCrystals = m_nbPixelsTrans*m_nbPixelsAxial;
00319   }
00320   else // initialization with number of bins
00321   {
00322     m_nbCrystals = mp_nbOfBins[0]*mp_nbOfBins[1];
00323   }
00324   
00325   mp_crystalCentralPositionX = new FLTNB[m_nbOfProjections*m_nbCrystals];
00326   mp_crystalCentralPositionY = new FLTNB[m_nbOfProjections*m_nbCrystals];
00327   mp_crystalCentralPositionZ = new FLTNB[m_nbOfProjections*m_nbCrystals];
00328 
00329   mp_crystalOrientationX = new FLTNB[m_nbOfProjections*m_nbCrystals];
00330   mp_crystalOrientationY = new FLTNB[m_nbOfProjections*m_nbCrystals];
00331   mp_crystalOrientationZ = new FLTNB[m_nbOfProjections*m_nbCrystals];
00332   
00333   mp_crystalFocalPositionX = new FLTNB[m_nbOfProjections*m_nbCrystals];
00334   mp_crystalFocalPositionY = new FLTNB[m_nbOfProjections*m_nbCrystals];
00335   mp_crystalFocalPositionZ = new FLTNB[m_nbOfProjections*m_nbCrystals]; 
00336     
00337   // Either generate the LUT from a generic file, or load the user precomputed LUT
00338   if (!a_scannerFileIsLUT)
00339   {
00340     if (ComputeLUT())
00341     {
00342      Cerr("***** iScannerSPECTConv::BuildLUT() -> A problem occured while generating scanner LUT !" << endl);
00343      return 1;
00344     }
00345   }
00346   else 
00347   {
00348     if (LoadLUT())
00349     {
00350       Cerr("***** iScannerSPECTConv::BuildLUT() -> A problem occured while loading scanner LUT !" << endl);
00351       return 1;
00352     }
00353   }
00354   
00355   return 0;
00356 }
00357 
00358 
00359 
00360 
00361 // =====================================================================
00362 // ---------------------------------------------------------------------
00363 // ---------------------------------------------------------------------
00364 // =====================================================================
00365 /*
00366   \fn CheckParameters
00367   \brief Check that all parameters have been correctly initialized.
00368   \return 0 if success, positive value otherwise
00369   \todo Keep the check on crystal depth ?
00370 */
00371 int iScannerSPECTConv::CheckParameters()
00372 {  
00373   if(m_verbose>=2) Cout("iScannerSPECTConv::CheckParameters ..."<< endl);
00374   
00375   // Check if all parameters have been correctly initialized. Return error otherwise
00376 
00377   if(m_nbCrystals<0)
00378   {
00379     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, number of crystals has not been initialized !" <<endl);
00380     return 1;
00381   }
00382 
00383   if(m_nbHeads<0)
00384   {
00385     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, number of heads in the SPECT system has not been initialized !" <<endl);
00386     return 1;
00387   }
00388 
00389   if(m_nbOfProjections<=0)
00390   {
00391     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, number of projection angles has not been initialized !" <<endl);
00392     return 1;
00393   }
00394   
00395   if(m_nbPixelsTrans<=0 || m_nbPixelsAxial<=0 )
00396   {
00397     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, number of transaxial/axial pixels have not correctly been initialized ! (should be >0)" <<endl);
00398     return 1;
00399   }
00400     
00401   if(m_pixelsSizeTrans<=0 || m_pixelsSizeAxial<=0 )
00402   {
00403     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, transaxial/axial pixel sizes have not correctly been initialized ! (should be >0)" <<endl);
00404     return 1;
00405   }
00406 
00407 
00408   if(m_vNbPixelsTrans<=0 || m_vNbPixelsAxial<=0 )
00409   {
00410     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, transaxial/axial number of virtual pixels have not correctly been initialized ! (should be >0)" <<endl);
00411     return 1;
00412   }
00413 
00414 
00415   if(m_vPixelsSizeTrans<=0 || m_vPixelsSizeAxial<=0 )
00416   {
00417     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, transaxial/axial virtual pixel sizes have not correctly been initialized ! (should be >0)" <<endl);
00418     return 1;
00419   }
00420 
00421 
00422   if(m_gapSizeTrans<0 || m_gapSizeAxial<0 )
00423   {
00424     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, transaxial/axial pixel gap sizes have not correctly been initialized ! (should be >0)" <<endl);
00425     return 1;
00426   }
00427 
00428   // todo : maybe delete this as we don't used it
00429   if(m_crystalDepth<=0)
00430   {
00431     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, crystal depth has not correctly been initialized ! (should be >0)" <<endl);
00432     return 1;
00433   }
00434 
00435   if(mp_focalModelTrans == NULL || mp_focalModelAxial == NULL)
00436   {
00437     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, transaxial/axial focal models have not correctly been initialized !" <<endl);
00438     return 1;
00439   }
00440 
00441   if(mp_nbCoefModelTrans == NULL || mp_nbCoefModelAxial == NULL)
00442   {
00443     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, number of coefficients for the transaxial/axial focal models have not correctly been initialized !" <<endl);
00444     return 1;
00445   }
00446   
00447   if(m2p_transFocalParameters == NULL || m2p_axialFocalParameters == NULL)
00448   {
00449     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, parameters for the transaxial/axial focal models have not correctly been initialized !" <<endl);
00450     return 1;
00451   }
00452   
00453   if(mp_projectionAngles == NULL)
00454   {
00455     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, projection angles have not correctly been initialized !" <<endl);
00456     return 1;
00457   }
00458 
00459   if(mp_radius == NULL)
00460   {
00461     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, default scanner radius for each detector heads (scanner file) not correctly initialized !" <<endl);
00462     return 1;
00463   }
00464   
00465   if(mp_CORtoDetectorDistance == NULL)
00466   {
00467     Cerr("*****iScannerSPECTConv::CheckParameters()-> Error, distances between center of rotation and each detector heads have not correctly been initialized !" <<endl);
00468     return 1;
00469   }
00470   
00471   if(mp_crystalCentralPositionX == NULL ||
00472      mp_crystalCentralPositionY == NULL ||
00473      mp_crystalCentralPositionZ == NULL  )
00474   {
00475     Cerr("*****iScannerSPECTConv::CheckParameters()-> LUT elements (crystal central positions) have not correctly been initialized !" <<endl);
00476     return 1;
00477   }
00478     
00479   if(mp_crystalOrientationX == NULL ||
00480      mp_crystalOrientationY == NULL ||
00481      mp_crystalOrientationZ == NULL  )
00482   {
00483     Cerr("*****iScannerSPECTConv::CheckParameters()-> LUT elements (crystal orientations) have not correctly been initialized !" <<endl);
00484     return 1;
00485   }
00486 
00487   if(mp_crystalFocalPositionX == NULL ||
00488      mp_crystalFocalPositionY == NULL ||
00489      mp_crystalFocalPositionZ == NULL  )
00490   {
00491     Cerr("*****iScannerSPECTConv::CheckParameters()-> LUT elements (crystal focal positions) have not correctly been initialized !" <<endl);
00492     return 1;
00493   }
00494 
00495   // No need to check mp_nbOfBins, Default values = 0
00496 
00497   m_allParametersChecked = true;
00498   
00499   return 0;
00500 }
00501 
00502 
00503 
00504 // =====================================================================
00505 // ---------------------------------------------------------------------
00506 // ---------------------------------------------------------------------
00507 // =====================================================================
00508 /*
00509   \fn Initialize
00510   \brief Check general initialization and set several parameters to their default value
00511   \return 0 if success, positive value otherwise
00512 */
00513 int iScannerSPECTConv::Initialize()
00514 {
00515   if(m_verbose>=2) Cout("iScannerSPECTConv::Initialize ..."<< endl); 
00516   
00517   if(m_allParametersChecked == false)
00518   {
00519     Cerr("***** iScannerSPECTConv::Initialize() -> Parameters have not been checked !" << endl);
00520     return 1;
00521   }
00522   
00523   // Any initialization
00524   
00525   return 0;
00526 }
00527 
00528 
00529 
00530 // =====================================================================
00531 // ---------------------------------------------------------------------
00532 // ---------------------------------------------------------------------
00533 // =====================================================================
00534 /*
00535   \fn LoadLUT
00536   \brief Load a precomputed scanner LUT
00537   \details Read mandatory data from the header of the LUT. Then load the LUT elements for each crystal
00538   \todo Not yet implemented
00539   \return 0 if success, positive value otherwise
00540 */
00541 int iScannerSPECTConv::LoadLUT()
00542 {
00543   if(m_verbose>=2) Cout("iScannerSPECTConv::LoadLUT ..."<< endl); 
00544   
00545   Cerr("iScannerSPECTConv::LoadLUT() -> Not yet implemented !" << endl);
00546   return 1;
00547   // Read LUT according to SPECT camera hscan/LUT files. Check the Castor presentation file to see mandatory/optional fields to read
00548 }
00549 
00550 
00551 
00552 // =====================================================================
00553 // ---------------------------------------------------------------------
00554 // ---------------------------------------------------------------------
00555 // =====================================================================
00556 /*
00557   \fn ComputeLUT
00558   \brief Computes the LUT of the scanner from a generic (.geom) file.
00559   \details Read mandatory data from the geom file. Then compute the LUT elements for each crystal from the geometry described in the file
00560            Compute the look-up-tables of the system containing the locations of the scanner elements center in space and their orientations
00561   \todo  center of rotation & head first angles : get this from acquisition header file
00562   \return 0 if success, positive value otherwise
00563 */
00564 int iScannerSPECTConv::ComputeLUT()
00565 {
00566   if(m_verbose>=2) Cout("iScannerSPECTConv::ComputeLUT() -> Start LUT generation" << endl);
00567   
00568   // Compute LUT according to SPECT camera geom files. Check the Castor presentation file for more details about the related  mandatory/optional fields to be read
00569 
00570   // ============================================================================================================
00571   // Parameters declarations
00572   // ============================================================================================================
00573   
00574   // todo center of rotation & head first angles : get this from acquisition header file
00575   FLTNB *CORx, *CORy, *CORz;
00576   FLTNB *head_angleX, *head_angleY, *head_angleZ;
00577   
00578   CORx = new FLTNB[m_nbHeads];
00579   CORy = new FLTNB[m_nbHeads]; 
00580   CORz = new FLTNB[m_nbHeads];
00581   head_angleX = new FLTNB[m_nbHeads];
00582   head_angleY = new FLTNB[m_nbHeads];
00583   head_angleZ = new FLTNB[m_nbHeads];
00584     
00585   //  for(int hId=0 ; hId<m_nbHeads ; hId++)
00586     // todo Initialisation COR and head_angle
00587 
00588   // ============================================================================================================
00589   // Generate the LUT
00590   // ============================================================================================================
00591   
00592   // oMatrix crystal_center_ref will be used to gather cartesian positions of the crystals center (on the surface of the crystals) 
00593   // in the reference head (directly above isocenter)
00594   oMatrix** crystal_center_ref = new oMatrix *[m_nbCrystals];
00595   // oMatrix crystal_center_out will be used to recover positions of each crystal after each rotation (each projection angles)
00596   oMatrix* crystal_center_out = new oMatrix(3,1);
00597   
00598   // same method for matrices recovering the positions of focal point
00599   oMatrix* focal_projection_position_mtx = new oMatrix(3,3);
00600   oMatrix* focal_projection_position_mtx_output = new oMatrix(3,3);
00601   
00602   for (int c = 0; c<m_nbCrystals; c++)
00603     crystal_center_ref[c]  = new oMatrix(3,1);
00604 
00605 
00606   for(int i=0 ; i<3 ; i++)
00607   {
00608     crystal_center_out->SetMatriceElt(i,0,0);
00609     
00610     for(int j=0 ; j<3 ; j++)
00611     {
00612       focal_projection_position_mtx->SetMatriceElt(i,j,0);
00613       focal_projection_position_mtx_output->SetMatriceElt(i,j,0);
00614     }
00615   }
00616 
00617   // Generation of the rotation matrix allowing to compute the position of all the rsectors. 
00618   oMatrix** rotation_mtx = new oMatrix*[m_nbOfProjections];
00619 
00620   for(int i=0; i<m_nbOfProjections; i++)
00621   {
00622     rotation_mtx[i] = new oMatrix(3,3);
00623     
00624     int dir = (m_rotDirection == GEO_ROT_CCW) ? -1 : 1;
00625     
00626     rotation_mtx[i]->SetMatriceElt(0,0, cos(mp_projectionAngles[i] * M_PI/180.) );
00627     rotation_mtx[i]->SetMatriceElt(1,0, -dir*sin(mp_projectionAngles[i] * M_PI/180.) );
00628     rotation_mtx[i]->SetMatriceElt(2,0,0);
00629     rotation_mtx[i]->SetMatriceElt(0,1, dir*sin(mp_projectionAngles[i] * M_PI/180.) );
00630     rotation_mtx[i]->SetMatriceElt(1,1, cos(mp_projectionAngles[i] * M_PI/180.) );
00631     rotation_mtx[i]->SetMatriceElt(2,1,0);
00632     rotation_mtx[i]->SetMatriceElt(0,2,0);
00633     rotation_mtx[i]->SetMatriceElt(1,2,0);
00634     rotation_mtx[i]->SetMatriceElt(2,2,1);
00635   }
00636 
00637   // Initialization of pixel size
00638   FLTNB size_pixel_trans = 0., size_pixel_axial = 0.;
00639   int   nb_pixel_trans=0, nb_pixel_axial=0;
00640 
00641   // nb of bins have been recovered from the datafile (>0)
00642   if(mp_nbOfBins[0]>0 && mp_nbOfBins[1]>0)
00643   {
00644     size_pixel_trans = m_pixelsSizeTrans/mp_nbOfBins[0];
00645     size_pixel_axial = m_pixelsSizeAxial/mp_nbOfBins[1];
00646     
00647     // Initialize pixel value
00648     nb_pixel_trans = mp_nbOfBins[0];
00649     nb_pixel_axial = mp_nbOfBins[1];
00650     
00651     // Set the member variable recovering the pixel value
00652     m_vNbPixelsTrans = mp_nbOfBins[0];
00653     m_vNbPixelsAxial = mp_nbOfBins[1];
00654   }
00655   else // Otherwise, we recover these informations from the geom file
00656   {
00657     size_pixel_trans = m_pixelsSizeTrans;
00658     size_pixel_axial = m_pixelsSizeAxial;
00659     nb_pixel_trans = m_nbPixelsTrans;
00660     nb_pixel_axial = m_nbPixelsAxial;
00661 
00662     // Set the member variable recovering the pixel value
00663     m_vNbPixelsTrans = m_nbPixelsTrans;
00664     m_vNbPixelsAxial = m_nbPixelsAxial;
00665   }
00666 
00667   // Recover the actual trans/axial size of the pixels in member variable, in case we need them during reconstruction
00668   m_vPixelsSizeTrans = size_pixel_trans;
00669   m_vPixelsSizeAxial = size_pixel_axial;
00670   
00671 
00672   // Recover the trans/axial gap size from the geom file
00673   sScannerManager* p_scannerManager; 
00674   p_scannerManager = sScannerManager::GetInstance();
00675 
00676   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "trans gap size", &m_gapSizeTrans, 1, KEYWORD_MANDATORY))
00677   {
00678     Cerr("***** iScannerSPECTConv::ComputeLUT() -> An error occurred while trying to read the transaxial gap size !" << endl);
00679     return 1;
00680   } 
00681   
00682   if(ReadDataASCIIFile(p_scannerManager->GetPathToScannerFile(), "axial gap size", &m_gapSizeAxial, 1, KEYWORD_MANDATORY))
00683   {
00684     Cerr("***** iScannerSPECTConv::ComputeLUT() -> An error occurred while trying to read the axial gap size !" << endl);
00685     return 1;
00686   } 
00687   
00688   
00689   // Generate cartesian coordinates of the crystal centers for the SPECT at the reference position (directly above isocenter)
00690   // Starting position of the SPECT camera for all axis
00691   FLTNB x_start = -(nb_pixel_trans*size_pixel_trans + (nb_pixel_trans-1)*m_gapSizeTrans) / 2 + (size_pixel_trans/2);
00692   FLTNB z_start = -(nb_pixel_axial*size_pixel_axial + (nb_pixel_axial-1)*m_gapSizeAxial) / 2 + (size_pixel_axial/2);
00693 
00694   for( int jj = 0; jj < nb_pixel_axial; ++jj )
00695   {
00696     FLTNB Zcrist = z_start + jj * (size_pixel_axial + m_gapSizeAxial);
00697     for( int ii = 0; ii < nb_pixel_trans; ++ ii )
00698     {
00699       FLTNB Xcrist = x_start + ii * (size_pixel_trans + m_gapSizeTrans);
00700 
00701       crystal_center_ref[ii + nb_pixel_trans * jj]->SetMatriceElt(0,0,Xcrist);
00702       crystal_center_ref[ii + nb_pixel_trans * jj]->SetMatriceElt(1,0,     0); // This value will be set for each projection angles
00703       crystal_center_ref[ii + nb_pixel_trans * jj]->SetMatriceElt(2,0,Zcrist);
00704     }
00705   }
00706 
00707   // ============================================================================================================
00708   // Loop over all the projection angles
00709   // Positions of the scanner elements are progressively stored in the LUT file.
00710   // ============================================================================================================
00711   if (m_verbose>=2) Cout("  --> Generate positions for each projection angle"<< endl); 
00712   
00713   for (int a=0 ; a<m_nbOfProjections ; a++)
00714   {
00715     // Set y-position of the crystal reference matrix according to the distance between SPECT camera and center of rotation of the specific head.(mp_CORtoDetectorDistance)
00716     int hId = a*m_nbHeads/m_nbOfProjections;
00717 
00718     // Get surface crystal position (and not center crystal positions for SPECT), and set the reference crystal matrix
00719     FLTNB Ycrist = mp_CORtoDetectorDistance[hId];
00720 
00721     for (int c=0 ; c < m_nbCrystals ; c++) 
00722       crystal_center_ref[c]->SetMatriceElt(1,0,Ycrist);
00723 
00724     for (int c=0 ; c<m_nbCrystals ; c++)
00725     {
00726       // crystal indexation
00727       int cryID = a*m_nbCrystals + c;
00728 
00729       // SET CARTESIAN COORDINATES OF THE CRYSTAL SURFACE CENTER POSITIONS      
00730       // Rotation
00731       rotation_mtx[a]->Multiplication(crystal_center_ref[c], crystal_center_out);
00732 
00733       // Get crystal surface positions
00734       mp_crystalCentralPositionX[cryID] = crystal_center_out->GetMatriceElt(0,0);
00735       mp_crystalCentralPositionY[cryID] = crystal_center_out->GetMatriceElt(1,0);
00736       mp_crystalCentralPositionZ[cryID] = crystal_center_out->GetMatriceElt(2,0);
00737 
00738       // COMPUTE FOCAL POSITIONS AND SET CARTESIAN COORDINATES OF THE CRYSTAL FOCAL POSITIONS
00739       if(ComputeFocalPositions(crystal_center_ref[c]->GetMatriceElt(0,0), 
00740                                crystal_center_ref[c]->GetMatriceElt(1,0), 
00741                                crystal_center_ref[c]->GetMatriceElt(2,0), 
00742                                                                     hId, 
00743                                                                   cryID) )
00744       {
00745         Cerr("***** iScannerSPECTConv::ComputeLUT() -> An error occurred while computing the focal positions ! " << endl);
00746         return 1;
00747       }
00748       
00749       // Set elements of the focal matrix
00750       focal_projection_position_mtx->SetMatriceElt(0,0,mp_crystalFocalPositionX[cryID] );
00751       focal_projection_position_mtx->SetMatriceElt(1,0,mp_crystalFocalPositionY[cryID] );
00752       focal_projection_position_mtx->SetMatriceElt(2,0,mp_crystalFocalPositionZ[cryID] );
00753       focal_projection_position_mtx->SetMatriceElt(0,1,0);
00754       focal_projection_position_mtx->SetMatriceElt(1,1,0);
00755       focal_projection_position_mtx->SetMatriceElt(2,1,0);
00756       focal_projection_position_mtx->SetMatriceElt(0,2,0);
00757       focal_projection_position_mtx->SetMatriceElt(1,2,0);
00758       focal_projection_position_mtx->SetMatriceElt(2,2,1);
00759 
00760       // Rotate and compute projections of focal position for this crystal
00761       rotation_mtx[a]->Multiplication(focal_projection_position_mtx, focal_projection_position_mtx_output);
00762       mp_crystalFocalPositionX[cryID] = focal_projection_position_mtx_output->GetMatriceElt(0,0);
00763       mp_crystalFocalPositionY[cryID] = focal_projection_position_mtx_output->GetMatriceElt(1,0); 
00764       mp_crystalFocalPositionZ[cryID] = focal_projection_position_mtx_output->GetMatriceElt(2,0); 
00765 
00766       // GET CRYSTAL ORIENTATIONS
00767       mp_crystalOrientationX[cryID] = rotation_mtx[a]->GetMatriceElt(0,0);
00768       mp_crystalOrientationY[cryID] = rotation_mtx[a]->GetMatriceElt(0,1);
00769       mp_crystalOrientationZ[cryID] = 0;
00770     }
00771   }
00772 
00773   for(int i=0; i<m_nbOfProjections; i++)
00774     delete rotation_mtx[i];
00775 
00776   delete[] rotation_mtx;
00777 
00778 
00779   for (int c=0; c<m_nbCrystals; c++)
00780     delete crystal_center_ref[c];
00781 
00782   delete[] crystal_center_ref;
00783   delete crystal_center_out;
00784   delete focal_projection_position_mtx;
00785   delete focal_projection_position_mtx_output;
00786 
00787   delete[] head_angleX;
00788   delete[] head_angleY;
00789   delete[] head_angleZ;
00790   delete[] CORx;
00791   delete[] CORy;
00792   delete[] CORz;
00793 
00794   if (m_verbose>=2) Cout("  --> LUT generation completed" << endl);
00795 
00796   return 0;
00797 }
00798 
00799 
00800 
00801 
00802 // =====================================================================
00803 // ---------------------------------------------------------------------
00804 // ---------------------------------------------------------------------
00805 // =====================================================================
00806 /*
00807   \fn ComputeFocalPositions
00808   \param a_posX : cartesian position of the crystal on the x-axis 
00809   \param a_posY : cartesian position of the crystal on the y-axis 
00810   \param a_posZ : cartesian position of the crystal on the z-axis 
00811   \param a_headID : head index of the crystal 
00812                    (required to select the related focal model parameters
00813                     and distance to center of rotation)
00814   \param a_cryID : crystal index in the LUT
00815   \brief Compute focal positions for a specific crystal ID
00816   \details Compute the focal positions using the implemented "constant", 
00817            "polynomial", "slanthole" focal models related to the gamma cameras
00818            The "custom" focal model is dedicated to user-made focal model
00819            and should be implemented by the user
00820   \return 0 if success, positive value otherwise
00821 */
00822 int iScannerSPECTConv::ComputeFocalPositions(FLTNB a_posX, FLTNB a_posY, FLTNB a_posZ, int a_headID, int a_cryID)
00823 {
00824   #ifdef CASTOR_DEBUG
00825   if(m_verbose>=4) Cout("iScannerSPECTConv::ComputeFocalPositions ..." << endl);
00826   #endif
00827   
00828   mp_crystalFocalPositionY[a_cryID] = -a_posY;
00829 
00830   // ===================================================================
00831   // AXIAL FOCAL POSITIONS
00832   // ===================================================================
00833   // constant
00834   if(mp_focalModelAxial[a_headID] == "constant")
00835   {
00836     mp_crystalFocalPositionZ[a_cryID] = a_posZ;
00837   }
00838   
00839   // polynomial
00840   else if(mp_focalModelAxial[a_headID] == "polynomial" ) 
00841   {
00842     if (mp_nbCoefModelAxial[a_headID] >= 1 && mp_nbCoefModelAxial[a_headID] <= 3)
00843     {
00844       FLTNB focal_posZ = 0;
00845       
00846       for(int coef=0 ; coef<mp_nbCoefModelAxial[a_headID] ; coef++)
00847         focal_posZ += m2p_axialFocalParameters[a_headID][coef]*abs(pow(a_posZ,coef));
00848         
00849       // Compute the projection of the focal position on the Y plane (thales) in order to be sure that the focal positions are not in the field of view (LOR would not go through the whole FOV) 
00850       mp_crystalFocalPositionZ[a_cryID] = -(2*mp_CORtoDetectorDistance[a_headID]-focal_posZ)*a_posZ/focal_posZ;
00851       
00852     }
00853     else if (mp_nbCoefModelAxial[a_headID] > 3) // Error (nb parameters >3)
00854     {
00855       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, the number of coeffs for the axial model should be <4 (max : polynom order 2 = 3 coeffs) ! " << endl);
00856       return 1;
00857     }
00858     else // Error (nb parameters == 0)
00859     {
00860       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, the number of coeffs for the axial model should be >0 ('axial number of coef model' in geom file) ! " << endl);
00861       return 1;
00862     }
00863   }
00864 
00865   // slanthole
00866   else if(mp_focalModelAxial[a_headID] == "slanthole" )
00867   {
00868     if (mp_nbCoefModelAxial[a_headID] == 1) 
00869     {
00870       FLTNB cst = a_posZ - m2p_axialFocalParameters[a_headID][0]*mp_CORtoDetectorDistance[a_headID];
00871       
00872       // Compute the projection of the focal position on the Y plane
00873       mp_crystalFocalPositionZ[a_cryID] = -m2p_axialFocalParameters[a_headID][0]*mp_CORtoDetectorDistance[a_headID] + cst;
00874     } 
00875     else // Error (nb parameters != 1)
00876     {
00877       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, the number of coeffs for a slanthole model should be equal to 1 (slope) : 'axial number of coef model' in geom file ! " << endl);
00878       return 1;
00879     }
00880   }
00881   
00882   // custom
00883   else if(mp_focalModelAxial[a_headID] == "custom" )
00884   {
00885     if (mp_nbCoefModelAxial[a_headID] == 1) // Uni-Parameter
00886     {
00887       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Custom model should be implemented by the user (in iScannerSPECTConv::ComputeFocalPositions()) ! " << endl);
00888       return 1;
00889     } 
00890     else if (mp_nbCoefModelAxial[a_headID] > 1) // Multi-Parameters
00891     {
00892       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Custom model should be implemented by the user (in iScannerSPECTConv::ComputeFocalPositions()) ! " << endl);
00893       return 1;
00894     }
00895     else // Error (nb parameters == 0)
00896     {
00897       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Custom model should be implemented by the user (in iScannerSPECTConv::ComputeFocalPositions()) ! " << endl);
00898       return 1;
00899     }
00900   }
00901   else  // Error, unknown model
00902   {
00903     Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, current model " << mp_focalModelAxial[a_headID] << " is unknown !" << endl);
00904     Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Should be either 'constant' (parallel), 'polynomial', 'hyperbolic, or 'custom'" << endl);
00905     return 1;
00906   }
00907   
00908   
00909   
00910   // ===================================================================
00911   // TRANSAXIAL FOCAL POSITIONS
00912   // ===================================================================
00913   // constant
00914   if(mp_focalModelTrans[a_headID] == "constant")
00915   {
00916     mp_crystalFocalPositionX[a_cryID] = a_posX;
00917   }
00918   
00919   // polynomial
00920   else if(mp_focalModelTrans[a_headID] == "polynomial" ) 
00921   {
00922     if (mp_nbCoefModelTrans[a_headID] >= 1 && mp_nbCoefModelTrans[a_headID] <= 3)
00923     {
00924       FLTNB focal_posX = 0;
00925       
00926       for(int coef=0 ; coef<mp_nbCoefModelTrans[a_headID] ; coef++)
00927         focal_posX += m2p_transFocalParameters[a_headID][coef]*abs(pow(a_posX,coef));
00928         
00929       // Compute the projection of the focal position on the Y plane (thales) in order to be sure that the focal positions are not in the field of view (LOR would not go through the whole FOV) 
00930       mp_crystalFocalPositionX[a_cryID] = -(2*mp_CORtoDetectorDistance[a_headID]-focal_posX)*a_posX/focal_posX;
00931       
00932     } 
00933     else if (mp_nbCoefModelTrans[a_headID] > 3)  // Error (nb parameters >3)
00934     {
00935       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, the number of coeffs for the trans model should be <4 (max : polynom order 2 = 3 coeffs) ! " << endl);
00936       return 1;
00937     }
00938     else // Error (nb parameters == 0)
00939     {
00940       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, the number of coeffs for the axial model should be >0 ('trans number of coef model' in geom file) ! " << endl);
00941       return 1;
00942     }
00943   }
00944   
00945   // slanthole
00946   else if(mp_focalModelTrans[a_headID] == "slanthole" ) 
00947   {
00948     if (mp_nbCoefModelTrans[a_headID] == 1) 
00949     {
00950       FLTNB cst = a_posX - m2p_transFocalParameters[a_headID][0]*mp_CORtoDetectorDistance[a_headID];
00951       
00952       // Compute the projection of the focal position on the Y plane
00953       mp_crystalFocalPositionX[a_cryID] = -m2p_transFocalParameters[a_headID][0]*mp_CORtoDetectorDistance[a_headID] + cst;
00954       
00955     } 
00956     else // Error (nb parameters != 1
00957     {
00958       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, the number of coeffs for a slanthole model should be equal to 1 (slope) : 'trans number of coef model' in geom file ! " << endl);
00959       return 1;
00960     }
00961   }
00962   
00963   // custom
00964   else if(mp_focalModelTrans[a_headID] == "custom" )
00965   {
00966     if (mp_nbCoefModelTrans[a_headID] == 1) // Uni-Parameter
00967     {
00968       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Custom model should be implemented by the user (in iScannerSPECTConv::ComputeFocalPositions()) ! " << endl);
00969       return 1;
00970     } 
00971     else if (mp_nbCoefModelTrans[a_headID] > 1) // Multi-Parameters
00972     {
00973       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Custom model should be implemented by the user (in iScannerSPECTConv::ComputeFocalPositions()) ! " << endl);
00974       return 1;
00975     }
00976     else // Error (nb parameters == 0)
00977     {
00978       Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Custom model should be implemented by the user (in iScannerSPECTConv::ComputeFocalPositions()) ! " << endl);
00979       return 1;
00980     }
00981   }
00982   else  // Error, unknown model
00983   {
00984     Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Error, current model " << mp_focalModelTrans[a_headID] << " is unknown !" << endl);
00985     Cerr("***** iScannerSPECTConv::ComputeFocalPositions() -> Should be either 'constant' (parallel), 'polynomial', 'hyperbolic, or 'custom'" << endl);
00986     return 1;
00987   }
00988   
00989   return 0;
00990 }
00991 
00992 
00993 
00994 // =====================================================================
00995 // ---------------------------------------------------------------------
00996 // ---------------------------------------------------------------------
00997 // =====================================================================
00998 /*
00999   \fn GetPositionsAndOrientations
01000   \param a_index1 : 1st index of the event (projection angle)
01001   \param a_index2 : 2nd index of the event (crystal index in the gamma camera)
01002   \param ap_Position1[3] : x,y,z cartesian position of the focal point
01003   \param ap_Position2[3] : x,y,z cartesian position of the crystal
01004   \param ap_Orientation1[3] : return -1 by default (no orientation components required for the focal point)
01005   \param ap_Orientation2[3] : x,y,z components of the orientation vector related to the crystal
01006   \param ap_POI1 : ignored in SPECT (no POI component required for the focal point)
01007   \param ap_POI2 : x,y,z components of the Point Of Interation related to the crystal.
01008                    Currently ignored (POI management not implemented in SPECT)
01009   \brief Get the central positions and orientations of the scanner elements from their indices.
01010   \todo : Point Of Interactions management is NOT implemented and ignored
01011   \return 0 if success, positive value otherwise
01012 */
01013 int iScannerSPECTConv::GetPositionsAndOrientations( int a_index1, int a_index2,
01014                                                FLTNB ap_Position1[3], FLTNB ap_Position2[3],
01015                                                FLTNB ap_Orientation1[3], FLTNB ap_Orientation2[3],
01016                                                FLTNB* ap_POI1, FLTNB* ap_POI2 )
01017 {
01018   #ifdef CASTOR_VERBOSE
01019   if(m_verbose>=4) Cout("iScannerSPECTConv::GetPositionsAndOrientations ..." << endl);
01020   #endif
01021 
01022   // SPECT indexes : 1st for the projection, 2nd for the crystal
01023 
01024   // First check projection angle existency
01025   if (a_index1<0 || a_index1>=m_nbOfProjections)
01026   {
01027     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> Projection index (" << a_index1 << ") out of range [0:" << m_nbOfProjections-1 << "] !" << endl);
01028     return 1;
01029   }
01030   
01031   // Second check crystals existency
01032   if (a_index2<0 || a_index2>=m_nbCrystals)
01033   {
01034     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> Crystal index (" << a_index2 << ") out of range [0:" << m_nbCrystals-1 << "] !" << endl);
01035     return 1;
01036   }
01037 
01038   // Get crystal index related to the projection
01039   int index = a_index1*m_nbCrystals + a_index2;
01040   
01041   // Get position of the focal point related to the crystal
01042   ap_Position1[0] = mp_crystalFocalPositionX[index];
01043   ap_Position1[1] = mp_crystalFocalPositionY[index];
01044   ap_Position1[2] = mp_crystalFocalPositionZ[index];
01045 
01046   // todo : Due to the current implementation of SPECT projection, POI 
01047   //        and DOI are not handled and ignored.
01048   //        An error is returned if POI are provided
01049 
01050   // Case when POI is not provided
01051   if (ap_POI2==NULL)
01052   {
01053     //FLTNB depth = mp_meanDepthOfInteraction[GetLayer(a_index2)] - mp_sizeCrystalDepth[GetLayer(a_index2)]/2;
01054     //ap_Position2[0] = mp_crystalCentralPositionX[a_index2] + depth*mp_crystalOrientationX[a_index2];
01055     //ap_Position2[1] = mp_crystalCentralPositionY[a_index2] + depth*mp_crystalOrientationY[a_index2];
01056     //ap_Position2[2] = mp_crystalCentralPositionZ[a_index2] + depth*mp_crystalOrientationZ[a_index2];
01057     ap_Position2[0] = mp_crystalCentralPositionX[index];
01058     ap_Position2[1] = mp_crystalCentralPositionY[index];
01059     ap_Position2[2] = mp_crystalCentralPositionZ[index];
01060   }
01061   // Case when POI[2] is negative (meaning we only have POI[0] or POI[1] specified and to be taken into account)
01062   else if (ap_POI2[2]<0.)
01063   {
01064     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> POI management not implemented yet for SPECT !" << endl);
01065     return 1;
01066   }
01067   // Case when only the DOI is provided
01068   else if (ap_POI2[0]==0. && ap_POI2[1]==0.)
01069   {
01070     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> POI management not implemented yet for SPECT !" << endl);
01071     return 1;
01072   }
01073   // Case when the full POI is taken into account
01074   else
01075   {
01076     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> POI management not implemented yet for SPECT !" << endl);
01077     return 1;
01078   }
01079 
01080   // Get orientations
01081   ap_Orientation1[0] = -mp_crystalOrientationX[a_index2];
01082   ap_Orientation1[1] = -mp_crystalOrientationY[a_index2];
01083   ap_Orientation1[2] = -mp_crystalOrientationZ[a_index2];
01084   ap_Orientation2[0] = mp_crystalOrientationX[a_index2];
01085   ap_Orientation2[1] = mp_crystalOrientationY[a_index2];
01086   ap_Orientation2[2] = mp_crystalOrientationZ[a_index2];
01087 
01088   return 0;
01089 }
01090 
01091 
01092 
01093 // =====================================================================
01094 // ---------------------------------------------------------------------
01095 // ---------------------------------------------------------------------
01096 // =====================================================================
01097 /*
01098   \fn GetRdmPositionsAndOrientations()
01099   \param a_index1 : 1st index of the event (projection angle)
01100   \param a_index2 : 2nd index of the event (crystal index in the gamma camera)
01101   \param ap_Position1[3] : x,y,z cartesian position of the focal point
01102   \param ap_Position2[3] : x,y,z cartesian position of the crystal
01103   \param ap_Orientation1[3] : return -1 by default (no orientation components required for the focal point)
01104   \param ap_Orientation2[3] : x,y,z components of the orientation vector related to the crystal
01105   \brief Get the focal point and random positions on the crystal surface and its orientations from the event indices.
01106   \details - Computed the LUT index described by the projection angle and crystal index passed in parameters. 
01107            - Compute random positions on the surface of the crystal
01108            - Write the corresponding random cartesian coordinates in the positions parameters.
01109   \todo This implementation has to be checked and adapted,
01110         as the current implementation of SPECT projection assumes crystal position located on the center of the crystal surface
01111   \return 0 if success, positive value otherwise
01112 */
01113 int iScannerSPECTConv::GetRdmPositionsAndOrientations(int a_index1, int a_index2,
01114                                                 FLTNB ap_Position1[3], FLTNB ap_Position2[3],
01115                                                 FLTNB ap_Orientation1[3], FLTNB ap_Orientation2[3] )
01116 {
01117   #ifdef CASTOR_VERBOSE
01118   if(m_verbose>=4) Cout("iScannerSPECTConv::GetRdmPositionsAndOrientations ..." << endl);
01119   #endif
01120 
01121   // SPECT indexes : 1st for the projection, 2nd for the crystal
01122 
01123   // First check projection angle existency
01124   if (a_index1<0 || a_index1>=m_nbOfProjections)
01125   {
01126     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> Projection index (" << a_index1 << ") out of range [0:" << m_nbOfProjections-1 << "] !" << endl);
01127     return 1;
01128   }
01129   
01130   // Second check crystals existency
01131   if (a_index2<0 || a_index2>=m_nbCrystals)
01132   {
01133     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> Crystal index (" << a_index2 << ") out of range [0:" << m_nbCrystals-1 << "] !" << endl);
01134     return 1;
01135   }
01136   
01137   // Get crystal index related to the projection
01138   int index = a_index1*m_nbCrystals + a_index2;
01139 
01140   // Get position of the focal point related to the crystal
01141   ap_Position1[0] = mp_crystalFocalPositionX[index];
01142   ap_Position1[1] = mp_crystalFocalPositionY[index];
01143   ap_Position1[2] = mp_crystalFocalPositionZ[index];
01144   
01145   // Get instance of random number generator
01146   sRNG* p_RNG = sRNG::GetInstance(); 
01147 
01148   // Get random numbers for the first crystal
01149   FLTNB axial = (p_RNG->GenerateRdmNber()-0.5) * m_pixelsSizeAxial;
01150   FLTNB trans = (p_RNG->GenerateRdmNber()-0.5) * m_pixelsSizeTrans;
01151   // Do not consider random depth (position on the surface of the crystal)
01152   //FLTNB depth = (p_RNG->GenerateRdmNber()-0.5) * m_crystalDepth;
01153   
01154   ap_Position2[0] = mp_crystalCentralPositionX[index] + trans*mp_crystalOrientationY[index] + axial*mp_crystalOrientationX[index]*mp_crystalOrientationZ[index];
01155   ap_Position2[1] = mp_crystalCentralPositionY[index] + trans*mp_crystalOrientationX[index] + axial*mp_crystalOrientationY[index]*mp_crystalOrientationZ[index];
01156   ap_Position2[2] = mp_crystalCentralPositionZ[index] + axial*sqrt(1-mp_crystalOrientationZ[index]*mp_crystalOrientationZ[index]);
01157 
01158   // Get orientations
01159   ap_Orientation1[0] = -1.;
01160   ap_Orientation1[1] = -1.;
01161   ap_Orientation1[2] = -1.;
01162   ap_Orientation2[0] = mp_crystalOrientationX[a_index2];
01163   ap_Orientation2[1] = mp_crystalOrientationY[a_index2];
01164   ap_Orientation2[2] = mp_crystalOrientationZ[a_index2];
01165   
01166   return 0;
01167 }
01168 
01169 
01170   
01171 // =====================================================================
01172 // ---------------------------------------------------------------------
01173 // ---------------------------------------------------------------------
01174 // =====================================================================
01175 /*
01176   \fn GetPositionWithRandomDepth
01177   \param a_index1 :
01178   \param a_index2 : index of the crystal
01179   \param ap_Position1[3] :
01180   \param ap_Position2[3] : x,y,z cartesian position of the point related to the crystal
01181   \brief Get the positions and orientations of scanner elements from their indices, with a random depth.
01182   \todo Not yet implemented
01183   \return 0 if success, positive value otherwise
01184 */
01185 int iScannerSPECTConv::GetPositionWithRandomDepth(int a_index1, int a_index2, FLTNB ap_Position1[3], FLTNB ap_Position2[3])
01186 {
01187   #ifdef CASTOR_VERBOSE
01188   if(m_verbose>=4) Cout("iScannerSPECTConv::GetPositionWithRandomDepth ..." << endl);
01189   #endif
01190   
01191   // This function was first implemented for PET testing purposed. Not implemented yet.
01192   Cerr("***** iScannerSPECTConv::GetPositionWithRandomDepth() -> This function was implemented for PET testing purposes. Not implemented for SPECT !" << endl);
01193   return 1;
01194 }
01195 
01196 
01197 
01198 // =====================================================================
01199 // ---------------------------------------------------------------------
01200 // ---------------------------------------------------------------------
01201 // =====================================================================
01202 /*
01203   \fn GetTwoCorners
01204   \param a_index1 : index of the projection angle
01205   \param a_index2 : index of the  crystal 
01206   \param ap_CornerInf1[3]
01207   \param ap_CornerSup1[3]
01208   \param ap_CornerInf2[3]
01209   \param ap_CornerSup2[3]
01210   \brief Get the cartesian coordinaters of the two opposite corners of a scanner element.
01211   \todo Not yet implemented
01212   \return 0 if success, positive value otherwise
01213 */
01214 int iScannerSPECTConv::GetTwoCorners(int a_index1, int a_index2,
01215                                FLTNB ap_CornerInf1[3], FLTNB ap_CornerSup1[3],
01216                                FLTNB ap_CornerInf2[3], FLTNB ap_CornerSup2[3])
01217 {
01218   #ifdef CASTOR_VERBOSE
01219   if(m_verbose>=4) Cout("iScannerSPECTConv::GetTwoCorners ..." << endl);
01220   #endif
01221   
01222   // First check projection angle existency
01223   if (a_index1<0 || a_index1>=m_nbOfProjections)
01224   {
01225     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> Projection index (" << a_index1 << ") out of range [0:" << m_nbOfProjections-1 << "] !" << endl);
01226     return 1;
01227   }
01228   
01229   // Second check crystals existency
01230   if (a_index2<0 || a_index2>=m_nbCrystals)
01231   {
01232     Cerr("***** iScannerSPECTConv::GetPositionsAndOrientations() -> Crystal index (" << a_index2 << ") out of range [0:" << m_nbCrystals-1 << "] !" << endl);
01233     return 1;
01234   }
01235   
01236   Cerr("***** iScannerSPECTConv::GetTwoCorners() -> Not implemented yet !" << endl);
01237   return 1;
01238 }
01239 
01240 
01241 
01242 
01243 // =====================================================================
01244 // ---------------------------------------------------------------------
01245 // ---------------------------------------------------------------------
01246 // =====================================================================
01247 /*
01248   \fn GetGeometricInfoFromDatafile
01249   \param a_pathToDF : string containing the path to datafile header
01250   \brief Recover geometric informations specific to the scanner class from the datafile header
01251   \details -Recover nb of bins and projections
01252            -Recover the projection angles from the header 
01253            (directly read from the datafile, or extrapolated from a first and last angle)
01254            -Recover the distance between the gamma camera detector surfaces and the center of rotation
01255            (directly read from the datafile, or extracted from the gamma camera configuratino file)
01256   \return 0 if success, positive value otherwise
01257 */
01258 int iScannerSPECTConv::GetGeometricInfoFromDatafile(string a_pathToDF)
01259 {
01260   if(m_verbose>=2) Cout("iScannerSPECTConv::GetGeometricInfoFromDatafile ..." << endl);
01261   
01262   if (ReadDataASCIIFile(a_pathToDF , "Number of bins", mp_nbOfBins, 2, KEYWORD_OPTIONAL) == 1)
01263   {
01264     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error while reading number of bins in the header data file " << endl);
01265     return 1;
01266   }
01267 
01268   if (ReadDataASCIIFile(a_pathToDF , "Number of projections", &m_nbOfProjections, 1, KEYWORD_MANDATORY))
01269   {
01270     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error while reading number of projections in the header data file " << endl);
01271     return 1;
01272   }
01273 
01274   string rotation_direction = "";
01275   if (ReadDataASCIIFile(a_pathToDF , "Head rotation direction", &rotation_direction, 1, KEYWORD_OPTIONAL) == 1)
01276   {
01277     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error while reading head rotation orientation in the header data file " << endl);
01278     return 1;
01279   }
01280  
01281   if (PROJ_SetSPECTRotDirection(rotation_direction) )
01282   {
01283     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error occured while trying to initialize head rotation orientation " << endl);
01284     return 1;
01285   }
01286   
01287   // Allocate a one-dimensional vector to retrieve angles from the datafile, then copy it in the member variables
01288   FLTNB* angles = new FLTNB[m_nbOfProjections];
01289   FLTNB first_and_last_angles[2] = {-1.,-1.};
01290 
01291   // Two possible initializations for projection angles :
01292   // - All angles are provided with the keyword "Angles"
01293   // - The first and last angles are provided, and the intermediate angles are extrapolated from the number of projections
01294   
01295   // 'First/Last angles' tags : checking issue during data reading/conversion (==1)
01296   if (ReadDataASCIIFile(a_pathToDF, "First and last projection angles", first_and_last_angles, 2, KEYWORD_OPTIONAL) == 1)
01297   {
01298     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error while reading Angle mandatory field in the header data file '" << endl);
01299     return 1;
01300   }
01301   
01302   // Check for 'Projection angles' tag
01303   int rvalue = ReadDataASCIIFile(a_pathToDF, "Projection angles", angles, m_nbOfProjections, KEYWORD_OPTIONAL);
01304   
01305   // Error while reading "Angles" tag (==1)
01306   if(rvalue==1)
01307   {
01308     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error while reading Angles field in the header data file !'" << endl);
01309     return 1;
01310   }
01311 
01312   // Check if information on projection angles has been provided
01313   if ( rvalue>=2 &&  // "Angles" tag not found
01314       (first_and_last_angles[0] <0 || first_and_last_angles[1] <0) ) // Tags first/last angles not found)
01315   {
01316     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> No information on projection angles provided in the datafile !'" << endl);
01317     Cerr("                                                           This information should be provided using either the 'Angles' tag, or both 'First angles', 'Last angles' tags !'" << endl);
01318     return 1;
01319   }
01320   else if (rvalue>=2) // "Angles" tag not found, but first angle and last angle provided
01321   {
01322     for(int a=0 ; a<m_nbOfProjections ; a++)
01323       angles[a] = first_and_last_angles[0] + a*(first_and_last_angles[1]-first_and_last_angles[0]) / (m_nbOfProjections-1);
01324   }
01325   // else : Angles have been recovered using ReadDataASCIIFile() above
01326 
01327 
01328   // Instanciate here the projection angles variable
01329   mp_projectionAngles = new FLTNB[m_nbOfProjections];
01330     
01331   for(int a=0 ; a<m_nbOfProjections ; a++)
01332     mp_projectionAngles[a] = angles[a];
01333     
01334     
01335     
01336   // Recover distance between the detectors and scanner center of rotation
01337   // Allocate with the number of projections by default
01338   mp_CORtoDetectorDistance = new FLTNB[m_nbOfProjections]; 
01339   
01340   // Initialize by default with the scanner radius
01341   for(int hId=0 ; hId<m_nbHeads ; hId++)
01342     for(int a=0 ; a<m_nbOfProjections/m_nbHeads ; a++)
01343       mp_CORtoDetectorDistance[a+hId*m_nbOfProjections/m_nbHeads] = mp_radius[hId];
01344   
01345   // Read datafile value if any. First case : we have a radius specific to each projections
01346   int read_flag = 0;
01347   read_flag = ReadDataASCIIFile(a_pathToDF, "Distance camera surface to COR", mp_CORtoDetectorDistance, m_nbOfProjections, KEYWORD_OPTIONAL);
01348   
01349   if(read_flag==1)
01350   {
01351     // Error during reading
01352     Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error while reading the distance between the camera detectors to the center of rotation in the header data file " << endl);
01353     return 1;
01354   } 
01355   // Check the second case : we have a global radius for each projection
01356   else if (read_flag==2)
01357   {
01358     read_flag = ReadDataASCIIFile(a_pathToDF, "Global distance camera surface to COR", mp_CORtoDetectorDistance, 1, KEYWORD_OPTIONAL);
01359 
01360     if(read_flag==0) 
01361     {
01362       // Field was found : Initialize the distance for each projection angle with the global value
01363       for(int a=1 ; a<m_nbOfProjections ; a++)
01364         mp_CORtoDetectorDistance[a] = mp_CORtoDetectorDistance[0];
01365     }
01366     else if(read_flag==1)
01367     {
01368       // Error during reading
01369       Cerr("***** iScannerSPECTConv::GetGeometricInfoFromDatafile() -> Error while reading the global distance between the camera detectors to the center of rotation in the header data file " << endl);
01370       return 1;
01371     }
01372     else if (read_flag==2)
01373     {
01374       // Initialization with default values from the scanner file
01375       for(int hId=0 ; hId<m_nbHeads ; hId++)
01376         for(int a=0 ; a<m_nbOfProjections/m_nbHeads ; a++)
01377           mp_CORtoDetectorDistance[a+hId*m_nbOfProjections/m_nbHeads] = mp_radius[hId];
01378     }
01379   }
01380 
01381   delete[] angles;
01382   
01383   return 0;
01384 }
01385 
01386 
01387 
01388 
01389 // =====================================================================
01390 // ---------------------------------------------------------------------
01391 // ---------------------------------------------------------------------
01392 // =====================================================================
01393 /*
01394   \fn GetSPECTSpecificParameters
01395   \param ap_nbOfProjections : total number of views
01396   \param ap_nbHeads : number of heads in the system
01397   \param ap_nbOfBins : 2 elements array containing transaxial/axial number of pixels
01398   \param ap_pixSizeXY : 2 elements array containing transaxial/axial pixel sizes
01399   \param ap_angles : Array containing angles of each projection view
01400   \param ap_CORtoDetectorDistance : Radius (distance between FOV center and detector)
01401   \param ap_headRotDirection : head rotation direction
01402   \brief Set pointers passed in argument with the related SPECT specific variables
01403          This function is used to recover these values in the datafile object
01404   \return 0 if success, positive value otherwise
01405 */
01406 int iScannerSPECTConv::GetSPECTSpecificParameters(uint16_t* ap_nbOfProjections, 
01407                                                   uint16_t* ap_nbHeads, 
01408                                                   uint16_t* ap_nbOfBins,
01409                                                    FLTNB*  ap_pixSizeXY, 
01410                                                    FLTNB*& ap_angles, 
01411                                                    FLTNB*& ap_CORtoDetectorDistance,
01412                                                    int*    ap_headRotDirection)
01413 {
01414   if(m_verbose>=2) Cout("iScannerSPECTConv::GetSPECTSpecificParameters ..." << endl);
01415     
01416   // Verify that all parameters have been correctly checked
01417   if(m_allParametersChecked == false)
01418   {
01419     Cerr("***** iScannerSPECTConv::GetSPECTSpecificParameters() -> Parameters have not been checked !" << endl);
01420     return 1;
01421   }
01422 
01423   *ap_nbOfProjections = m_nbOfProjections;
01424   *ap_nbHeads = m_nbHeads;
01425   ap_nbOfBins[0] = mp_nbOfBins[0];
01426   ap_nbOfBins[1] = mp_nbOfBins[1];
01427   ap_pixSizeXY[0] = m_vPixelsSizeTrans;
01428   ap_pixSizeXY[1] = m_vPixelsSizeAxial;
01429   ap_angles = mp_projectionAngles;
01430   ap_CORtoDetectorDistance = mp_CORtoDetectorDistance;
01431   *ap_headRotDirection = m_rotDirection;
01432   
01433   return 0;
01434 }
01435 
01436 
01437 
01438 
01439 // =====================================================================
01440 // ---------------------------------------------------------------------
01441 // ---------------------------------------------------------------------
01442 // =====================================================================
01443 /*
01444   \fn PROJ_SetSPECTAngles
01445   \param ap_projectionAngles : an array containing the projection angles
01446   \brief Set the projection angles with the array provided in parameter
01447   \return 0 if success, positive value otherwise
01448 */
01449 int iScannerSPECTConv::PROJ_SetSPECTAngles(FLTNB* ap_projectionAngles)
01450 {
01451   if(m_verbose>=2) Cout("iScannerSPECTConv::PROJ_SetSPECTAngles ..." << endl);
01452 
01453   // Check initialization of the number of projections
01454   if(m_nbOfProjections <= 0)
01455   {
01456     Cerr("***** iScannerSPECTConv::PROJ_SetSPECTAngles -> Error number of projection should be >0 ! '" << endl);
01457     return 1;
01458   }
01459   else
01460   {
01461     mp_projectionAngles = new FLTNB[m_nbOfProjections];
01462     
01463     for(int a=0 ; a<m_nbOfProjections ; a++)
01464       mp_projectionAngles[a] = ap_projectionAngles[a];
01465   }  
01466   
01467   return 0;
01468 }
01469 
01470 
01471 
01472 // =====================================================================
01473 // ---------------------------------------------------------------------
01474 // ---------------------------------------------------------------------
01475 // =====================================================================
01476 /*
01477   \fn PROJ_SetSPECTCORtoDetectorDistance
01478   \param a_distance
01479   \brief Set distance between the center of rotation and SPECT detectors if arg value>0, 
01480          Set with the geometric information in the scanner configuration file otherwise
01481   \return 0 if success, positive value otherwise
01482 */
01483 int iScannerSPECTConv::PROJ_SetSPECTCORtoDetectorDistance(FLTNB a_distance)
01484 {
01485   if(m_verbose>=2) Cout("iScannerSPECTConv::PROJ_SetSPECTCORtoDetectorDistance ..." << endl);
01486   
01487   // Check initialization of the number of projections
01488   if(m_nbOfProjections <= 0)
01489   {
01490     Cerr("***** iScannerSPECTConv::PROJ_SetSPECTCORtoDetectorDistance -> Error number of projection should be >0 ! '" << endl);
01491     return 1;
01492   }
01493   else
01494   {
01495     mp_CORtoDetectorDistance = new FLTNB[m_nbOfProjections];
01496     
01497     if(a_distance>0)
01498     {
01499       // Set all radius to the provided distance
01500       for(int a=0 ; a<m_nbOfProjections ; a++)
01501         mp_CORtoDetectorDistance[a] = a_distance;
01502     }
01503     else
01504     {
01505       // Set all distance according to scanner geometric informations (default)
01506       for(int hId=0 ; hId<m_nbHeads ; hId++)
01507         for(int a=0 ; a<m_nbOfProjections/m_nbHeads ; a++)
01508           mp_CORtoDetectorDistance[a+hId*m_nbOfProjections/m_nbHeads] = mp_radius[hId];
01509     }
01510   }
01511   return 0;
01512 }
01513 
01514 
01515 
01516 
01517 // =====================================================================
01518 // ---------------------------------------------------------------------
01519 // ---------------------------------------------------------------------
01520 // =====================================================================
01521 /*
01522   \fn PROJ_GetSPECTNbBins
01523   \brief Get the number of SPECT heads in the pointer provided in parameter
01524   \return 0 by default (no error)
01525 */
01526 int iScannerSPECTConv::PROJ_GetSPECTNbBins(uint16_t* ap_nbOfBins) 
01527 {
01528   ap_nbOfBins = mp_nbOfBins;
01529   return 0;
01530 }
01531 
01532 
01533 
01534 // =====================================================================
01535 // ---------------------------------------------------------------------
01536 // ---------------------------------------------------------------------
01537 // =====================================================================
01538 /*
01539   \fn PROJ_SetSPECTNbBins
01540   \param ap_nbOfBins
01541   \brief Set number of bins
01542   \return 0 by default (no error)
01543 */
01544 int iScannerSPECTConv::PROJ_SetSPECTNbBins(uint16_t* ap_nbOfBins)
01545 {
01546   for(int i=0 ; i<2 ; i++)
01547     mp_nbOfBins[i]=ap_nbOfBins[i]; 
01548   return 0;
01549 }
01550 
01551 
01552 
01553 
01554 // =====================================================================
01555 // ---------------------------------------------------------------------
01556 // ---------------------------------------------------------------------
01557 // =====================================================================
01558 /*
01559   \fn PROJ_SetSPECTNbProjections
01560   \param a_nbOfProjections
01561   \brief Set number of projections
01562   \return 0 by default (no error)
01563 */
01564 int iScannerSPECTConv::PROJ_SetSPECTNbProjections(uint32_t a_nbOfProjections)
01565 {
01566   m_nbOfProjections = a_nbOfProjections; 
01567   return 0;
01568 }
01569 
01570 
01571 
01572 
01573 // =====================================================================
01574 // ---------------------------------------------------------------------
01575 // ---------------------------------------------------------------------
01576 // =====================================================================
01577 /*
01578   \fn PROJ_SetSPECTRotOrientation
01579   \param a_rotDirection
01580   \brief Set head rotation orientation
01581   \details This function is surcharged by the SPECT scanner daughter classes
01582            Returns an error by default.
01583   \return 1 (error) if not surcharged by a daughter class
01584 */
01585 int iScannerSPECTConv::PROJ_SetSPECTRotDirection( string a_rotDirection )
01586 {
01587   if(a_rotDirection == "CCW" ||
01588           a_rotDirection == "Ccw" ||
01589           a_rotDirection == "ccw" )
01590     m_rotDirection = GEO_ROT_CCW ;
01591     
01592   else if(a_rotDirection == ""   || // Default
01593           a_rotDirection == "CW" ||
01594           a_rotDirection == "Cw" ||
01595           a_rotDirection == "cw" )
01596     m_rotDirection = GEO_ROT_CW ;
01597     
01598   else
01599   {
01600     Cerr("***** iScannerSPECTConv::PROJ_SetSPECTRotDirection -> Error while initializing head rotation direction !" << endl);
01601     Cerr("     "<< a_rotDirection <<"' is unknown. Direction must be  'CW' (clockwise) or 'CCW' (counter-clockwise).");
01602     return 1;
01603   }
01604   
01605   return 0;
01606 }
01607 
01608 
01609     
01610     
01611 // =====================================================================
01612 // ---------------------------------------------------------------------
01613 // ---------------------------------------------------------------------
01614 // =====================================================================
01615 /*
01616   \fn ShowHelp
01617   \brief Display help
01618   \todo Provide informations about SPECT system initialization ?
01619 */
01620 void iScannerSPECTConv::ShowHelp()
01621 {
01622   if(m_verbose>=2) Cout("iScannerSPECTConv::ShowHelp ..." << endl);
01623   
01624   cout << "This scanner class is dedicated to the description of parallel, convergent and multi-convergent SPECT systems." << endl;
01625 }
 All Classes Files Functions Variables Typedefs Defines