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