* mln/topo/skeleton/breadth_first_thinning.hh: Remove a comment.
* mln/topo/skeleton/priority_driven_thinning.hh: Likewise.
Rename p_queue to queue to avoid confusions with mln::p_queue and
improve uniformity w.r.t. topo::breadth_first_thinning.
---
milena/ChangeLog | 9 +++++++
milena/mln/topo/skeleton/breadth_first_thinning.hh | 9 -------
.../mln/topo/skeleton/priority_driven_thinning.hh | 23 ++++++-------------
3 files changed, 16 insertions(+), 25 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 7554064..11924f1 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,14 @@
2010-09-17 Roland Levillain <roland(a)lrde.epita.fr>
+ Aesthetic changes in thinning algorithms.
+
+ * mln/topo/skeleton/breadth_first_thinning.hh: Remove a comment.
+ * mln/topo/skeleton/priority_driven_thinning.hh: Likewise.
+ Rename p_queue to queue to avoid confusions with mln::p_queue and
+ improve uniformity w.r.t. topo::breadth_first_thinning.
+
+2010-09-17 Roland Levillain <roland(a)lrde.epita.fr>
+
Fix the processing order in topo::breadth_first_thinning.
* mln/topo/skeleton/breadth_first_thinning.hh: Use a p_queue_fast
diff --git a/milena/mln/topo/skeleton/breadth_first_thinning.hh b/milena/mln/topo/skeleton/breadth_first_thinning.hh
index 348b271..d2f33b5 100644
--- a/milena/mln/topo/skeleton/breadth_first_thinning.hh
+++ b/milena/mln/topo/skeleton/breadth_first_thinning.hh
@@ -135,15 +135,6 @@ namespace mln
while (!queue.is_empty())
{
psite p = queue.pop_front();
-
- /* FIXME: We compute the cell and attachment of P twice:
- during the call to is_simple() and within detach().
- How could we reuse this elegantly, without breaking
- the genericity of the skeleton algorithm?
- Also, keep in mind that functors can maintain an
- internal state and make side effects, meaning that
- e.g. constraint(p) might not be constant for a
- given p during the thinning. */
if (output(p) && constraint(p) && is_simple(p))
{
detach(p, output);
diff --git a/milena/mln/topo/skeleton/priority_driven_thinning.hh b/milena/mln/topo/skeleton/priority_driven_thinning.hh
index f074b6a..42e1b13 100644
--- a/milena/mln/topo/skeleton/priority_driven_thinning.hh
+++ b/milena/mln/topo/skeleton/priority_driven_thinning.hh
@@ -126,9 +126,9 @@ namespace mln
typedef mln_psite(I) psite;
typedef p_queue_fast<psite> queue_t;
- typedef p_priority<mln_value(J), queue_t> p_queue_t;
- p_queue_t p_queue;
- // Populate P_QUEUE with candidate simple points.
+ typedef p_priority<mln_value(J), queue_t> priority_queue_t;
+ priority_queue_t queue;
+ // Populate QUEUE with candidate simple points.
mln_piter(I) p_(output.domain());
for_all(p_)
{
@@ -139,21 +139,12 @@ namespace mln
the compiler and pass an actual, explicit psite. */
psite p = p_;
if (output(p) && constraint(p) && is_simple(p))
- p_queue.push(priority(p), p);
+ queue.push(priority(p), p);
}
- while (!p_queue.is_empty())
+ while (!queue.is_empty())
{
- psite p = p_queue.pop_front();
-
- /* FIXME: We compute the cell and attachment of P twice:
- during the call to is_simple() and within detach().
- How could we reuse this elegantly, without breaking
- the genericity of the skeleton algorithm?
- Also, keep in mind that functors can maintain an
- internal state and make side effects, meaning that
- e.g. constraint(p) might not be constant for a
- given p during the thinning. */
+ psite p = queue.pop_front();
if (output(p) && constraint(p) && is_simple(p))
{
detach(p, output);
@@ -164,7 +155,7 @@ namespace mln
psite n = n_;
if (output.domain().has(n)
&& output(n) && constraint(n) && is_simple(n))
- p_queue.push(priority(n), n);
+ queue.push(priority(n), n);
}
}
}
--
1.5.6.5
* mln/topo/skeleton/breadth_first_thinning.hh: Use a p_queue_fast
site set instead of a pair of p_set's to ensure an actual
breadth-first processing of sites.
---
milena/ChangeLog | 8 +++
milena/mln/topo/skeleton/breadth_first_thinning.hh | 63 ++++++++-----------
2 files changed, 35 insertions(+), 36 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 45c94c8..7554064 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,11 @@
+2010-09-17 Roland Levillain <roland(a)lrde.epita.fr>
+
+ Fix the processing order in topo::breadth_first_thinning.
+
+ * mln/topo/skeleton/breadth_first_thinning.hh: Use a p_queue_fast
+ site set instead of a pair of p_set's to ensure an actual
+ breadth-first processing of sites.
+
2010-09-16 Roland Levillain <roland(a)lrde.epita.fr>
Split interface and implementation of topo::is_not_end_point.
diff --git a/milena/mln/topo/skeleton/breadth_first_thinning.hh b/milena/mln/topo/skeleton/breadth_first_thinning.hh
index 3be9539..348b271 100644
--- a/milena/mln/topo/skeleton/breadth_first_thinning.hh
+++ b/milena/mln/topo/skeleton/breadth_first_thinning.hh
@@ -37,7 +37,7 @@
# include <mln/core/concept/image.hh>
# include <mln/core/concept/neighborhood.hh>
-# include <mln/core/site_set/p_set.hh>
+# include <mln/core/site_set/p_queue_fast.hh>
# include <mln/fun/p2b/tautology.hh>
@@ -116,9 +116,9 @@ namespace mln
is_simple.set_image(output);
typedef mln_psite(I) psite;
- typedef p_set<psite> set_t;
- set_t set;
- // Populate SET with candidate simple points.
+ typedef p_queue_fast<psite> queue_t;
+ queue_t queue;
+ // Populate QUEUE with candidate simple points.
mln_piter(I) p_(output.domain());
for_all(p_)
{
@@ -129,43 +129,34 @@ namespace mln
the compiler and pass an actual, explicit psite. */
psite p = p_;
if (output(p) && constraint(p) && is_simple(p))
- set.insert(p);
+ queue.push(p);
}
- while (!set.is_empty())
+ while (!queue.is_empty())
{
- set_t next_set;
-
- mln_piter(set_t) ps(set);
- for_all(ps)
- {
- // Same remark as above.
- psite p = ps;
-
- /* FIXME: We compute the cell and attachment of P twice:
- during the call to is_simple() and within detach().
- How could we reuse this elegantly, without breaking
- the genericity of the skeleton algorithm?
- Also, keep in mind that functors can maintain an
- internal state and make side effects, meaning that
- e.g. constraint(p) might not be constant for a
- given p during the thinning. */
- if (output(p) && constraint(p) && is_simple(p))
+ psite p = queue.pop_front();
+
+ /* FIXME: We compute the cell and attachment of P twice:
+ during the call to is_simple() and within detach().
+ How could we reuse this elegantly, without breaking
+ the genericity of the skeleton algorithm?
+ Also, keep in mind that functors can maintain an
+ internal state and make side effects, meaning that
+ e.g. constraint(p) might not be constant for a
+ given p during the thinning. */
+ if (output(p) && constraint(p) && is_simple(p))
+ {
+ detach(p, output);
+ mln_niter(N) n_(nbh, p);
+ for_all(n_)
{
- detach(p, output);
- mln_niter(N) n_(nbh, p);
- for_all(n_)
- {
- // Same remark as above regarding P and P_.
- psite n = n_;
- if (output.domain().has(n)
- && output(n) && constraint(n) && is_simple(n))
- next_set.insert(n);
- }
+ // Same remark as above regarding P and P_.
+ psite n = n_;
+ if (output.domain().has(n)
+ && output(n) && constraint(n) && is_simple(n))
+ queue.push(n);
}
- }
- set.clear();
- std::swap(set, next_set);
+ }
}
trace::exiting("topo::skeleton::breadth_first_thinning");
--
1.5.6.5
* mln/io/vtk/load.hh: New file.
Include it...
* mln/io/vtk/all.hh: ...here.
* tests/io/vtk/load_bin.cc,
* tests/io/vtk/load_save_bin.cc:
New.
* tests/io/vtk/Makefile.am (check_PROGRAMS): Add load_bin and
load_save_bin.
(load_bin_SOURCES, load_save_bin_SOURCES): New.
(MOSTLYCLEANFILES): Add load_save_bin-out.vtk.
---
milena/ChangeLog | 15 +
milena/mln/io/vtk/all.hh | 3 +-
milena/mln/io/vtk/load.hh | 615 +++++++++++++++++++++++++
milena/tests/io/vtk/Makefile.am | 7 +-
milena/tests/io/{off => vtk}/load_bin.cc | 12 +-
milena/tests/io/{off => vtk}/load_save_bin.cc | 15 +-
6 files changed, 654 insertions(+), 13 deletions(-)
create mode 100644 milena/mln/io/vtk/load.hh
copy milena/tests/io/{off => vtk}/load_bin.cc (87%)
copy milena/tests/io/{off => vtk}/load_save_bin.cc (80%)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 8f604a9..690a83b 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,20 @@
2011-03-01 Roland Levillain <roland(a)lrde.epita.fr>
+ Add preliminary VTK input for binary images.
+
+ * mln/io/vtk/load.hh: New file.
+ Include it...
+ * mln/io/vtk/all.hh: ...here.
+ * tests/io/vtk/load_bin.cc,
+ * tests/io/vtk/load_save_bin.cc:
+ New.
+ * tests/io/vtk/Makefile.am (check_PROGRAMS): Add load_bin and
+ load_save_bin.
+ (load_bin_SOURCES, load_save_bin_SOURCES): New.
+ (MOSTLYCLEANFILES): Add load_save_bin-out.vtk.
+
+2011-03-01 Roland Levillain <roland(a)lrde.epita.fr>
+
Add VTK-format meshes.
* mesh/tetrahedron.vtk,
diff --git a/milena/mln/io/vtk/all.hh b/milena/mln/io/vtk/all.hh
index 6ff98ce..74d37c8 100644
--- a/milena/mln/io/vtk/all.hh
+++ b/milena/mln/io/vtk/all.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -41,6 +41,7 @@ namespace mln
}
+# include <mln/io/vtk/load.hh>
# include <mln/io/vtk/save.hh>
#endif // ! MLN_IO_VTK_ALL_HH
diff --git a/milena/mln/io/vtk/load.hh b/milena/mln/io/vtk/load.hh
new file mode 100644
index 0000000..ec078cb
--- /dev/null
+++ b/milena/mln/io/vtk/load.hh
@@ -0,0 +1,615 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to produce
+// an executable, this file does not by itself cause the resulting
+// executable to be covered by the GNU General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef MLN_IO_VTK_LOAD_HH
+# define MLN_IO_VTK_LOAD_HH
+
+/// \file
+/// Input saving function for VTK files.
+///
+/// \see http://www.vtk.org/VTK/img/file-formats.pdf
+/// \see http://dunne.uni-hd.de/VisuSimple/documents/vtkfileformat.html
+///
+/// The routines of this file only supported a subset of the file
+/// format(s) defined in the VTK documentation.
+
+# include <cstdlib>
+# include <iostream>
+# include <fstream>
+# include <sstream>
+# include <string>
+
+# include <mln/core/alias/complex_image.hh>
+
+
+namespace mln
+{
+
+ namespace io
+ {
+
+ namespace vtk
+ {
+
+ /** \brief Load a (binary) VTK image into a complex image.
+
+ \param[in] ima A reference to the image to construct.
+ \param[in] filename The name of the file to load.
+ */
+ void load(bin_2complex_image3df& ima, const std::string& filename);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // FIXME: To be put elsewehre (factored), or encapsulated in a
+ // class containing the `load' routine as well.
+ namespace internal
+ {
+
+ inline
+ void
+ error(const std::string& caller, const std::string& filename,
+ const std::string& message)
+ {
+ std::cerr << caller << ": `" << filename << "': "
+ << message << std::endl;
+ std::exit(1);
+ }
+
+ inline
+ void
+ accept(const std::string& token, const std::string& expected,
+ const std::string& caller, const std::string& filename,
+ const std::string& message)
+ {
+ if (token != expected)
+ error(caller, filename, message);
+ }
+
+ // Likewise, with default message.
+ inline
+ void
+ accept(const std::string& token, const std::string& expected,
+ const std::string& caller, const std::string& filename)
+ {
+ accept(token, expected, caller, filename,
+ std::string("parse error (`") + expected + "' expected, "
+ + "got `" + token + "').");
+ }
+
+ // FIXME: To be moved elsewhere.
+ /// Create a string from X using operator<<.
+ template <typename T>
+ std::string
+ str(const T& x)
+ {
+ std::stringstream s;
+ s << x;
+ return s.str();
+ }
+
+ } // end of namespace mln::io::vtk::internal
+
+
+ inline
+ void
+ load(bin_2complex_image3df& ima, const std::string& filename)
+ {
+ typedef bin_2complex_image3df I;
+
+ const std::string me = "mln::io::off::load";
+
+ std::ifstream istr(filename.c_str());
+ if (!istr)
+ {
+ std::cerr << me << ": `" << filename << "' not found."
+ << 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.)'' */
+ std::string version;
+ std::getline(istr, version);
+ // FIXME: Check the format of VERSION.
+
+ /* ``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.'' */
+ std::string header;
+ std::getline(istr, header);
+
+ /* ``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.'' */
+ std::string format;
+ istr >> format;
+ if (format == "BINARY")
+ internal::error(me, filename,
+ "`BINARY' VTK format is not supported "
+ "(only `ASCII' is supported yet).");
+ else if (format != "ASCII")
+ internal::error(me, filename,
+ std::string("invalid file format: `")
+ + format + "'.");
+
+ /*-------.
+ | 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.'' */
+
+ std::string dataset_keyword, dataset_type;
+ istr >> dataset_keyword >> dataset_type;
+ internal::accept(dataset_keyword, "DATASET", me, filename);
+ internal::accept(dataset_type, "POLYDATA", me, filename,
+ "unsupported dataset structure "
+ "(only `POLYDATA' is supported yet).");
+
+ // --------- //
+ // Complex. //
+ // --------- //
+
+ const unsigned D = 2;
+ topo::complex<D> c;
+
+ /* ``* 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.'' */
+
+ // ----------------------------------------- //
+ // Vertices and geometry (point locations). //
+ // ----------------------------------------- //
+
+ std::string points_keyword;
+ unsigned npoints;
+ std::string points_datatype;
+ istr >> points_keyword >> npoints >> points_datatype;
+ internal::accept(points_keyword, "POINTS", me, filename);
+ internal::accept(points_datatype, "float", me, filename,
+ "unsupported points data type "
+ "(only `float' is supported yet).");
+
+ typedef point3df P;
+ typedef mln_coord_(P) C;
+ typedef mln_geom_(I) G;
+ G geom;
+ geom.reserve(npoints);
+ for (unsigned i = 0; i < npoints; ++i)
+ {
+ // Create a 0-face.
+ c.add_face();
+
+ // Record the geometry (point) associated to this vertex.
+ C x, y, z;
+ istr >> x >> y >> z;
+ geom.add_location(P(x, y, z));
+ }
+
+ /* ``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: Add another constraint: a bijection between
+ VERTICES and POINTS shall exist. Update the following
+ comment accordingly. */
+
+ /* The VTK file format contains both a POINTS and a VERTICES
+ section. Despite its name, the former is used to create
+ the set of vertices of the complex (because POINTS are
+ later used to form line (edges) and polygons. The latter
+ (VERTICES) is used to attach values (data) to 0-faces,
+ and act as an indirection toward POINTS. The fact is,
+ most VTK file we use have a VERTICES section where the
+ N-th line (starting at 0) contains
+
+ 1 N
+
+ which makes the VERTICES section kind of useless.
+ However, we have to parse it and take it into account for
+ the sake of the file format. */
+
+ std::string vertices_keyword;
+ unsigned nvertices, vertices_size;
+ istr >> vertices_keyword >> nvertices >> vertices_size;
+ internal::accept(vertices_keyword, "VERTICES", me, filename);
+
+ /* 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. */
+ // FIXME: This test is not really robust: we should involve
+ // the VERTICES_SIZE value in the parsing process.
+ if (vertices_size != nvertices * 2)
+ internal::error(me, filename, "ill-formed `VERTICES' section.");
+
+ // Vertices built on points.
+ std::vector<unsigned> vertices;
+ vertices.reserve(npoints);
+ for (unsigned i = 0; i < nvertices; ++i)
+ {
+ unsigned numpoints, p;
+ istr >> numpoints >> p;
+ if (numpoints != 1)
+ internal::error(me, filename, "ill-formed vertex item.");
+ if (p > npoints)
+ internal::error(me, filename,
+ "point id out of bounds in vertex item.");
+ vertices.push_back(p);
+ }
+
+ // ------- //
+ // Edges. //
+ // ------- //
+
+ std::string lines_keyword;
+ unsigned nedges, edges_size;
+ istr >> lines_keyword >> nedges >> edges_size;
+ internal::accept(lines_keyword, "LINES", me, filename);
+
+ /* 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. */
+ // FIXME: This test is not really robust: we should involve
+ // the EDGES_SIZE value in the parsing process.
+ if (edges_size != nedges * 3)
+ internal::error(me, filename, "ill-formed `LINES' section.");
+
+ // An adjacenty matrix recording the edges seen so far.
+ typedef std::vector< std::vector<bool> > complex_edges_t;
+ complex_edges_t complex_edges (npoints,
+ std::vector<bool>(npoints, false));
+
+ // Populate the complex and the adjacency matrix
+ for (unsigned i = 0; i < nedges; ++i)
+ {
+ // Create a 1-face.
+ unsigned numpoints, p1, p2;
+ istr >> numpoints >> p1 >> p2;
+ if (numpoints != 2)
+ internal::error(me, filename, "ill-formed line item.");
+ if (p1 > npoints || p2 > npoints)
+ internal::error(me, filename,
+ "point id out of bounds in line item.");
+ topo::n_face<0, D> v1(c, p1);
+ topo::n_face<0, D> v2(c, p2);
+ c.add_face(v1 - v2);
+ // Tag this edged (and its opposite) in the adjacency matrix.
+ complex_edges[p1][p2] = true;
+ complex_edges[p2][p1] = true;
+ }
+
+ // ---------- //
+ // Polygons. //
+ // ---------- //
+
+ std::string polygons_keyword;
+ unsigned npolygons, polygons_size;
+ istr >> polygons_keyword >> npolygons >> polygons_size;
+ internal::accept(polygons_keyword, "POLYGONS", me, filename);
+
+ // Read polygon values.
+ unsigned npolygons_values = 0;
+
+ for (unsigned i = 0; i < npolygons; ++i)
+ {
+ unsigned numpoints;
+ istr >> numpoints;
+ ++npolygons_values;
+ if (numpoints <= 2)
+ {
+ internal::error(me, filename,
+ std::string("ill-formed face (having ")
+ + internal::str(numpoints)
+ + (numpoints < 2 ? "vertex" : "vertices")
+ + ").");
+ }
+
+ /* FIXME: This part (computing the set of edges on which
+ a polygon is built) is also shared by
+ mln::io::off::load; we can probably factor it. */
+
+ // The edges of the face.
+ topo::n_faces_set<1, D> face_edges_set;
+ face_edges_set.reserve(numpoints);
+
+ // Remember the first point id of the face.
+ unsigned first_point_id;
+ istr >> first_point_id;
+ ++npolygons_values;
+ // The current point id, initialized with the first id.
+ unsigned point_id = first_point_id;
+ if (point_id >= npoints)
+ internal::error(me, filename,
+ std::string("invalid point id: `")
+ + internal::str(point_id) + "'.");
+ for (unsigned p = 0; p < numpoints; ++p)
+ {
+ /* The next point id. The pair (point_id,
+ next_point_id) is an edge of the
+ mesh/complex. */
+ unsigned next_point_id;
+ /* When P is the id of the last point of the face,
+ set NEXT_POINT_ID to FIRST_VERTEX_ID; otherwise,
+ read it from the input. */
+ if (p == numpoints - 1)
+ next_point_id = first_point_id;
+ else
+ {
+ istr >> next_point_id;
+ ++npolygons_values;
+ if (next_point_id >= npoints)
+ internal::error(me, filename,
+ std::string("invalid point id: `")
+ // In-line ``itoa'' of NEXT_POINT_ID.
+ + internal::str(next_point_id) + "'.");
+ }
+ // The ends of the current edge.
+ topo::n_face<0, D> vertex(c, point_id);
+ topo::n_face<0, D> next_vertex(c, next_point_id);
+ // The current edge.
+ topo::algebraic_n_face<1, D> edge;
+ /* The edge (POINT_ID, NEXT_POINT_ID) (or its
+ opposite (NEXT_POINT_ID, POINT_ID) must have been
+ inserted previously. In other words, the sides
+ of POLYGON items must belong to the list of
+ LINES. */
+ if (!complex_edges[point_id][next_point_id])
+ internal::error(me, filename,
+ "ill-formed polygon, having a side "
+ "(edge) not part of the list of LINES.");
+ edge = topo::edge(vertex, next_vertex);
+ mln_assertion(edge.is_valid());
+ // Add this edge a side of the polygon.
+ face_edges_set += edge;
+ // Next vertex.
+ point_id = next_point_id;
+ }
+
+ // Add face.
+ c.add_face(face_edges_set);
+ }
+
+ // FIXME: This test is not really robust: we should involve
+ // the POLYGONS_SIZE value in the parsing process.
+ if (polygons_size != npolygons_values)
+ internal::error(me, filename, "ill-formed `LINES' section.");
+
+ // -------------------- //
+ // Dataset attributes. //
+ // -------------------- //
+
+ /* ``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).'' */
+ std::string dataset_kind;
+ istr >> dataset_kind;
+ if (dataset_kind == "POINT_DATA")
+ internal::error(me, filename,
+ "`POINT_DATA' datasets are not supported "
+ "(only `CELL_DATA' datasets are supported yet).");
+ else if (dataset_kind != "CELL_DATA")
+ internal::error(me, filename,
+ std::string("invalid dataset kind: `")
+ + dataset_kind + "'.");
+ unsigned nfaces = nvertices + nedges + npolygons;
+ unsigned ncell_data;
+ istr >> ncell_data;
+ if (ncell_data != nfaces)
+ internal::error(me, filename,
+ std::string("wrong number of dataset attributes ")
+ + "(expected " + internal::str(nfaces)
+ + ", got " + internal::str(ncell_data) + ").");
+
+ /* ``Dataset Attribute Format. The Visualization Toolkit
+ supports the following dataset attributes: scalars
+ (one to four components), vectors, normals,
+ texture coordinates (1D, 2D, and 3D), 3 x 3
+ tensors, and field data. In addition, a lookup
+ table using the RGBA color specification,
+ associated with the scalar data, can be defined as
+ well. Dataset attributes are supported for both
+ points and cells.
+ Each type of attribute data has a `dataName'
+ associated with it. This is a character string
+ (without embedded whitespace) used to identify a
+ particular data. The `dataName' is used by the VTK
+ readers to extract data. As a result, more than
+ one attribute data of the same type can be
+ included in a file. For example, two different
+ scalar fields defined on the dataset points,
+ pressure and temperature, can be contained in the
+ same file. (If the appropriate dataName is not
+ specified in the VTK reader, then the first data
+ of that type is extracted from the file.)
+
+ * Scalars
+ Scalar definition includes specification of a
+ lookup table. The definition of a lookup table
+ is optional.
+
+ [...]
+
+ SCALARS dataName dataType numComp
+ LOOKUP_TABLE tableName
+ s0
+ s1
+ ...
+ sn-1''
+
+ Note: values accepted by Paraview 3.8 for `dataType' are:
+ "bit", "char", "unsigned_char", "short", "unsigned_short",
+ "vtkidtype", "int", "unsigned_int", "long",
+ "unsigned_long", "vtktypeint64", "vtktypeuint64", "float",
+ "double", "string", "utf8_string" and "variant". */
+
+ std::string scalars_keyword, data_name, data_type;
+ istr >> scalars_keyword >> data_name >> data_type;
+ internal::accept(scalars_keyword, "SCALARS", me, filename);
+ // FIXME: As in the rest of this routine's code, we only
+ // handle the case of binary values (for the moment).
+ if (data_type != "bit")
+ internal::error(me, filename,
+ std::string("unsupported data (value) type : `")
+ + data_type + "' (only `bit' is supported yet).");
+
+ std::string lookup_table_keyword, lookup_table_name;
+ istr >> lookup_table_keyword >> lookup_table_name;
+ internal::accept(lookup_table_keyword, "LOOKUP_TABLE", me, filename);
+
+ // Values.
+ typedef mln_value_(I) V;
+ typedef metal::vec<D + 1, std::vector<V> > values;
+ values vs;
+
+ // Populate values associated to 0-faces.
+ /* FIXME: The default value used (here 0) depends on the
+ images's value type. */
+ vs[0].resize(npoints, 0);
+ // Iterate on VERTICES (not ``points''). We cannot copy
+ // VERTICES into VS[0] as-is, since VS[0] corresponds to
+ // points.
+ for (std::vector<unsigned>::const_iterator v = vertices.begin();
+ v != vertices.end(); ++ v)
+ {
+ V value;
+ istr >> value;
+ // The point id on which the vertex V is built.
+ unsigned p = *v;
+ vs[0][p] = value;
+ }
+
+ // Populate values associated to 1-faces.
+ for(unsigned e = 0; e < nedges; ++e)
+ {
+ V value;
+ istr >> value;
+ vs[1].push_back(value);
+ }
+
+ // Populate values associated to 2-faces.
+ for(unsigned f = 0; f < npolygons; ++f)
+ {
+ V value;
+ istr >> value;
+ vs[2].push_back(value);
+ }
+
+ /*--------.
+ | Image. |
+ `--------*/
+
+ // Site set.
+ typedef mln_domain_(I) domain;
+ domain s(c, geom);
+
+ // Image.
+ ima.init_(s, vs);
+
+ /*--------------.
+ | End of file. |
+ `--------------*/
+
+ // FIXME: Eat comments and whitespace, and check the end of
+ // the file has been reached.
+ // ...
+ istr.close();
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+ } // end of namespace mln::io::vtk
+
+ } // end of namespace mln::io
+
+} // end of namespace mln
+
+
+#endif // ! MLN_IO_VTK_LOAD_HH
diff --git a/milena/tests/io/vtk/Makefile.am b/milena/tests/io/vtk/Makefile.am
index 548f1b5..9554a4b 100644
--- a/milena/tests/io/vtk/Makefile.am
+++ b/milena/tests/io/vtk/Makefile.am
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 EPITA Research and Development Laboratory (LRDE).
+# Copyright (C) 2010, 2011 EPITA Research and Development Laboratory (LRDE).
#
# This file is part of Olena.
#
@@ -16,13 +16,16 @@
include $(top_srcdir)/milena/tests/tests.mk
-check_PROGRAMS = save
+check_PROGRAMS = load_bin load_save_bin save
+load_bin_SOURCES = load_bin.cc
+load_save_bin_SOURCES = load_save_bin.cc
save_SOURCES = save.cc
TESTS = $(check_PROGRAMS)
MOSTLYCLEANFILES = \
+ load_save_bin-out.vtk \
save-tetrahedron-bool.vtk \
save-tetrahedron-int_u8.vtk \
save-tetrahedron-unsigned.vtk \
diff --git a/milena/tests/io/off/load_bin.cc b/milena/tests/io/vtk/load_bin.cc
similarity index 87%
copy from milena/tests/io/off/load_bin.cc
copy to milena/tests/io/vtk/load_bin.cc
index 3d35a44..a4ddf10 100644
--- a/milena/tests/io/off/load_bin.cc
+++ b/milena/tests/io/vtk/load_bin.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -23,22 +23,26 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
+/// \file
+/// \brief Exercise mln::io::vtk::load on binary mesh images.
+
#include <algorithm>
#include <iterator>
#include <iostream>
-#include <mln/io/off/load.hh>
+#include <mln/io/vtk/load.hh>
#include "tests/data.hh"
-int main()
+int
+main()
{
using namespace mln;
typedef bin_2complex_image3df ima_t;
ima_t ima;
- io::off::load(ima, MLN_MESH_DIR "/tetrahedron.off");
+ io::vtk::load(ima, MLN_MESH_DIR "/tetrahedron.vtk");
std::cout << ima.domain().cplx() << std::endl;
diff --git a/milena/tests/io/off/load_save_bin.cc b/milena/tests/io/vtk/load_save_bin.cc
similarity index 80%
copy from milena/tests/io/off/load_save_bin.cc
copy to milena/tests/io/vtk/load_save_bin.cc
index 3287910..a4fc777 100644
--- a/milena/tests/io/off/load_save_bin.cc
+++ b/milena/tests/io/vtk/load_save_bin.cc
@@ -1,5 +1,4 @@
-// Copyright (C) 2008, 2009, 2010 EPITA Research and Development
-// Laboratory (LRDE)
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -24,12 +23,16 @@
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
+/// \file
+/// \brief Exercise mln::io::vtk::load and mln::io::vtk::save on
+/// binary mesh images.
+
#include <algorithm>
#include <iterator>
#include <iostream>
-#include <mln/io/off/load.hh>
-#include <mln/io/off/save.hh>
+#include <mln/io/vtk/load.hh>
+#include <mln/io/vtk/save.hh>
#include "tests/data.hh"
@@ -40,6 +43,6 @@ int main()
typedef bin_2complex_image3df ima_t;
ima_t ima;
- io::off::load(ima, MLN_MESH_DIR "/tetrahedron.off");
- io::off::save(ima, "load_save_bin-out.off");
+ io::vtk::load(ima, MLN_MESH_DIR "/tetrahedron.vtk");
+ io::vtk::save(ima, "load_save_bin-out.vtk");
}
--
1.5.6.5
* mln/geom/complex_geometry.hh
(mln::geom::complex_geometry<D, P>::reserve): New.
Use it...
* mln/io/off/load.hh: ...here.
Aesthetic changes.
---
milena/ChangeLog | 10 ++++++++++
milena/mln/geom/complex_geometry.hh | 17 +++++++++++++++--
milena/mln/io/off/load.hh | 30 +++++++++++++++---------------
3 files changed, 40 insertions(+), 17 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 4697665..b1288ef 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,13 @@
+2011-03-01 Roland Levillain <roland(a)lrde.epita.fr>
+
+ Add a pre-allocation routine to mln::geom::complex_geometry.
+
+ * mln/geom/complex_geometry.hh
+ (mln::geom::complex_geometry<D, P>::reserve): New.
+ Use it...
+ * mln/io/off/load.hh: ...here.
+ Aesthetic changes.
+
2010-07-28 Roland Levillain <roland(a)lrde.epita.fr>
Regen Milena's Makefile helpers.
diff --git a/milena/mln/geom/complex_geometry.hh b/milena/mln/geom/complex_geometry.hh
index f1c604c..7ca99f8 100644
--- a/milena/mln/geom/complex_geometry.hh
+++ b/milena/mln/geom/complex_geometry.hh
@@ -1,4 +1,5 @@
-// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2008, 2009, 2011 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -43,7 +44,7 @@
/* FIXME: Also provide functors where the locations are computed using
- a function (useful for a complex on a regular grid/support. */
+ a function (useful for a complex on a regular grid/support). */
/* FIXME: This class could probably be turned into something more
generic, usable for other other purpose, e.g. attaching sites to
@@ -106,6 +107,9 @@ namespace mln
/// Retrieve the site associated to \a f.
site operator()(const mln::topo::face<D>& f) const;
+ /// Pre-allocate memory.
+ void reserve(size_t n);
+
private:
mln::util::tracked_ptr< internal::complex_geometry_data<P> > data_;
};
@@ -170,6 +174,15 @@ namespace mln
return s;
}
+ template <unsigned D, typename P>
+ inline
+ void
+ complex_geometry<D, P>::reserve(size_t n)
+ {
+ mln_precondition(data_);
+ data_->zero_faces_geom.reserve(n);
+ }
+
# endif // ! MLN_INCLUDE_ONLY
} // end of mln::geom
diff --git a/milena/mln/io/off/load.hh b/milena/mln/io/off/load.hh
index c9c4af7..e66ae28 100644
--- a/milena/mln/io/off/load.hh
+++ b/milena/mln/io/off/load.hh
@@ -1,4 +1,5 @@
-// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2008, 2009, 2011 EPITA Research and Development
+// Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -296,17 +297,17 @@ namespace mln
/* ``The vertices are listed with x, y, z coordinates, written
one per line.'' */
- /* FIXME: We should have a faster way to create a bunch of
- 0-faces (vertices). */
- for (unsigned v = 0; v < nvertices; ++v)
- c.add_face();
-
typedef point3df P;
typedef mln_coord_(P) C;
typedef geom::complex_geometry<D, P> G;
G geom;
+ geom.reserve(nvertices);
for (unsigned v = 0; v < nvertices; ++v)
{
+ // Create a 0-face.
+ c.add_face();
+
+ // Record the geometry (point) associated to this vertex.
C x, y, z;
istr >> &self::eat_comment >> x
>> &self::eat_comment >> y
@@ -346,10 +347,10 @@ namespace mln
topo::n_faces_set<1, D> face_edges_set;
face_edges_set.reserve(nface_vertices);
- // The first vertex id of the face.
+ // Remember the first vertex id of the face.
unsigned first_vertex_id;
istr >> &self::eat_comment >> first_vertex_id;
- // The current vertex id initialized with the first id.
+ // The current vertex id, initialized with the first id.
unsigned vertex_id = first_vertex_id;
if (first_vertex_id >= nvertices)
{
@@ -366,7 +367,7 @@ namespace mln
mesh/complex. */
unsigned next_vertex_id;
/* When V is the id of the last vertex of the face F,
- set next_vertex_id to first_vertex_id; otherwise,
+ set NEXT_VERTEX_ID to FIRST_VERTEX_ID; otherwise,
read it from the input. */
if (v == nface_vertices - 1)
next_vertex_id = first_vertex_id;
@@ -376,7 +377,7 @@ namespace mln
if (next_vertex_id >= nvertices)
{
std::cerr << me << ": `" << filename
- << "': invalid vertex id "
+ << "': invalid vertex id: "
<< next_vertex_id << std::endl;
std::exit(1);
}
@@ -386,15 +387,14 @@ namespace mln
topo::n_face<0, D> next_vertex(c, next_vertex_id);
// The current edge.
topo::algebraic_n_face<1, D> edge;
- // If the edge has been constructed yet, create it;
- // otherwise, retrieve its id from the complex.
+ // If the edge has not been constructed yet, create
+ // it; otherwise, retrieve its id from the complex.
if (!complex_edges[vertex_id][next_vertex_id])
{
complex_edges[vertex_id][next_vertex_id] = true;
complex_edges[next_vertex_id][vertex_id] = true;
edge =
- make_algebraic_n_face(c.add_face(vertex -
- next_vertex),
+ make_algebraic_n_face(c.add_face(vertex - next_vertex),
true);
}
else
@@ -422,7 +422,7 @@ namespace mln
// Site set.
domain s(c, geom);
- // Values
+ // Values.
values vs;
exact(this)->assign(vs, s);
--
1.5.6.5
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Olena, a generic and efficient image processing platform".
The branch vtk-format has been updated
via 6629f93070da7d9eea9fa6a7b99e96154d624565 (commit)
via e402de7a1c8b372d768e93fdb76718e73ab48681 (commit)
via 21a5b46f16b712625498aaa2b01a601cdd614990 (commit)
from 57d5538008bc881e674005421f55b85b43a5125e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
6629f93 Add preliminary VTK input for binary images.
e402de7 Add VTK-format meshes.
21a5b46 Add a pre-allocation routine to mln::geom::complex_geometry.
-----------------------------------------------------------------------
Summary of changes:
milena/ChangeLog | 35 ++
milena/mesh/Makefile.am | 20 +-
milena/mesh/pseudo-manifold.vtk | 188 ++++++++
milena/mesh/tetrahedron.vtk | 48 ++
milena/mln/geom/complex_geometry.hh | 17 +-
milena/mln/io/off/load.hh | 30 +-
milena/mln/io/vtk/all.hh | 3 +-
milena/mln/io/vtk/load.hh | 615 +++++++++++++++++++++++++
milena/tests/io/vtk/Makefile.am | 7 +-
milena/tests/io/{off => vtk}/load_bin.cc | 12 +-
milena/tests/io/{off => vtk}/load_save_bin.cc | 15 +-
11 files changed, 956 insertions(+), 34 deletions(-)
create mode 100644 milena/mesh/pseudo-manifold.vtk
create mode 100644 milena/mesh/tetrahedron.vtk
create mode 100644 milena/mln/io/vtk/load.hh
copy milena/tests/io/{off => vtk}/load_bin.cc (87%)
copy milena/tests/io/{off => vtk}/load_save_bin.cc (80%)
hooks/post-receive
--
Olena, a generic and efficient image processing platform
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Olena, a generic and efficient image processing platform".
The branch igr has been deleted
was dab5d674ff5a32dbbba0dbe53543864f89d405cc
-----------------------------------------------------------------------
dab5d674ff5a32dbbba0dbe53543864f89d405cc mln/io/dicom/load.hh: Fix invalid image loading.
-----------------------------------------------------------------------
hooks/post-receive
--
Olena, a generic and efficient image processing platform