]> Creatis software - clitk.git/blob - vv/vvLandmarks.cxx
Merge branch 'master' of git.creatis.insa-lyon.fr:clitk
[clitk.git] / vv / vvLandmarks.cxx
1 /*=========================================================================
2   Program:   vv                     http://www.creatis.insa-lyon.fr/rio/vv
3
4   Authors belong to:
5   - University of LYON              http://www.universite-lyon.fr/
6   - Léon Bérard cancer center       http://www.centreleonberard.fr
7   - CREATIS CNRS laboratory         http://www.creatis.insa-lyon.fr
8
9   This software is distributed WITHOUT ANY WARRANTY; without even
10   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11   PURPOSE.  See the copyright notices for more information.
12
13   It is distributed under dual licence
14
15   - BSD        See included LICENSE.txt file
16   - CeCILL-B   http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17   ===========================================================================**/
18 #include "vvLandmarks.h"
19
20 #include <ios>
21 #include <fstream>
22 #include <sstream>
23 #include <string>
24 #include <locale.h>
25
26 #include "vtkPolyData.h"
27 #include "vtkPoints.h"
28 #include "vtkFloatArray.h"
29 #include "vtkPointData.h"
30 #include "clitkCommon.h"
31 #include <itksys/SystemTools.hxx>
32
33 //--------------------------------------------------------------------
34 vvLandmarks::vvLandmarks(int size)
35 {
36   mLandmarks.resize(size);
37   mFilenames.resize(0);
38   mTime = 0;
39
40   for (int i = 0; i < size; i++) {
41     mLandmarks[i].resize(0);
42     vtkPoints *points = vtkPoints::New();
43     mPoints.push_back(points);
44     mIds.push_back(vtkFloatArray::New());
45     mLabels.push_back(vtkStringArray::New());
46     mLabels.back()->SetName("labels");
47   }
48   mPolyData = vtkPolyData::New();
49 }
50 //--------------------------------------------------------------------
51
52
53 //--------------------------------------------------------------------
54 vvLandmarks::~vvLandmarks()
55 {
56   for (unsigned int i = 0; i < mPoints.size(); i++) {
57     mPoints[i]->Delete();
58     mIds[i]->Delete();
59     mLabels[i]->Delete();
60   }
61   /*for(unsigned int i = 0; i < mText.size(); i++) {
62     mText[i]->Delete();
63     }*/
64   if (mPolyData)
65     mPolyData->Delete();
66 }
67 //--------------------------------------------------------------------
68
69
70 //--------------------------------------------------------------------
71 void vvLandmarks::AddLandmark(float x,float y,float z,float t,double value)
72 {
73   vvLandmark point;
74   vtkIdType idPoint;
75   point.coordinates[0] = x;
76   point.coordinates[1] = y;
77   point.coordinates[2] = z;
78   point.coordinates[3] = t;
79   point.pixel_value=value;
80   mLandmarks[mTime].push_back(point);
81
82   idPoint = mPoints[int(t)]->InsertNextPoint(x,y,z);
83   std::string str_vtkIdType;        // string which will contain the result
84   std::ostringstream convert;       // stream used for the conversion
85   convert << idPoint;                   // insert the textual representation of 'idPoint' in the characters in the stream
86   str_vtkIdType = convert.str();    // set 'str_vtkIdType' to the contents of the stream
87   mLabels[mTime]->InsertNextValue(str_vtkIdType.c_str());
88
89   std::stringstream numberVal;
90   numberVal << (mLandmarks.size()-1);
91   /*
92   vvLandmarksGlyph *number = vvLandmarksGlyph::New();
93   number->SetText(numberVal.str().c_str());
94   number->BackingOff();
95   DD(numberVal.str().c_str());
96   mText.push_back(number);
97   */
98
99   mIds[mTime]->InsertNextTuple1(0.55);
100   //mIds->InsertTuple1(mLandmarks.size(),mLandmarks.size());
101   SetTime(int(t));
102 }
103 //--------------------------------------------------------------------
104
105
106 //--------------------------------------------------------------------
107 void vvLandmarks::RemoveLastLandmark()
108 {
109   mPoints[mTime]->SetNumberOfPoints(mPoints[mTime]->GetNumberOfPoints()-1);
110   //  mText.pop_back();
111   mLandmarks[mTime].pop_back();
112   mIds[mTime]->RemoveLastTuple();
113   mLabels[mTime]->SetNumberOfValues(mLabels[mTime]->GetNumberOfValues()-1);
114   mLabels[mTime]->Modified();
115   mPolyData->Modified();
116 }
117 //--------------------------------------------------------------------
118
119
120 //--------------------------------------------------------------------
121 void vvLandmarks::RemoveLandmark(int index)
122 {
123   // erase a vtkPoint by shifiting the array .
124   // not a problem here because there are no 
125   // pologyons linking the points
126   int t = mTime;//mLandmarks[index].coordinates[3];
127   int npoints = mPoints[t]->GetNumberOfPoints();
128   for (int i = index; i < npoints - 1; i++) {
129     mPoints[t]->InsertPoint(i, mPoints[t]->GetPoint(i+1));
130         std::string str_i;                   // string which will contain the result
131         std::ostringstream convert;      // stream used for the conversion
132         convert << i;                        // insert the textual representation of 'i' in the characters in the stream
133         str_i = convert.str();           // set 'str_i' to the contents of the stream
134         mLabels[t]->SetValue(i,str_i.c_str());
135     }
136   mPoints[t]->SetNumberOfPoints(npoints-1);
137   mLabels[t]->SetNumberOfValues(npoints-1);
138   mLabels[t]->Modified();
139   mPolyData->Modified();
140
141   mLandmarks[t].erase(mLandmarks[t].begin() + index);
142   mIds[t]->RemoveLastTuple();
143 }
144 //--------------------------------------------------------------------
145
146 //--------------------------------------------------------------------
147 void vvLandmarks::RemoveAll()
148 {
149   for (unsigned int i = 0; i < mLandmarks.size(); i++) {
150     mLandmarks[i].clear();
151     mPoints[i]->SetNumberOfPoints(0);
152     mLabels[i]->SetNumberOfValues(0);
153     mIds[i]->SetNumberOfValues(0);
154   }
155 }
156 //--------------------------------------------------------------------
157
158 //--------------------------------------------------------------------
159 void vvLandmarks::ChangeComments(int index, std::string comments)
160 {
161   mLandmarks[mTime][index].comments = comments;
162 }
163 //--------------------------------------------------------------------
164
165
166 //--------------------------------------------------------------------
167 double vvLandmarks::GetPixelValue(int index)
168 {
169   return mLandmarks[mTime][index].pixel_value;
170 }
171 //--------------------------------------------------------------------
172
173
174 //--------------------------------------------------------------------
175 float* vvLandmarks::GetCoordinates(int index)
176 {
177   return mLandmarks[mTime][index].coordinates;
178 }
179 //--------------------------------------------------------------------
180
181
182 //--------------------------------------------------------------------
183 std::string vvLandmarks::GetComments(int index)
184 {
185   return mLandmarks[mTime][index].comments;
186 }
187 //--------------------------------------------------------------------
188
189
190 //--------------------------------------------------------------------
191 bool vvLandmarks::LoadFile(std::vector<std::string> filenames)
192 {
193   // all files in the sequence must be of the same type
194   std::string extension = itksys::SystemTools::GetFilenameExtension(filenames[0]);
195   if (extension == ".txt")
196     return LoadTxtFile(filenames);
197   else if (extension == ".pts")
198     return LoadPtsFile(filenames);
199
200   return false;
201 }
202
203 //--------------------------------------------------------------------
204 bool vvLandmarks::LoadTxtFile(std::vector<std::string> filenames)
205 {
206   mFilenames = filenames;
207   for (unsigned int i = 0; i < mPoints.size(); i++) {
208     mLandmarks[i].clear();
209     mPoints[i]->SetNumberOfPoints(0);
210   }
211
212   int err = 0;
213   for (unsigned int f = 0; f < filenames.size(); f++) {
214     std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
215     if (!fp.is_open()) {
216       std::cerr <<"Unable to open file " << filenames[f] << std::endl;
217       err++;
218     }
219     vtkIdType idPoint;
220     char line[255];
221     bool first_line=true;
222     while (fp.getline(line,255)) {
223       //    DD(line);
224       std::string stringline = line;
225       stringline += "\n";
226       
227       if (first_line) {
228         first_line=false;
229         ///New landmark format: first line is "LANDMARKSXX", where XX is the version number
230         if (stringline.size() >= 10 && stringline.compare(0,9,"LANDMARKS")==0) {
231           std::istringstream ss(stringline.c_str()+9);
232           ss >> mFormatVersion;
233           continue; //skip first line
234         } else
235           mFormatVersion=0;
236       }
237       if (stringline.size() > 1) {
238         vvLandmark point;
239         int previousSpace = 0;
240         int space=0;
241         if (mFormatVersion>0) {
242           space = stringline.find(" ", previousSpace+1);
243           if (space < -1 || space > (int)stringline.size()) {
244             ErrorMsg(mLandmarks.size(),"index");
245             continue;
246           }
247           //int index = atoi(stringline.substr(previousSpace,space - previousSpace).c_str());
248           previousSpace = space;
249         }
250         space = stringline.find(" ", previousSpace+1);
251         if (space < -1 || space > (int)stringline.size()) {
252           ErrorMsg(mLandmarks.size(),"x position");
253           continue;
254         }
255         point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
256         //      DD(point.coordinates[0]);
257         previousSpace = space;
258         space = stringline.find(" ", previousSpace+1);
259         if (space < -1 || space > (int)stringline.size()) {
260           ErrorMsg(mLandmarks.size(),"y position");
261           continue;
262         }
263         point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
264         //      DD(point.coordinates[1]);
265         previousSpace = space;
266         space = stringline.find(" ", previousSpace+1);
267         if (space < -1 || space > (int)stringline.size()) {
268           ErrorMsg(mLandmarks.size(),"z position");
269           continue;
270         }
271         point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
272         previousSpace = space;
273         if (mFormatVersion>0) {
274           space = stringline.find(" ", previousSpace+1);
275           if (space < -1 || space > (int)stringline.size()) {
276             ErrorMsg(mLandmarks.size(),"t position");
277             continue;
278           }
279           point.coordinates[3] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
280           previousSpace = space;
281           space = stringline.find(" ", previousSpace+1);
282           if (space < -1 || space > (int)stringline.size()) {
283             ErrorMsg(mLandmarks.size(),"pixel value");
284             continue;
285           }
286           point.pixel_value = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
287           //        DD(point.pixel_value);
288         } else {
289           point.pixel_value=0.; //Not in file
290           point.coordinates[3]=(float)f;
291         }
292         previousSpace = space;
293         //this is the maximum size of comments
294         space = (stringline.find("\n", previousSpace+1) < 254 ? stringline.find("\n", previousSpace+1) : 254);
295         if (previousSpace != -1) {
296           point.comments = stringline.substr(previousSpace,space - (previousSpace)).c_str();
297         }
298         //      DD(point.comments);
299         mLandmarks[int(point.coordinates[3])].push_back(point);
300         mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
301         idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
302                                                             point.coordinates[0],point.coordinates[1],point.coordinates[2]);
303         std::string str_vtkIdType;          // string which will contain the result
304         std::ostringstream convert;     // stream used for the conversion
305         convert << idPoint;                 // insert the textual representation of 'idPoint' in the characters in the stream
306         str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
307         mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
308       }
309     }
310   }
311
312   if (err > 0 && err == filenames.size())
313     return false;
314   
315   SetTime(0);
316   
317   return true;
318 }
319 //--------------------------------------------------------------------
320
321 //--------------------------------------------------------------------
322 bool vvLandmarks::LoadPtsFile(std::vector<std::string> filenames)
323 {
324   mFilenames = filenames;
325   for (unsigned int i = 0; i < mPoints.size(); i++) {
326     mPoints[i]->SetNumberOfPoints(0);
327     mLandmarks[i].clear();
328   }
329
330   int err = 0;
331   for (unsigned int f = 0; f < filenames.size(); f++) {
332     std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
333     if (!fp.is_open()) {
334       std::cerr <<"Unable to open file " << filenames[f] << std::endl;
335       err++;
336     }
337     vtkIdType idPoint;
338     char line[255];
339     bool first_line=true;
340     while (fp.getline(line,255)) {
341       std::string stringline = line;
342       stringline += "\n";
343       
344       std::string separators = "\t\n\r ";
345       if (stringline.size() > 1) {
346         vvLandmark point;
347         int previousSpace = 0;
348         int space=0;
349
350         if (stringline[0] == '#') // comments
351           continue;
352         
353         space = stringline.find_first_of(separators, previousSpace+1);
354         if (space == std::string::npos) {
355           ErrorMsg(mLandmarks.size(),"x position");
356           continue;
357         }
358         point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
359         //      DD(point.coordinates[0]);
360         previousSpace = space;
361         space = stringline.find_first_of(separators, previousSpace+1);
362         if (space == std::string::npos) {
363           ErrorMsg(mLandmarks.size(),"y position");
364           continue;
365         }
366         point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
367         //      DD(point.coordinates[1]);
368         previousSpace = space;
369         space = stringline.find_first_of(separators, previousSpace+1);
370         if (space == std::string::npos) {
371           ErrorMsg(mLandmarks.size(),"z position");
372           continue;
373         }
374         point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
375         previousSpace = space;
376         point.pixel_value=0.; //Not in file
377         point.coordinates[3]=(float)f;  //Not in file
378         point.comments = "";  //Not in file
379
380         //      DD(point.comments);
381         mLandmarks[int(point.coordinates[3])].push_back(point);
382         mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
383         idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
384                                                             point.coordinates[0],point.coordinates[1],point.coordinates[2]);
385         std::string str_vtkIdType;     // string which will contain the result
386         std::ostringstream convert;  // stream used for the conversion
387         convert << idPoint;        // insert the textual representation of 'idPoint' in the characters in the stream
388         str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
389         mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
390       }
391     }
392   }
393   
394   SetTime(0);
395   DD("vvLandmarks::LoadPtsFile")
396   if (err > 0 && err == filenames.size())
397     return false;
398
399   
400   return true;
401 }
402 //--------------------------------------------------------------------
403
404 //--------------------------------------------------------------------
405 bool vvLandmarks::ErrorMsg(int num,const char * text)
406 {
407   std::cerr << "error when loading point " << num << " at " << text << std::endl;
408   return false;
409 }
410 //--------------------------------------------------------------------
411
412
413 //--------------------------------------------------------------------
414 void vvLandmarks::SaveFile(std::string filename)
415 {
416   std::string fileContent = "LANDMARKS1\n"; //File format version identification
417   for (unsigned int t = 0; t < mLandmarks.size(); t++) {
418     for (unsigned int i = 0; i < mLandmarks[t].size(); i++) {
419       std::stringstream out;
420       out.imbue(std::locale("C")); //This is to specify that the dot is to be used as the decimal separator
421       out << i << " "
422           << mLandmarks[t][i].coordinates[0] << " "
423           << mLandmarks[t][i].coordinates[1] << " "
424           << mLandmarks[t][i].coordinates[2] << " "
425           << mLandmarks[t][i].coordinates[3] << " "
426           << mLandmarks[t][i].pixel_value << " ";
427       fileContent += out.str();
428       if (mLandmarks[t][i].comments.size() == 0)
429         fileContent += " ";
430       else
431         fileContent += mLandmarks[t][i].comments;
432       fileContent += "\n";
433     }
434   }
435   std::ofstream fp(filename.c_str(), std::ios::trunc);
436   if ( !fp ) {
437     std::cerr << "Unable to open file" << std::endl;
438     return;
439   }
440   fp << fileContent.c_str()<< std::endl;
441   fp.close();
442 }
443 //--------------------------------------------------------------------
444
445
446 //--------------------------------------------------------------------
447 void vvLandmarks::SetTime(int time)
448 {
449   if (time >= 0 && time <= ((int)mPoints.size() -1)) {
450     mPolyData->SetPoints(mPoints[time]);
451     mPolyData->GetPointData()->SetScalars(mIds[time]);
452     mPolyData->GetPointData()->AddArray(mLabels[time]);
453     mPolyData->Modified();
454     mPolyData->Update();
455     mTime = time;
456   }
457 }
458 //--------------------------------------------------------------------
459
460
461 //--------------------------------------------------------------------
462 std::string vvLandmarks::replace_dots(std::string input)
463 {
464   ///Replaces the dots used in the file with the decimal separator in use on the platform
465   lconv * conv=localeconv();
466   unsigned int position = input.find( "." );
467   while ( position < input.size() ) {
468     input.replace(position, 1, conv->decimal_point);
469     position = input.find( ".", position + 1 );
470   }
471   return input;
472 }
473 //--------------------------------------------------------------------