]> Creatis software - gdcm.git/blob - src/gdcmSerieHeader.cxx
ENH: update gdcmDebug after Benoit comments
[gdcm.git] / src / gdcmSerieHeader.cxx
1 /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmSerieHeader.cxx,v $
5   Language:  C++
6   Date:      $Date: 2005/01/06 20:03:28 $
7   Version:   $Revision: 1.3 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmSerieHeader.h"
20 #include "gdcmDirList.h"
21 #include "gdcmHeader.h"
22
23 #include <math.h>
24 #include <algorithm>
25 #include <vector>
26
27 namespace gdcm 
28 {
29
30 typedef std::vector<Header* > GdcmHeaderVector;
31 //-----------------------------------------------------------------------------
32 // Constructor / Destructor
33 SerieHeader::SerieHeader()
34 {
35    CoherentGdcmFileList.clear();
36 }
37
38 SerieHeader::~SerieHeader()
39 {
40    /// \todo
41    for ( GdcmHeaderList::const_iterator it = CoherentGdcmFileList.begin();
42          it != CoherentGdcmFileList.end(); ++it)
43    {
44       delete *it;
45    }
46    CoherentGdcmFileList.clear();
47 }
48
49 //-----------------------------------------------------------------------------
50 // Print
51
52 //-----------------------------------------------------------------------------
53 // Public
54 /**
55  * \brief add a File to the list based on file name
56  * @param   filename Name of the file to deal with
57  */
58 void SerieHeader::AddFileName(std::string const &filename)
59 {
60    Header *header = new Header( filename );
61    CoherentGdcmFileList.push_back( header );
62 }
63
64 /**
65  * \brief add a File to the list
66  * @param   file Header to add
67  */
68 void SerieHeader::AddGdcmFile(Header *file)
69 {
70    CoherentGdcmFileList.push_back( file );
71 }
72
73 /**
74  * \brief Sets the Directory
75  * @param   dir Name of the directory to deal with
76  */
77 void SerieHeader::SetDirectory(std::string const &dir)
78 {
79    DirList filenames_list(dir);  //OS specific
80   
81    for( DirList::const_iterator it = filenames_list.begin(); 
82         it != filenames_list.end(); ++it)
83    {
84       //directly use string and not const char*:
85       Header *header = new Header( *it ); 
86       if( header->IsReadable() )
87       {
88          CoherentGdcmFileList.push_back( header );
89       }
90       else
91       {
92          delete header;
93       }
94    }
95 }
96
97 /**
98  * \brief Sorts the File List
99  * \warning This could be implemented in a 'Strategy Pattern' approach
100  *          But as I don't know how to do it, I leave it this way
101  *          BTW, this is also a Strategy, I don't know this is the best approach :)
102  */
103 void SerieHeader::OrderGdcmFileList()
104 {
105    if( ImagePositionPatientOrdering() ) 
106    {
107       return ;
108    }
109    else if( ImageNumberOrdering() )
110    {
111       return ;
112    }
113    else  
114    {
115       FileNameOrdering();
116    }
117 }
118
119 //-----------------------------------------------------------------------------
120 // Protected
121
122 //-----------------------------------------------------------------------------
123 // Private
124 /**
125  * \ingroup Header
126  * \brief sorts the images, according to their Patient Position
127  *  We may order, considering :
128  *   -# Image Number
129  *   -# Image Position Patient
130  *   -# More to come :)
131  * @return false only if the header is bugged !
132  */
133 bool SerieHeader::ImagePositionPatientOrdering()
134 //based on Jolinda's algorithm
135 {
136    //iop is calculated based on the file file
137    float *cosines = new float[6];
138    float normal[3];
139    float ipp[3];
140    float dist;
141    float min = 0, max = 0;
142    bool first = true;
143    int n=0;
144    std::vector<float> distlist;
145
146    //!\todo rewrite this for loop.
147    for ( GdcmHeaderList::const_iterator 
148          it = CoherentGdcmFileList.begin();
149          it != CoherentGdcmFileList.end(); ++it )
150    {
151       if( first ) 
152       {
153          (*it)->GetImageOrientationPatient( cosines );
154       
155          //You only have to do this once for all slices in the volume. Next, 
156          // for each slice, calculate the distance along the slice normal 
157          // using the IPP tag ("dist" is initialized to zero before reading 
158          // the first slice) :
159          normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
160          normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
161          normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
162   
163          ipp[0] = (*it)->GetXOrigin();
164          ipp[1] = (*it)->GetYOrigin();
165          ipp[2] = (*it)->GetZOrigin();
166
167          dist = 0;
168          for ( int i = 0; i < 3; ++i )
169          {
170             dist += normal[i]*ipp[i];
171          }
172     
173          if( dist == 0 )
174          {
175             delete[] cosines;
176             return false;
177          }
178
179          distlist.push_back( dist );
180
181          max = min = dist;
182          first = false;
183       }
184       else 
185       {
186          ipp[0] = (*it)->GetXOrigin();
187          ipp[1] = (*it)->GetYOrigin();
188          ipp[2] = (*it)->GetZOrigin();
189   
190          dist = 0;
191          for ( int i = 0; i < 3; ++i )
192          {
193             dist += normal[i]*ipp[i];
194          }
195
196          if( dist == 0 )
197          {
198             delete[] cosines;
199             return false;
200          }
201       
202          distlist.push_back( dist );
203
204          min = (min < dist) ? min : dist;
205          max = (max > dist) ? max : dist;
206       }
207       ++n;
208    }
209
210    // Then I order the slices according to the value "dist". Finally, once
211    // I've read in all the slices, I calculate the z-spacing as the difference
212    // between the "dist" values for the first two slices.
213    GdcmHeaderVector CoherentGdcmFileVector(n);
214    // CoherentGdcmFileVector.reserve( n );
215    CoherentGdcmFileVector.resize( n );
216    // assert( CoherentGdcmFileVector.capacity() >= n );
217
218    float step = (max - min)/(n - 1);
219    int pos;
220    n = 0;
221     
222    //VC++ don't understand what scope is !! it -> it2
223    for (GdcmHeaderList::const_iterator it2  = CoherentGdcmFileList.begin();
224         it2 != CoherentGdcmFileList.end(); ++it2, ++n)
225    {
226       //2*n sort algo !!
227       //Assumption: all files are present (no one missing)
228       pos = (int)( fabs( (distlist[n]-min)/step) + .5 );
229             
230       CoherentGdcmFileVector[pos] = *it2;
231    }
232
233    CoherentGdcmFileList.clear();  //this doesn't delete list's element, node only
234   
235    //VC++ don't understand what scope is !! it -> it3
236    for (GdcmHeaderVector::const_iterator it3  = CoherentGdcmFileVector.begin();
237         it3 != CoherentGdcmFileVector.end(); ++it3)
238    {
239       CoherentGdcmFileList.push_back( *it3 );
240    }
241
242    distlist.clear();
243    CoherentGdcmFileVector.clear();
244    delete[] cosines;
245
246    return true;
247 }
248
249 /**
250  * \ingroup Header
251  * \brief sorts the images, according to their Image Number
252  * @return false only if the header is bugged !
253  */
254
255 bool SerieHeader::ImageNumberOrdering() 
256 {
257    int min, max, pos;
258    int n = 0;//CoherentGdcmFileList.size() is a O(N) operation
259    unsigned char *partition;
260   
261    GdcmHeaderList::const_iterator it = CoherentGdcmFileList.begin();
262    min = max = (*it)->GetImageNumber();
263
264    for (; it != CoherentGdcmFileList.end(); ++it, ++n)
265    {
266       pos = (*it)->GetImageNumber();
267
268       //else
269       min = (min < pos) ? min : pos;
270       max = (max > pos) ? max : pos;
271    }
272
273    // Find out if sorting worked:
274    if( min == max || max == 0 || max > (n+min)) return false;
275
276    //bzeros(partition, n); //This function is deprecated, better use memset.
277    partition = new unsigned char[n];
278    memset(partition, 0, n);
279
280    GdcmHeaderVector CoherentGdcmFileVector(n);
281
282    //VC++ don't understand what scope is !! it -> it2
283    for (GdcmHeaderList::const_iterator it2 = CoherentGdcmFileList.begin();
284         it2 != CoherentGdcmFileList.end(); ++it2)
285    {
286       pos = (*it2)->GetImageNumber();
287       CoherentGdcmFileVector[pos - min] = *it2;
288       partition[pos - min]++;
289    }
290   
291    unsigned char mult = 1;
292    for( int i=0; i<n ; i++ )
293    {
294       mult *= partition[i];
295    }
296
297    //VC++ don't understand what scope is !! it -> it3
298    CoherentGdcmFileList.clear();  //this doesn't delete list's element, node only
299    for ( GdcmHeaderVector::const_iterator it3 = CoherentGdcmFileVector.begin();
300          it3 != CoherentGdcmFileVector.end(); ++it3 )
301    {
302       CoherentGdcmFileList.push_back( *it3 );
303    }
304    CoherentGdcmFileVector.clear();
305   
306    delete[] partition;
307
308    return (mult != 0);
309 }
310
311
312 /**
313  * \ingroup Header
314  * \brief sorts the images, according to their File Name
315  * @return false only if the header is bugged !
316  */
317 bool SerieHeader::FileNameOrdering()
318 {
319    //using the sort
320    //sort(CoherentGdcmFileList.begin(), CoherentGdcmFileList.end());
321    return true;
322 }
323
324 } // end namespace gdcm
325 //-----------------------------------------------------------------------------