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