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