]> Creatis software - gdcm.git/blob - src/gdcmHeaderHelper.cxx
* removal of file gdcmHeader2.cxx
[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 {
231   float resInter = 0.;
232   std::string StrRescInter = GetEntryByNumber(0x0028,0x1052); //0028 1052 DS IMG Rescale Intercept
233   if (StrRescInter != GDCM_UNFOUND) {
234       if( sscanf( StrRescInter.c_str(), "%f", &resInter) != 1) {
235          dbg.Verbose(0, "gdcmHeader::GetRescaleIntercept: Rescale Slope is empty");
236            // bug in the element 0x0028,0x1052
237       }    
238    }
239   return resInter;
240 }
241
242 float gdcmHeaderHelper::GetRescaleSlope()
243 {
244   float resSlope = 1.;
245   std::string StrRescSlope = GetEntryByNumber(0x0028,0x1053); //0028 1053 DS IMG Rescale Slope
246   if (StrRescSlope != GDCM_UNFOUND) {
247       if( sscanf( StrRescSlope.c_str(), "%f", &resSlope) != 1) {
248          dbg.Verbose(0, "gdcmHeader::GetRescaleSlope: Rescale Slope is empty");
249            // bug in the element 0x0028,0x1053
250       }    
251    }  
252         return resSlope;
253 }
254
255 /**
256   * \ingroup gdcmHeaderHelper
257   * \brief This function is intended to user who doesn't whan 
258   * \ to have to manage a LUT and expects to get an RBG Pixel image
259   * \ (or a monochrome one ...) 
260   * \warning to be used with GetImagePixels()
261   * @return 1 if Gray level, 3 if Color (RGB, YBR or PALETTE COLOR)
262   */
263 int gdcmHeaderHelper::GetNumberOfScalarComponents() {
264
265    if (GetSamplesPerPixel() ==3)
266       return 3;
267       
268      // 0028 0100 US IMG Bits Allocated
269      // (in order no to be messed up by old RGB images)
270    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
271       return 3;
272        
273    std::string PhotometricInterpretation = 
274                   gdcmHeader::GetEntryByNumber(0x0028,0x0004);
275
276    if ( ( PhotometricInterpretation == "PALETTE COLOR ") ) {
277       if (HasLUT())   // PALETTE COLOR is NOT enough
278          return 3;
279       else
280          return 1;       
281    }   
282                   
283       //beware of trailing space at end of string                                               
284    if (PhotometricInterpretation.find(GDCM_UNFOUND) < 
285                            PhotometricInterpretation.length() || 
286        PhotometricInterpretation.find("MONOCHROME1") < 
287                            PhotometricInterpretation.length() || 
288        PhotometricInterpretation.find("MONOCHROME2") < 
289                            PhotometricInterpretation.length() ) 
290        return 1;
291     else
292     // we assume that *all* kinds of YBR are dealt with
293       return 3;
294 }
295
296 /**
297   * \ingroup gdcmHeaderHelper
298   * \brief This function is intended to user that DOESN'T want 
299   * \to get RGB pixels image when it's stored as a PALETTE COLOR image
300   * \ - the (vtk) user is supposed to know how deal with LUTs - 
301   * \warning to be used with GetImagePixelsRaw()
302   * @return 1 if Gray level, 3 if Color (RGB or YBR - NOT 'PALETTE COLOR' -)
303   */
304 int gdcmHeaderHelper::GetNumberOfScalarComponentsRaw() {
305       
306      // 0028 0100 US IMG Bits Allocated
307      // (in order no to be messed up by old RGB images)
308    if (gdcmHeader::GetEntryByNumber(0x0028,0x0100) == "24")
309       return 3;
310
311     // we assume that *all* kinds of YBR are dealt with
312       return GetSamplesPerPixel();
313 }
314
315 std::string gdcmHeaderHelper::GetStudyUID()
316 {
317   return GetEntryByNumber(0x0020,0x000d); //0020 000d UI REL Study Instance UID
318 }
319
320 std::string gdcmHeaderHelper::GetSeriesUID()
321 {
322   return GetEntryByNumber(0x0020,0x000e); //0020 000e UI REL Series Instance UID
323 }
324
325 std::string gdcmHeaderHelper::GetClassUID()
326 {
327   return GetEntryByNumber(0x0008,0x0016); //0008 0016 UI ID SOP Class UID
328 }
329
330 std::string gdcmHeaderHelper::GetInstanceUID()
331 {
332   return GetEntryByNumber(0x0008,0x0018); //0008 0018 UI ID SOP Instance UID
333 }
334
335 // Image Position Patient                              (0020,0032):
336 // If not found (ACR_NEMA) we try Image Position       (0020,0030)
337 // If not found (ACR-NEMA), we consider Slice Location (0020,1041)
338 //                                   or Location       (0020,0050) 
339 // as the Z coordinate, 
340 // 0. for all the coordinates if nothing is found
341
342 // TODO : find a way to inform the caller nothing was found
343 // TODO : How to tell the caller a wrong number of values was found?
344 /**
345   * \ingroup gdcmHeaderHelper
346   * \brief gets the info from 0020,0032 : Image Position Patient
347   *\                else from 0020,0030 : Image Position (RET)
348   *\                else 0.
349   * @return up-left image corner position
350   */
351 float gdcmHeaderHelper::GetXOrigin() {
352     float xImPos, yImPos, zImPos;  
353     std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
354
355     if (StrImPos == GDCM_UNFOUND) {
356        dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position Patient (0020,0032)");
357        StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
358        if (StrImPos == GDCM_UNFOUND) {
359           dbg.Verbose(0, "gdcmHeader::GetXImagePosition: unfound Image Position (RET) (0020,0030)");
360           // How to tell the caller nothing was found ?
361          return 0.;
362        }  
363      }
364    if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
365      return 0.;
366    return xImPos;
367 }
368
369 /**
370   * \ingroup gdcmHeaderHelper
371   * \brief gets the info from 0020,0032 : Image Position Patient
372   * \               else from 0020,0030 : Image Position (RET)
373   * \               else 0.
374   * @return up-left image corner position
375   */
376 float gdcmHeaderHelper::GetYOrigin() {
377     float xImPos, yImPos, zImPos;
378     std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
379
380     if (StrImPos == GDCM_UNFOUND) {
381        dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position Patient (0020,0032)");
382        StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
383        if (StrImPos == GDCM_UNFOUND) {
384           dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Image Position (RET) (0020,0030)");
385           // How to tell the caller nothing was found ?
386            return 0.;
387        }  
388      }
389    if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3)
390      return 0.;
391    return yImPos;
392 }
393
394 /**
395   * \ingroup gdcmHeaderHelper
396   * \brief gets the info from 0020,0032 : Image Position Patient
397   * \               else from 0020,0030 : Image Position (RET)
398   * \               else from 0020,1041 : Slice Location
399   * \               else from 0020,0050 : Location
400   * \               else 0.
401   * @return up-left image corner position
402   */
403 float gdcmHeaderHelper::GetZOrigin() {
404    float xImPos, yImPos, zImPos; 
405    std::string StrImPos = GetEntryByNumber(0x0020,0x0032);
406    if (StrImPos != GDCM_UNFOUND) {
407       if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) {
408          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position Patient (0020,0032)");
409          return 0.;  // bug in the element 0x0020,0x0032
410       } else {
411          return zImPos;
412       }    
413    }  
414    StrImPos = GetEntryByNumber(0x0020,0x0030); // For ACR-NEMA images
415    if (StrImPos != GDCM_UNFOUND) {
416       if( sscanf( StrImPos.c_str(), "%f\\%f\\%f", &xImPos, &yImPos, &zImPos) != 3) {
417          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Image Position (RET) (0020,0030)");
418          return 0.;  // bug in the element 0x0020,0x0032
419       } else {
420          return zImPos;
421       }    
422    }                
423    std::string StrSliceLocation = GetEntryByNumber(0x0020,0x1041);// for *very* old ACR-NEMA images
424    if (StrSliceLocation != GDCM_UNFOUND) {
425       if( sscanf( StrSliceLocation.c_str(), "%f", &zImPos) !=1) {
426          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Slice Location (0020,1041)");
427          return 0.;  // bug in the element 0x0020,0x1041
428       } else {
429          return zImPos;
430       }
431    }   
432    dbg.Verbose(0, "gdcmHeader::GetZImagePosition: unfound Slice Location (0020,1041)");
433    std::string StrLocation = GetEntryByNumber(0x0020,0x0050);
434    if (StrLocation != GDCM_UNFOUND) {
435       if( sscanf( StrLocation.c_str(), "%f", &zImPos) !=1) {
436          dbg.Verbose(0, "gdcmHeader::GetZImagePosition: wrong Location (0020,0050)");
437          return 0.;  // bug in the element 0x0020,0x0050
438       } else {
439          return zImPos;
440       }
441    }
442    dbg.Verbose(0, "gdcmHeader::GetYImagePosition: unfound Location (0020,0050)");  
443    return 0.; // Hopeless
444 }
445
446 /**
447   * \ingroup gdcmHeaderHelper
448   * \brief gets the info from 0020,0013 : Image Number
449   * \               else 0.
450   * @return image number
451   */
452 int gdcmHeaderHelper::GetImageNumber() {
453   //The function i atoi() takes the address of an area of memory as parameter and converts 
454   //the string stored at that location to an integer using the external decimal to internal
455   //binary conversion rules. This may be preferable to sscanf() since atoi() is a much smaller,
456   // simpler and faster function. sscanf() can do all possible conversions whereas atoi() can 
457   //only do single decimal integer conversions.
458   std::string StrImNumber = GetEntryByNumber(0x0020,0x0013); //0020 0013 IS REL Image Number
459   if (StrImNumber != GDCM_UNFOUND) {
460     return atoi( StrImNumber.c_str() );
461   }
462   return 0;   //Hopeless
463 }
464
465 /**
466   * \ingroup gdcmHeaderHelper
467   * \brief gets the info from 0008,0060 : Modality
468   * @return ModalityType
469   */
470 ModalityType gdcmHeaderHelper::GetModality(void) {
471   std::string StrModality = GetEntryByNumber(0x0008,0x0060); //0008 0060 CS ID Modality
472   if (StrModality != GDCM_UNFOUND) {
473          if ( StrModality.find("AU") < StrModality.length()) return AU;
474     else if ( StrModality.find("AS") < StrModality.length()) return AS;
475     else if ( StrModality.find("BI") < StrModality.length()) return BI;
476     else if ( StrModality.find("CF") < StrModality.length()) return CF;
477     else if ( StrModality.find("CP") < StrModality.length()) return CP;
478     else if ( StrModality.find("CR") < StrModality.length()) return CR;
479     else if ( StrModality.find("CT") < StrModality.length()) return CT;
480     else if ( StrModality.find("CS") < StrModality.length()) return CS;
481     else if ( StrModality.find("DD") < StrModality.length()) return DD;
482     else if ( StrModality.find("DF") < StrModality.length()) return DF;
483     else if ( StrModality.find("DG") < StrModality.length()) return DG;
484     else if ( StrModality.find("DM") < StrModality.length()) return DM;
485     else if ( StrModality.find("DS") < StrModality.length()) return DS;
486     else if ( StrModality.find("DX") < StrModality.length()) return DX;
487     else if ( StrModality.find("ECG") < StrModality.length()) return ECG;
488     else if ( StrModality.find("EPS") < StrModality.length()) return EPS;
489     else if ( StrModality.find("FA") < StrModality.length()) return FA;
490     else if ( StrModality.find("FS") < StrModality.length()) return FS;
491     else if ( StrModality.find("HC") < StrModality.length()) return HC;
492     else if ( StrModality.find("HD") < StrModality.length()) return HD;
493     else if ( StrModality.find("LP") < StrModality.length()) return LP;
494     else if ( StrModality.find("LS") < StrModality.length()) return LS;
495     else if ( StrModality.find("MA") < StrModality.length()) return MA;
496     else if ( StrModality.find("MR") < StrModality.length()) return MR;
497     else if ( StrModality.find("NM") < StrModality.length()) return NM;
498     else if ( StrModality.find("OT") < StrModality.length()) return OT;
499     else if ( StrModality.find("PT") < StrModality.length()) return PT;
500     else if ( StrModality.find("RF") < StrModality.length()) return RF;
501     else if ( StrModality.find("RG") < StrModality.length()) return RG;
502     else if ( StrModality.find("RTDOSE")  < StrModality.length()) return RTDOSE;
503     else if ( StrModality.find("RTIMAGE") < StrModality.length()) return RTIMAGE;
504     else if ( StrModality.find("RTPLAN")  < StrModality.length()) return RTPLAN;
505     else if ( StrModality.find("RTSTRUCT")< StrModality.length()) return RTSTRUCT;
506     else if ( StrModality.find("SM") < StrModality.length()) return SM;
507     else if ( StrModality.find("ST") < StrModality.length()) return ST;
508     else if ( StrModality.find("TG") < StrModality.length()) return TG;
509     else if ( StrModality.find("US") < StrModality.length()) return US;
510     else if ( StrModality.find("VF") < StrModality.length()) return VF;
511     else if ( StrModality.find("XA") < StrModality.length()) return XA;
512     else if ( StrModality.find("XC") < StrModality.length()) return XC;
513
514     else
515     {
516       //throw error return value ???
517       // specified <> unknow in our database
518       return Unknow;
519     }
520   }
521   return Unknow;
522 }
523
524 /**
525   * \ingroup gdcmHeaderHelper
526   * \brief gets the info from 0020,0037 : Image Orientation Patient
527   * @return cosines of image orientation patient
528   */
529 void gdcmHeaderHelper::GetImageOrientationPatient( float* iop ) {
530
531   //iop is supposed to be float[6]
532   iop[0] = iop[1] = iop[2] = iop[3] = iop[4] = iop[5] = 0;
533   
534   std::string StrImOriPat = GetEntryByNumber(0x0020,0x0037); // 0020 0037 DS REL Image Orientation (Patient)
535   if (StrImOriPat != GDCM_UNFOUND) {
536     if( sscanf( StrImOriPat.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", 
537             &iop[0], &iop[1], &iop[2], &iop[3], &iop[4], &iop[5]) != 6) {
538          dbg.Verbose(0, "gdcmHeader::GetImageOrientationPatient: wrong Image Orientation Patient (0020,0037)");
539          return ;  // bug in the element 0x0020,0x0037
540     } 
541     else
542       return ;
543   }
544   
545   //For ACR-NEMA
546   StrImOriPat = GetEntryByNumber(0x0020,0x0035); //0020 0035 DS REL Image Orientation (RET)
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,0035)");
551          return ;  // bug in the element 0x0020,0x0035
552     } 
553     else
554       return ;
555   }
556 }
557
558 //-----------------------------------------------------------------------------
559 // Protected
560
561 //-----------------------------------------------------------------------------
562 // Private
563
564 //-----------------------------------------------------------------------------
565
566
567
568 //-----------------------------------------------------------------------------
569 // gdcmSerieHeaderHelper
570 //-----------------------------------------------------------------------------
571 // Constructor / Destructor
572 gdcmSerieHeaderHelper::~gdcmSerieHeaderHelper()
573 {
574   //! \todo
575   for (std::list<gdcmHeaderHelper*>::iterator it  = CoherentGdcmFileList.begin();
576         it != CoherentGdcmFileList.end(); it++)
577   {
578     delete *it;
579   }
580   CoherentGdcmFileList.clear();
581 }
582
583 //-----------------------------------------------------------------------------
584 // Print
585
586 //-----------------------------------------------------------------------------
587 // Public
588 /**
589  * \ingroup gdcmHeaderHelper
590  * \brief add a gdcmFile to the list based on file name
591  */
592 void gdcmSerieHeaderHelper::AddFileName(std::string filename)
593 {
594   gdcmHeaderHelper *GdcmFile = new gdcmHeaderHelper( filename.c_str() );
595   this->CoherentGdcmFileList.push_back( GdcmFile );
596 }
597
598 /**
599  * \ingroup gdcmHeaderHelper
600  * \brief add a gdcmFile to the list
601  */
602 void gdcmSerieHeaderHelper::AddGdcmFile(gdcmHeaderHelper *file)
603 {
604   this->CoherentGdcmFileList.push_back( file );
605 }
606
607 /**
608  * \ingroup gdcmHeaderHelper
609  * \brief \todo
610  */
611 void gdcmSerieHeaderHelper::SetDirectory(std::string dir)
612 {
613   std::list<std::string> filenames_list;
614   GetDir(dir, filenames_list);  //OS specific
615   
616   for(std::list<std::string>::iterator it = filenames_list.begin(); it !=
617   filenames_list.end(); it++)
618   {
619     gdcmHeaderHelper *file = new gdcmHeaderHelper( it->c_str() );
620     this->CoherentGdcmFileList.push_back( file );
621   }
622 }
623
624 //This could be implemented in a 'Strategy Pattern' approach
625 //But as I don't know how to do it, I leave it this way
626 //BTW, this is also a Strategy, I don't know this is the best approach :)
627 void gdcmSerieHeaderHelper::OrderGdcmFileList()
628 {
629   if( ImagePositionPatientOrdering() )
630   {
631     return ;
632   }
633   else if( ImageNumberOrdering() )
634   {
635     return ;
636   }
637   else
638   {
639     FileNameOrdering();
640   }
641 }
642
643 std::list<gdcmHeaderHelper*> &gdcmSerieHeaderHelper::GetGdcmFileList()
644 {
645   return CoherentGdcmFileList;
646 }
647
648 //-----------------------------------------------------------------------------
649 // Protected
650
651 //-----------------------------------------------------------------------------
652 // Private
653 /**
654  * \ingroup gdcmHeaderHelper
655  * \brief 
656  *  We may order, considering :
657  *   -# Image Number
658  *   -# Image Position Patient
659  *   -# More to come :)
660  */
661 bool gdcmSerieHeaderHelper::ImagePositionPatientOrdering()
662 //based on Jolinda's algorithm
663 {
664   //iop is calculated based on the file file
665   float *cosines = new float[6];
666   float normal[3];
667   float ipp[3];
668   float dist;
669   float min, max;
670   bool first = true;
671   int n=0;
672   std::vector<float> distlist;
673
674   //!\todo rewrite this for loop.
675   for (std::list<gdcmHeaderHelper*>::iterator it  = CoherentGdcmFileList.begin();
676         it != CoherentGdcmFileList.end(); it++)
677   {
678     if(first) {
679       (*it)->GetImageOrientationPatient(cosines);
680       
681       //You only have to do this once for all slices in the volume. Next, for
682       //each slice, calculate the distance along the slice normal using the IPP
683       //tag ("dist" is initialized to zero before reading the first slice) :
684       normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
685       normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
686       normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
687   
688       ipp[0] = (*it)->GetXOrigin();
689       ipp[1] = (*it)->GetYOrigin();
690       ipp[2] = (*it)->GetZOrigin();
691
692       dist = 0;
693       for (int i = 0; i < 3; ++i)
694           dist += normal[i]*ipp[i];
695     
696       if( dist == 0 )
697       {
698         delete[] cosines;
699         return false;
700       }
701
702       distlist.push_back( dist );
703
704       max = min = dist;
705       first = false;
706     }
707     else {
708       ipp[0] = (*it)->GetXOrigin();
709       ipp[1] = (*it)->GetYOrigin();
710       ipp[2] = (*it)->GetZOrigin();
711   
712       dist = 0;
713       for (int i = 0; i < 3; ++i)
714           dist += normal[i]*ipp[i];
715
716       if( dist == 0 )
717       {
718         delete[] cosines;
719         return false;
720       }
721
722       
723       distlist.push_back( dist );
724
725       min = (min < dist) ? min : dist;
726       max = (max > dist) ? max : dist;
727     }
728     n++;
729   }
730
731     //Then I order the slices according to the value "dist". Finally, once
732     //I've read in all the slices, I calculate the z-spacing as the difference
733     //between the "dist" values for the first two slices.
734     std::vector<gdcmHeaderHelper*> CoherentGdcmFileVector(n);
735     //CoherentGdcmFileVector.reserve( n );
736     CoherentGdcmFileVector.resize( n );
737     //assert( CoherentGdcmFileVector.capacity() >= n );
738
739     float step = (max - min)/(n - 1);
740     int pos;
741     n = 0;
742     
743     //VC++ don't understand what scope is !! it -> it2
744     for (std::list<gdcmHeaderHelper*>::iterator it2  = CoherentGdcmFileList.begin();
745         it2 != CoherentGdcmFileList.end(); it2++, n++)
746     {
747       //2*n sort algo !!
748       //Assumption: all files are present (no one missing)
749       pos = (int)( fabs( (distlist[n]-min)/step) + .5 );
750             
751       CoherentGdcmFileVector[pos] = *it2;
752     }
753
754   CoherentGdcmFileList.clear();  //this doesn't delete list's element, node only
755   
756   //VC++ don't understand what scope is !! it -> it3
757   for (std::vector<gdcmHeaderHelper*>::iterator it3  = CoherentGdcmFileVector.begin();
758         it3 != CoherentGdcmFileVector.end(); it3++)
759   {
760     CoherentGdcmFileList.push_back( *it3 );
761   }
762
763   distlist.clear();
764   CoherentGdcmFileVector.clear();
765   delete[] cosines;
766   
767   return true;
768 }
769
770 //Based on Image Number
771 bool gdcmSerieHeaderHelper::ImageNumberOrdering()
772 {
773   int min, max, pos;
774   int n = 0;//CoherentGdcmFileList.size(); //O(N) operation !!
775   unsigned char *partition;
776   
777   std::list<gdcmHeaderHelper*>::iterator it  = CoherentGdcmFileList.begin();
778   min = max = (*it)->GetImageNumber();
779
780   for (; it != CoherentGdcmFileList.end(); it++, n++)
781   {
782     pos = (*it)->GetImageNumber();
783
784     //else
785     min = (min < pos) ? min : pos;
786   }
787
788   //bzeros(partition, n); //Cette fonction est déconseillée, utilisez plutôt memset.
789   partition = new unsigned char[n];
790   memset(partition, 0, n);
791
792   std::vector<gdcmHeaderHelper*> CoherentGdcmFileVector(n);
793
794   //VC++ don't understand what scope is !! it -> it2
795   for (std::list<gdcmHeaderHelper*>::iterator it2  = CoherentGdcmFileList.begin();
796         it2 != CoherentGdcmFileList.end(); it2++)
797   {
798     pos = (*it2)->GetImageNumber();
799     CoherentGdcmFileVector[pos - min] = *it2;
800     partition[pos - min]++;
801   }
802   
803   unsigned char mult;
804   for(int i=0; i<n ; i++)
805   {
806     mult *= partition[i];
807   }
808
809   //VC++ don't understand what scope is !! it -> it3
810   CoherentGdcmFileList.clear();  //this doesn't delete list's element, node only
811   for (std::vector<gdcmHeaderHelper*>::iterator it3  = CoherentGdcmFileVector.begin();
812         it3 != CoherentGdcmFileVector.end(); it3++)
813   {
814     CoherentGdcmFileList.push_back( *it3 );
815   }
816   CoherentGdcmFileVector.clear();
817   
818   delete[] partition;
819   return (mult!=0);
820 }
821
822 bool gdcmSerieHeaderHelper::FileNameOrdering()
823 {
824   //using the sort
825   //sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end());
826   return true;
827 }
828
829 //-----------------------------------------------------------------------------