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