• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

load.hh

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

Generated on Tue Oct 4 2011 15:24:02 for Milena (Olena) by  doxygen 1.7.1