$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
save_bin_alt.hh
1 // Copyright (C) 2009, 2010 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 APPS_MESH_SEGM_SKEL_SAVE_BIN_ALT_HH
27 # define APPS_MESH_SEGM_SKEL_SAVE_BIN_ALT_HH
28 
29 /*-------------------------------------------------------------------.
30 | FIXME: Copied and adjusted (in a hurry) from mln/io/off/save.hh, |
31 | and mln/io/vtk/save.hh,because fixing image_if + complex_image was |
32 | much too long. Sorry. |
33 `-------------------------------------------------------------------*/
34 
35 # include <cstdlib>
36 
37 # include <iostream>
38 # include <fstream>
39 # include <sstream>
40 
41 # include <string>
42 
43 # include <mln/core/alias/complex_image.hh>
44 # include <mln/core/image/complex_neighborhoods.hh>
45 # include <mln/core/image/complex_neighborhood_piter.hh>
46 
47 namespace mln
48 {
49 
50  namespace io
51  {
52 
53  /*------.
54  | OFF. |
55  `------*/
56 
57  namespace off
58  {
59 
63  template <typename I>
64  void save_bin_alt(const I& ima,
65  const std::string& filename)
66  {
67  const std::string me = "mln::io::off::save";
68 
69  std::ofstream ostr(filename.c_str());
70  if (!ostr)
71  {
72  std::cerr << me << ": `" << filename << "' invalid file."
73  << std::endl;
74  /* FIXME: Too violent. We should allow the use of
75  exceptions, at least to have Milena's code behave
76  correctly in interpreted environments (std::exit() or
77  std::abort() causes the termination of a Python
78  interpreter, for instance!). */
79  std::exit(1);
80  }
81 
82  /*---------.
83  | Header. |
84  `---------*/
85 
86  static const unsigned D = I::dim;
87  typedef mln_geom(I) G;
88 
89  /* ``The .off files in the Princeton Shape Benchmark conform
90  to the following standard.'' */
91 
92  /* ``OFF files are all ASCII files beginning with the
93  keyword OFF. '' */
94  ostr << "OFF" << std::endl;
95 
96  // A comment.
97  ostr << "# Generated by Milena 1.0 http://olena.lrde.epita.fr\n"
98  << "# EPITA Research and Development Laboratory (LRDE)"
99  << std::endl;
100 
101  // Count the number of 2-faces set to `true'.
102  unsigned n2faces = 0;
103  p_n_faces_fwd_piter<D, G> f(ima.domain(), 2);
104  for_all(f)
105  if (ima(f))
106  ++n2faces;
107 
108  /* ``The next line states the number of vertices, the number
109  of faces, and the number of edges. The number of edges can
110  be safely ignored.'' */
111  /* FIXME: This is too long. We shall be able to write
112 
113  ima.domain().template nfaces_of_static_dim<0>()
114 
115  or even
116 
117  ima.template nfaces_of_static_dim<0>().
118  */
119  ostr << ima.domain().cplx().template nfaces_of_static_dim<0>() << ' '
120  << n2faces << ' '
121  << ima.domain().cplx().template nfaces_of_static_dim<1>()
122  << std::endl;
123 
124  /*-------.
125  | Data. |
126  `-------*/
127 
128  // ------------------------------------------ //
129  // Vertices & geometry (vertices locations). //
130  // ------------------------------------------ //
131 
132  /* ``The vertices are listed with x, y, z coordinates, written
133  one per line.'' */
134 
135  // Traverse the 0-faces (vertices).
136  p_n_faces_fwd_piter<D, G> v(ima.domain(), 0);
137  for_all(v)
138  {
139  mln_invariant(v.to_site().size() == 1);
140  ostr << v.to_site().front()[0] << ' '
141  << v.to_site().front()[1] << ' '
142  << v.to_site().front()[2] << std::endl;
143  }
144 
145  // --------------- //
146  // Faces & edges. //
147  // --------------- //
148 
149  /* ``After the list of vertices, the faces are listed, with one
150  face per line. For each face, the number of vertices is
151  specified, followed by indices into the list of
152  vertices.'' */
153 
154  // Traverse the 2-faces (polygons).
155  typedef complex_m_face_neighborhood<D, G> nbh_t;
156  // A neighborhood where neighbors are the set of 0-faces
157  // transitively adjacent to the reference point.
158  nbh_t nbh;
159  mln_fwd_niter(nbh_t) u(nbh, f);
160  /* FIXME: We should be able to pas this value (m) either at
161  the construction of the neighborhood or at the construction
162  of the iterator. */
163  u.iter().set_m(0);
164 
165  // For each (2-)face, iterate on (transitively) ajacent
166  // vertices (0-faces).
167  for_all(f)
168  if (ima(f))
169  {
170  unsigned nvertices = 0;
171  std::ostringstream vertices;
172  for_all(u)
173  {
174  // FIXME: Likewise, this is a bit too long...
175  vertices << ' ' << u.unproxy_().face().face_id();
176  ++nvertices;
177  }
178  ostr << nvertices << vertices.str();
179  ostr << std::endl;
180  }
181 
182  ostr.close();
183  }
184 
185  } // end of namespace mln::io::off
186 
187 
188  /*------.
189  | VTK. |
190  `------*/
191 
192  namespace vtk
193  {
197  template <typename I>
198  void save_bin_alt(const I& ima,
199  const std::string& filename)
200  {
201  const std::string me = "mln::io::vtk::save";
202 
203  std::ofstream ostr(filename.c_str());
204  if (!ostr)
205  {
206  std::cerr << me << ": `" << filename << "' invalid file."
207  << std::endl;
208  /* FIXME: Too violent. We should allow the use of
209  exceptions, at least to have Milena's code behave
210  correctly in interpreted environments (std::exit() or
211  std::abort() causes the termination of a Python
212  interpreter, for instance!). */
213  std::exit(1);
214  }
215 
216  /*---------.
217  | Header. |
218  `---------*/
219 
220  /* ``The legacy VTK file formats consist of five basic
221  parts.'' */
222 
223  /* ``1. The first part is the file version and
224  identifier. This part contains the single line:
225 
226  # vtk DataFile Version x.x.
227 
228  This line must be exactly as shown with the
229  exception of the version number x.x, which will vary
230  with different releases of VTK. (Note: the current
231  version number is 3.0. Version 1.0 and 2.0 files are
232  compatible with version 3.0 files.)'' */
233  ostr << "# vtk DataFile Version 2.0" << std::endl;
234 
235  /* ``2. The second part is the header. The header consists
236  of a character string terminated by end-of-line
237  character `\n'. The header is 256 characters
238  maximum. The header can be used to describe the data
239  and include any other pertinent information.'' */
240  ostr << "Generated by Milena 1.0 http://olena.lrde.epita.fr"
241  << std::endl;
242 
243  /* ``3. The next part is the file format. The file format
244  describes the type of file, either ASCII or
245  binary. On this line the single word ASCII or BINARY
246  must appear.'' */
247  ostr << "ASCII" << std::endl;
248 
249  /*-------.
250  | Data. |
251  `-------*/
252 
253  /* ``4. The fourth part is the dataset structure. The
254  geometry part describes the geometry and topology of
255  the dataset. This part begins with a line containing
256  the keyword DATASET followed by a keyword describing
257  the type of dataset. Then, depending upon the type
258  of dataset, other keyword/data combinations define
259  the actual data.''
260 
261  [...]
262 
263  Dataset Format. The Visualization Toolkit supports
264  five different dataset formats: structured points,
265  structured grid, rectilinear grid, unstructured
266  grid, and polygonal data.'' */
267 
268  ostr << "DATASET POLYDATA" << std::endl << std::endl;
269 
270  // --------- //
271  // Complex. //
272  // --------- //
273 
274  static const unsigned D = I::dim;
275  typedef mln_geom(I) G;
276 
277  /* ``* Polygonal Data
278  The polygonal dataset consists of arbitrary
279  combinations of surface graphics primitives
280  vertices (and polyvertices), lines (and
281  polylines), polygons (of various types), and
282  triangle strips. Polygonal data is defined by
283  the POINTS, VERTICES, LINES, POLYGONS, or
284  TRIANGLE_STRIPS sections. The POINTS definition
285  is the same as we saw for structured grid
286  datasets.'' */
287 
288  // ---------------------------- //
289  // Geometry (point locations). //
290  // ---------------------------- //
291 
292  ostr << "POINTS "
293  << ima.domain().cplx().template nfaces_of_static_dim<0>()
294  << " float" << std::endl;
295  // Iterate on 0-faces (vertices).
296  p_n_faces_fwd_piter<D, G> v(ima.domain(), 0);
297  for_all(v)
298  {
299  mln_invariant(v.to_site().size() == 1);
300  ostr << v.to_site().front()[0] << ' '
301  << v.to_site().front()[1] << ' '
302  << v.to_site().front()[2] << std::endl;
303  }
304  ostr << std::endl;
305 
306  /* ``The VERTICES, LINES, POLYGONS, or
307  TRIANGLE_STRIPS keywords define the polygonal
308  dataset topology. Each of these keywords
309  requires two parameters: the number of cells `n'
310  and the size of the cell list `size'. The cell
311  list size is the total number of integer values
312  required to represent the list (i.e., sum of
313  `numPoints' and connectivity indices over each
314  cell). None of the keywords VERTICES, LINES,
315  POLYGONS, or TRIANGLE_STRIPS is required.'' */
316 
317  // ---------- //
318  // Vertices. //
319  // ---------- //
320 
321  /* FIXME: Do not create a VERTICES section if there is no
322  vertex.
323 
324  Likewise, only process vertices having a value attached
325  to them, i.e., which are part of the domain of the image
326  (which is different from the complex, upon which the
327  domain is based). */
328 
329  /* We do not use
330 
331  ima.domain().cplx().template nfaces_of_static_dim<N>()
332 
333  to get the number of N-faces, since the image may be
334  masked, and exhibit less N-faces than its underlying
335  complex. Iterating on the N-faces is safer. */
336  /* FIXME: Is there anything faster? See what the interface
337  of the (morphed) image can provide. */
338  unsigned nvertices = 0;
339  for_all(v) if (ima(v))
340  ++nvertices;
341 
342  ostr << "VERTICES " << nvertices << ' '
343  /* Each vertex requires two numbers: the cardinal of its
344  ends (which is always 1) and the indices of the point
345  among the POINTS section. Hence the total number of
346  values in the VERTEX section is nvertices * 2. */
347  << nvertices * 2 << std::endl;
348 
349  for_all(v) if (ima(v))
350  ostr << "1 " << v.unproxy_().face().face_id() << std::endl;
351  ostr << std::endl;
352 
353  // ------- //
354  // Edges. //
355  // ------- //
356 
357  /* FIXME: Do not create a LINES section if there is no
358  edge.
359 
360  Likewise, only process edges having a value attached
361  to them, i.e., which are part of the domain of the image
362  (which is different from the complex, upon which the
363  domain is based). */
364 
365  // Same comment as above about the count of N-faces.
366  unsigned nedges = 0;
367  p_n_faces_fwd_piter<D, G> e(ima.domain(), 1);
368  for_all (e) if (ima(e))
369  ++nedges;
370 
371  ostr << "LINES " << nedges << ' '
372  /* Each edge requires three numbers: the cardinal of its
373  ends (which is always 2) and the indices of these ends
374  among the POINTS section. Hence the total number of
375  values in the LINES section is nedges * 3. */
376  << nedges * 3 << std::endl;
377 
378  // Vertices adjacent to edges.
379  typedef complex_lower_neighborhood<D, G> adj_vertices_nbh_t;
380  adj_vertices_nbh_t adj_vertices_nbh;
381  mln_niter(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, e);
382  // Iterate on 1-faces (edges).
383  for_all (e) if (ima(e))
384  {
385  ostr << "2";
386  // Iterate on vertices (0-faces).
387  for_all (adj_v)
388  {
389  // FIXME: Accessing the face id is too complicated.
390  ostr << " " << adj_v.unproxy_().face().face_id();
391  }
392  ostr << std::endl;
393  }
394  ostr << std::endl;
395 
396  // ---------- //
397  // Polygons. //
398  // ---------- //
399 
400  /* FIXME: Do not create a POLYGONS section if there is no
401  polygon.
402 
403  Likewise, only process polygons having a value attached
404  to them, i.e., which are part of the domain of the image
405  (which is different from the complex, upon which the
406  domain is based). */
407 
408  // Same comment as above about the count of N-faces.
409  unsigned npolygons = 0;
410  p_n_faces_fwd_piter<D, G> p(ima.domain(), 2);
411 
412  // FIXME: Merge this loop with the next one.
413 
414  for_all (p) if (ima(p))
415  ++npolygons;
416 
417  // A neighborhood where neighbors are the set of 0-faces
418  // transitively adjacent to the reference point.
419  typedef complex_m_face_neighborhood<D, G> nbh_t;
420  nbh_t nbh;
421  mln_fwd_niter(nbh_t) u(nbh, p);
422  /* FIXME: We should be able to pass this value (m) either at
423  the construction of the neighborhood or at the construction
424  of the iterator. */
425  u.iter().set_m(0);
426 
427  /* Compute the number of values (`size') to be passed as
428  second parameter of the POLYGONS keyword. */
429  unsigned polygons_size = 0;
430  // Iterate on polygons (2-face).
431  for_all(p) if (ima(p))
432  {
433  unsigned nvertices = 0;
434  /* FIXME: There may be a faster way to do this (e.g.,
435  the neighbordhood may provide a method returning the
436  number of P's neighbors. */
437  // Iterate on transitively adjacent vertices (0-face).
438  for_all(u)
439  ++nvertices;
440  // The number of values describing this polygon P is the
441  // cardinal of its set of vertices (1 value) plus the
442  // NVERTICES indices of these vertices.
443  polygons_size += 1 + nvertices;
444  }
445  ostr << "POLYGONS " << npolygons << ' ' << polygons_size
446  << std::endl;
447 
448  /* Output polygons (one per line), with their number of
449  vertices and the indices of these vertices. */
450  // Iterate on polygons (2-face).
451  for_all(p) if (ima(p))
452  {
453  unsigned nvertices = 0;
454  std::ostringstream vertices;
455  // Iterate on transitively adjacent vertices (0-face).
456  for_all(u)
457  {
458  // FIXME: Likewise, this is a bit too long...
459  vertices << ' ' << u.unproxy_().face().face_id();
460  ++nvertices;
461  }
462  ostr << nvertices << vertices.str() << std::endl;
463  }
464 
465  /* ``5. The final part describes the dataset
466  attributes. This part begins with the keywords
467  POINT_DATA or CELL_DATA,followed by an integer
468  number specifying the number of points or cells,
469  respectively. (It doesn't matter whether POINT_DATA
470  or CELL_DATA comes first.) Other keyword/data
471  combinations then define the actual dataset
472  attribute values (i.e., scalars, vectors, tensors,
473  normals, texture coordinates, or field data).'' */
474 
475  // FIXME: To do.
476 
477  ostr.close();
478  }
479 
480  } // end of namespace mln::io::vtk
481 
482  } // end of namespace mln::io
483 
484 } // end of namespace mln
485 
486 
487 #endif // ! APPS_MESH_SEGM_SKEL_SAVE_BIN_ALT_HH