]> Creatis software - gdcm.git/blob - src/gdcmHeaderHelper.cxx
27aafc3de3e535e5950b2220673feed9b7fff60f
[gdcm.git] / src / gdcmHeaderHelper.cxx
1 // gdcmHeaderHelper.cxx
2 //-----------------------------------------------------------------------------
3 #include "gdcmHeaderHelper.h"
4
5 #include "gdcmUtil.h" //for debug
6 #include <math.h>
7 #include <algorithm>
8
9 #ifdef _MSC_VER 
10    #include <windows.h> 
11
12    int GetDir(std::string dPath, std::list<std::string> &filenames)
13    {
14      //For now dPath should have an ending "\"
15      WIN32_FIND_DATA FileData; 
16      HANDLE hFile; 
17      hFile = FindFirstFile((dPath+"*").c_str(), &FileData); 
18      if ( hFile == INVALID_HANDLE_VALUE ) 
19      { 
20        //No files !
21        return false; 
22      } 
23   
24      if( strncmp(FileData.cFileName, ".", 1) != 0 )
25        filenames.push_back( dPath+FileData.cFileName );
26      while( FindNextFile(hFile, &FileData ) != 0)
27      { 
28        if( strncmp(FileData.cFileName, ".", 1) != 0 )
29          filenames.push_back( dPath+FileData.cFileName );
30      }
31      return true;
32    }
33
34 #else
35    #include <dirent.h>
36
37    int GetDir(std::string dPath, std::list<std::string> &filenames)
38    {
39     DIR *dir = opendir( dPath.c_str() );
40     if (dir == NULL)
41        return false;
42     struct dirent *entry;
43     while((entry = readdir(dir)) != NULL)
44     {
45    //   if( strncmp(entry->d_name, ".", 1) != 0 && strncmp(entry->d_name, "..", 2) != 0)
46       if( strncmp(entry->d_name, ".", 1) != 0 )
47       {
48          filenames.push_back( dPath + "/" + entry->d_name );
49       }
50     }
51     closedir(dir);
52     return true;
53    }
54
55 #endif
56
57 //-----------------------------------------------------------------------------
58 // gdcmHeaderHelper
59 //-----------------------------------------------------------------------------
60 // Constructor / Destructor
61 /**
62  * \ingroup gdcmHeaderHelper
63  * \brief   cstor
64  */
65 gdcmHeaderHelper::gdcmHeaderHelper() : gdcmHeader( ) {
66
67 }
68
69 /**
70  * \ingroup gdcmHeaderHelper
71  * \brief   cstor
72  */
73 gdcmHeaderHelper::gdcmHeaderHelper(const char *InFilename, 
74                                    bool exception_on_error,
75                                    bool enable_sequences,
76                                    bool ignore_shadow)                             
77                  : gdcmHeader( InFilename, 
78                                exception_on_error,
79                                enable_sequences,
80                                ignore_shadow)
81 {
82 }
83
84 //-----------------------------------------------------------------------------
85 // Print
86
87 //-----------------------------------------------------------------------------
88 // Public
89 /**
90  * \ingroup gdcmHeaderHelper
91  * \brief   Return the size (in bytes) of a single pixel of data.
92  * @return  The size in bytes of a single pixel of data.
93  *
94  */
95 int gdcmHeaderHelper::GetPixelSize() {
96
97      // 0028 0100 US IMG Bits Allocated
98      // (in order no to be messed up by old RGB images)
99    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
100       return 3;
101          
102    std::string PixelType = GetPixelType();
103    if (PixelType == "8U"  || PixelType == "8S")
104       return 1;
105    if (PixelType == "16U" || PixelType == "16S")
106       return 2;
107    if (PixelType == "32U" || PixelType == "32S")
108       return 4;
109    if (PixelType == "FD") // to help unfortunate users to manage DOUBLE
110       return 8;
111    dbg.Verbose(0, "gdcmHeader::GetPixelSize: Unknown pixel type");
112    return 0;
113 }
114
115 /**
116  * \ingroup gdcmHeaderHelper
117  * \brief   Build the Pixel Type of the image.
118  *          Possible values are:
119  *          - 8U  unsigned  8 bit,
120  *          - 8S    signed  8 bit,
121  *          - 16U unsigned 16 bit,
122  *          - 16S   signed 16 bit,
123  *          - 32U unsigned 32 bit,
124  *          - 32S   signed 32 bit,
125  *          - FD    Double,
126  * \warning 12 bit images appear as 16 bit.
127  * \        24 bit images appear as 8 bit
128  * \        64 bit means 'DOUBLE' images 
129  * \               (no DOUBLE images in kosher DICOM,
130  * \                but so usefull for people that miss them ;-)
131  * @return  
132  */
133 std::string gdcmHeaderHelper::GetPixelType() {
134    std::string BitsAlloc;
135    BitsAlloc = GetEntryByNumber(0x0028, 0x0100);
136    if (BitsAlloc == GDCM_UNFOUND) { // Bits Allocated
137       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Bits Allocated");
138       BitsAlloc = std::string("16");
139    }
140    if (BitsAlloc == "12")           // It will be unpacked
141       BitsAlloc = std::string("16");
142    else if (BitsAlloc == "24")      // (in order no to be messed up
143       BitsAlloc = std::string("8"); // by old RGB images)
144     
145    std::string Signed;
146    Signed = GetEntryByNumber(0x0028, 0x0103);
147    if (Signed == GDCM_UNFOUND) { // "Pixel Representation"
148       dbg.Verbose(0, "gdcmHeader::GetPixelType: unfound Pixel Representation");
149       BitsAlloc = std::string("0");
150    }
151    if (BitsAlloc == "64") // to help users that want to deal with DOUBLE
152       return("FD");
153       
154    if (Signed == "0")
155       Signed = std::string("U");
156    else
157       Signed = std::string("S");
158
159    return( BitsAlloc + Signed);
160 }
161
162 /**
163   * \ingroup gdcmHeaderHelper
164   * \brief gets the info from 0028,0030 : Pixel Spacing
165   * \           else 1.
166   * @return X dimension of a pixel
167   */
168 float gdcmHeaderHelper::GetXSpacing() {
169     float xspacing, yspacing;
170     std::string StrSpacing = GetEntryByNumber(0x0028,0x0030);
171     
172    if (StrSpacing == GDCM_UNFOUND) {
173       dbg.Verbose(0, "gdcmHeader::GetXSpacing: unfound Pixel Spacing (0028,0030)");
174       return 1.;
175     }
176   if( sscanf( StrSpacing.c_str(), "%f\\%f", &yspacing, &xspacing) != 2)
177     return 0.;
178   if (xspacing == 0.) {
179     dbg.Verbose(0, "gdcmHeader::GetYSpacing: gdcmData/CT-MONO2-8-abdo.dcm problem");
180     // seems to be a bug in the header ...
181     sscanf( StrSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing);
182   }
183   return xspacing;
184 }
185
186 /**
187   * \ingroup gdcmHeaderHelper
188   * \brief gets the info from 0028,0030 : Pixel Spacing
189   * \           else 1.
190   * @return Y dimension of a pixel
191   */
192 float gdcmHeaderHelper::GetYSpacing() {
193    float xspacing, yspacing;
194    std::string StrSpacing = GetEntryByNumber(0x0028,0x0030);
195   
196    if (StrSpacing == GDCM_UNFOUND) {
197       dbg.Verbose(0, "gdcmHeader::GetYSpacing: unfound Pixel Spacing (0028,0030)");
198       return 1.;
199     }
200   if( sscanf( StrSpacing.c_str(), "%f\\%f", &yspacing, &xspacing) != 2)
201     return 0.;
202   if (xspacing == 0.) {
203     dbg.Verbose(0, "gdcmHeader::GetYSpacing: gdcmData/CT-MONO2-8-abdo.dcm problem");
204     // seems to be a bug in the header ...
205     sscanf( StrSpacing.c_str(), "%f\\0\\%f", &yspacing, &xspacing);
206   }
207   return yspacing;
208
209
210 /**
211   *\ingroup gdcmHeaderHelper
212   *\brief gets the info from 0018,0088 : Space Between Slices
213   *\               else from 0018,0050 : Slice Thickness
214   *\               else 1.
215   * @return Z dimension of a voxel-to be
216   */
217 float gdcmHeaderHelper::GetZSpacing() {
218    // Spacing Between Slices : distance entre le milieu de chaque coupe
219    // Les coupes peuvent etre :
220    //   jointives     (Spacing between Slices = Slice Thickness)
221    //   chevauchantes (Spacing between Slices < Slice Thickness)
222    //   disjointes    (Spacing between Slices > Slice Thickness)
223    // Slice Thickness : epaisseur de tissus sur laquelle est acquis le signal
224    //   ca interesse le physicien de l'IRM, pas le visualisateur de volumes ...
225    //   Si le Spacing Between Slices est absent, 
226    //   on suppose que les coupes sont jointives
227    
228    std::string StrSpacingBSlices = GetEntryByNumber(0x0018,0x0088);
229
230    if (StrSpacingBSlices == GDCM_UNFOUND) {
231       dbg.Verbose(0, "gdcmHeader::GetZSpacing: unfound StrSpacingBSlices");
232       std::string StrSliceThickness = GetEntryByNumber(0x0018,0x0050);       
233       if (StrSliceThickness == GDCM_UNFOUND)
234          return 1.;
235       else
236          // if no 'Spacing Between Slices' is found, 
237          // we assume slices join together
238          // (no overlapping, no interslice gap)
239          // if they don't, we're fucked up
240          return atof(StrSliceThickness.c_str());  
241    } else {
242       return atof(StrSpacingBSlices.c_str());
243    }
244 }
245
246 float gdcmHeaderHelper::GetRescaleIntercept() {
247   float resInter = 0.;
248   std::string StrRescInter = GetEntryByNumber(0x0028,0x1052); //0028 1052 DS IMG Rescale Intercept
249   if (StrRescInter != GDCM_UNFOUND) {
250       if( sscanf( StrRescInter.c_str(), "%f", &resInter) != 1) {
251          dbg.Verbose(0, "gdcmHeader::GetRescaleIntercept: Rescale Slope is empty");
252            // bug in the element 0x0028,0x1052
253       }    
254    }
255   return resInter;
256 }
257
258 float gdcmHeaderHelper::GetRescaleSlope() {
259   float resSlope = 1.;
260   std::string StrRescSlope = GetEntryByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope
261   if (StrRescSlope != GDCM_UNFOUND) {
262       if( sscanf( StrRescSlope.c_str(), "%f", &resSlope) != 1) {
263          dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty");
264            // bug in the element 0x0028,0x1053
265       }    
266    }  
267         return resSlope;
268 }
269
270 /**
271   * \ingroup gdcmHeaderHelper
272   * \brief This function is intended to user who doesn't whan 
273   * \ to have to manage a LUT and expects to get an RBG Pixel image
274   * \ (or a monochrome one ...) 
275   * \warning to be used with GetImagePixels()
276   * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR)
277   */
278 int gdcmHeaderHelper::GetNumberOfScalarComponents() {
279
280    if (GetSamplesPerPixel() ==3)
281       return 3;
282       
283      // 0028 0100 US IMG Bits Allocated
284      // (in order no to be messed up by old RGB images)
285    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
286       return 3;
287        
288    std::string PhotometricInterpretation = 
289                   gdcmHeader::GetEntryByNumber(0x0028,0x0004);
290
291    if ( ( PhotometricInterpretation == "PALETTE COLOR ") ) {
292       if (HasLUT())   // PALETTE COLOR is NOT enough
293          return 3;
294       else
295          return 1;       
296    }   
297                   
298       //beware of trailing space at end of string                                               
299    if (PhotometricInterpretation.find(GDCM_UNFOUND) < 
300                            PhotometricInterpretation.length() || 
301        PhotometricInterpretation.find("MONOCHROME1") < 
302                            PhotometricInterpretation.length() || 
303        PhotometricInterpretation.find("MONOCHROME2") < 
304                            PhotometricInterpretation.length() ) 
305        return 1;
306     else
307     // we assume that *all* kinds of YBR are dealt with
308       return 3;
309 }
310
311 /**
312   * \ingroup gdcmHeaderHelper
313   * \brief This function is intended to user that DOESN'T want 
314   * \to get RGB pixels image when it's stored as a PALETTE COLOR image
315   * \ - the (vtk) user is supposed to know how deal with LUTs - 
316   * \warning to be used with GetImagePixelsRaw()
317   * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -)
318   */
319 int gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() {
320       
321      // 0028 0100 US IMG Bits Allocated
322      // (in order no to be messed up by old RGB images)
323    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
324       return 3;
325
326     // we assume that *all* kinds of YBR are dealt with
327       return GetSamplesPerPixel();
328 }
329
330 std::string gdcmHeaderHelper::GetStudyUID(){
331   return GetEntryByNumber(0x0020,0x000d); //0020 000d UI REL Study Instance UID
332 }
333
334 std::string gdcmHeaderHelper::GetSeriesUID(){
335   return GetEntryByNumber(0x0020,0x000e); //0020 000e UI REL Series Instance UID
336 }
337
338 std::string gdcmHeaderHelper::GetClassUID(){
339   return GetEntryByNumber(0x0008,0x0016); //0008 0016 UI ID SOP Class UID
340 }
341
342 std::string gdcmHeaderHelper::GetInstanceUID(){
343   return GetEntryByNumber(0x0008,0x0018); //0008 0018 UI ID SOP Instance UID
344 }
345
346 // Image Position Patient                              (0020,0032):
347 // If not found (ACR_NEMA) we try Image Position       (0020,0030)
348 // If not found (ACR-NEMA), we consider Slice Location (0020,1041)
349 //                                   or Location       (0020,0050) 
350 // as the Z coordinate, 
351 // 0. for all the coordinates if nothing is found
352
353 // TODO : find a way to inform the caller nothing was found
354 // TODO : How to tell the caller a wrong number of values was found?
355 /**
356   * \ingroup gdcmHeaderHelper
357   * \brief gets the info from 0020,0032 : Image Position Patient
358   *\                else from 0020,0030 : Image Position (RET)
359   *\                else 0.
360   * @return up-left image corner position
361   */
362 float gdcmHeaderHelper::GetXOrigin() {
363     float xImPos, yImPos, zImPos;  
364     std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
365
366     if (StrImPos == GDCM_UNFOUND) {
367        dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position Patient (0020,0032)");
368        StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
369        if (StrImPos == GDCM_UNFOUND) {
370           dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position (RET) (0020,0030)");
371           // How to tell the caller nothing was found ?
372          return 0.;
373        }  
374      }
375    if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
376      return 0.;
377    return xImPos;
378 }
379
380 /**
381   * \ingroup gdcmHeaderHelper
382   * \brief gets the info from 0020,0032 : Image Position Patient
383   * \               else from 0020,0030 : Image Position (RET)
384   * \               else 0.
385   * @return up-left image corner position
386   */
387 float gdcmHeaderHelper::GetYOrigin() {
388     float xImPos, yImPos, zImPos;
389     std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
390
391     if (StrImPos == GDCM_UNFOUND) {
392        dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position Patient (0020,0032)");
393        StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
394        if (StrImPos == GDCM_UNFOUND) {
395           dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position (RET) (0020,0030)");
396           // How to tell the caller nothing was found ?
397            return 0.;
398        }  
399      }
400    if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
401      return 0.;
402    return yImPos;
403 }
404
405 /**
406   * \ingroup gdcmHeaderHelper
407   * \brief gets the info from 0020,0032 : Image Position Patient
408   * \               else from 0020,0030 : Image Position (RET)
409   * \               else from 0020,1041 : Slice Location
410   * \               else from 0020,0050 : Location
411   * \               else 0.
412   * @return up-left image corner position
413   */
414 float gdcmHeaderHelper::GetZOrigin() {
415    float xImPos, yImPos, zImPos; 
416    std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
417    if (StrImPos != GDCM_UNFOUND) {
418       if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) {
419          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position Patient (0020,0032)");
420          return 0.;  // bug in the element 0x0020,0x0032
421       } else {
422          return zImPos;
423       }    
424    }  
425    StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
426    if (StrImPos != GDCM_UNFOUND) {
427       if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) {
428          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position (RET) (0020,0030)");
429          return 0.;  // bug in the element 0x0020,0x0032
430       } else {
431          return zImPos;
432       }    
433    }                
434    std::string StrSliceLocation = GetEntryByNumber(0x0020,0x1041);// for *very* old ACR-NEMA images
435    if (StrSliceLocation != GDCM_UNFOUND) {
436       if( sscanf( StrSliceLocation.c_str(), "%f", &zImPos) !=1) {
437          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Slice Location (0020,1041)");
438          return 0.;  // bug in the element 0x0020,0x1041
439       } else {
440          return zImPos;
441       }
442    }   
443    dbg.Verbose(0, "gdcmHeader::GetZImagePosition: unfound Slice Location (0020,1041)");
444    std::string StrLocation = GetEntryByNumber(0x0020,0x0050);
445    if (StrLocation != GDCM_UNFOUND) {
446       if( sscanf( StrLocation.c_str(), "%f", &zImPos) !=1) {
447          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Location (0020,0050)");
448          return 0.;  // bug in the element 0x0020,0x0050
449       } else {
450          return zImPos;
451       }
452    }
453    dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)");  
454    return 0.; // Hopeless
455 }
456
457 /**
458   * \ingroup gdcmHeaderHelper
459   * \brief gets the info from 0020,0013 : Image Number
460   * \               else 0.
461   * @return image number
462   */
463 int gdcmHeaderHelper::GetImageNumber() {
464   //The function i atoi() takes the address of an area of memory as parameter and converts 
465   //the string stored at that location to an integer using the external decimal to internal
466   //binary conversion rules. This may be preferable to sscanf() since atoi() is a much smaller,
467   // simpler and faster function. sscanf() can do all possible conversions whereas atoi() can 
468   //only do single decimal integer conversions.
469   std::string StrImNumber = GetEntryByNumber(0x0020,0x0013); //0020 0013 IS REL Image Number
470   if (StrImNumber != GDCM_UNFOUND) {
471     return atoi( StrImNumber.c_str() );
472   }
473   return 0;   //Hopeless
474 }
475
476 /**
477   * \ingroup gdcmHeaderHelper
478   * \brief gets the info from 0008,0060 : Modality
479   * @return ModalityType
480   */
481 ModalityType gdcmHeaderHelper::GetModality(void) {
482   std::string StrModality = GetEntryByNumber(0x0008,0x0060); //0008 0060 CS ID Modality
483   if (StrModality != GDCM_UNFOUND) {
484          if ( StrModality.find("AU") < StrModality.length()) return AU;
485     else if ( StrModality.find("AS") < StrModality.length()) return AS;
486     else if ( StrModality.find("BI") < StrModality.length()) return BI;
487     else if ( StrModality.find("CF") < StrModality.length()) return CF;
488     else if ( StrModality.find("CP") < StrModality.length()) return CP;
489     else if ( StrModality.find("CR") < StrModality.length()) return CR;
490     else if ( StrModality.find("CT") < StrModality.length()) return CT;
491     else if ( StrModality.find("CS") < StrModality.length()) return CS;
492     else if ( StrModality.find("DD") < StrModality.length()) return DD;
493     else if ( StrModality.find("DF") < StrModality.length()) return DF;
494     else if ( StrModality.find("DG") < StrModality.length()) return DG;
495     else if ( StrModality.find("DM") < StrModality.length()) return DM;
496     else if ( StrModality.find("DS") < StrModality.length()) return DS;
497     else if ( StrModality.find("DX") < StrModality.length()) return DX;
498     else if ( StrModality.find("ECG") < StrModality.length()) return ECG;
499     else if ( StrModality.find("EPS") < StrModality.length()) return EPS;
500     else if ( StrModality.find("FA") < StrModality.length()) return FA;
501     else if ( StrModality.find("FS") < StrModality.length()) return FS;
502     else if ( StrModality.find("HC") < StrModality.length()) return HC;
503     else if ( StrModality.find("HD") < StrModality.length()) return HD;
504     else if ( StrModality.find("LP") < StrModality.length()) return LP;
505     else if ( StrModality.find("LS") < StrModality.length()) return LS;
506     else if ( StrModality.find("MA") < StrModality.length()) return MA;
507     else if ( StrModality.find("MR") < StrModality.length()) return MR;
508     else if ( StrModality.find("NM") < StrModality.length()) return NM;
509     else if ( StrModality.find("OT") < StrModality.length()) return OT;
510     else if ( StrModality.find("PT") < StrModality.length()) return PT;
511     else if ( StrModality.find("RF") < StrModality.length()) return RF;
512     else if ( StrModality.find("RG") < StrModality.length()) return RG;
513     else if ( StrModality.find("RTDOSE")  < StrModality.length()) return RTDOSE;
514     else if ( StrModality.find("RTIMAGE") < StrModality.length()) return RTIMAGE;
515     else if ( StrModality.find("RTPLAN")  < StrModality.length()) return RTPLAN;
516     else if ( StrModality.find("RTSTRUCT")< StrModality.length()) return RTSTRUCT;
517     else if ( StrModality.find("SM") < StrModality.length()) return SM;
518     else if ( StrModality.find("ST") < StrModality.length()) return ST;
519     else if ( StrModality.find("TG") < StrModality.length()) return TG;
520     else if ( StrModality.find("US") < StrModality.length()) return US;
521     else if ( StrModality.find("VF") < StrModality.length()) return VF;
522     else if ( StrModality.find("XA") < StrModality.length()) return XA;
523     else if ( StrModality.find("XC") < StrModality.length()) return XC;
524
525     else
526     {
527       //throw error return value ???
528       // specified <> unknow in our database
529       return Unknow;
530     }
531   }
532   return Unknow;
533 }
534
535 /**
536   * \ingroup gdcmHeaderHelper
537   * \brief gets the info from 0020,0037 : Image Orientation Patient
538   * @return cosines of image orientation patient
539   */
540 void gdcmHeaderHelper::GetImageOrientationPatient( float* iop ) {
541
542   //iop is supposed to be float[6]
543   iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0;
544   
545   std::string StrImOriPat = GetEntryByNumber(0x0020,0x0037); // 0020 0037 DS REL Image Orientation (Patient)
546   if (StrImOriPat != GDCM_UNFOUND) {
547     if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", 
548             &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) {
549          dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0037)");
550          return ;  // bug in the element 0x0020,0x0037
551     } 
552     else
553       return ;
554   }
555   
556   //For ACR-NEMA
557   StrImOriPat = GetEntryByNumber(0x0020,0x0035); //0020 0035 DS REL Image Orientation (RET)
558   if (StrImOriPat != GDCM_UNFOUND) {
559     if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", 
560             &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) {
561          dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0035)");
562          return ;  // bug in the element 0x0020,0x0035
563     } 
564     else
565       return ;
566   }
567 }
568
569 //-----------------------------------------------------------------------------
570 // Protected
571
572 //-----------------------------------------------------------------------------
573 // Private
574
575 //-----------------------------------------------------------------------------
576
577
578
579 //-----------------------------------------------------------------------------
580 // gdcmSerieHeaderHelper
581 //-----------------------------------------------------------------------------
582 // Constructor / Destructor
583 gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper(){
584   //! \todo
585   for (std::list<gdcmHeaderHelper*>::iterator it  = CoherentGdcmFileList.begin();
586         it != CoherentGdcmFileList.end(); it++)
587   {
588     delete *it;
589   }
590   CoherentGdcmFileList.clear();
591 }
592
593 //-----------------------------------------------------------------------------
594 // Print
595
596 //-----------------------------------------------------------------------------
597 // Public
598 /**
599  * \ingroup gdcmHeaderHelper
600  * \brief add a gdcmFile to the list based on file name
601  */
602 void gdcmSerieHeaderHelper::AddFileName(std::string filename) {
603   gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() );
604   this->CoherentGdcmFileList.push_back( GdcmFile );
605 }
606
607 /**
608  * \ingroup gdcmHeaderHelper
609  * \brief add a gdcmFile to the list
610  */
611 void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file){
612   this->CoherentGdcmFileList.push_back( file );
613 }
614
615 /**
616  * \ingroup gdcmHeaderHelper
617  * \brief \todo
618  */
619 void gdcmSerieHeaderHelper::SetDirectory(std::string dir){
620   std::list<std::string> filenames_list;
621   GetDir(dir, filenames_list);  //OS specific
622   
623   for(std::list<std::string>::iterator it = filenames_list.begin(); it !=
624   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 //-----------------------------------------------------------------------------