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 //--------------------------------------------------------------------
147 //--------------------------------------------------------------------
148 void vvLandmarks::ChangeComments(int index, std::string comments)
150 mLandmarks[mTime][index].comments = comments;
152 //--------------------------------------------------------------------
155 //--------------------------------------------------------------------
156 double vvLandmarks::GetPixelValue(int index)
158 return mLandmarks[mTime][index].pixel_value;
160 //--------------------------------------------------------------------
163 //--------------------------------------------------------------------
164 float* vvLandmarks::GetCoordinates(int index)
166 return mLandmarks[mTime][index].coordinates;
168 //--------------------------------------------------------------------
171 //--------------------------------------------------------------------
172 std::string vvLandmarks::GetComments(int index)
174 return mLandmarks[mTime][index].comments;
176 //--------------------------------------------------------------------
179 //--------------------------------------------------------------------
180 bool vvLandmarks::LoadFile(std::vector<std::string> filenames)
182 // all files in the sequence must be of the same type
183 std::string extension = itksys::SystemTools::GetFilenameExtension(filenames[0]);
184 if (extension == ".txt")
185 return LoadTxtFile(filenames);
186 else if (extension == ".pts")
187 return LoadPtsFile(filenames);
192 //--------------------------------------------------------------------
193 bool vvLandmarks::LoadTxtFile(std::vector<std::string> filenames)
195 mFilenames = filenames;
196 for (unsigned int i = 0; i < mPoints.size(); i++) {
197 mLandmarks[i].clear();
198 mPoints[i]->SetNumberOfPoints(0);
202 for (unsigned int f = 0; f < filenames.size(); f++) {
203 std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
205 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
210 bool first_line=true;
211 while (fp.getline(line,255)) {
213 std::string stringline = line;
218 ///New landmark format: first line is "LANDMARKSXX", where XX is the version number
219 if (stringline.size() >= 10 && stringline.compare(0,9,"LANDMARKS")==0) {
220 std::istringstream ss(stringline.c_str()+9);
221 ss >> mFormatVersion;
222 continue; //skip first line
226 if (stringline.size() > 1) {
228 int previousSpace = 0;
230 if (mFormatVersion>0) {
231 space = stringline.find(" ", previousSpace+1);
232 if (space < -1 || space > (int)stringline.size()) {
233 ErrorMsg(mLandmarks.size(),"index");
236 //int index = atoi(stringline.substr(previousSpace,space - previousSpace).c_str());
237 previousSpace = space;
239 space = stringline.find(" ", previousSpace+1);
240 if (space < -1 || space > (int)stringline.size()) {
241 ErrorMsg(mLandmarks.size(),"x position");
244 point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
245 // DD(point.coordinates[0]);
246 previousSpace = space;
247 space = stringline.find(" ", previousSpace+1);
248 if (space < -1 || space > (int)stringline.size()) {
249 ErrorMsg(mLandmarks.size(),"y position");
252 point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
253 // DD(point.coordinates[1]);
254 previousSpace = space;
255 space = stringline.find(" ", previousSpace+1);
256 if (space < -1 || space > (int)stringline.size()) {
257 ErrorMsg(mLandmarks.size(),"z position");
260 point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
261 previousSpace = space;
262 if (mFormatVersion>0) {
263 space = stringline.find(" ", previousSpace+1);
264 if (space < -1 || space > (int)stringline.size()) {
265 ErrorMsg(mLandmarks.size(),"t position");
268 point.coordinates[3] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
269 previousSpace = space;
270 space = stringline.find(" ", previousSpace+1);
271 if (space < -1 || space > (int)stringline.size()) {
272 ErrorMsg(mLandmarks.size(),"pixel value");
275 point.pixel_value = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
276 // DD(point.pixel_value);
278 point.pixel_value=0.; //Not in file
279 point.coordinates[3]=(float)f;
281 previousSpace = space;
282 //this is the maximum size of comments
283 space = (stringline.find("\n", previousSpace+1) < 254 ? stringline.find("\n", previousSpace+1) : 254);
284 if (previousSpace != -1) {
285 point.comments = stringline.substr(previousSpace,space - (previousSpace)).c_str();
287 // DD(point.comments);
288 mLandmarks[int(point.coordinates[3])].push_back(point);
289 mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
290 idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
291 point.coordinates[0],point.coordinates[1],point.coordinates[2]);
292 std::string str_vtkIdType; // string which will contain the result
293 std::ostringstream convert; // stream used for the conversion
294 convert << idPoint; // insert the textual representation of 'idPoint' in the characters in the stream
295 str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
296 mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
301 if (err > 0 && err == filenames.size())
308 //--------------------------------------------------------------------
310 //--------------------------------------------------------------------
311 bool vvLandmarks::LoadPtsFile(std::vector<std::string> filenames)
313 mFilenames = filenames;
314 for (unsigned int i = 0; i < mPoints.size(); i++) {
315 mPoints[i]->SetNumberOfPoints(0);
316 mLandmarks[i].clear();
320 for (unsigned int f = 0; f < filenames.size(); f++) {
321 std::ifstream fp(filenames[f].c_str(), std::ios::in|std::ios::binary);
323 std::cerr <<"Unable to open file " << filenames[f] << std::endl;
328 bool first_line=true;
329 while (fp.getline(line,255)) {
330 std::string stringline = line;
333 std::string separators = "\t\n\r ";
334 if (stringline.size() > 1) {
336 int previousSpace = 0;
339 if (stringline[0] == '#') // comments
342 space = stringline.find_first_of(separators, previousSpace+1);
343 if (space == std::string::npos) {
344 ErrorMsg(mLandmarks.size(),"x position");
347 point.coordinates[0] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
348 // DD(point.coordinates[0]);
349 previousSpace = space;
350 space = stringline.find_first_of(separators, previousSpace+1);
351 if (space == std::string::npos) {
352 ErrorMsg(mLandmarks.size(),"y position");
355 point.coordinates[1] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
356 // DD(point.coordinates[1]);
357 previousSpace = space;
358 space = stringline.find_first_of(separators, previousSpace+1);
359 if (space == std::string::npos) {
360 ErrorMsg(mLandmarks.size(),"z position");
363 point.coordinates[2] = atof(replace_dots(stringline.substr(previousSpace,space - previousSpace)).c_str());
364 previousSpace = space;
365 point.pixel_value=0.; //Not in file
366 point.coordinates[3]=(float)f; //Not in file
367 point.comments = ""; //Not in file
369 // DD(point.comments);
370 mLandmarks[int(point.coordinates[3])].push_back(point);
371 mIds[int(point.coordinates[3])]->InsertNextTuple1(0.55);
372 idPoint = mPoints[int(point.coordinates[3])]->InsertNextPoint(
373 point.coordinates[0],point.coordinates[1],point.coordinates[2]);
374 std::string str_vtkIdType; // string which will contain the result
375 std::ostringstream convert; // stream used for the conversion
376 convert << idPoint; // insert the textual representation of 'idPoint' in the characters in the stream
377 str_vtkIdType = convert.str(); // set 'str_vtkIdType' to the contents of the stream
378 mLabels[int(point.coordinates[3])]->InsertNextValue(str_vtkIdType.c_str());
384 DD("vvLandmarks::LoadPtsFile")
385 if (err > 0 && err == filenames.size())
391 //--------------------------------------------------------------------
393 //--------------------------------------------------------------------
394 bool vvLandmarks::ErrorMsg(int num,const char * text)
396 std::cerr << "error when loading point " << num << " at " << text << std::endl;
399 //--------------------------------------------------------------------
402 //--------------------------------------------------------------------
403 void vvLandmarks::SaveFile(std::string filename)
405 std::string fileContent = "LANDMARKS1\n"; //File format version identification
406 for (unsigned int t = 0; t < mLandmarks.size(); t++) {
407 for (unsigned int i = 0; i < mLandmarks[t].size(); i++) {
408 std::stringstream out;
409 out.imbue(std::locale("C")); //This is to specify that the dot is to be used as the decimal separator
411 << mLandmarks[t][i].coordinates[0] << " "
412 << mLandmarks[t][i].coordinates[1] << " "
413 << mLandmarks[t][i].coordinates[2] << " "
414 << mLandmarks[t][i].coordinates[3] << " "
415 << mLandmarks[t][i].pixel_value << " ";
416 fileContent += out.str();
417 if (mLandmarks[t][i].comments.size() == 0)
420 fileContent += mLandmarks[t][i].comments;
424 std::ofstream fp(filename.c_str(), std::ios::trunc);
426 std::cerr << "Unable to open file" << std::endl;
429 fp << fileContent.c_str()<< std::endl;
432 //--------------------------------------------------------------------
435 //--------------------------------------------------------------------
436 void vvLandmarks::SetTime(int time)
438 if (time >= 0 && time <= ((int)mPoints.size() -1)) {
439 mPolyData->SetPoints(mPoints[time]);
440 mPolyData->GetPointData()->SetScalars(mIds[time]);
441 mPolyData->GetPointData()->AddArray(mLabels[time]);
442 mPolyData->Modified();
447 //--------------------------------------------------------------------
450 //--------------------------------------------------------------------
451 std::string vvLandmarks::replace_dots(std::string input)
453 ///Replaces the dots used in the file with the decimal separator in use on the platform
454 lconv * conv=localeconv();
455 unsigned int position = input.find( "." );
456 while ( position < input.size() ) {
457 input.replace(position, 1, conv->decimal_point);
458 position = input.find( ".", position + 1 );
462 //--------------------------------------------------------------------