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 "vtkPolyData.h"
27 #include "vtkPoints.h"
28 #include "vtkFloatArray.h"
29 #include "vtkPointData.h"
30 #include "clitkCommon.h"
31 #include <itksys/SystemTools.hxx>
33 //--------------------------------------------------------------------
34 vvLandmarks::vvLandmarks(int size)
36 mLandmarks.resize(size);
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");
48 mPolyData = vtkPolyData::New();
50 //--------------------------------------------------------------------
53 //--------------------------------------------------------------------
54 vvLandmarks::~vvLandmarks()
56 for (unsigned int i = 0; i < mPoints.size(); i++) {
61 /*for(unsigned int i = 0; i < mText.size(); i++) {
67 //--------------------------------------------------------------------
70 //--------------------------------------------------------------------
71 void vvLandmarks::AddLandmark(float x,float y,float z,float t,double value)
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);
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());
89 std::stringstream numberVal;
90 numberVal << (mLandmarks.size()-1);
92 vvLandmarksGlyph *number = vvLandmarksGlyph::New();
93 number->SetText(numberVal.str().c_str());
95 DD(numberVal.str().c_str());
96 mText.push_back(number);
99 mIds[mTime]->InsertNextTuple1(0.55);
100 //mIds->InsertTuple1(mLandmarks.size(),mLandmarks.size());
103 //--------------------------------------------------------------------
106 //--------------------------------------------------------------------
107 void vvLandmarks::RemoveLastLandmark()
109 mPoints[mTime]->SetNumberOfPoints(mPoints[mTime]->GetNumberOfPoints()-1);
111 mLandmarks[mTime].pop_back();
112 mIds[mTime]->RemoveLastTuple();
113 mLabels[mTime]->SetNumberOfValues(mLabels[mTime]->GetNumberOfValues()-1);
114 mLabels[mTime]->Modified();
115 mPolyData->Modified();
117 //--------------------------------------------------------------------
120 //--------------------------------------------------------------------
121 void vvLandmarks::RemoveLandmark(int index)
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());
136 mPoints[t]->SetNumberOfPoints(npoints-1);
137 mLabels[t]->SetNumberOfValues(npoints-1);
138 mLabels[t]->Modified();
139 mPolyData->Modified();
141 mLandmarks[t].erase(mLandmarks[t].begin() + index);
142 mIds[t]->RemoveLastTuple();
144 //--------------------------------------------------------------------
146 //--------------------------------------------------------------------
147 void vvLandmarks::RemoveAll()
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);
156 //--------------------------------------------------------------------
158 //--------------------------------------------------------------------
159 void vvLandmarks::ChangeComments(int index, std::string comments)
161 mLandmarks[mTime][index].comments = comments;
163 //--------------------------------------------------------------------
166 //--------------------------------------------------------------------
167 double vvLandmarks::GetPixelValue(int index)
169 return mLandmarks[mTime][index].pixel_value;
171 //--------------------------------------------------------------------
174 //--------------------------------------------------------------------
175 float* vvLandmarks::GetCoordinates(int index)
177 return mLandmarks[mTime][index].coordinates;
179 //--------------------------------------------------------------------
182 //--------------------------------------------------------------------
183 std::string vvLandmarks::GetComments(int index)
185 return mLandmarks[mTime][index].comments;
187 //--------------------------------------------------------------------
190 //--------------------------------------------------------------------
191 bool vvLandmarks::LoadFile(std::vector<std::string> filenames)
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);
203 //--------------------------------------------------------------------
204 bool vvLandmarks::LoadTxtFile(std::vector<std::string> filenames)
206 mFilenames = filenames;
207 for (unsigned int i = 0; i < mPoints.size(); i++) {
208 mLandmarks[i].clear();
209 mPoints[i]->SetNumberOfPoints(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);
216 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
221 bool first_line=true;
222 while (fp.getline(line,255)) {
224 std::string stringline = line;
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
237 if (stringline.size() > 1) {
239 int previousSpace = 0;
241 if (mFormatVersion>0) {
242 space = stringline.find(" ", previousSpace+1);
243 if (space < -1 || space > (int)stringline.size()) {
244 ErrorMsg(mLandmarks.size(),"index");
247 //int index = atoi(stringline.substr(previousSpace,space - previousSpace).c_str());
248 previousSpace = space;
250 space = stringline.find(" ", previousSpace+1);
251 if (space < -1 || space > (int)stringline.size()) {
252 ErrorMsg(mLandmarks.size(),"x position");
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");
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");
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");
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");
286 point.pixel_value = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
287 // DD(point.pixel_value);
289 point.pixel_value=0.; //Not in file
290 point.coordinates[3]=(float)f;
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();
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());
312 if (err > 0 && err == filenames.size())
319 //--------------------------------------------------------------------
321 //--------------------------------------------------------------------
322 bool vvLandmarks::LoadPtsFile(std::vector<std::string> filenames)
324 mFilenames = filenames;
325 for (unsigned int i = 0; i < mPoints.size(); i++) {
326 mPoints[i]->SetNumberOfPoints(0);
327 mLandmarks[i].clear();
331 for (unsigned int f = 0; f < filenames.size(); f++) {
332 std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
334 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
339 bool first_line=true;
340 while (fp.getline(line,255)) {
341 std::string stringline = line;
344 std::string separators = "\t\n\r ";
345 if (stringline.size() > 1) {
347 int previousSpace = 0;
350 if (stringline[0] == '#') // comments
353 space = stringline.find_first_of(separators, previousSpace+1);
354 if (space == std::string::npos) {
355 ErrorMsg(mLandmarks.size(),"x position");
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");
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");
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
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());
395 DD("vvLandmarks::LoadPtsFile")
396 if (err > 0 && err == filenames.size())
402 //--------------------------------------------------------------------
404 //--------------------------------------------------------------------
405 bool vvLandmarks::ErrorMsg(int num,const char * text)
407 std::cerr << "error when loading point " << num << " at " << text << std::endl;
410 //--------------------------------------------------------------------
413 //--------------------------------------------------------------------
414 void vvLandmarks::SaveFile(std::string filename)
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
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)
431 fileContent += mLandmarks[t][i].comments;
435 std::ofstream fp(filename.c_str(), std::ios::trunc);
437 std::cerr << "Unable to open file" << std::endl;
440 fp << fileContent.c_str()<< std::endl;
443 //--------------------------------------------------------------------
446 //--------------------------------------------------------------------
447 void vvLandmarks::SetTime(int time)
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();
458 //--------------------------------------------------------------------
461 //--------------------------------------------------------------------
462 std::string vvLandmarks::replace_dots(std::string input)
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 );
473 //--------------------------------------------------------------------