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