$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
vtk/load.hh
1 // Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
2 //
3 // This file is part of Olena.
4 //
5 // Olena is free software: you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation, version 2 of the License.
8 //
9 // Olena is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // As a special exception, you may use this file as part of a free
18 // software project without restriction. Specifically, if other files
19 // instantiate templates or use macros or inline functions from this
20 // file, or you compile this file and link it with other files to produce
21 // an executable, this file does not by itself cause the resulting
22 // executable to be covered by the GNU General Public License. This
23 // exception does not however invalidate any other reasons why the
24 // executable file might be covered by the GNU General Public License.
25 
26 #ifndef MLN_IO_VTK_LOAD_HH
27 # define MLN_IO_VTK_LOAD_HH
28 
37 
38 # include <cstdlib>
39 # include <iostream>
40 # include <fstream>
41 # include <sstream>
42 # include <string>
43 
44 # include <mln/core/alias/complex_image.hh>
45 
46 
47 namespace mln
48 {
49 
50  namespace io
51  {
52 
53  namespace vtk
54  {
55 
61  void load(bin_2complex_image3df& ima, const std::string& filename);
62 
63 
64 
65 # ifndef MLN_INCLUDE_ONLY
66 
67  // FIXME: To be put elsewehre (factored), or encapsulated in a
68  // class containing the `load' routine as well.
69  namespace internal
70  {
71 
72  inline
73  void
74  error(const std::string& caller, const std::string& filename,
75  const std::string& message)
76  {
77  std::cerr << caller << ": `" << filename << "': "
78  << message << std::endl;
79  std::exit(1);
80  }
81 
82  inline
83  void
84  accept(const std::string& token, const std::string& expected,
85  const std::string& caller, const std::string& filename,
86  const std::string& message)
87  {
88  if (token != expected)
89  error(caller, filename, message);
90  }
91 
92  // Likewise, with default message.
93  inline
94  void
95  accept(const std::string& token, const std::string& expected,
96  const std::string& caller, const std::string& filename)
97  {
98  accept(token, expected, caller, filename,
99  std::string("parse error (`") + expected + "' expected, "
100  + "got `" + token + "').");
101  }
102 
103  // FIXME: To be moved elsewhere.
105  template <typename T>
106  std::string
107  str(const T& x)
108  {
109  std::stringstream s;
110  s << x;
111  return s.str();
112  }
113 
114  } // end of namespace mln::io::vtk::internal
115 
116 
117  inline
118  void
119  load(bin_2complex_image3df& ima, const std::string& filename)
120  {
121  typedef bin_2complex_image3df I;
122 
123  const std::string me = "mln::io::off::load";
124 
125  std::ifstream istr(filename.c_str());
126  if (!istr)
127  {
128  std::cerr << me << ": `" << filename << "' not found."
129  << std::endl;
130  /* FIXME: Too violent. We should allow the use of
131  exceptions, at least to have Milena's code behave
132  correctly in interpreted environments (std::exit() or
133  std::abort() causes the termination of a Python
134  interpreter, for instance!). */
135  std::exit(1);
136  }
137 
138  /*---------.
139  | Header. |
140  `---------*/
141 
142  /* ``The legacy VTK file formats consist of five basic
143  parts.'' */
144 
145  /* ``1. The first part is the file version and
146  identifier. This part contains the single line:
147 
148  # vtk DataFile Version x.x.
149 
150  This line must be exactly as shown with the
151  exception of the version number x.x, which will vary
152  with different releases of VTK. (Note: the current
153  version number is 3.0. Version 1.0 and 2.0 files are
154  compatible with version 3.0 files.)'' */
155  std::string version;
156  std::getline(istr, version);
157  // FIXME: Check the format of VERSION.
158 
159  /* ``2. The second part is the header. The header consists
160  of a character string terminated by end-of-line
161  character `\n'. The header is 256 characters
162  maximum. The header can be used to describe the data
163  and include any other pertinent information.'' */
164  std::string header;
165  std::getline(istr, header);
166 
167  /* ``3. The next part is the file format. The file format
168  describes the type of file, either ASCII or
169  binary. On this line the single word ASCII or BINARY
170  must appear.'' */
171  std::string format;
172  istr >> format;
173  if (format == "BINARY")
174  internal::error(me, filename,
175  "`BINARY' VTK format is not supported "
176  "(only `ASCII' is supported yet).");
177  else if (format != "ASCII")
178  internal::error(me, filename,
179  std::string("invalid file format: `")
180  + format + "'.");
181 
182  /*-------.
183  | Data. |
184  `-------*/
185 
186  /* ``4. The fourth part is the dataset structure. The
187  geometry part describes the geometry and topology of
188  the dataset. This part begins with a line containing
189  the keyword DATASET followed by a keyword describing
190  the type of dataset. Then, depending upon the type
191  of dataset, other keyword/data combinations define
192  the actual data.''
193 
194  [...]
195 
196  Dataset Format. The Visualization Toolkit supports
197  five different dataset formats: structured points,
198  structured grid, rectilinear grid, unstructured
199  grid, and polygonal data.'' */
200 
201  std::string dataset_keyword, dataset_type;
202  istr >> dataset_keyword >> dataset_type;
203  internal::accept(dataset_keyword, "DATASET", me, filename);
204  internal::accept(dataset_type, "POLYDATA", me, filename,
205  "unsupported dataset structure "
206  "(only `POLYDATA' is supported yet).");
207 
208  // --------- //
209  // Complex. //
210  // --------- //
211 
212  const unsigned D = 2;
213  topo::complex<D> c;
214 
215  /* ``* Polygonal Data
216  The polygonal dataset consists of arbitrary
217  combinations of surface graphics primitives
218  vertices (and polyvertices), lines (and
219  polylines), polygons (of various types), and
220  triangle strips. Polygonal data is defined by
221  the POINTS, VERTICES, LINES, POLYGONS, or
222  TRIANGLE_STRIPS sections. The POINTS definition
223  is the same as we saw for structured grid
224  datasets.'' */
225 
226  // ----------------------------------------- //
227  // Vertices and geometry (point locations). //
228  // ----------------------------------------- //
229 
230  std::string points_keyword;
231  unsigned npoints;
232  std::string points_datatype;
233  istr >> points_keyword >> npoints >> points_datatype;
234  internal::accept(points_keyword, "POINTS", me, filename);
235  internal::accept(points_datatype, "float", me, filename,
236  "unsupported points data type "
237  "(only `float' is supported yet).");
238 
239  typedef point3df P;
240  typedef mln_coord_(P) C;
241  typedef mln_geom_(I) G;
242  G geom;
243  geom.reserve(npoints);
244  for (unsigned i = 0; i < npoints; ++i)
245  {
246  // Create a 0-face.
247  c.add_face();
248 
249  // Record the geometry (point) associated to this vertex.
250  C x, y, z;
251  istr >> x >> y >> z;
252  geom.add_location(P(x, y, z));
253  }
254 
255  /* ``The VERTICES, LINES, POLYGONS, or
256  TRIANGLE_STRIPS keywords define the polygonal
257  dataset topology. Each of these keywords
258  requires two parameters: the number of cells `n'
259  and the size of the cell list `size'. The cell
260  list size is the total number of integer values
261  required to represent the list (i.e., sum of
262  `numPoints' and connectivity indices over each
263  cell). None of the keywords VERTICES, LINES,
264  POLYGONS, or TRIANGLE_STRIPS is required.'' */
265 
266  // ---------- //
267  // Vertices. //
268  // ---------- //
269 
270  /* FIXME: Add another constraint: a bijection between
271  VERTICES and POINTS shall exist. Update the following
272  comment accordingly. */
273 
274  /* The VTK file format contains both a POINTS and a VERTICES
275  section. Despite its name, the former is used to create
276  the set of vertices of the complex (because POINTS are
277  later used to form line (edges) and polygons. The latter
278  (VERTICES) is used to attach values (data) to 0-faces,
279  and act as an indirection toward POINTS. The fact is,
280  most VTK file we use have a VERTICES section where the
281  N-th line (starting at 0) contains
282 
283  1 N
284 
285  which makes the VERTICES section kind of useless.
286  However, we have to parse it and take it into account for
287  the sake of the file format. */
288 
289  std::string vertices_keyword;
290  unsigned nvertices, vertices_size;
291  istr >> vertices_keyword >> nvertices >> vertices_size;
292  internal::accept(vertices_keyword, "VERTICES", me, filename);
293 
294  /* Each vertex requires two numbers: the cardinal of
295  its ends (which is always 1) and the indices of the
296  point among the POINTS section. Hence the total
297  number of values in the VERTEX section is
298  nvertices * 2. */
299  // FIXME: This test is not really robust: we should involve
300  // the VERTICES_SIZE value in the parsing process.
301  if (vertices_size != nvertices * 2)
302  internal::error(me, filename, "ill-formed `VERTICES' section.");
303 
304  // Vertices built on points.
305  std::vector<unsigned> vertices;
306  vertices.reserve(npoints);
307  for (unsigned i = 0; i < nvertices; ++i)
308  {
309  unsigned numpoints, p;
310  istr >> numpoints >> p;
311  if (numpoints != 1)
312  internal::error(me, filename, "ill-formed vertex item.");
313  if (p > npoints)
314  internal::error(me, filename,
315  "point id out of bounds in vertex item.");
316  vertices.push_back(p);
317  }
318 
319  // ------- //
320  // Edges. //
321  // ------- //
322 
323  std::string lines_keyword;
324  unsigned nedges, edges_size;
325  istr >> lines_keyword >> nedges >> edges_size;
326  internal::accept(lines_keyword, "LINES", me, filename);
327 
328  /* Each edge requires three numbers: the cardinal of
329  its ends (which is always 2) and the indices of
330  these ends among the POINTS section. Hence the
331  total number of values in the LINES section is
332  nedges * 3. */
333  // FIXME: This test is not really robust: we should involve
334  // the EDGES_SIZE value in the parsing process.
335  if (edges_size != nedges * 3)
336  internal::error(me, filename, "ill-formed `LINES' section.");
337 
338  // An adjacenty matrix recording the edges seen so far.
339  typedef std::vector< std::vector<bool> > complex_edges_t;
340  complex_edges_t complex_edges (npoints,
341  std::vector<bool>(npoints, false));
342 
343  // Populate the complex and the adjacency matrix
344  for (unsigned i = 0; i < nedges; ++i)
345  {
346  // Create a 1-face.
347  unsigned numpoints, p1, p2;
348  istr >> numpoints >> p1 >> p2;
349  if (numpoints != 2)
350  internal::error(me, filename, "ill-formed line item.");
351  if (p1 > npoints || p2 > npoints)
352  internal::error(me, filename,
353  "point id out of bounds in line item.");
354  topo::n_face<0, D> v1(c, p1);
355  topo::n_face<0, D> v2(c, p2);
356  c.add_face(v1 - v2);
357  // Tag this edged (and its opposite) in the adjacency matrix.
358  complex_edges[p1][p2] = true;
359  complex_edges[p2][p1] = true;
360  }
361 
362  // ---------- //
363  // Polygons. //
364  // ---------- //
365 
366  std::string polygons_keyword;
367  unsigned npolygons, polygons_size;
368  istr >> polygons_keyword >> npolygons >> polygons_size;
369  internal::accept(polygons_keyword, "POLYGONS", me, filename);
370 
371  // Read polygon values.
372  unsigned npolygons_values = 0;
373 
374  for (unsigned i = 0; i < npolygons; ++i)
375  {
376  unsigned numpoints;
377  istr >> numpoints;
378  ++npolygons_values;
379  if (numpoints <= 2)
380  {
381  internal::error(me, filename,
382  std::string("ill-formed face (having ")
383  + internal::str(numpoints)
384  + (numpoints < 2 ? "vertex" : "vertices")
385  + ").");
386  }
387 
388  /* FIXME: This part (computing the set of edges on which
389  a polygon is built) is also shared by
390  mln::io::off::load; we can probably factor it. */
391 
392  // The edges of the face.
393  topo::n_faces_set<1, D> face_edges_set;
394  face_edges_set.reserve(numpoints);
395 
396  // Remember the first point id of the face.
397  unsigned first_point_id;
398  istr >> first_point_id;
399  ++npolygons_values;
400  // The current point id, initialized with the first id.
401  unsigned point_id = first_point_id;
402  if (point_id >= npoints)
403  internal::error(me, filename,
404  std::string("invalid point id: `")
405  + internal::str(point_id) + "'.");
406  for (unsigned p = 0; p < numpoints; ++p)
407  {
408  /* The next point id. The pair (point_id,
409  next_point_id) is an edge of the
410  mesh/complex. */
411  unsigned next_point_id;
412  /* When P is the id of the last point of the face,
413  set NEXT_POINT_ID to FIRST_VERTEX_ID; otherwise,
414  read it from the input. */
415  if (p == numpoints - 1)
416  next_point_id = first_point_id;
417  else
418  {
419  istr >> next_point_id;
420  ++npolygons_values;
421  if (next_point_id >= npoints)
422  internal::error(me, filename,
423  std::string("invalid point id: `")
424  // In-line ``itoa'' of NEXT_POINT_ID.
425  + internal::str(next_point_id) + "'.");
426  }
427  // The ends of the current edge.
428  topo::n_face<0, D> vertex(c, point_id);
429  topo::n_face<0, D> next_vertex(c, next_point_id);
430  // The current edge.
431  topo::algebraic_n_face<1, D> edge;
432  /* The edge (POINT_ID, NEXT_POINT_ID) (or its
433  opposite (NEXT_POINT_ID, POINT_ID) must have been
434  inserted previously. In other words, the sides
435  of POLYGON items must belong to the list of
436  LINES. */
437  if (!complex_edges[point_id][next_point_id])
438  internal::error(me, filename,
439  "ill-formed polygon, having a side "
440  "(edge) not part of the list of LINES.");
441  edge = topo::edge(vertex, next_vertex);
442  mln_assertion(edge.is_valid());
443  // Add this edge a side of the polygon.
444  face_edges_set += edge;
445  // Next vertex.
446  point_id = next_point_id;
447  }
448 
449  // Add face.
450  c.add_face(face_edges_set);
451  }
452 
453  // FIXME: This test is not really robust: we should involve
454  // the POLYGONS_SIZE value in the parsing process.
455  if (polygons_size != npolygons_values)
456  internal::error(me, filename, "ill-formed `LINES' section.");
457 
458  // -------------------- //
459  // Dataset attributes. //
460  // -------------------- //
461 
462  /* ``5. The final part describes the dataset attributes.
463  This part begins with the keywords POINT_DATA or
464  CELL_DATA, followed by an integer number specifying
465  the number of points or cells, respectively. (It
466  doesn't matter whether POINT_DATA or CELL_DATA comes
467  first.) Other keyword/data combinations then define
468  the actual dataset attribute values (i.e., scalars,
469  vectors, tensors, normals, texture coordinates, or
470  field data).'' */
471  std::string dataset_kind;
472  istr >> dataset_kind;
473  if (dataset_kind == "POINT_DATA")
474  internal::error(me, filename,
475  "`POINT_DATA' datasets are not supported "
476  "(only `CELL_DATA' datasets are supported yet).");
477  else if (dataset_kind != "CELL_DATA")
478  internal::error(me, filename,
479  std::string("invalid dataset kind: `")
480  + dataset_kind + "'.");
481  unsigned nfaces = nvertices + nedges + npolygons;
482  unsigned ncell_data;
483  istr >> ncell_data;
484  if (ncell_data != nfaces)
485  internal::error(me, filename,
486  std::string("wrong number of dataset attributes ")
487  + "(expected " + internal::str(nfaces)
488  + ", got " + internal::str(ncell_data) + ").");
489 
490  /* ``Dataset Attribute Format. The Visualization Toolkit
491  supports the following dataset attributes: scalars
492  (one to four components), vectors, normals,
493  texture coordinates (1D, 2D, and 3D), 3 x 3
494  tensors, and field data. In addition, a lookup
495  table using the RGBA color specification,
496  associated with the scalar data, can be defined as
497  well. Dataset attributes are supported for both
498  points and cells.
499  Each type of attribute data has a `dataName'
500  associated with it. This is a character string
501  (without embedded whitespace) used to identify a
502  particular data. The `dataName' is used by the VTK
503  readers to extract data. As a result, more than
504  one attribute data of the same type can be
505  included in a file. For example, two different
506  scalar fields defined on the dataset points,
507  pressure and temperature, can be contained in the
508  same file. (If the appropriate dataName is not
509  specified in the VTK reader, then the first data
510  of that type is extracted from the file.)
511 
512  * Scalars
513  Scalar definition includes specification of a
514  lookup table. The definition of a lookup table
515  is optional.
516 
517  [...]
518 
519  SCALARS dataName dataType numComp
520  LOOKUP_TABLE tableName
521  s0
522  s1
523  ...
524  sn-1''
525 
526  Note: values accepted by Paraview 3.8 for `dataType' are:
527  "bit", "char", "unsigned_char", "short", "unsigned_short",
528  "vtkidtype", "int", "unsigned_int", "long",
529  "unsigned_long", "vtktypeint64", "vtktypeuint64", "float",
530  "double", "string", "utf8_string" and "variant". */
531 
532  std::string scalars_keyword, data_name, data_type;
533  istr >> scalars_keyword >> data_name >> data_type;
534  internal::accept(scalars_keyword, "SCALARS", me, filename);
535  // FIXME: As in the rest of this routine's code, we only
536  // handle the case of binary values (for the moment).
537  if (data_type != "bit")
538  internal::error(me, filename,
539  std::string("unsupported data (value) type : `")
540  + data_type + "' (only `bit' is supported yet).");
541 
542  std::string lookup_table_keyword, lookup_table_name;
543  istr >> lookup_table_keyword >> lookup_table_name;
544  internal::accept(lookup_table_keyword, "LOOKUP_TABLE", me, filename);
545 
546  // Values.
547  typedef mln_value_(I) V;
548  typedef metal::vec<D + 1, std::vector<V> > values;
549  values vs;
550 
551  // Populate values associated to 0-faces.
552  /* FIXME: The default value used (here 0) depends on the
553  images's value type. */
554  vs[0].resize(npoints, 0);
555  // Iterate on VERTICES (not ``points''). We cannot copy
556  // VERTICES into VS[0] as-is, since VS[0] corresponds to
557  // points.
558  for (std::vector<unsigned>::const_iterator v = vertices.begin();
559  v != vertices.end(); ++ v)
560  {
561  V value;
562  istr >> value;
563  // The point id on which the vertex V is built.
564  unsigned p = *v;
565  vs[0][p] = value;
566  }
567 
568  // Populate values associated to 1-faces.
569  for(unsigned e = 0; e < nedges; ++e)
570  {
571  V value;
572  istr >> value;
573  vs[1].push_back(value);
574  }
575 
576  // Populate values associated to 2-faces.
577  for(unsigned f = 0; f < npolygons; ++f)
578  {
579  V value;
580  istr >> value;
581  vs[2].push_back(value);
582  }
583 
584  /*--------.
585  | Image. |
586  `--------*/
587 
588  // Site set.
589  typedef mln_domain_(I) domain;
590  domain s(c, geom);
591 
592  // Image.
593  ima.init_(s, vs);
594 
595  /*--------------.
596  | End of file. |
597  `--------------*/
598 
599  // FIXME: Eat comments and whitespace, and check the end of
600  // the file has been reached.
601  // ...
602  istr.close();
603  }
604 
605 # endif // ! MLN_INCLUDE_ONLY
606 
607 
608  } // end of namespace mln::io::vtk
609 
610  } // end of namespace mln::io
611 
612 } // end of namespace mln
613 
614 
615 #endif // ! MLN_IO_VTK_LOAD_HH