ANIMA  4.0
animaShapesReader.cxx
Go to the documentation of this file.
1 #include <animaShapesReader.h>
2 #include <itkMacro.h>
3 
4 #include <vtkPolyDataReader.h>
5 #include <vtkXMLPolyDataReader.h>
6 #include <vtksys/SystemTools.hxx>
7 #include <tinyxml2.h>
8 
9 #include <vtkDoubleArray.h>
10 #include <vtkPointData.h>
11 
12 #include <fstream>
13 #include <algorithm>
14 
15 namespace anima
16 {
17 
19 {
20  std::string extensionName = m_FileName.substr(m_FileName.find_last_of('.') + 1);
21 
22  if (extensionName == "vtk")
23  this->ReadFileAsVTKAscii();
24  else if ((extensionName == "vtp")||(extensionName == ""))
25  {
26  if (extensionName == "")
27  m_FileName += ".vtp";
28  this->ReadFileAsVTKXML();
29  }
30  else if (extensionName == "fds")
32  else if (extensionName == "csv")
33  this->ReadFileAsCSV();
34  else
35  throw itk::ExceptionObject(__FILE__, __LINE__,"Unsupported shapes extension.",ITK_LOCATION);
36 }
37 
39 {
40  vtkSmartPointer <vtkPolyDataReader> vtkReader = vtkPolyDataReader::New();
41  vtkReader->SetFileName(m_FileName.c_str());
42  vtkReader->Update();
43 
44  m_OutputData = vtkSmartPointer <vtkPolyData>::New();
45  m_OutputData->ShallowCopy(vtkReader->GetOutput());
46 }
47 
49 {
50  vtkSmartPointer <vtkXMLPolyDataReader> vtkReader = vtkXMLPolyDataReader::New();
51  vtkReader->SetFileName(m_FileName.c_str());
52  vtkReader->Update();
53 
54  m_OutputData = vtkSmartPointer <vtkPolyData>::New();
55  m_OutputData->ShallowCopy(vtkReader->GetOutput());
56 }
57 
59 {
60  std::replace(m_FileName.begin(),m_FileName.end(),'\\','/');
61 
62  std::string baseName;
63  std::size_t lastSlashPos = m_FileName.find_last_of('/');
64  if (lastSlashPos != std::string::npos)
65  baseName.append(m_FileName.begin(),m_FileName.begin() + lastSlashPos + 1);
66 
67  tinyxml2::XMLDocument doc;
68  tinyxml2::XMLError loadOk = doc.LoadFile(m_FileName.c_str());
69 
70  if (loadOk != tinyxml2::XML_SUCCESS)
71  throw itk::ExceptionObject(__FILE__, __LINE__,"Error reading XML FDS file header",ITK_LOCATION);
72 
73  tinyxml2::XMLElement *vtkFileNode = doc.FirstChildElement("VTKFile");
74  if (!vtkFileNode)
75  throw itk::ExceptionObject(__FILE__, __LINE__,"Malformed FDS file",ITK_LOCATION);
76 
77  tinyxml2::XMLElement *datasetNode = vtkFileNode->FirstChildElement("vtkFiberDataSet");
78  if (!datasetNode)
79  throw itk::ExceptionObject(__FILE__, __LINE__,"Malformed FDS file",ITK_LOCATION);
80 
81  tinyxml2::XMLElement *fibersNode = datasetNode->FirstChildElement("Fibers");
82  std::string vtkFileName = baseName + fibersNode->Attribute("file");
83 
84  std::string extensionName = vtkFileName.substr(vtkFileName.find_last_of('.') + 1);
85 
86  if (extensionName == "vtk")
87  {
88  vtkSmartPointer <vtkPolyDataReader> vtkReader = vtkPolyDataReader::New();
89  vtkReader->SetFileName(vtkFileName.c_str());
90  vtkReader->Update();
91 
92  m_OutputData = vtkSmartPointer <vtkPolyData>::New();
93  m_OutputData->ShallowCopy(vtkReader->GetOutput());
94  }
95  else if (extensionName == "vtp")
96  {
97  vtkSmartPointer <vtkXMLPolyDataReader> vtkReader = vtkXMLPolyDataReader::New();
98  vtkReader->SetFileName(vtkFileName.c_str());
99  vtkReader->Update();
100 
101  m_OutputData = vtkSmartPointer <vtkPolyData>::New();
102  m_OutputData->ShallowCopy(vtkReader->GetOutput());
103  }
104  else
105  throw itk::ExceptionObject(__FILE__, __LINE__,"Unsupported fibers extension inside FDS files.",ITK_LOCATION);
106 }
107 
109 {
110  std::string extension = vtksys::SystemTools::GetFilenameLastExtension(m_FileName);
111  std::ifstream file(m_FileName);
112 
113  if (!file)
114  throw itk::ExceptionObject(__FILE__, __LINE__, "The input file does not exist.", ITK_LOCATION);
115 
116  // Read headers
117  std::vector<std::string> header;
118  std::string file_line;
119  std::getline(file, file_line);
120  std::stringstream iss(file_line);
121  unsigned int numberOfColumns = 0;
122 
123  std::cout << "Header:" << std::endl;
124  while (iss.good())
125  {
126  std::string val;
127  std::getline(iss, val, ',');
128  std::stringstream convertor(val);
129 
130  header.resize(numberOfColumns + 1);
131  convertor >> header[numberOfColumns];
132  std::cout << " " << header[numberOfColumns] << std::endl;
133  ++numberOfColumns;
134  }
135 
136  std::cout << "Number of columns: " << numberOfColumns << std::endl;
137 
138  if (numberOfColumns < 5)
139  throw itk::ExceptionObject(__FILE__, __LINE__, "The CSV should contain at least 5 columns.", ITK_LOCATION);
140 
141  if (header[0] != "X" || header[1] != "Y" || header[2] != "Z" || header[3] != "PointId" || header[4] != "StreamlineId")
142  throw itk::ExceptionObject(__FILE__, __LINE__, "The CSV should contain at least the following first 5 variables in order: X, Y, Z, PointId, StreamlineId.", ITK_LOCATION);
143 
144  std::vector<unsigned int> numberOfComponents;
145  unsigned int pos = 5;
146  while (pos < numberOfColumns)
147  {
148  // Dealing with arrays now
149  if (header[pos].find_last_of("#") == -1) // Array value is scalar
150  {
151  numberOfComponents.push_back(1);
152  ++pos;
153  }
154  else
155  {
156  unsigned int count = 0;
157  while (header[pos+count].find_last_of("#") != -1)
158  ++count;
159  numberOfComponents.push_back(count);
160  pos += count;
161  }
162  }
163 
164  // Retrieve data matrix
165  std::vector< std::vector<double> > data;
166  unsigned int numberOfRows = 0;
167 
168  while (file.good())
169  {
170  data.resize(numberOfRows + 1);
171  data[numberOfRows].resize(numberOfColumns);
172  std::string file_line;
173  std::getline(file, file_line);
174  std::stringstream iss(file_line);
175 
176  for (unsigned int i = 0;i < numberOfColumns;++i)
177  {
178  std::string val;
179  std::getline(iss, val, ',');
180  std::stringstream convertor(val);
181 
182  if (val == "")
183  data[numberOfRows][i] = std::numeric_limits<double>::quiet_NaN();
184  else
185  convertor >> data[numberOfRows][i];
186  }
187 
188  ++numberOfRows;
189  }
190 
191  // ISO standards for CSVs insert a new line at the end of the file as ENDOFFILE
192  // This line has to be removed if present
193 
194  // First, check if the CSV was ISO-formatted or not
195  bool isoFormat = true;
196  for (unsigned int j = 0;j < numberOfColumns;++j)
197  if (!std::isnan(data[numberOfRows - 1][j]))
198  {
199  isoFormat = false;
200  break;
201  }
202 
203  // If ISO standard, do not consider last line
204  if (isoFormat)
205  --numberOfRows;
206 
207  std::cout << "Number of data points: " << numberOfRows << std::endl;
208 
209  // Initialize output polydata object
210  m_OutputData = vtkSmartPointer<vtkPolyData>::New();
211  m_OutputData->Initialize();
212  m_OutputData->Allocate();
213 
214  //--------------------------------
215  // Add geometry to the output polydata object
216  //--------------------------------
217 
218  vtkSmartPointer<vtkPoints> myPoints = vtkSmartPointer<vtkPoints>::New();
219 
220  // Add streamlines
221  unsigned int numberOfStreamlines = data[numberOfRows-1][4];
222  std::cout << "Number of streamlines: " << numberOfStreamlines << std::endl;
223 
224  unsigned int initialPosition = 0;
225  for (unsigned int i = 0;i < numberOfStreamlines;++i)
226  {
227  // Retrieve number of points along i-th streamline
228  unsigned int npts = 0;
229  while (initialPosition + npts < numberOfRows && data[initialPosition+npts][4] == i+1) // numeration in CSV starts at one.
230  ++npts;
231 
232  vtkIdType* ids = new vtkIdType[npts];
233 
234  for (unsigned int j = 0;j < npts;++j)
235  {
236  unsigned int tmpPos = initialPosition + j;
237  ids[j] = myPoints->InsertNextPoint(data[tmpPos][0], data[tmpPos][1], data[tmpPos][2]);
238  }
239 
240  m_OutputData->InsertNextCell(VTK_POLY_LINE, npts, ids);
241  delete[] ids;
242  initialPosition += npts;
243  }
244 
245  m_OutputData->SetPoints(myPoints);
246 
247  // Add array information
248  std::cout << "Number of arrays: " << numberOfComponents.size() << std::endl;
249  pos = 5;
250  unsigned int arrayPos = 0;
251  while (pos < numberOfColumns)
252  {
253  unsigned int nbComponents = numberOfComponents[arrayPos];
254 
255  vtkSmartPointer<vtkDoubleArray> arrayData = vtkSmartPointer<vtkDoubleArray>::New();
256  std::string tmpStr;
257 
258  if (nbComponents == 1)
259  tmpStr = header[pos];
260  else
261  tmpStr = header[pos].substr(0, header[pos].find_last_of("#"));
262 
263  arrayData->SetName(tmpStr.c_str());
264  arrayData->SetNumberOfComponents(nbComponents);
265 
266  for (unsigned int i = 0;i < numberOfRows;++i)
267  for (unsigned int j = 0;j < nbComponents;++j)
268  arrayData->InsertNextValue(data[i][pos+j]);
269 
270  m_OutputData->GetPointData()->AddArray(arrayData);
271  pos += nbComponents;
272  ++arrayPos;
273  }
274 }
275 
276 } // end namespace anima