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);
38 mLandmarksInitial.resize(size);
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");
51 mPolyData = vtkPolyData::New();
53 //--------------------------------------------------------------------
56 //--------------------------------------------------------------------
57 vvLandmarks::~vvLandmarks()
59 for (unsigned int i = 0; i < mPoints.size(); i++) {
64 /*for(unsigned int i = 0; i < mText.size(); i++) {
70 //--------------------------------------------------------------------
73 //--------------------------------------------------------------------
74 void vvLandmarks::AddLandmark(float x,float y,float z,float t,double value)
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);
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());
93 std::stringstream numberVal;
94 numberVal << (mLandmarks.size()-1);
96 vvLandmarksGlyph *number = vvLandmarksGlyph::New();
97 number->SetText(numberVal.str().c_str());
99 DD(numberVal.str().c_str());
100 mText.push_back(number);
103 mIds[mTime]->InsertNextTuple1(0.55);
104 //mIds->InsertTuple1(mLandmarks.size(),mLandmarks.size());
107 //--------------------------------------------------------------------
109 //--------------------------------------------------------------------
110 void vvLandmarks::TransformUpdate(vtkAbstractTransform* transform)
112 //For all Time, For all landmarks, I apply the transform
113 for(int time=0; time<mLandmarks.size(); ++time)
115 for(int landmark=0; landmark<mLandmarks[time].size(); ++landmark)
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);
123 mLandmarks[time][landmark].coordinates[0]= ptAfterTransform[0];
124 mLandmarks[time][landmark].coordinates[1]= ptAfterTransform[1];
125 mLandmarks[time][landmark].coordinates[2]= ptAfterTransform[2];
129 //--------------------------------------------------------------------
131 //--------------------------------------------------------------------
132 void vvLandmarks::RemoveLastLandmark()
134 mPoints[mTime]->SetNumberOfPoints(mPoints[mTime]->GetNumberOfPoints()-1);
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();
143 //--------------------------------------------------------------------
146 //--------------------------------------------------------------------
147 void vvLandmarks::RemoveLandmarkWithLabel(vtkStdString label, int time)
149 if (label != "P1" && label != "P2")
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();
157 //search of the index corresponding to the label
159 while (mLabels[t]->GetValue(index) != label)
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));
170 mPoints[t]->SetNumberOfPoints(npoints-1);
171 mLabels[t]->SetNumberOfValues(npoints-1);
172 mLabels[t]->Modified();
173 mPolyData->Modified();
175 mLandmarks[t].erase(mLandmarks[t].begin() + index);
176 mLandmarksInitial[t].erase(mLandmarksInitial[t].begin() + index);
177 mIds[t]->RemoveLastTuple();
179 //--------------------------------------------------------------------
182 //--------------------------------------------------------------------
183 void vvLandmarks::RemoveLandmark(int index)
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());
198 mPoints[t]->SetNumberOfPoints(npoints-1);
199 mLabels[t]->SetNumberOfValues(npoints-1);
200 mLabels[t]->Modified();
201 mPolyData->Modified();
203 mLandmarks[t].erase(mLandmarks[t].begin() + index);
204 mLandmarksInitial[t].erase(mLandmarksInitial[t].begin() + index);
205 mIds[t]->RemoveLastTuple();
207 //--------------------------------------------------------------------
209 //--------------------------------------------------------------------
210 void vvLandmarks::RemoveAll()
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);
220 //--------------------------------------------------------------------
222 //--------------------------------------------------------------------
223 void vvLandmarks::ChangeComments(int index, std::string comments)
225 mLandmarks[mTime][index].comments = comments;
226 mLandmarksInitial[mTime][index].comments = comments;
228 //--------------------------------------------------------------------
231 //--------------------------------------------------------------------
232 double vvLandmarks::GetPixelValue(int index)
234 return mLandmarks[mTime][index].pixel_value;
236 //--------------------------------------------------------------------
239 //--------------------------------------------------------------------
240 float* vvLandmarks::GetCoordinates(int index)
242 return mLandmarks[mTime][index].coordinates;
244 //--------------------------------------------------------------------
247 //--------------------------------------------------------------------
248 std::string vvLandmarks::GetComments(int index)
250 return mLandmarks[mTime][index].comments;
252 //--------------------------------------------------------------------
255 //--------------------------------------------------------------------
256 bool vvLandmarks::LoadFile(std::vector<std::string> filenames)
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);
268 //--------------------------------------------------------------------
269 bool vvLandmarks::LoadTxtFile(std::vector<std::string> filenames)
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);
279 for (unsigned int f = 0; f < filenames.size(); f++) {
280 std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
282 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
287 bool first_line=true;
288 while (fp.getline(line,255)) {
290 std::string stringline = line;
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
303 if (stringline.size() > 1) {
305 int previousSpace = 0;
307 if (mFormatVersion>0) {
308 space = stringline.find(" ", previousSpace+1);
309 if (space < -1 || space > (int)stringline.size()) {
310 ErrorMsg(mLandmarks.size(),"index");
313 //int index = atoi(stringline.substr(previousSpace,space - previousSpace).c_str());
314 previousSpace = space;
316 space = stringline.find(" ", previousSpace+1);
317 if (space < -1 || space > (int)stringline.size()) {
318 ErrorMsg(mLandmarks.size(),"x position");
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");
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");
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");
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");
352 point.pixel_value = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
353 // DD(point.pixel_value);
355 point.pixel_value=0.; //Not in file
356 point.coordinates[3]=(float)f;
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();
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());
379 if (err > 0 && err == filenames.size())
386 //--------------------------------------------------------------------
388 //--------------------------------------------------------------------
389 bool vvLandmarks::LoadPtsFile(std::vector<std::string> filenames)
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();
399 for (unsigned int f = 0; f < filenames.size(); f++) {
400 std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
402 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
407 bool first_line=true;
408 while (fp.getline(line,255)) {
409 std::string stringline = line;
412 std::string separators = "\t\n\r ";
413 if (stringline.size() > 1) {
415 int previousSpace = 0;
418 if (stringline[0] == '#') // comments
421 space = stringline.find_first_of(separators, previousSpace+1);
422 if (space == std::string::npos) {
423 ErrorMsg(mLandmarks.size(),"x position");
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");
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");
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
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());
464 DD("vvLandmarks::LoadPtsFile")
465 if (err > 0 && err == filenames.size())
471 //--------------------------------------------------------------------
473 //--------------------------------------------------------------------
474 bool vvLandmarks::ErrorMsg(int num,const char * text)
476 std::cerr << "error when loading point " << num << " at " << text << std::endl;
479 //--------------------------------------------------------------------
482 //--------------------------------------------------------------------
483 void vvLandmarks::SaveFile(std::string filename)
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
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)
500 fileContent += mLandmarksInitial[t][i].comments;
504 std::ofstream fp(filename.c_str(), std::ios::trunc);
506 std::cerr << "Unable to open file" << std::endl;
509 fp << fileContent.c_str()<< std::endl;
512 //--------------------------------------------------------------------
515 //--------------------------------------------------------------------
516 void vvLandmarks::SetTime(int time)
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
526 //mPolyData->Update();
531 //--------------------------------------------------------------------
534 //--------------------------------------------------------------------
535 std::string vvLandmarks::replace_dots(std::string input)
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 );
546 //--------------------------------------------------------------------