]> Creatis software - gdcm.git/blob - src/gdcmHeaderHelper.cxx
doxygenation
[gdcm.git] / src / gdcmHeaderHelper.cxx
1 // gdcmHeaderHelper.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmHeaderHelper.h"
4 #include "gdcmDirList.h"
5
6 #include "gdcmUtil.h" //for debug
7 #include <math.h>
8 #include <algorithm>
9
10 /*#ifdef _MSC_VER 
11    #include <windows.h> 
12
13    int GetDir(std::string dPath, std::list<std::string> &filenames)
14    {
15      //For now dPath should have an ending "\"
16      WIN32_FIND_DATA FileData; 
17      HANDLE hFile; 
18      hFile = FindFirstFile((dPath+"*").c_str(), &FileData); 
19      if ( hFile == INVALID_HANDLE_VALUE ) 
20      { 
21        //No files !
22        return false; 
23      } 
24   
25      if( strncmp(FileData.cFileName, ".", 1) != 0 )
26        filenames.push_back( dPath+FileData.cFileName );
27      while( FindNextFile(hFile, &FileData ) != 0)
28      { 
29        if( strncmp(FileData.cFileName, ".", 1) != 0 )
30          filenames.push_back( dPath+FileData.cFileName );
31      }
32      return true;
33    }
34
35 #else
36    #include <dirent.h>
37
38    int GetDir(std::string dPath, std::list<std::string> &filenames)
39    {
40     DIR *dir = opendir( dPath.c_str() );
41     if (dir == NULL)
42        return false;
43     struct dirent *entry;
44     while((entry = readdir(dir)) != NULL)
45     {
46    //   if( strncmp(entry->d_name, ".", 1) != 0 && strncmp(entry->d_name, "..", 2) != 0)
47       if( strncmp(entry->d_name, ".", 1) != 0 )
48       {
49          filenames.push_back( dPath + "/" + entry->d_name );
50       }
51     }
52     closedir(dir);
53     return true;
54    }
55
56 #endif*/
57
58 //-----------------------------------------------------------------------------
59 // gdcmHeaderHelper
60 //-----------------------------------------------------------------------------
61 // Constructor / Destructor
62 /**
63  * \ingroup gdcmHeaderHelper
64  * \brief   constructor
65  */
66 gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( ) {
67
68 }
69
70 /**
71  * \ingroup gdcmHeaderHelper
72  * \brief   constructor
73  * @param   InFilename Name of the file to deal with
74  * @param   exception_on_error
75  * @param   enable_sequences = true to allow the header 
76  *          to be parsed *inside* the SeQuences, 
77  *          when they have an actual length 
78  * @param   ignore_shadow = true if user wants to skip shadow groups 
79  *           during parsing, to save memory space         
80  */
81 gdcmHeaderHelper::gdcmHeaderHelper(const char *InFilename, 
82                                    bool exception_on_error,
83                                    bool enable_sequences,
84                                    bool ignore_shadow)                             
85                  : gdcmHeader( InFilename, 
86                                exception_on_error,
87                                enable_sequences,
88                                ignore_shadow)
89 {
90 }
91
92 //-----------------------------------------------------------------------------
93 // Print
94
95 //-----------------------------------------------------------------------------
96 // Public
97 /**
98  * \ingroup gdcmHeaderHelper
99  * \brief   Returns the size (in bytes) of a single pixel of data.
100  * @return  The size in bytes of a single pixel of data.
101  *
102  */
103 int gdcmHeaderHelper::GetPixelSize() {
104
105      // 0028 0100 US IMG Bits Allocated
106      // (in order no to be messed up by old RGB images)
107    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
108       return 3;
109          
110    std::string PixelType = GetPixelType();
111    if (PixelType == "8U"  || PixelType == "8S")
112       return 1;
113    if (PixelType == "16U" || PixelType == "16S")
114       return 2;
115    if (PixelType == "32U" || PixelType == "32S")
116       return 4;
117    if (PixelType == "FD") // to help unfortunate users to manage DOUBLE
118       return 8;
119    dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
120    return 0;
121 }
122
123 /**
124  * \ingroup gdcmHeaderHelper
125  * \brief   Build the Pixel Type of the image.
126  *          Possible values are:
127  *          - 8U  unsigned  8 bit,
128  *          - 8S    signed  8 bit,
129  *          - 16U unsigned 16 bit,
130  *          - 16S   signed 16 bit,
131  *          - 32U unsigned 32 bit,
132  *          - 32S   signed 32 bit,
133  *          - FD    Double,
134  * \warning 12 bit images appear as 16 bit.
135  *          24 bit images appear as 8 bit
136  *          64 bit means 'DOUBLE' images 
137  *                 (no DOUBLE images in kosher DICOM,
138  *                  but so usefull for people that miss them ;-)
139  * @return  
140  */
141 std::string gdcmHeaderHelper::GetPixelType() {
142    std::string BitsAlloc;
143    BitsAlloc = GetEntryByNumber(0x0028, 0x0100);
144    if (BitsAlloc == GDCM_UNFOUND) { // Bits Allocated
145       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
146       BitsAlloc = std::string("16");
147    }
148    if (BitsAlloc == "12")           // It will be unpacked
149       BitsAlloc = std::string("16");
150    else if (BitsAlloc == "24")      // (in order no to be messed up
151       BitsAlloc = std::string("8"); // by old RGB images)
152     
153    std::string Signed;
154    Signed = GetEntryByNumber(0x0028, 0x0103);
155    if (Signed == GDCM_UNFOUND) { // "Pixel Representation"
156       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
157       BitsAlloc = std::string("0");
158    }
159    if (BitsAlloc == "64") // to help users that want to deal with DOUBLE
160       return("FD");
161       
162    if (Signed == "0")
163       Signed = std::string("U");
164    else
165       Signed = std::string("S");
166
167    return( BitsAlloc + Signed);
168 }
169
170 /**
171   * \ingroup gdcmHeaderHelper
172   * \brief gets the info from 0028,0030 : Pixel Spacing
173   * \           else 1.
174   * @return X dimension of a pixel
175   */
176 float gdcmHeaderHelper::GetXSpacing() {
177     float xspacing, yspacing;
178     std::string StrSpacing = GetEntryByNumber(0x0028,0x0030);
179     
180    if (StrSpacing == GDCM_UNFOUND) {
181       dbg.Verbose(0, "gdcmHeader::GetXSpacing: unfound Pixel Spacing (0028,0030)");
182       return 1.;
183     }
184   if( sscanf( StrSpacing.c_str(), "%f\\%f", &yspacing, &xspacing) != 2)
185     return 0.;
186   if (xspacing == 0.) {
187     dbg.Verbose(0, "gdcmHeader::GetYSpacing: gdcmData/CT-MONO2-8-abdo.dcm problem");
188     // seems to be a bug in the header ...
189     sscanf( StrSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing);
190   }
191   return xspacing;
192 }
193
194 /**
195   * \ingroup gdcmHeaderHelper
196   * \brief gets the info from 0028,0030 : Pixel Spacing
197   * \           else 1.
198   * @return Y dimension of a pixel
199   */
200 float gdcmHeaderHelper::GetYSpacing() {
201    float xspacing, yspacing;
202    std::string StrSpacing = GetEntryByNumber(0x0028,0x0030);
203   
204    if (StrSpacing == GDCM_UNFOUND) {
205       dbg.Verbose(0, "gdcmHeader::GetYSpacing: unfound Pixel Spacing (0028,0030)");
206       return 1.;
207     }
208   if( sscanf( StrSpacing.c_str(), "%f\\%f", &yspacing, &xspacing) != 2)
209     return 0.;
210   if (xspacing == 0.) {
211     dbg.Verbose(0, "gdcmHeader::GetYSpacing: gdcmData/CT-MONO2-8-abdo.dcm problem");
212     // seems to be a bug in the header ...
213     sscanf( StrSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing);
214   }
215   return yspacing;
216
217
218 /**
219   *\ingroup gdcmHeaderHelper
220   *\brief gets the info from 0018,0088 : Space Between Slices
221   *\               else from 0018,0050 : Slice Thickness
222   *\               else 1.
223   * @return Z dimension of a voxel-to be
224   */
225 float gdcmHeaderHelper::GetZSpacing() {
226    // Spacing Between Slices : distance entre le milieu de chaque coupe
227    // Les coupes peuvent etre :
228    //   jointives     (Spacing between Slices = Slice Thickness)
229    //   chevauchantes (Spacing between Slices < Slice Thickness)
230    //   disjointes    (Spacing between Slices > Slice Thickness)
231    // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
232    //   ca interesse le physicien de l'IRM, pas le visualisateur de volumes ...
233    //   Si le Spacing Between Slices est absent, 
234    //   on suppose que les coupes sont jointives
235    
236    std::string StrSpacingBSlices = GetEntryByNumber(0x0018,0x0088);
237
238    if (StrSpacingBSlices == GDCM_UNFOUND) {
239       dbg.Verbose(0, "gdcmHeader::GetZSpacing: unfound StrSpacingBSlices");
240       std::string StrSliceThickness = GetEntryByNumber(0x0018,0x0050);       
241       if (StrSliceThickness == GDCM_UNFOUND)
242          return 1.;
243       else
244          // if no 'Spacing Between Slices' is found, 
245          // we assume slices join together
246          // (no overlapping, no interslice gap)
247          // if they don't, we're fucked up
248          return atof(StrSliceThickness.c_str());  
249    } else {
250       return atof(StrSpacingBSlices.c_str());
251    }
252 }
253
254 /**
255   *\ingroup gdcmHeaderHelper
256   *\brief gets the info from 0028,1052 : Rescale Intercept
257   * @return Rescale Intercept
258  */
259 float gdcmHeaderHelper::GetRescaleIntercept() {
260   float resInter = 0.;
261   std::string StrRescInter = GetEntryByNumber(0x0028,0x1052); //0028 1052 DS IMG Rescale Intercept
262   if (StrRescInter != GDCM_UNFOUND) {
263       if( sscanf( StrRescInter.c_str(), "%f", &resInter) != 1) {
264          dbg.Verbose(0, "gdcmHeader::GetRescaleIntercept: Rescale Slope is empty");
265            // bug in the element 0x0028,0x1052
266       }    
267    }
268   return resInter;
269 }
270
271 /**
272   *\ingroup gdcmHeaderHelper
273   *\brief gets the info from 0028,1053 : Rescale Slope
274   * @return Rescale Slope
275  */
276  float gdcmHeaderHelper::GetRescaleSlope() {
277   float resSlope = 1.;
278   std::string StrRescSlope = GetEntryByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope
279   if (StrRescSlope != GDCM_UNFOUND) {
280       if( sscanf( StrRescSlope.c_str(), "%f", &resSlope) != 1) {
281          dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty");
282            // bug in the element 0x0028,0x1053
283       }    
284    }  
285    return resSlope;
286 }
287
288 /**
289   * \ingroup gdcmHeaderHelper
290   * \brief This function is intended to user who doesn't want 
291   * \ to have to manage a LUT and expects to get an RBG Pixel image
292   * \ (or a monochrome one ...) 
293   * \warning to be used with GetImagePixels()
294   * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR)
295   */
296 int gdcmHeaderHelper::GetNumberOfScalarComponents() {
297    if (GetSamplesPerPixel() ==3)
298       return 3;
299       
300      // 0028 0100 US IMG Bits Allocated
301      // (in order no to be messed up by old RGB images)
302    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
303       return 3;
304        
305    std::string PhotometricInterpretation = 
306                   gdcmHeader::GetEntryByNumber(0x0028,0x0004);
307
308    if ( ( PhotometricInterpretation == "PALETTE COLOR ") ) {
309       if (HasLUT())   // PALETTE COLOR is NOT enough
310          return 3;
311       else
312          return 1;       
313    }   
314                   
315       //beware of trailing space at end of string                                               
316    if (PhotometricInterpretation.find(GDCM_UNFOUND) < 
317                            PhotometricInterpretation.length() || 
318        PhotometricInterpretation.find("MONOCHROME1") < 
319                            PhotometricInterpretation.length() || 
320        PhotometricInterpretation.find("MONOCHROME2") < 
321                            PhotometricInterpretation.length() ) 
322        return 1;
323     else
324     // we assume that *all* kinds of YBR are dealt with
325       return 3;
326 }
327
328 /**
329   * \ingroup gdcmHeaderHelper
330   * \brief This function is intended to user that DOESN'T want 
331   * \to get RGB pixels image when it's stored as a PALETTE COLOR image
332   * \ - the (vtk) user is supposed to know how deal with LUTs - 
333   * \warning to be used with GetImagePixelsRaw()
334   * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -)
335   */
336 int gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() {
337       
338      // 0028 0100 US IMG Bits Allocated
339      // (in order no to be messed up by old RGB images)
340    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
341       return 3;
342
343     // we assume that *all* kinds of YBR are dealt with
344       return GetSamplesPerPixel();
345 }
346
347 /**
348   *\ingroup gdcmHeaderHelper
349   *\brief gets the info from 0020,000d : Study Instance UID
350   *\todo ? : return the ACR-NEMA element value if DICOM one is not found 
351   * @return Study Instance UID
352  */
353  std::string gdcmHeaderHelper::GetStudyUID(){
354   return GetEntryByNumber(0x0020,0x000d); //0020 000d UI REL Study Instance UID
355 }
356
357 /**
358   *\ingroup gdcmHeaderHelper
359   *\brief gets the info from 0020,000e : Series Instance UID
360   *\todo ? : return the ACR-NEMA element value if DICOM one is not found 
361   * @return Series Instance UID
362  */
363  std::string gdcmHeaderHelper::GetSeriesUID(){
364   return GetEntryByNumber(0x0020,0x000e); //0020 000e UI REL Series Instance UID
365 }
366
367 /**
368   *\ingroup gdcmHeaderHelper
369   *\brief gets the info from 0008,0016 : SOP Class UID
370   *\todo ? : return the ACR-NEMA element value if DICOM one is not found 
371   * @return SOP Class UID
372  */
373  std::string gdcmHeaderHelper::GetClassUID(){
374   return GetEntryByNumber(0x0008,0x0016); //0008 0016 UI ID SOP Class UID
375 }
376
377 /**
378   *\ingroup gdcmHeaderHelper
379   *\brief gets the info from 0008,0018 : SOP Instance UID
380   *\todo ? : return the ACR-NEMA element value if DICOM one is not found 
381   * @return SOP Instance UID
382  */
383  std::string gdcmHeaderHelper::GetInstanceUID(){
384   return GetEntryByNumber(0x0008,0x0018); //0008 0018 UI ID SOP Instance UID
385 }
386 //
387 // --------------  Remember ! ----------------------------------
388 //
389 // Image Position Patient                              (0020,0032):
390 // If not found (ACR_NEMA) we try Image Position       (0020,0030)
391 // If not found (ACR-NEMA), we consider Slice Location (0020,1041)
392 //                                   or Location       (0020,0050) 
393 // as the Z coordinate, 
394 // 0. for all the coordinates if nothing is found
395
396 // TODO : find a way to inform the caller nothing was found
397 // TODO : How to tell the caller a wrong number of values was found?
398 //
399 // ---------------------------------------------------------------
400 //
401
402 /**
403   * \ingroup gdcmHeaderHelper
404   * \brief gets the info from 0020,0032 : Image Position Patient
405   *\                else from 0020,0030 : Image Position (RET)
406   *\                else 0.
407   * @return up-left image corner X position
408   */
409     
410 float gdcmHeaderHelper::GetXOrigin() {
411     float xImPos, yImPos, zImPos;  
412     std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
413
414     if (StrImPos == GDCM_UNFOUND) {
415        dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position Patient (0020,0032)");
416        StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
417        if (StrImPos == GDCM_UNFOUND) {
418           dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position (RET) (0020,0030)");
419           // How to tell the caller nothing was found ?
420          return 0.;
421        }  
422      }
423    if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
424      return 0.;
425    return xImPos;
426 }
427
428 /**
429   * \ingroup gdcmHeaderHelper
430   * \brief gets the info from 0020,0032 : Image Position Patient
431   * \               else from 0020,0030 : Image Position (RET)
432   * \               else 0.
433   * @return up-left image corner Y position
434   */
435 float gdcmHeaderHelper::GetYOrigin() {
436     float xImPos, yImPos, zImPos;
437     std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
438
439     if (StrImPos == GDCM_UNFOUND) {
440        dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position Patient (0020,0032)");
441        StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
442        if (StrImPos == GDCM_UNFOUND) {
443           dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position (RET) (0020,0030)");
444           // How to tell the caller nothing was found ?
445            return 0.;
446        }  
447      }
448    if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
449      return 0.;
450    return yImPos;
451 }
452
453 /**
454   * \ingroup gdcmHeaderHelper
455   * \brief gets the info from 0020,0032 : Image Position Patient
456   * \               else from 0020,0030 : Image Position (RET)
457   * \               else from 0020,1041 : Slice Location
458   * \               else from 0020,0050 : Location
459   * \               else 0.
460   * @return up-left image corner Z position
461   */
462 float gdcmHeaderHelper::GetZOrigin() {
463    float xImPos, yImPos, zImPos; 
464    std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
465    if (StrImPos != GDCM_UNFOUND) {
466       if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) {
467          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position Patient (0020,0032)");
468          return 0.;  // bug in the element 0x0020,0x0032
469       } else {
470          return zImPos;
471       }    
472    }  
473    StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
474    if (StrImPos != GDCM_UNFOUND) {
475       if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) {
476          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position (RET) (0020,0030)");
477          return 0.;  // bug in the element 0x0020,0x0032
478       } else {
479          return zImPos;
480       }    
481    }                
482    std::string StrSliceLocation = GetEntryByNumber(0x0020,0x1041);// for *very* old ACR-NEMA images
483    if (StrSliceLocation != GDCM_UNFOUND) {
484       if( sscanf( StrSliceLocation.c_str(), "%f", &zImPos) !=1) {
485          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Slice Location (0020,1041)");
486          return 0.;  // bug in the element 0x0020,0x1041
487       } else {
488          return zImPos;
489       }
490    }   
491    dbg.Verbose(0, "gdcmHeader::GetZImagePosition: unfound Slice Location (0020,1041)");
492    std::string StrLocation = GetEntryByNumber(0x0020,0x0050);
493    if (StrLocation != GDCM_UNFOUND) {
494       if( sscanf( StrLocation.c_str(), "%f", &zImPos) !=1) {
495          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Location (0020,0050)");
496          return 0.;  // bug in the element 0x0020,0x0050
497       } else {
498          return zImPos;
499       }
500    }
501    dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)");  
502    return 0.; // Hopeless
503 }
504
505 /**
506   * \ingroup gdcmHeaderHelper
507   * \brief gets the info from 0020,0013 : Image Number
508   * \               else 0.
509   * @return image number
510   */
511 int gdcmHeaderHelper::GetImageNumber() {
512   //The function i atoi() takes the address of an area of memory as parameter and converts 
513   //the string stored at that location to an integer using the external decimal to internal
514   //binary conversion rules. This may be preferable to sscanf() since atoi() is a much smaller,
515   // simpler and faster function. sscanf() can do all possible conversions whereas atoi() can 
516   //only do single decimal integer conversions.
517   std::string StrImNumber = GetEntryByNumber(0x0020,0x0013); //0020 0013 IS REL Image Number
518   if (StrImNumber != GDCM_UNFOUND) {
519     return atoi( StrImNumber.c_str() );
520   }
521   return 0;   //Hopeless
522 }
523
524 /**
525   * \ingroup gdcmHeaderHelper
526   * \brief gets the info from 0008,0060 : Modality
527   * @return Modality Type
528   */
529 ModalityType gdcmHeaderHelper::GetModality(void) {
530   std::string StrModality = GetEntryByNumber(0x0008,0x0060); //0008 0060 CS ID Modality
531   if (StrModality != GDCM_UNFOUND) {
532          if ( StrModality.find("AU") < StrModality.length()) return AU;
533     else if ( StrModality.find("AS") < StrModality.length()) return AS;
534     else if ( StrModality.find("BI") < StrModality.length()) return BI;
535     else if ( StrModality.find("CF") < StrModality.length()) return CF;
536     else if ( StrModality.find("CP") < StrModality.length()) return CP;
537     else if ( StrModality.find("CR") < StrModality.length()) return CR;
538     else if ( StrModality.find("CT") < StrModality.length()) return CT;
539     else if ( StrModality.find("CS") < StrModality.length()) return CS;
540     else if ( StrModality.find("DD") < StrModality.length()) return DD;
541     else if ( StrModality.find("DF") < StrModality.length()) return DF;
542     else if ( StrModality.find("DG") < StrModality.length()) return DG;
543     else if ( StrModality.find("DM") < StrModality.length()) return DM;
544     else if ( StrModality.find("DS") < StrModality.length()) return DS;
545     else if ( StrModality.find("DX") < StrModality.length()) return DX;
546     else if ( StrModality.find("ECG") < StrModality.length()) return ECG;
547     else if ( StrModality.find("EPS") < StrModality.length()) return EPS;
548     else if ( StrModality.find("FA") < StrModality.length()) return FA;
549     else if ( StrModality.find("FS") < StrModality.length()) return FS;
550     else if ( StrModality.find("HC") < StrModality.length()) return HC;
551     else if ( StrModality.find("HD") < StrModality.length()) return HD;
552     else if ( StrModality.find("LP") < StrModality.length()) return LP;
553     else if ( StrModality.find("LS") < StrModality.length()) return LS;
554     else if ( StrModality.find("MA") < StrModality.length()) return MA;
555     else if ( StrModality.find("MR") < StrModality.length()) return MR;
556     else if ( StrModality.find("NM") < StrModality.length()) return NM;
557     else if ( StrModality.find("OT") < StrModality.length()) return OT;
558     else if ( StrModality.find("PT") < StrModality.length()) return PT;
559     else if ( StrModality.find("RF") < StrModality.length()) return RF;
560     else if ( StrModality.find("RG") < StrModality.length()) return RG;
561     else if ( StrModality.find("RTDOSE")  < StrModality.length()) return RTDOSE;
562     else if ( StrModality.find("RTIMAGE") < StrModality.length()) return RTIMAGE;
563     else if ( StrModality.find("RTPLAN")  < StrModality.length()) return RTPLAN;
564     else if ( StrModality.find("RTSTRUCT")< StrModality.length()) return RTSTRUCT;
565     else if ( StrModality.find("SM") < StrModality.length()) return SM;
566     else if ( StrModality.find("ST") < StrModality.length()) return ST;
567     else if ( StrModality.find("TG") < StrModality.length()) return TG;
568     else if ( StrModality.find("US") < StrModality.length()) return US;
569     else if ( StrModality.find("VF") < StrModality.length()) return VF;
570     else if ( StrModality.find("XA") < StrModality.length()) return XA;
571     else if ( StrModality.find("XC") < StrModality.length()) return XC;
572
573     else
574     {
575       //throw error return value ???
576       // specified <> unknow in our database
577       return Unknow;
578     }
579   }
580   return Unknow;
581 }
582
583 /**
584   * \ingroup gdcmHeaderHelper
585   * \brief gets the info from 0020,0037 : Image Orientation Patient
586   * @param iop adress of the (6)float aray to receive values
587   * @return cosines of image orientation patient
588   */
589 void gdcmHeaderHelper::GetImageOrientationPatient( float* iop ) {
590
591   //iop is supposed to be float[6]
592   iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0;
593   
594   std::string StrImOriPat = GetEntryByNumber(0x0020,0x0037); // 0020 0037 DS REL Image Orientation (Patient)
595   if (StrImOriPat != GDCM_UNFOUND) {
596     if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", 
597             &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) {
598          dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0037)");
599          return ;  // bug in the element 0x0020,0x0037
600     } 
601     else
602       return ;
603   }
604   
605   //For ACR-NEMA
606   StrImOriPat = GetEntryByNumber(0x0020,0x0035); //0020 0035 DS REL Image Orientation (RET)
607   if (StrImOriPat != GDCM_UNFOUND) {
608     if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", 
609             &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) {
610          dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0035)");
611          return ;  // bug in the element 0x0020,0x0035
612     } 
613     else
614       return ;
615   }
616 }
617
618 //-----------------------------------------------------------------------------
619 // Protected
620
621 //-----------------------------------------------------------------------------
622 // Private
623
624 //-----------------------------------------------------------------------------
625
626
627
628 //-----------------------------------------------------------------------------
629 // gdcmSerieHeaderHelper
630 //-----------------------------------------------------------------------------
631 // Constructor / Destructor
632 gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper(){
633   //! \todo
634   for (std::list<gdcmHeaderHelper*>::iterator it  = CoherentGdcmFileList.begin();
635         it != CoherentGdcmFileList.end(); it++)
636   {
637     delete *it;
638   }
639   CoherentGdcmFileList.clear();
640 }
641
642 //-----------------------------------------------------------------------------
643 // Print
644
645 //-----------------------------------------------------------------------------
646 // Public
647 /**
648  * \ingroup gdcmHeaderHelper
649  * \brief add a gdcmFile to the list based on file name
650  * @param   filename Name of the file to deal with
651  */
652 void gdcmSerieHeaderHelper::AddFileName(std::string filename) {
653   gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() );
654   this->CoherentGdcmFileList.push_back( GdcmFile );
655 }
656
657 /**
658  * \ingroup gdcmHeaderHelper
659  * \brief add a gdcmFile to the list
660  * @param   file gdcmHeaderHelper to add
661  */
662 void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file){
663   this->CoherentGdcmFileList.push_back( file );
664 }
665
666 /**
667  * \ingroup gdcmHeaderHelper
668  * \brief Sets the Directory
669  * @param   dir Name of the directory to deal with
670  */
671 void gdcmSerieHeaderHelper::SetDirectory(std::string dir){
672   gdcmDirList filenames_list(dir);  //OS specific
673   
674   for(gdcmDirList::iterator it = filenames_list.begin(); 
675       it !=filenames_list.end(); it++)
676   {
677     gdcmHeaderHelper *file = new gdcmHeaderHelper( it->c_str() );
678     this->CoherentGdcmFileList.push_back( file );
679   }
680 }
681
682 /**
683  * \ingroup gdcmHeaderHelper
684  * \brief Sorts the File List
685  * \warning This could be implemented in a 'Strategy Pattern' approach
686  *          But as I don't know how to do it, I leave it this way
687  *          BTW, this is also a Strategy, I don't know this is the best approach :)
688 */
689 void gdcmSerieHeaderHelper::OrderGdcmFileList(){
690   if( ImagePositionPatientOrdering() ) {
691     return ;
692   }
693   else if( ImageNumberOrdering() ) {
694     return ;
695   } else  {
696     FileNameOrdering();
697   }
698 }
699
700 /**
701  * \ingroup gdcmHeaderHelper
702  * \brief Gets the *coherent* File List
703  * @return the *coherent* File List
704 */
705 std::list<gdcmHeaderHelper*> &gdcmSerieHeaderHelper::GetGdcmFileList() {
706   return CoherentGdcmFileList;
707 }
708
709 //-----------------------------------------------------------------------------
710 // Protected
711
712 //-----------------------------------------------------------------------------
713 // Private
714 /**
715  * \ingroup gdcmHeaderHelper
716  * \brief sorts the images, according to their Patient Position
717  *  We may order, considering :
718  *   -# Image Number
719  *   -# Image Position Patient
720  *   -# More to come :)
721  * @return false only if the header is bugged !
722  */
723 bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering()
724 //based on Jolinda's algorithm
725 {
726   //iop is calculated based on the file file
727   float *cosines = new float[6];
728   float normal[3];
729   float ipp[3];
730   float dist;
731   float min, max;
732   bool first = true;
733   int n=0;
734   std::vector<float> distlist;
735
736   //!\todo rewrite this for loop.
737   for (std::list<gdcmHeaderHelper*>::iterator it  = CoherentGdcmFileList.begin();
738         it != CoherentGdcmFileList.end(); it++)
739   {
740     if(first) {
741       (*it)->GetImageOrientationPatient(cosines);
742       
743       //You only have to do this once for all slices in the volume. Next, for
744       //each slice, calculate the distance along the slice normal using the IPP
745       //tag ("dist" is initialized to zero before reading the first slice) :
746       normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
747       normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
748       normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
749   
750       ipp[0] = (*it)->GetXOrigin();
751       ipp[1] = (*it)->GetYOrigin();
752       ipp[2] = (*it)->GetZOrigin();
753
754       dist = 0;
755       for (int i = 0; i < 3; ++i)
756           dist += normal[i]*ipp[i];
757     
758       if( dist == 0 )
759       {
760         delete[] cosines;
761         return false;
762       }
763
764       distlist.push_back( dist );
765
766       max = min = dist;
767       first = false;
768     }
769     else {
770       ipp[0] = (*it)->GetXOrigin();
771       ipp[1] = (*it)->GetYOrigin();
772       ipp[2] = (*it)->GetZOrigin();
773   
774       dist = 0;
775       for (int i = 0; i < 3; ++i)
776           dist += normal[i]*ipp[i];
777
778       if( dist == 0 )
779       {
780         delete[] cosines;
781         return false;
782       }
783       
784       distlist.push_back( dist );
785
786       min = (min < dist) ? min : dist;
787       max = (max > dist) ? max : dist;
788     }
789     n++;
790   }
791
792     //Then I order the slices according to the value "dist". Finally, once
793     //I've read in all the slices, I calculate the z-spacing as the difference
794     //between the "dist" values for the first two slices.
795     std::vector<gdcmHeaderHelper*> CoherentGdcmFileVector(n);
796     //CoherentGdcmFileVector.reserve( n );
797     CoherentGdcmFileVector.resize( n );
798     //assert( CoherentGdcmFileVector.capacity() >= n );
799
800     float step = (max - min)/(n - 1);
801     int pos;
802     n = 0;
803     
804     //VC++ don't understand what scope is !! it -> it2
805     for (std::list<gdcmHeaderHelper*>::iterator it2  = CoherentGdcmFileList.begin();
806         it2 != CoherentGdcmFileList.end(); it2++, n++)
807     {
808       //2*n sort algo !!
809       //Assumption: all files are present (no one missing)
810       pos = (int)( fabs( (distlist[n]-min)/step) + .5 );
811             
812       CoherentGdcmFileVector[pos] = *it2;
813     }
814
815   CoherentGdcmFileList.clear();  //this doesn't delete list's element, node only
816   
817   //VC++ don't understand what scope is !! it -> it3
818   for (std::vector<gdcmHeaderHelper*>::iterator it3  = CoherentGdcmFileVector.begin();
819         it3 != CoherentGdcmFileVector.end(); it3++)
820   {
821     CoherentGdcmFileList.push_back( *it3 );
822   }
823
824   distlist.clear();
825   CoherentGdcmFileVector.clear();
826   delete[] cosines;
827   
828   return true;
829 }
830
831 /**
832  * \ingroup gdcmHeaderHelper
833  * \brief sorts the images, according to their Image Number
834  * @return false only if the header is bugged !
835  */
836
837 bool gdcmSerieHeaderHelper::ImageNumberOrdering() {
838   int min, max, pos;
839   int n = 0;//CoherentGdcmFileList.size(); //O(N) operation !!
840   unsigned char *partition;
841   
842   std::list<gdcmHeaderHelper*>::iterator it  = CoherentGdcmFileList.begin();
843   min = max = (*it)->GetImageNumber();
844
845   for (; it != CoherentGdcmFileList.end(); it++, n++)
846   {
847     pos = (*it)->GetImageNumber();
848
849     //else
850     min = (min < pos) ? min : pos;
851   }
852
853   //bzeros(partition, n); //Cette fonction est déconseillée, utilisez plutôt memset.
854   partition = new unsigned char[n];
855   memset(partition, 0, n);
856
857   std::vector<gdcmHeaderHelper*> CoherentGdcmFileVector(n);
858
859   //VC++ don't understand what scope is !! it -> it2
860   for (std::list<gdcmHeaderHelper*>::iterator it2  = CoherentGdcmFileList.begin();
861         it2 != CoherentGdcmFileList.end(); it2++)
862   {
863     pos = (*it2)->GetImageNumber();
864     CoherentGdcmFileVector[pos - min] = *it2;
865     partition[pos - min]++;
866   }
867   
868   unsigned char mult = 1;
869   for(int i=0; i<n ; i++)
870   {
871     mult *= partition[i];
872   }
873
874   //VC++ don't understand what scope is !! it -> it3
875   CoherentGdcmFileList.clear();  //this doesn't delete list's element, node only
876   for (std::vector<gdcmHeaderHelper*>::iterator it3  = CoherentGdcmFileVector.begin();
877         it3 != CoherentGdcmFileVector.end(); it3++)
878   {
879     CoherentGdcmFileList.push_back( *it3 );
880   }
881   CoherentGdcmFileVector.clear();
882   
883   delete[] partition;
884   return (mult!=0);
885 }
886
887
888 /**
889  * \ingroup gdcmHeaderHelper
890  * \brief sorts the images, according to their File Name
891  * @return false only if the header is bugged !
892  */
893  bool gdcmSerieHeaderHelper::FileNameOrdering() {
894   //using the sort
895   //sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end());
896   return true;
897 }
898
899 //-----------------------------------------------------------------------------