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