Milena (Olena)  User documentation 2.0a Id
load.hh
00001 // Copyright (C) 2008, 2009, 2011 EPITA Research and Development
00002 // Laboratory (LRDE)
00003 //
00004 // This file is part of Olena.
00005 //
00006 // Olena is free software: you can redistribute it and/or modify it under
00007 // the terms of the GNU General Public License as published by the Free
00008 // Software Foundation, version 2 of the License.
00009 //
00010 // Olena is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Olena.  If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 // As a special exception, you may use this file as part of a free
00019 // software project without restriction.  Specifically, if other files
00020 // instantiate templates or use macros or inline functions from this
00021 // file, or you compile this file and link it with other files to produce
00022 // an executable, this file does not by itself cause the resulting
00023 // executable to be covered by the GNU General Public License.  This
00024 // exception does not however invalidate any other reasons why the
00025 // executable file might be covered by the GNU General Public License.
00026 
00027 #ifndef MLN_IO_OFF_LOAD_HH
00028 # define MLN_IO_OFF_LOAD_HH
00029 
00036 
00037 # include <cstdlib>
00038 # include <iostream>
00039 # include <fstream>
00040 # include <string>
00041 
00042 # include <mln/literal/black.hh>
00043 # include <mln/core/concept/object.hh>
00044 # include <mln/core/alias/complex_image.hh>
00045 
00046 
00047 namespace mln
00048 {
00049 
00050   namespace io
00051   {
00052 
00053     namespace off
00054     {
00055 
00063       void load(bin_2complex_image3df& ima, const std::string& filename);
00064 
00065       // FIXME: Implement a load routine for for
00066       // int_u8_2complex_image3df.
00067 
00075       void load(float_2complex_image3df& ima, const std::string& filename);
00076 
00084       void load(rgb8_2complex_image3df& ima, const std::string& filename);
00085 
00086 
00087       namespace internal
00088       {
00089 
00090         template <typename I, typename E>
00091         struct off_loader : public Object<E>
00092         {
00093           typedef off_loader<I, E> self;
00094 
00096           static const unsigned D = 2;
00098           typedef metal::vec<D + 1, std::vector< mln_value(I) > > values;
00100           typedef mln_domain(I) domain;
00101 
00103           off_loader();
00104 
00106           void operator()(I& ima, const std::string& filename);
00107 
00110           static std::istream& eat_comment(std::istream& istr);
00111         };
00112 
00113 
00114         struct bin_off_loader
00115           : public off_loader< bin_2complex_image3df, bin_off_loader >
00116         {
00120           void read_face_data(std::istream& istr);
00121 
00123           void assign(values& vs, const domain& s);
00124 
00128           void reserve(unsigned nvertices, unsigned nedges, unsigned nfaces);
00129         };
00130 
00131 
00132         /* Factor float_off_loader::reserve and rgb8_off_loader::reserve
00133            and float_off_loader::assign and rgb8_off_loader::assign
00134            by introducing an intermediate class.  */
00135 
00136         struct float_off_loader
00137           : public off_loader< float_2complex_image3df, float_off_loader >
00138         {
00140           void read_face_data(std::istream& istr);
00141 
00143           void reserve(unsigned nvertices, unsigned nedges, unsigned nfaces);
00144 
00146           void assign(values& vs, const domain& s);
00147 
00149           std::vector<float> face_value;
00150         };
00151 
00152 
00153         struct rgb8_off_loader
00154           : public off_loader< rgb8_2complex_image3df, rgb8_off_loader >
00155         {
00157           void read_face_data(std::istream& istr);
00158 
00160           void reserve(unsigned nvertices, unsigned nedges, unsigned nfaces);
00161 
00163           void assign(values& vs, const domain& s);
00164 
00166           std::vector<value::rgb8> face_value;
00167         };
00168 
00169       } // end of namespace mln::io::off::internal
00170 
00171 
00172 
00173 # ifndef MLN_INCLUDE_ONLY
00174 
00175       /*----------.
00176       | Facades.  |
00177       `----------*/
00178 
00179       inline
00180       void
00181       load(bin_2complex_image3df& ima, const std::string& filename)
00182       {
00183         trace::entering("mln::io::off::load");
00184         internal::bin_off_loader()(ima, filename);
00185         trace::exiting("mln::io::off::load");
00186       }
00187 
00188       inline
00189       void
00190       load(float_2complex_image3df& ima, const std::string& filename)
00191       {
00192         trace::entering("mln::io::off::load");
00193         internal::float_off_loader()(ima, filename);
00194         trace::exiting("mln::io::off::load");
00195       }
00196 
00197       inline
00198       void
00199       load(rgb8_2complex_image3df& ima, const std::string& filename)
00200       {
00201         trace::entering("mln::io::off::load");
00202         internal::rgb8_off_loader()(ima, filename);
00203         trace::exiting("mln::io::off::load");
00204       }
00205 
00206 
00207 
00208       /*-------------------------.
00209       | Actual implementations.  |
00210       `-------------------------*/
00211 
00212       // -------- //
00213       // Canvas.  //
00214       // -------- //
00215 
00216       namespace internal
00217       {
00218 
00219         template <typename I, typename E>
00220         inline
00221         off_loader<I, E>::off_loader()
00222         {
00223           // Concept checking.
00224           void (E::*m1)(std::istream&) = &E::read_face_data;
00225           m1 = 0;
00226           void (E::*m2)(unsigned, unsigned, unsigned) = &E::reserve;
00227           m2 = 0;
00228           void (E::*m3)(values&, const domain&) = &E::assign;
00229           m3 = 0;
00230         }
00231 
00232 
00233         template <typename I, typename E>
00234         inline
00235         void
00236         off_loader<I, E>::operator()(I& ima, const std::string& filename)
00237         {
00238           const std::string me = "mln::io::off::load";
00239 
00240           std::ifstream istr(filename.c_str());
00241           if (!istr)
00242             {
00243               std::cerr << me << ": `" << filename << "' not found."
00244                         << std::endl;
00245               /* FIXME: Too violent.  We should allow the use of
00246                  exceptions, at least to have Milena's code behave
00247                  correctly in interpreted environments (std::exit() or
00248                  std::abort() causes the termination of a Python
00249                  interpreter, for instance!).  */
00250               std::exit(1);
00251             }
00252 
00253           /*---------.
00254           | Header.  |
00255           `---------*/
00256 
00257           /* ``The .off files in the Princeton Shape Benchmark conform
00258              to the following standard''. */
00259 
00260           /* ``OFF files are all ASCII files beginning with the keyword
00261              OFF. ''  */
00262           std::string type;
00263           istr >> &self::eat_comment >> type;
00264           if (type != "OFF")
00265             {
00266               std::cerr << me << ": `" << filename << "': ill-formed header."
00267                         << std::endl;
00268               std::exit(1);
00269             }
00270 
00271           /* ``The next line states the number of vertices, the number
00272              of faces, and the number of edges. The number of edges can
00273              be safely ignored.'' */
00274           unsigned nvertices, nfaces, nedges;
00275           istr >> &self::eat_comment >> nvertices
00276                >> &self::eat_comment >> nfaces
00277                >> &self::eat_comment >> nedges;
00278 
00280           exact(this)->reserve(nvertices, nedges, nfaces);
00281 
00282           /*-------.
00283           | Data.  |
00284           `-------*/
00285 
00286           /* FIXME: Maybe we could sugar all this (using make_whatever
00287              helpers?).  */
00288 
00289           // --------- //
00290           // Complex.  //
00291           // --------- //
00292 
00293           const unsigned D = 2;
00294           topo::complex<D> c;
00295 
00296           // ------------------------------------------ //
00297           // Vertices & geometry (vertices locations).  //
00298           // ------------------------------------------ //
00299 
00300           /* ``The vertices are listed with x, y, z coordinates, written
00301              one per line.''  */
00302 
00303           /* FIXME: We should have a faster way to create a bunch of
00304              0-faces (vertices).  */
00305           for (unsigned v = 0; v < nvertices; ++v)
00306             c.add_face();
00307 
00308           typedef point3df P;
00309           typedef mln_coord_(P) C;
00310           typedef geom::complex_geometry<D, P> G;
00311           G geom;
00312           for (unsigned v = 0; v < nvertices; ++v)
00313             {
00314               C x, y, z;
00315               istr >> &self::eat_comment >> x
00316                    >> &self::eat_comment >> y
00317                    >> &self::eat_comment >> z;
00318               geom.add_location(point3df(x, y, z));
00319             }
00320 
00321           // --------------- //
00322           // Faces & edges.  //
00323           // --------------- //
00324 
00325           /* ``After the list of vertices, the faces are listed, with
00326              one face per line. For each face, the number of vertices
00327              is specified, followed by indices into the list of
00328              vertices.''  */
00329 
00330           // An adjacenty matrix recording the edges seen so far.
00331           typedef std::vector< std::vector<bool> > complex_edges_t;
00332           complex_edges_t complex_edges (nvertices,
00333                                          std::vector<bool>(nvertices, false));
00334 
00335           for (unsigned f = 0; f < nfaces; ++f)
00336             {
00337               unsigned nface_vertices;
00338               istr >> &self::eat_comment >> nface_vertices;
00339               if (nface_vertices <= 2)
00340                 {
00341                   std::cerr << me << ": `" << filename
00342                             << "': ill-formed face (having "
00343                             << nface_vertices << ' '
00344                             << (nface_vertices < 2 ? "vertex" : "vertices")
00345                             << ')' << std::endl;
00346                   std::exit(1);
00347                 }
00348 
00349               // The edges of the face.
00350               topo::n_faces_set<1, D> face_edges_set;
00351               face_edges_set.reserve(nface_vertices);
00352 
00353               // The first vertex id of the face.
00354               unsigned first_vertex_id;
00355               istr >> &self::eat_comment >> first_vertex_id;
00356               // The current vertex id initialized with the first id.
00357               unsigned vertex_id = first_vertex_id;
00358               if (first_vertex_id >= nvertices)
00359                 {
00360                   std::cerr << me << ": `" << filename
00361                             << "': invalid vertex id " << first_vertex_id
00362                             << std::endl;
00363                   std::exit(1);
00364                 }
00365               // Iterate on vertices and form edges.
00366               for (unsigned v = 0; v < nface_vertices; ++v)
00367                 {
00368                   /* The next vertex id.  The pair (vertex_id,
00369                      next_vertex_id) is an edge of the
00370                      mesh/complex.  */
00371                   unsigned next_vertex_id;
00372                   /* When V is the id of the last vertex of the face F,
00373                      set next_vertex_id to first_vertex_id; otherwise,
00374                      read it from the input.  */
00375                   if (v == nface_vertices - 1)
00376                     next_vertex_id = first_vertex_id;
00377                   else
00378                     {
00379                       istr >> &self::eat_comment >> next_vertex_id;
00380                       if (next_vertex_id >= nvertices)
00381                         {
00382                           std::cerr << me << ": `" << filename
00383                                     << "': invalid vertex id "
00384                                     << next_vertex_id << std::endl;
00385                           std::exit(1);
00386                         }
00387                     }
00388                   // The ends of the current edge.
00389                   topo::n_face<0, D> vertex(c, vertex_id);
00390                   topo::n_face<0, D> next_vertex(c, next_vertex_id);
00391                   // The current edge.
00392                   topo::algebraic_n_face<1, D> edge;
00393                   // If the edge has been constructed yet, create it;
00394                   // otherwise, retrieve its id from the complex.
00395                   if (!complex_edges[vertex_id][next_vertex_id])
00396                     {
00397                       complex_edges[vertex_id][next_vertex_id] = true;
00398                       complex_edges[next_vertex_id][vertex_id] = true;
00399                       edge =
00400                         make_algebraic_n_face(c.add_face(vertex -
00401                                                          next_vertex),
00402                                               true);
00403                     }
00404                   else
00405                     {
00406                       edge = topo::edge(vertex, next_vertex);
00407                       mln_assertion(edge.is_valid());
00408                     }
00409                   // Record this edge.
00410                   face_edges_set += edge;
00411                   // Next vertex.
00412                   vertex_id = next_vertex_id;
00413                 }
00414 
00415               // Possibly read a value (depends on the actual format).
00416               exact(this)->read_face_data(istr);
00417 
00418               // Add face.
00419               c.add_face(face_edges_set);
00420             }
00421 
00422           /*--------.
00423           | Image.  |
00424           `--------*/
00425 
00426           // Site set.
00427           domain s(c, geom);
00428 
00429           // Values
00430           values vs;
00431           exact(this)->assign(vs, s);
00432 
00433           // Image.
00434           ima.init_(s, vs);
00435 
00436           /*--------------.
00437           | End of file.  |
00438           `--------------*/
00439 
00440           istr >> &self::eat_comment;
00441           if (!istr.eof())
00442             {
00443               std::cerr << me << ": `" << filename
00444                         << "': end of file not reached" << std::endl;
00445               std::exit(1);
00446             }
00447           istr.close();
00448         }
00449 
00450 
00451         // ---------------- //
00452         // Specific parts.  //
00453         // ---------------- //
00454 
00455         /* FIXME: We do not honor the part
00456 
00457              ``Line breaks are significant here: the color description
00458              begins after VertN and ends with the end of the line (or
00459              the next # comment).
00460 
00461           in the following comment.  */
00462 
00502         inline
00503         void
00504         bin_off_loader::read_face_data(std::istream& /* istr */)
00505         {
00506           // Do nothing (no data associated to faces).
00507         }
00508 
00509         inline
00510         void
00511         float_off_loader::read_face_data(std::istream& istr)
00512         {
00513           /* We just use R and ignore G, B and A (transparency) when
00514              considering the value (``color'') associated to a face as
00515              a (scalar) floating-point value (though it really is an
00516              RGB triplet).
00517 
00518              To ensure consistency, we /might/ (later) check that R, G
00519              and B are equal---or better, ``almost equal'', as they
00520              are floats.
00521 
00522              Moreover, R must (and G, B and A should) be
00523              floating-point values between 0 and 1, according to the
00524              OFF file format definition.  */
00525           // FIXME: `A' should be optional.
00526           float r, g, b, a;
00527           istr >> r >> g >> b >> a;
00528           mln_assertion(0.0f <= r);  mln_assertion(r <= 1.0f);
00529           mln_assertion(0.0f <= g);  mln_assertion(g <= 1.0f);
00530           mln_assertion(0.0f <= b);  mln_assertion(b <= 1.0f);
00531           mln_assertion(0.0f <= a);  mln_assertion(a <= 1.0f);
00532           face_value.push_back(r);
00533         }
00534 
00535         inline
00536         void
00537         rgb8_off_loader::read_face_data(std::istream& istr)
00538         {
00539           /* We just use R, G, and B and ignore A (transparency) when
00540              considering the value (``color'') associated to a face.
00541 
00542              R must (and G, B and A should) be floating-point values
00543              between 0 and 1, according to the OFF file format
00544              definition.  */
00545           // FIXME: `A' should be optional.
00546           float r, g, b, a;
00547           istr >> r >> g >> b >> a;
00548           mln_assertion(0.0f <= r);  mln_assertion(r <= 1.0f);
00549           mln_assertion(0.0f <= g);  mln_assertion(g <= 1.0f);
00550           mln_assertion(0.0f <= b);  mln_assertion(b <= 1.0f);
00551           mln_assertion(0.0f <= a);  mln_assertion(a <= 1.0f);
00552           face_value.push_back(value::rgb8(int(255 * r),
00553                                            int(255 * g),
00554                                            int(255 * b)));
00555         }
00556         /* \} */
00557 
00558 
00559         inline
00560         void
00561         bin_off_loader::reserve(unsigned /* nvertices */,
00562                                 unsigned /* nedges */,
00563                                 unsigned /* nfaces */)
00564         {
00565           // Do nothing (no data associated to faces).
00566         }
00567 
00568         inline
00569         void
00570         float_off_loader::reserve(unsigned /* nvertices */,
00571                                   unsigned /* nedges */,
00572                                   unsigned nfaces)
00573         {
00574           face_value.reserve(nfaces);
00575         }
00576 
00577 
00578         inline
00579         void
00580         rgb8_off_loader::reserve(unsigned /* nvertices */,
00581                                  unsigned /* nedges */,
00582                                  unsigned nfaces)
00583         {
00584           face_value.reserve(nfaces);
00585         }
00586 
00587 
00588         inline
00589         void
00590         bin_off_loader::assign(values& vs, const domain& s)
00591         {
00592           // Default values.
00593           for (unsigned i = 0; i <= D; ++i)
00594             vs[i].insert(vs[i].begin(), s.cplx().nfaces_of_dim(i), true);
00595         }
00596 
00597         inline
00598         void
00599         float_off_loader::assign(values& vs, const domain& s)
00600         {
00601           // Default values for n-face with n in [0, D[.
00602           for (unsigned i = 0; i < D; ++i)
00603             vs[i].insert(vs[i].begin(), s.cplx().nfaces_of_dim(i), 0.0f);
00604           // Values for D-faces.
00605           vs[D] = face_value;
00606         }
00607 
00608         inline
00609         void
00610         rgb8_off_loader::assign(values& vs, const domain& s)
00611         {
00612           // Default values for n-face with n in [0, D[.
00613           for (unsigned i = 0; i < D; ++i)
00614             vs[i].insert(vs[i].begin(), s.cplx().nfaces_of_dim(i),
00615                          literal::black);
00616           // Values for D-faces.
00617           vs[D] = face_value;
00618         }
00619 
00620 
00621         // --------- //
00622         // Helpers.  //
00623         // --------- //
00624 
00625         template <typename I, typename E>
00626         inline
00627         std::istream&
00628         off_loader<I, E>::eat_comment(std::istream& istr)
00629         {
00630           // Skip whitespace and newlines.
00631           std::ws(istr);
00632           while (istr.peek() == '#')
00633             {
00634               /* Eat the `#' and the rest of the line until `\n' or
00635                  `\r' is found or the end of the file is reached.  */
00636               char c;
00637               do
00638                 istr.get(c);
00639               while (c != '\n' && c != '\r' && !istr.eof());
00640               // Skip whitespace and newlines.
00641               std::ws(istr);
00642             }
00643           return istr;
00644         }
00645 
00646       } // end of namespace mln::io::off::internal
00647 
00648 
00649 # endif // ! MLN_INCLUDE_ONLY
00650 
00651 
00652     } // end of namespace mln::io::off
00653 
00654   } // end of namespace mln::io
00655 
00656 } // end of namespace mln
00657 
00658 
00659 #endif // ! MLN_IO_OFF_LOAD_HH
 All Classes Namespaces Functions Variables Typedefs Enumerator