Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
off/save.hh
1 // Copyright (C) 2008, 2009, 2011 EPITA Research and Development
2 // Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef MLN_IO_OFF_SAVE_HH
28 # define MLN_IO_OFF_SAVE_HH
29 
35 
36 # include <cstdlib>
37 
38 # include <iostream>
39 # include <fstream>
40 # include <sstream>
41 
42 # include <string>
43 
44 # include <mln/core/alias/complex_image.hh>
45 # include <mln/core/image/complex_neighborhoods.hh>
46 # include <mln/core/image/complex_neighborhood_piter.hh>
47 
48 
49 namespace mln
50 {
51 
52  namespace io
53  {
54 
55  namespace off
56  {
57 
65  void save(const bin_2complex_image3df& ima,
66  const std::string& filename);
67 
75  void save(const int_u8_2complex_image3df& ima,
76  const std::string& filename);
77 
86  void save(const float_2complex_image3df& ima,
87  const std::string& filename);
88 
96  void save(const rgb8_2complex_image3df& ima,
97  const std::string& filename);
98 
99 
100  namespace internal
101  {
102 
103  template <typename I, typename E>
104  struct off_saver : public Object<E>
105  {
107  typedef mln_value(I) value;
108 
110  static const unsigned D = 2;
111 
113  off_saver();
114 
116  void operator()(const I& ima, const std::string& filename) const;
117  };
118 
119 
120  struct bin_off_saver
121  : public off_saver< bin_2complex_image3df, bin_off_saver >
122  {
126  void write_face_data(std::ostream& ostr, const value& v) const;
127  };
128 
129  struct int_u8_off_saver
130  : public off_saver< int_u8_2complex_image3df, int_u8_off_saver >
131  {
133  void write_face_data(std::ostream& ostr, const value& v) const;
134  };
135 
136 
137  /* FIXME: We should turn float_off_saver into a
138  float01_off_saver (see FIXME/comment in implementation
139  below). */
140  struct float_off_saver
141  : public off_saver< float_2complex_image3df, float_off_saver >
142  {
144  void write_face_data(std::ostream& ostr, const value& v) const;
145  };
146 
147 
148  struct rgb8_off_saver
149  : public off_saver< rgb8_2complex_image3df, rgb8_off_saver >
150  {
152  void write_face_data(std::ostream& ostr, const value& v) const;
153  };
154 
155  } // end of namespace mln::io::off::internal
156 
157 
158 
159 # ifndef MLN_INCLUDE_ONLY
160 
161  /*----------.
162  | Facades. |
163  `----------*/
164 
165  inline
166  void
167  save(const bin_2complex_image3df& ima, const std::string& filename)
168  {
169  trace::entering("mln::io::off::save");
170  internal::bin_off_saver()(ima, filename);
171  trace::exiting("mln::io::off::save");
172  }
173 
174  inline
175  void
176  save(const int_u8_2complex_image3df& ima, const std::string& filename)
177  {
178  trace::entering("mln::io::off::save");
179  internal::int_u8_off_saver()(ima, filename);
180  trace::exiting("mln::io::off::save");
181  }
182 
183  inline
184  void
185  save(const float_2complex_image3df& ima, const std::string& filename)
186  {
187  trace::entering("mln::io::off::save");
188  internal::float_off_saver()(ima, filename);
189  trace::exiting("mln::io::off::save");
190  }
191 
192  inline
193  void
194  save(const rgb8_2complex_image3df& ima, const std::string& filename)
195  {
196  trace::entering("mln::io::off::save");
197  internal::rgb8_off_saver()(ima, filename);
198  trace::exiting("mln::io::off::save");
199  }
200 
201 
202  /*-------------------------.
203  | Actual implementations. |
204  `-------------------------*/
205 
206  // -------- //
207  // Canvas. //
208  // -------- //
209 
210  namespace internal
211  {
212 
213  template <typename I, typename E>
214  off_saver<I, E>::off_saver()
215  {
216  // Concept checking.
217  void (E::*m1)(std::ostream&, const value&) const =
218  &E::write_face_data;
219  m1 = 0;
220  }
221 
222 
223  template <typename I, typename E>
224  void
225  off_saver<I, E>::operator()(const I& ima,
226  const std::string& filename) const
227  {
228  const std::string me = "mln::io::off::save";
229 
230  std::ofstream ostr(filename.c_str());
231  if (!ostr)
232  {
233  std::cerr << me << ": `" << filename << "' invalid file."
234  << std::endl;
235  /* FIXME: Too violent. We should allow the use of
236  exceptions, at least to have Milena's code behave
237  correctly in interpreted environments (std::exit() or
238  std::abort() causes the termination of a Python
239  interpreter, for instance!). */
240  std::exit(1);
241  }
242 
243  /*---------.
244  | Header. |
245  `---------*/
246 
247  /* ``The .off files in the Princeton Shape Benchmark conform
248  to the following standard.'' */
249 
250  /* ``OFF files are all ASCII files beginning with the
251  keyword OFF. '' */
252  ostr << "OFF" << std::endl;
253 
254  // A comment.
255  ostr << "# Generated by Milena 1.0 http://olena.lrde.epita.fr\n"
256  << "# EPITA Research and Development Laboratory (LRDE)"
257  << std::endl;
258 
259  /* ``The next line states the number of vertices, the number
260  of faces, and the number of edges. The number of edges can
261  be safely ignored.'' */
262  /* FIXME: This is too long. We shall be able to write
263 
264  ima.domain().template nfaces_of_static_dim<0>()
265 
266  or even
267 
268  ima.template nfaces_of_static_dim<0>().
269  */
270  ostr << ima.domain().cplx().template nfaces_of_static_dim<0>() << ' '
271  << ima.domain().cplx().template nfaces_of_static_dim<2>() << ' '
272  << ima.domain().cplx().template nfaces_of_static_dim<1>()
273  << std::endl;
274 
275  /*-------.
276  | Data. |
277  `-------*/
278 
279  // --------- //
280  // Complex. //
281  // --------- //
282 
283  typedef mln_geom(I) G;
284 
285  // ------------------------------------------ //
286  // Vertices & geometry (vertices locations). //
287  // ------------------------------------------ //
288 
289  /* ``The vertices are listed with x, y, z coordinates, written
290  one per line.'' */
291 
292  // Traverse the 0-faces (vertices).
293  p_n_faces_fwd_piter<D, G> v(ima.domain(), 0);
294  for_all(v)
295  {
296  mln_invariant(v.to_site().size() == 1);
297  ostr << v.to_site().front()[0] << ' '
298  << v.to_site().front()[1] << ' '
299  << v.to_site().front()[2] << std::endl;
300  }
301 
302  // --------------- //
303  // Faces & edges. //
304  // --------------- //
305 
306  /* ``After the list of vertices, the faces are listed, with one
307  face per line. For each face, the number of vertices is
308  specified, followed by indices into the list of
309  vertices.'' */
310 
311  // Traverse the 2-faces (polygons).
312  p_n_faces_fwd_piter<D, G> f(ima.domain(), 2);
313 
314  typedef complex_m_face_neighborhood<D, G> nbh_t;
315  // A neighborhood where neighbors are the set of 0-faces
316  // transitively adjacent to the reference point.
317  nbh_t nbh;
318  mln_fwd_niter(nbh_t) u(nbh, f);
319  /* FIXME: We should be able to pas this value (m) either at
320  the construction of the neighborhood or at the construction
321  of the iterator. */
322  u.iter().set_m(0);
323 
324  // For each (2-)face, iterate on (transitively) ajacent
325  // vertices (0-faces).
326  for_all(f)
327  {
328  unsigned nvertices = 0;
329  std::ostringstream vertices;
330  for_all(u)
331  {
332  // FIXME: Likewise, this is a bit too long...
333  vertices << ' ' << u.unproxy_().face().face_id();
334  ++nvertices;
335  }
336  ostr << nvertices << vertices.str();
337  // Possibly save a value (depends on the actual format).
338  exact(this)->write_face_data(ostr, ima(f));
339  ostr << std::endl;
340  }
341 
342  ostr.close();
343  }
344 
345  // ---------------- //
346  // Specific parts. //
347  // ---------------- //
348 
388  inline
389  void
390  bin_off_saver::write_face_data(std::ostream& /* ostr */,
391  const value& /* v */) const
392  {
393  // Do nothing (no data associated to faces).
394  }
395 
396  inline
397  void
398  int_u8_off_saver::write_face_data(std::ostream& ostr,
399  const value& v) const
400  {
401  /* Using RGBA colors to represent an 8-bit integer value.
402 
403  Each channel (R, G, B) of the color V is an integer in
404  the range 0..255. A fourth channel, A, controls the
405  transparency.
406 
407  We just set the same value for each channel, as the OFF
408  file format does not support gray-level values as-is. */
409  ostr << ' ' << v << ' ' << v << ' ' << v
410  << ' ' << 1.0f << std::endl;
411  }
412 
413  /* FIXME: We should turn float_off_saver into a
414  float01_off_saver to avoid the assertions below. */
415  inline
416  void
417  float_off_saver::write_face_data(std::ostream& ostr,
418  const value& v) const
419  {
420  /* Using RGBA colors to represent a floating-point value.
421 
422  Each channel (R, G, B) of the color V is a floating-point
423  number in the range 0..1. A fourth channel, A, controls
424  the transparency.
425 
426  We just set the same value for each channel, as the OFF
427  file format does not support gray-level values as
428  such. */
429  mln_assertion(0.0f <= v);
430  mln_assertion(v <= 1.0f);
431  ostr << ' ' << v << ' ' << v << ' ' << v
432  << ' ' << 1.0f;
433  }
434 
435  inline
436  void
437  rgb8_off_saver::write_face_data(std::ostream& ostr,
438  const value& v) const
439  {
440  /* RGBA color.
441 
442  Each channel (R, G, B) of the color V is an integer in
443  the range 0..255. A fourth channel, A, controls the
444  transparency. */
445  ostr << ' ' << v.red() << ' ' << v.green() << ' ' << v.blue()
446  << ' ' << 1.0f;
447  }
448  /* \} */
449 
450  } // end of namespace mln::io::off::internal
451 
452 
453 # endif // ! MLN_INCLUDE_ONLY
454 
455  } // end of namespace mln::io::off
456 
457  } // end of namespace mln::io
458 
459 } // end of namespace mln
460 
461 
462 #endif // ! MLN_IO_OFF_SAVE_HH