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