last-svn-commit-195-g96628ac 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. --- 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 ab27b56..3136661 100644 --- a/milena/ChangeLog +++ b/milena/ChangeLog @@ -1,5 +1,12 @@ 2010-06-24 Roland Levillain <roland@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@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
participants (1)
-
Roland Levillain