* apps/mesh-segm-skel/save_bin_alt.hh
(mln::io::vtk::save_bin_alt): New function.
---
milena/ChangeLog | 7 +
milena/apps/mesh-segm-skel/save_bin_alt.hh | 310 +++++++++++++++++++++++++++-
2 files changed, 312 insertions(+), 5 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index c8219e9..d850e40 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,12 @@
2010-06-24 Roland Levillain <roland(a)lrde.epita.fr>
+ Add a specific (temporary) VTK output routine for binary mesh images.
+
+ * apps/mesh-segm-skel/save_bin_alt.hh
+ (mln::io::vtk::save_bin_alt): New function.
+
+2010-06-24 Roland Levillain <roland(a)lrde.epita.fr>
+
Exercise mln::io::vtk::save.
* tests/io/vtk/save.cc: New.
diff --git a/milena/apps/mesh-segm-skel/save_bin_alt.hh
b/milena/apps/mesh-segm-skel/save_bin_alt.hh
index 034b840..b09fa88 100644
--- a/milena/apps/mesh-segm-skel/save_bin_alt.hh
+++ b/milena/apps/mesh-segm-skel/save_bin_alt.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009, 2010 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of the Milena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -28,10 +28,11 @@
#ifndef APPS_MESH_SEGM_SKEL_SAVE_BIN_ALT_HH
# define APPS_MESH_SEGM_SKEL_SAVE_BIN_ALT_HH
-/*--------------------------------------------------------------------.
-| FIXME: Copied and adjusted (in a hurry) from mln/io/off/save.hh, |
-| because fixing image_if + complex_image was much too long. Sorry. |
-`--------------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| FIXME: Copied and adjusted (in a hurry) from mln/io/off/save.hh, |
+| and mln/io/vtk/save.hh,because fixing image_if + complex_image was |
+| much too long. Sorry. |
+`-------------------------------------------------------------------*/
# include <cstdlib>
@@ -51,6 +52,10 @@ namespace mln
namespace io
{
+ /*------.
+ | OFF. |
+ `------*/
+
namespace off
{
@@ -181,6 +186,301 @@ namespace mln
} // end of namespace mln::io::off
+
+ /*------.
+ | VTK. |
+ `------*/
+
+ namespace vtk
+ {
+ /** FIXME: Similar to
+ mln::io::vtk::save(const bin_2complex_image3df&, const std::string&),
+ but does not save faces whose value is `false'. */
+ template <typename I>
+ void save_bin_alt(const I& ima,
+ const std::string& filename)
+ {
+ const std::string me = "mln::io::vtk::save";
+
+ std::ofstream ostr(filename.c_str());
+ if (!ostr)
+ {
+ std::cerr << me << ": `" << filename <<
"' invalid file."
+ << std::endl;
+ /* FIXME: Too violent. We should allow the use of
+ exceptions, at least to have Milena's code behave
+ correctly in interpreted environments (std::exit() or
+ std::abort() causes the termination of a Python
+ interpreter, for instance!). */
+ std::exit(1);
+ }
+
+ /*---------.
+ | Header. |
+ `---------*/
+
+ /* ``The legacy VTK file formats consist of five basic
+ parts.'' */
+
+ /* ``1. The first part is the file version and
+ identifier. This part contains the single line:
+
+ # vtk DataFile Version x.x.
+
+ This line must be exactly as shown with the
+ exception of the version number x.x, which will vary
+ with different releases of VTK. (Note: the current
+ version number is 3.0. Version 1.0 and 2.0 files are
+ compatible with version 3.0 files.)'' */
+ ostr << "# vtk DataFile Version 2.0" << std::endl;
+
+ /* ``2. The second part is the header. The header consists
+ of a character string terminated by end-of-line
+ character `\n'. The header is 256 characters
+ maximum. The header can be used to describe the data
+ and include any other pertinent information.'' */
+ ostr << "Generated by Milena 1.0
http://olena.lrde.epita.fr"
+ << std::endl;
+
+ /* ``3. The next part is the file format. The file format
+ describes the type of file, either ASCII or
+ binary. On this line the single word ASCII or BINARY
+ must appear.'' */
+ ostr << "ASCII" << std::endl;
+
+ /*-------.
+ | Data. |
+ `-------*/
+
+ /* ``4. The fourth part is the dataset structure. The
+ geometry part describes the geometry and topology of
+ the dataset. This part begins with a line containing
+ the keyword DATASET followed by a keyword describing
+ the type of dataset. Then, depending upon the type
+ of dataset, other keyword/data combinations define
+ the actual data.''
+
+ [...]
+
+ Dataset Format. The Visualization Toolkit supports
+ five different dataset formats: structured points,
+ structured grid, rectilinear grid, unstructured
+ grid, and polygonal data.'' */
+
+ ostr << "DATASET POLYDATA" << std::endl << std::endl;
+
+ // --------- //
+ // Complex. //
+ // --------- //
+
+ static const unsigned D = I::dim;
+ typedef mln_geom(I) G;
+
+ /* ``* Polygonal Data
+ The polygonal dataset consists of arbitrary
+ combinations of surface graphics primitives
+ vertices (and polyvertices), lines (and
+ polylines), polygons (of various types), and
+ triangle strips. Polygonal data is defined by
+ the POINTS, VERTICES, LINES, POLYGONS, or
+ TRIANGLE_STRIPS sections. The POINTS definition
+ is the same as we saw for structured grid
+ datasets.'' */
+
+ // ---------------------------- //
+ // Geometry (point locations). //
+ // ---------------------------- //
+
+ ostr << "POINTS "
+ << ima.domain().cplx().template nfaces_of_static_dim<0>()
+ << " float" << std::endl;
+ // Iterate on 0-faces (vertices).
+ p_n_faces_fwd_piter<D, G> v(ima.domain(), 0);
+ for_all(v)
+ {
+ mln_invariant(v.to_site().size() == 1);
+ ostr << v.to_site().front()[0] << ' '
+ << v.to_site().front()[1] << ' '
+ << v.to_site().front()[2] << std::endl;
+ }
+ ostr << std::endl;
+
+ /* ``The VERTICES, LINES, POLYGONS, or
+ TRIANGLE_STRIPS keywords define the polygonal
+ dataset topology. Each of these keywords
+ requires two parameters: the number of cells `n'
+ and the size of the cell list `size'. The cell
+ list size is the total number of integer values
+ required to represent the list (i.e., sum of
+ `numPoints' and connectivity indices over each
+ cell). None of the keywords VERTICES, LINES,
+ POLYGONS, or TRIANGLE_STRIPS is required.'' */
+
+ // ---------- //
+ // Vertices. //
+ // ---------- //
+
+ /* FIXME: Do not create a VERTICES section if there is no
+ vertex.
+
+ Likewise, only process vertices having a value attached
+ to them, i.e., which are part of the domain of the image
+ (which is different from the complex, upon which the
+ domain is based). */
+
+ /* We do not use
+
+ ima.domain().cplx().template nfaces_of_static_dim<N>()
+
+ to get the number of N-faces, since the image may be
+ masked, and exhibit less N-faces than its underlying
+ complex. Iterating on the N-faces is safer. */
+ /* FIXME: Is there anything faster? See what the interface
+ of the (morphed) image can provide. */
+ unsigned nvertices = 0;
+ for_all(v) if (ima(v))
+ ++nvertices;
+
+ ostr << "VERTICES " << nvertices << ' '
+ /* Each vertex requires two numbers: the cardinal of its
+ ends (which is always 1) and the indices of the point
+ among the POINTS section. Hence the total number of
+ values in the VERTEX section is nvertices * 2. */
+ << nvertices * 2 << std::endl;
+
+ for_all(v) if (ima(v))
+ ostr << "1 " << v.unproxy_().face().face_id() <<
std::endl;
+ ostr << std::endl;
+
+ // ------- //
+ // Edges. //
+ // ------- //
+
+ /* FIXME: Do not create a LINES section if there is no
+ edge.
+
+ Likewise, only process edges having a value attached
+ to them, i.e., which are part of the domain of the image
+ (which is different from the complex, upon which the
+ domain is based). */
+
+ // Same comment as above about the count of N-faces.
+ unsigned nedges = 0;
+ p_n_faces_fwd_piter<D, G> e(ima.domain(), 1);
+ for_all (e) if (ima(e))
+ ++nedges;
+
+ ostr << "LINES " << nedges << ' '
+ /* Each edge requires three numbers: the cardinal of its
+ ends (which is always 2) and the indices of these ends
+ among the POINTS section. Hence the total number of
+ values in the LINES section is nedges * 3. */
+ << nedges * 3 << std::endl;
+
+ // Vertices adjacent to edges.
+ typedef complex_lower_neighborhood<D, G> adj_vertices_nbh_t;
+ adj_vertices_nbh_t adj_vertices_nbh;
+ mln_niter(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, e);
+ // Iterate on 1-faces (edges).
+ for_all (e) if (ima(e))
+ {
+ ostr << "2";
+ // Iterate on vertices (0-faces).
+ for_all (adj_v)
+ {
+ // FIXME: Accessing the face id is too complicated.
+ ostr << " " << adj_v.unproxy_().face().face_id();
+ }
+ ostr << std::endl;
+ }
+ ostr << std::endl;
+
+ // ---------- //
+ // Polygons. //
+ // ---------- //
+
+ /* FIXME: Do not create a POLYGONS section if there is no
+ polygon.
+
+ Likewise, only process polygons having a value attached
+ to them, i.e., which are part of the domain of the image
+ (which is different from the complex, upon which the
+ domain is based). */
+
+ // Same comment as above about the count of N-faces.
+ unsigned npolygons = 0;
+ p_n_faces_fwd_piter<D, G> p(ima.domain(), 2);
+
+ // FIXME: Merge this loop with the next one.
+
+ for_all (p) if (ima(p))
+ ++npolygons;
+
+ // A neighborhood where neighbors are the set of 0-faces
+ // transitively adjacent to the reference point.
+ typedef complex_m_face_neighborhood<D, G> nbh_t;
+ nbh_t nbh;
+ mln_fwd_niter(nbh_t) u(nbh, p);
+ /* FIXME: We should be able to pass this value (m) either at
+ the construction of the neighborhood or at the construction
+ of the iterator. */
+ u.iter().set_m(0);
+
+ /* Compute the number of values (`size') to be passed as
+ second parameter of the POLYGONS keyword. */
+ unsigned polygons_size = 0;
+ // Iterate on polygons (2-face).
+ for_all(p) if (ima(p))
+ {
+ unsigned nvertices = 0;
+ /* FIXME: There may be a faster way to do this (e.g.,
+ the neighbordhood may provide a method returning the
+ number of P's neighbors. */
+ // Iterate on transitively adjacent vertices (0-face).
+ for_all(u)
+ ++nvertices;
+ // The number of values describing this polygon P is the
+ // cardinal of its set of vertices (1 value) plus the
+ // NVERTICES indices of these vertices.
+ polygons_size += 1 + nvertices;
+ }
+ ostr << "POLYGONS " << npolygons << ' ' <<
polygons_size
+ << std::endl;
+
+ /* Output polygons (one per line), with their number of
+ vertices and the indices of these vertices. */
+ // Iterate on polygons (2-face).
+ for_all(p) if (ima(p))
+ {
+ unsigned nvertices = 0;
+ std::ostringstream vertices;
+ // Iterate on transitively adjacent vertices (0-face).
+ for_all(u)
+ {
+ // FIXME: Likewise, this is a bit too long...
+ vertices << ' ' << u.unproxy_().face().face_id();
+ ++nvertices;
+ }
+ ostr << nvertices << vertices.str() << std::endl;
+ }
+
+ /* ``5. The final part describes the dataset
+ attributes. This part begins with the keywords
+ POINT_DATA or CELL_DATA,followed by an integer
+ number specifying the number of points or cells,
+ respectively. (It doesn't matter whether POINT_DATA
+ or CELL_DATA comes first.) Other keyword/data
+ combinations then define the actual dataset
+ attribute values (i.e., scalars, vectors, tensors,
+ normals, texture coordinates, or field data).'' */
+
+ // FIXME: To do.
+
+ ostr.close();
+ }
+
+ } // end of namespace mln::io::vtk
+
} // end of namespace mln::io
} // end of namespace mln
--
1.5.6.5