1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
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
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.
13 It is distributed under dual licence
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"
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>
34 //--------------------------------------------------------------------
35 vvLandmarks::vvLandmarks(int size)
37 mLandmarks.resize(size);
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");
49 mPolyData = vtkPolyData::New();
51 //--------------------------------------------------------------------
54 //--------------------------------------------------------------------
55 vvLandmarks::~vvLandmarks()
57 for (unsigned int i = 0; i < mPoints.size(); i++) {
62 /*for(unsigned int i = 0; i < mText.size(); i++) {
68 //--------------------------------------------------------------------
71 //--------------------------------------------------------------------
72 void vvLandmarks::AddLandmark(float x,float y,float z,float t,double value)
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);
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());
90 std::stringstream numberVal;
91 numberVal << (mLandmarks.size()-1);
93 vvLandmarksGlyph *number = vvLandmarksGlyph::New();
94 number->SetText(numberVal.str().c_str());
96 DD(numberVal.str().c_str());
97 mText.push_back(number);
100 mIds[mTime]->InsertNextTuple1(0.55);
101 //mIds->InsertTuple1(mLandmarks.size(),mLandmarks.size());
104 //--------------------------------------------------------------------
107 //--------------------------------------------------------------------
108 void vvLandmarks::RemoveLastLandmark()
110 mPoints[mTime]->SetNumberOfPoints(mPoints[mTime]->GetNumberOfPoints()-1);
112 mLandmarks[mTime].pop_back();
113 mIds[mTime]->RemoveLastTuple();
114 mLabels[mTime]->SetNumberOfValues(mLabels[mTime]->GetNumberOfValues()-1);
115 mLabels[mTime]->Modified();
116 mPolyData->Modified();
118 //--------------------------------------------------------------------
121 //--------------------------------------------------------------------
122 void vvLandmarks::RemoveLandmarkWithLabel(vtkStdString label, int time)
124 if (label != "P1" && label != "P2")
126 // erase a vtkPoint by shifiting the array .
127 // not a problem here because there are no
128 // pologyons linking the points
129 int t = time;//mLandmarks[index].coordinates[3];
130 int npoints = mPoints[t]->GetNumberOfPoints();
132 //search of the index corresponding to the label
134 while (mLabels[t]->GetValue(index) != label)
137 for (int i = index; i < npoints - 1; i++) {
138 mPoints[t]->InsertPoint(i, mPoints[t]->GetPoint(i+1));
139 std::string str_i; // string which will contain the result
140 std::ostringstream convert; // stream used for the conversion
141 convert << i; // insert the textual representation of 'i' in the characters in the stream
142 str_i = convert.str(); // set 'str_i' to the contents of the stream
143 mLabels[t]->SetValue(i,mLabels[t]->GetValue(i+1));
145 mPoints[t]->SetNumberOfPoints(npoints-1);
146 mLabels[t]->SetNumberOfValues(npoints-1);
147 mLabels[t]->Modified();
148 mPolyData->Modified();
150 mLandmarks[t].erase(mLandmarks[t].begin() + index);
151 mIds[t]->RemoveLastTuple();
153 //--------------------------------------------------------------------
156 //--------------------------------------------------------------------
157 void vvLandmarks::RemoveLandmark(int index)
159 // erase a vtkPoint by shifiting the array .
160 // not a problem here because there are no
161 // pologyons linking the points
162 int t = mTime;//mLandmarks[index].coordinates[3];
163 int npoints = mPoints[t]->GetNumberOfPoints();
164 for (int i = index; i < npoints - 1; i++) {
165 mPoints[t]->InsertPoint(i, mPoints[t]->GetPoint(i+1));
166 std::string str_i; // string which will contain the result
167 std::ostringstream convert; // stream used for the conversion
168 convert << i; // insert the textual representation of 'i' in the characters in the stream
169 str_i = convert.str(); // set 'str_i' to the contents of the stream
170 mLabels[t]->SetValue(i,str_i.c_str());
172 mPoints[t]->SetNumberOfPoints(npoints-1);
173 mLabels[t]->SetNumberOfValues(npoints-1);
174 mLabels[t]->Modified();
175 mPolyData->Modified();
177 mLandmarks[t].erase(mLandmarks[t].begin() + index);
178 mIds[t]->RemoveLastTuple();
180 //--------------------------------------------------------------------
182 //--------------------------------------------------------------------
183 void vvLandmarks::RemoveAll()
185 for (unsigned int i = 0; i < mLandmarks.size(); i++) {
186 mLandmarks[i].clear();
187 mPoints[i]->SetNumberOfPoints(0);
188 mLabels[i]->SetNumberOfValues(0);
189 mIds[i]->SetNumberOfValues(0);
192 //--------------------------------------------------------------------
194 //--------------------------------------------------------------------
195 void vvLandmarks::ChangeComments(int index, std::string comments)
197 mLandmarks[mTime][index].comments = comments;
199 //--------------------------------------------------------------------
202 //--------------------------------------------------------------------
203 double vvLandmarks::GetPixelValue(int index)
205 return mLandmarks[mTime][index].pixel_value;
207 //--------------------------------------------------------------------
210 //--------------------------------------------------------------------
211 float* vvLandmarks::GetCoordinates(int index)
213 return mLandmarks[mTime][index].coordinates;
215 //--------------------------------------------------------------------
218 //--------------------------------------------------------------------
219 std::string vvLandmarks::GetComments(int index)
221 return mLandmarks[mTime][index].comments;
223 //--------------------------------------------------------------------
226 //--------------------------------------------------------------------
227 bool vvLandmarks::LoadFile(std::vector<std::string> filenames)
229 // all files in the sequence must be of the same type
230 std::string extension = itksys::SystemTools::GetFilenameExtension(filenames[0]);
231 if (extension == ".txt")
232 return LoadTxtFile(filenames);
233 else if (extension == ".pts")
234 return LoadPtsFile(filenames);
239 //--------------------------------------------------------------------
240 bool vvLandmarks::LoadTxtFile(std::vector<std::string> filenames)
242 mFilenames = filenames;
243 for (unsigned int i = 0; i < mPoints.size(); i++) {
244 mLandmarks[i].clear();
245 mPoints[i]->SetNumberOfPoints(0);
249 for (unsigned int f = 0; f < filenames.size(); f++) {
250 std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
252 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
257 bool first_line=true;
258 while (fp.getline(line,255)) {
260 std::string stringline = line;
265 ///New landmark format: first line is "LANDMARKSXX", where XX is the version number
266 if (stringline.size() >= 10 && stringline.compare(0,9,"LANDMARKS")==0) {
267 std::istringstream ss(stringline.c_str()+9);
268 ss >> mFormatVersion;
269 continue; //skip first line
273 if (stringline.size() > 1) {
275 int previousSpace = 0;
277 if (mFormatVersion>0) {
278 space = stringline.find(" ", previousSpace+1);
279 if (space < -1 || space > (int)stringline.size()) {
280 ErrorMsg(mLandmarks.size(),"index");
283 //int index = atoi(stringline.substr(previousSpace,space - previousSpace).c_str());
284 previousSpace = space;
286 space = stringline.find(" ", previousSpace+1);
287 if (space < -1 || space > (int)stringline.size()) {
288 ErrorMsg(mLandmarks.size(),"x position");
291 point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
292 // DD(point.coordinates[0]);
293 previousSpace = space;
294 space = stringline.find(" ", previousSpace+1);
295 if (space < -1 || space > (int)stringline.size()) {
296 ErrorMsg(mLandmarks.size(),"y position");
299 point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
300 // DD(point.coordinates[1]);
301 previousSpace = space;
302 space = stringline.find(" ", previousSpace+1);
303 if (space < -1 || space > (int)stringline.size()) {
304 ErrorMsg(mLandmarks.size(),"z position");
307 point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
308 previousSpace = space;
309 if (mFormatVersion>0) {
310 space = stringline.find(" ", previousSpace+1);
311 if (space < -1 || space > (int)stringline.size()) {
312 ErrorMsg(mLandmarks.size(),"t position");
315 point.coordinates[3] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
316 previousSpace = space;
317 space = stringline.find(" ", previousSpace+1);
318 if (space < -1 || space > (int)stringline.size()) {
319 ErrorMsg(mLandmarks.size(),"pixel value");
322 point.pixel_value = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
323 // DD(point.pixel_value);
325 point.pixel_value=0.; //Not in file
326 point.coordinates[3]=(float)f;
328 previousSpace = space;
329 //this is the maximum size of comments
330 space = (stringline.find("\n", previousSpace+1) < 254 ? stringline.find("\n", previousSpace+1) : 254);
331 if (previousSpace != -1) {
332 point.comments = stringline.substr(previousSpace,space - (previousSpace)).c_str();
334 // DD(point.comments);
335 mLandmarks[int(point.coordinates[3])].push_back(point);
336 mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
337 idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
338 point.coordinates[0],point.coordinates[1],point.coordinates[2]);
339 std::string str_vtkIdType; // string which will contain the result
340 std::ostringstream convert; // stream used for the conversion
341 convert << idPoint; // insert the textual representation of 'idPoint' in the characters in the stream
342 str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
343 mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
348 if (err > 0 && err == filenames.size())
355 //--------------------------------------------------------------------
357 //--------------------------------------------------------------------
358 bool vvLandmarks::LoadPtsFile(std::vector<std::string> filenames)
360 mFilenames = filenames;
361 for (unsigned int i = 0; i < mPoints.size(); i++) {
362 mPoints[i]->SetNumberOfPoints(0);
363 mLandmarks[i].clear();
367 for (unsigned int f = 0; f < filenames.size(); f++) {
368 std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
370 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
375 bool first_line=true;
376 while (fp.getline(line,255)) {
377 std::string stringline = line;
380 std::string separators = "\t\n\r ";
381 if (stringline.size() > 1) {
383 int previousSpace = 0;
386 if (stringline[0] == '#') // comments
389 space = stringline.find_first_of(separators, previousSpace+1);
390 if (space == std::string::npos) {
391 ErrorMsg(mLandmarks.size(),"x position");
394 point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
395 // DD(point.coordinates[0]);
396 previousSpace = space;
397 space = stringline.find_first_of(separators, previousSpace+1);
398 if (space == std::string::npos) {
399 ErrorMsg(mLandmarks.size(),"y position");
402 point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
403 // DD(point.coordinates[1]);
404 previousSpace = space;
405 space = stringline.find_first_of(separators, previousSpace+1);
406 if (space == std::string::npos) {
407 ErrorMsg(mLandmarks.size(),"z position");
410 point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
411 previousSpace = space;
412 point.pixel_value=0.; //Not in file
413 point.coordinates[3]=(float)f; //Not in file
414 point.comments = ""; //Not in file
416 // DD(point.comments);
417 mLandmarks[int(point.coordinates[3])].push_back(point);
418 mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
419 idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
420 point.coordinates[0],point.coordinates[1],point.coordinates[2]);
421 std::string str_vtkIdType; // string which will contain the result
422 std::ostringstream convert; // stream used for the conversion
423 convert << idPoint; // insert the textual representation of 'idPoint' in the characters in the stream
424 str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
425 mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
431 DD("vvLandmarks::LoadPtsFile")
432 if (err > 0 && err == filenames.size())
438 //--------------------------------------------------------------------
440 //--------------------------------------------------------------------
441 bool vvLandmarks::ErrorMsg(int num,const char * text)
443 std::cerr << "error when loading point " << num << " at " << text << std::endl;
446 //--------------------------------------------------------------------
449 //--------------------------------------------------------------------
450 void vvLandmarks::SaveFile(std::string filename)
452 std::string fileContent = "LANDMARKS1\n"; //File format version identification
453 for (unsigned int t = 0; t < mLandmarks.size(); t++) {
454 for (unsigned int i = 0; i < mLandmarks[t].size(); i++) {
455 std::stringstream out;
456 out.imbue(std::locale("C")); //This is to specify that the dot is to be used as the decimal separator
458 << mLandmarks[t][i].coordinates[0] << " "
459 << mLandmarks[t][i].coordinates[1] << " "
460 << mLandmarks[t][i].coordinates[2] << " "
461 << mLandmarks[t][i].coordinates[3] << " "
462 << mLandmarks[t][i].pixel_value << " ";
463 fileContent += out.str();
464 if (mLandmarks[t][i].comments.size() == 0)
467 fileContent += mLandmarks[t][i].comments;
471 std::ofstream fp(filename.c_str(), std::ios::trunc);
473 std::cerr << "Unable to open file" << std::endl;
476 fp << fileContent.c_str()<< std::endl;
479 //--------------------------------------------------------------------
482 //--------------------------------------------------------------------
483 void vvLandmarks::SetTime(int time)
485 if (time >= 0 && time <= ((int)mPoints.size() -1)) {
486 mPolyData->SetPoints(mPoints[time]);
487 mPolyData->GetPointData()->SetScalars(mIds[time]);
488 mPolyData->GetPointData()->AddArray(mLabels[time]);
489 mPolyData->Modified();
490 #if VTK_MAJOR_VERSION <= 5
493 //mPolyData->Update();
498 //--------------------------------------------------------------------
501 //--------------------------------------------------------------------
502 std::string vvLandmarks::replace_dots(std::string input)
504 ///Replaces the dots used in the file with the decimal separator in use on the platform
505 lconv * conv=localeconv();
506 unsigned int position = input.find( "." );
507 while ( position < input.size() ) {
508 input.replace(position, 1, conv->decimal_point);
509 position = input.find( ".", position + 1 );
513 //--------------------------------------------------------------------