Milena (Olena)
User documentation 2.0a Id
|
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