mesh_io.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2007 by Pablo Diaz-Gutierrez   *
00003  *   pablo@ics.uci.edu   *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU Library General Public License as       *
00007  *   published by the Free Software Foundation; either version 2 of the    *
00008  *   License, or (at your option) any later version.                       *
00009  *                                                                         *
00010  *   This program 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         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU Library General Public     *
00016  *   License along with this program; if not, write to the                 *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 #include <string>
00022 #include <iterator>
00023 #include "polyhedron.h"
00024 #include "util.h"
00025 
00028 
00029 using namespace std;
00030 using namespace Geometry;
00031 using namespace HE;
00032 
00033 const int LEN = 128;
00034 
00035 
00036 filetype_e HE::fileFormat(const char* filename)
00037 {
00038         string name(filename);
00039         for (unsigned i=0 ; i<name.size() ; i++)
00040                 name[i] = tolower(name[i]);
00041 
00042         // Can we detect by just looking at the filename?
00043   if (name.find(".obj") < name.size() || name.find(".OBJ") < name.size())
00044                 return FT_OBJ;
00045   else if (name.find(".tri") < name.size() || name.find(".TRI") < name.size())
00046     return FT_TRI;
00047 
00048         ifstream in(filename);
00049         if (!in)
00050                 throw HE_exception("Cannot open file", filename);
00051 
00052         // Check the header's magic string
00053         string s;
00054         in >> s;
00055   if (s == "OFF")
00056   {
00057     assert(name.find(".off") < name.size());
00058     in.close();
00059     return FT_OFF;
00060   }
00061   
00062   if (s == "ply")
00063         {
00064                 assert(name.find(".ply") < name.size());
00065 
00066                 in >> s;
00067                 assert(s == "format");
00068                 in >> s;
00069                 in.close();
00070                 if (s == "ascii")
00071                         return FT_PLY_ASCII;
00072                 else
00073                         return FT_PLY_BIN;
00074         }
00075 
00076         in.close();
00077         return FT_NONE;
00078 }
00079 
00080 bool Polyhedron::readPly(const char* filename)
00081 {
00082         ifstream in(filename);
00083         if (!in)
00084         {
00085                 throw HE_exception("Cannot open file", filename);
00086                 return false;
00087         }
00088 
00089         int nv, nf;
00090         short order[11];                // order of x,y,z, nx,ny,nz, red,green,blue, tu,tv vertex properties
00091         bool result = readPlyHeader(in, nv, nf, order);
00092         assert(result);
00093 
00094         vector<float> verts;
00095         vector<vector<int> > faces;
00096         result = readPlyData(in, nv, nf, order, verts, faces);
00097         assert(result);
00098         loadVertices(verts);
00099         loadFaces(faces);
00100 
00101         return true;
00102 }
00103 
00104 bool Polyhedron::readPlyHeader(ifstream& in, int& nv, int& nf, short order[11])
00105 {
00106         char buf[LEN], type[LEN], c[LEN];
00107         int i;
00108 
00109   // read ply file header
00110         in.getline(buf, LEN);
00111         assert(strncmp(buf, "ply", 3) == 0);
00112 
00113         in.getline(buf, LEN);
00114         if (strncmp(buf, "format ascii", 12) != 0)
00115         {
00116                 cerr << "Error: Input file is not in ASCII format. Line read: " << buf << endl;
00117                 return false;
00118         }
00119 
00120         in.getline(buf, LEN);
00121         while (strncmp(buf, "comment", 7) == 0)
00122                 in.getline(buf, LEN);
00123 
00124   // read number of vertices
00125         if (strncmp(buf, "element vertex", 14) == 0)
00126         {
00127                 sscanf(buf, "element vertex %d\n", &nv);
00128         }
00129         else 
00130         {
00131                 cerr << "Error: number of vertices expected\n";
00132                 return false;
00133         }
00134         
00135         for (i=0 ; i<11 ; ++i)
00136                 order[i] = -1;
00137 
00138   // read vertex properties order
00139         i = 0;
00140         in.getline(buf, LEN);
00141         while (strncmp(buf, "property", 8) == 0)
00142         {
00143                 sscanf(buf, "property %s %s\n", type, c);
00144                 if (strncmp(c, "x", 1) == 0)
00145                         order[0] = i;
00146                 else if (strncmp(c, "y", 1) == 0)
00147                         order[1] = i;
00148                 else if (strncmp(c, "z", 1) == 0)
00149                         order[2] = i;
00150 
00151                 else if (strncmp(c, "nx", 2) == 0)
00152                         order[3] = i;
00153                 else if (strncmp(c, "ny", 2) == 0)
00154                         order[4] = i;
00155                 else if (strncmp(c, "nz", 2) == 0)
00156                         order[5] = i;
00157 
00158                 else if (strncmp(c, "red", 3) == 0)
00159                         order[6] = i;
00160                 else if (strncmp(c, "green", 5) == 0)
00161                         order[7] = i;
00162                 else if (strncmp(c, "blue", 4) == 0)
00163                         order[8] = i;
00164 
00165                 else if (strncmp(c, "tu", 2) == 0)
00166                         order[9] = i;
00167                 else if (strncmp(c, "tv", 2) == 0)
00168                         order[10] = i;
00169 
00170                 i++;
00171                 in.getline(buf, LEN);
00172         }
00173         //nproperties = i;
00174 
00175         for (i=0; i<3; i++)
00176         {
00177                 if (order[i] < 0)
00178                 {
00179                         cerr << "Error: not enough vertex coordinate fields (nx, ny, nz)\n";
00180                         return false;
00181                 }
00182         }
00183 #if 0
00184         hasnormal = true;
00185         for (i = 3; i < 6; i++)
00186                 if (order[i] < 0)
00187                         hasnormal = false;
00188         hascolor = true;
00189         for (i = 6; i < 9; i++)
00190                 if (order[i] < 0)
00191                         hascolor = false;
00192         hastexture = true;
00193         for (i = 9; i < 11; i++)
00194                 if (order[i] < 0)
00195                         hastexture = false;
00196 
00197         if (!hasnormal)
00198                 cerr << "Notice: no normal coordinates used from file\n";
00199         if (!hascolor)
00200                 cerr << "Notice: no color used from file\n";
00201         if (!hastexture)
00202                 cerr << "Notice: no texture coordinates used from file\n";
00203 #endif
00204 
00205   // number of faces and face properties
00206         if (strncmp(buf, "element face", 12) == 0)
00207                 sscanf(buf, "element face %d\n", &nf);
00208         else
00209         {
00210                 cerr << "Error: number of faces expected\n";
00211                 return false;
00212         }
00213 
00214         in.getline(buf, LEN);
00215         if (strncmp(buf, "property list", 13) != 0)
00216         {
00217                 cerr << "Error: property list expected\n";
00218                 return false;
00219         }
00220 
00221         // Skip everything up to the end of the header
00222         in.getline(buf, LEN);
00223         while (strncmp(buf, "end_header", 10) != 0)
00224                 in.getline(buf, LEN);
00225 
00226         return true;
00227 }
00228 
00229 bool Polyhedron::readPlyData(ifstream& in, int& nv, int& nf, const short order[11], vector<float>& verts, vector<vector<int> >& faces)
00230 {
00232         char buf[LEN];
00233         int i, k, v;
00234         float values[32];
00235         verts.clear();
00236         for (i = 0; i < nv; i++)
00237         {
00238                 in.getline(buf, LEN);
00239                 sscanf(buf,"%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", &values[0], &values[1], &values[2], &values[3],
00240                                          &values[4], &values[5], &values[6], &values[7], &values[8], &values[9], &values[10], &values[11],
00241                                          &values[12], &values[13], &values[14], &values[15]);
00242 
00243                 verts.push_back( values[order[0]] );
00244                 verts.push_back( values[order[1]] );
00245                 verts.push_back( values[order[2]] );
00246 #if 0
00247                 if (hasnormal)
00248                         for (j = 0; j < 3; j++)
00249                                 normals[i][j] = values[order[3+j]];
00250                 if (hascolor)
00251                         for (j = 0; j < 3; j++)
00252                                 colors[i][j] = (unsigned char)values[order[6+j]];
00253                 if (hastexture)
00254                         for (j = 0; j < 2; j++)
00255                                 texcoords[i][j] = values[order[9+j]];
00256 #endif
00257         }
00258 
00259 
00261   // read in face connectivity
00262         for (i = 0; i < nf; i++)
00263         {
00264                 in >> k;
00265                 vector<int> vi(k);
00266                 for (int j=0 ; j<k ; j++)
00267                 {
00268                         in >> v;
00269                         vi[j] = v;
00270                 }
00271 
00272                 faces.push_back(vi);
00273         }
00274 
00275         return true;
00276 }
00277 
00278 bool Polyhedron::readOff(const char* filename)
00279 {
00280   ifstream in(filename);
00281   if (!in)
00282   {
00283     throw HE_exception("Cannot open file", filename);
00284     return false;
00285   }
00286 
00287   string s;
00288   int n, i, nv, nf, dunno;
00289   vector<int> face;
00290   in >> s;
00291   assert(s == "OFF");
00292 
00293   in >> nv >> nf >> dunno;
00294   vector<float> verts(nv*3);
00295   for (int v=0 ; v<nv*3 ; v++)
00296     in >> verts[v];
00297   loadVertices(verts);
00298   
00299   vector<vector<int> > faces;
00300   for (int f=0 ; f<nf ; f++)
00301   {
00302     face.clear();
00303     in >> n;
00304     while (n-- > 0)
00305     {
00306       in >> i;
00307       face.push_back(i);
00308     }
00309     faces.push_back(face);
00310   }
00311   loadFaces(faces);
00312 
00313   return true;
00314 }
00315 
00316 bool Polyhedron::readTri(const char* filename)
00317 {
00318   ifstream in(filename);
00319   if (!in)
00320   {
00321     throw HE_exception("Cannot open file", filename);
00322     return false;
00323   }
00324 
00325   string s;
00326   int n, i, nv, nf;
00327   in >> nf;
00328   nv = 3*nf;
00329 
00330   vector<float> verts(nv*3);
00331   for (int v=0 ; v<nv*3 ; v++)
00332     in >> verts[v];
00333   loadVertices(verts);
00334   
00335   vector<vector<int> > faces;
00336   for (int f=0 ; f<nf ; f++)
00337   {
00338     vector<int> face(3);
00339     face[0] = 3*f;
00340     face[1] = 3*f+1;
00341     face[2] = 3*f+2;
00342     faces.push_back(face);
00343   }
00344   loadFaces(faces);
00345 
00346   return true;
00347 }
00348 
00349 bool Polyhedron::saveAsPly(const char* filename) const
00350 {
00351         ofstream out(filename);
00352         if (!out)
00353         {
00354                 throw HE_exception("Cannot open file", filename);
00355                 return false;
00356         }
00357         cerr << "Saving model to " << filename << endl;
00358 
00359         out << "ply\n"
00360                         << "format ascii 1.0\n"
00361                         << "element vertex " << numVertices() << endl
00362                         << "property float32 x\n"
00363                         << "property float32 y\n"
00364                         << "property float32 z\n"
00365                         << "element face " << numFaces() << endl
00366                         << "property list uint8 int32 vertex_indices\n"
00367                         << "end_header\n";
00368 
00369         writeVertices(out);
00370         writeFaces(out);
00371 
00372         out.close();
00373         return true;
00374 }
00375 
00376 
00377 void Polyhedron::writeVertices(std::ostream& out) const
00378 {
00379         for (const_vertex_iterator vit=vBegin() ; vit!=vEnd() ; ++vit)
00380                 out << (*vit)->position() << endl;
00381 }
00382 
00383 void Polyhedron::writeHalfEdges(std::ostream& out) const
00384 {
00385   for (const_edge_iterator eit=eBegin() ; eit!=eEnd() ; ++eit)
00386     out << (*eit)->prev()->dst()->index() << ' ' << (*eit)->dst()->index() << endl;
00387 }
00388 
00389 void Polyhedron::writeFaces(std::ostream& out, bool includeHoles) const
00390 {
00391         for (const_face_iterator fit=fBegin() ; fit!=fEnd() ; ++fit)
00392         {
00393                 const Face* f = *fit;
00394                 if (!includeHoles && f->hole())
00395                         continue;
00396       if (includeHoles)
00397         out << (f->hole() ? "h " : "  " );
00398       out << f->size();
00399 
00400                 Face::const_edge_circulator e = f->begin();
00401                 Face::const_edge_circulator sentinel = e;
00402         
00403                 do
00404                 {
00405                         out  << ' ' << (*e)->dst()->index();
00406                         ++e;
00407                 } while (e != sentinel) ;
00408                 
00409                 out << endl;
00410         }
00411 }
00412 
00413 
00414 bool Polyhedron::save(const char* filename) const
00415 {
00416         switch(_type)
00417         {
00418                 case FT_PLY_ASCII:
00419                         return saveAsPly(filename);
00420 
00421     case FT_OFF:
00422       return saveAsOff(filename);
00423 
00424     case FT_TRI:
00425       return saveAsTri(filename);
00426 
00427     default:
00428                         cerr << "Format not supported for output\n";
00429                         return false;
00430         }
00431 }
00432 
00433 
00434 bool Polyhedron::saveAsOff(const char* filename) const
00435 {
00436   ofstream out(filename);
00437   if (!out)
00438   {
00439     throw HE_exception("Cannot open file", filename);
00440     return false;
00441   }
00442 
00443   out << "OFF\n";
00444   out << numVertices() << ' ' << numFaces()-numHoles() << ' ' << 0 << endl << endl;
00445   writeVertices( out);
00446   writeFaces( out);
00447   
00448   out.close();
00449   return true;
00450 }
00451 
00452 bool Polyhedron::saveAsTri(const char* filename) const
00453 {
00454   ofstream out(filename);
00455   if (!out)
00456   {
00457     throw HE_exception("Cannot open file", filename);
00458     return false;
00459   }
00460 
00461   out << numFaces() << endl;
00462   
00463   for (const_face_iterator fit=fBegin() ; fit!=fEnd() ; ++fit)
00464   {
00465     const Face* f = *fit;
00466     if (f->hole())
00467       continue;
00468 
00469     Face::const_edge_circulator e = f->begin();
00470     Face::const_edge_circulator sentinel = e;
00471     do
00472     {
00473       out  << ' ' << (*e)->dst()->position();
00474       ++e;
00475     } while (e != sentinel) ;
00476     out << endl;
00477   }
00478 
00479   out.close();
00480   return true;
00481 }
00482 
00483 
00484 void Polyhedron::loadVertices(const std::vector<float>& verts)
00485 {
00486   assert(0 == verts.size()%3);
00487 #if 0
00488   cerr << verts.size()/3 << " vertices being loaded:\n";
00489                                 for (unsigned i=0 ; i<verts.size() ; ++i)
00490                                 cerr << (0==i%3 ? '\n' : ' ') << verts[i];
00491                                 cerr << endl;
00492 #endif
00493 
00494                                 int nv = verts.size()/3;
00495                             _vertices.resize(nv);
00496                             for(int i=0 ; i<nv ; ++i)
00497                             {
00498                               Vector3Df v(verts[3*i], verts[3*i+1], verts[3*i+2]);
00499                               _vertices[i] = new Vertex(v, i);
00500                             }
00501 }
00502 
00503 void Polyhedron::loadFaces(const std::vector<std::vector<int> >& faces)
00504 {
00505 #if 0
00506   cerr << faces.size() << " faces being loaded\n";
00507                               for (unsigned i=0 ; i<faces.size() ; ++i)
00508                           {
00509                               for (unsigned j=0 ; j<faces[i].size() ; ++j)
00510                               cerr << faces[i][j] << ' ';
00511                               cerr << endl;
00512 }
00513 #endif
00514 
00515   for( unsigned i=0 ; i<faces.size() ; ++i)
00516     addFace( faces[i] );
00517   finalize();
00518 }
00519 
00520 
00521 Face* Polyhedron::addFace(int a, int b, int c)
00522 {
00523   vector<int> corners(3);
00524   corners[0] = a;
00525   corners[1] = b;
00526   corners[2] = c;
00527   return addFace(corners);
00528 }
00529 
00530 Face* Polyhedron::addFace(const std::vector<int>& corners)
00531 {
00532 #if 0
00533   cerr << "Adding face #" << numFaces() << ": ";
00534   copy(corners.begin(), corners.end(), ostream_iterator<int>(cerr, ", "));
00535   cerr << endl;
00536 #endif
00537 
00538   Face* f = new Face(0);
00539   _faces.push_back(f);
00540 
00541   // Create one HalfEdge per consecutive pair of corners
00542   vector<HalfEdge*> edges;
00543   const unsigned nc = corners.size();
00544   for (unsigned i=0 ; i<nc ; ++i)
00545   {
00546     int c1 = corners[i];
00547     int c2 = corners[(i+1)%nc];
00548     HalfEdge* he = new HalfEdge(_vertices[c2], f);
00549     assert(!he->twin());
00550     assert(he->face());
00551     _halfEdges.push_back(he);
00552     f->edge(he);
00553     _vertices[c1]->edge(he);
00554     edges.push_back(he);
00555   }
00556         
00557         // Connect each HalfEdge to its next in the face
00558   assert(nc == edges.size());
00559   const unsigned& ne = nc;
00560   for (unsigned e=0 ; e<ne ; e++)
00561     edges[e]->next( edges[(e+1)%ne] );
00562 
00563   return f;
00564 }
00565 
00566 
00567 ostream& HE::operator<<(ostream& out, const Polyhedron& p)
00568 {
00569   out << p.numVertices() << " vertices:\n";
00570   p.writeVertices(out);
00571   out << p.numFaces() << " faces:\n";
00572   p.writeFaces(out, true);
00573   out << p.numHalfEdges() << " half-edges:\n";
00574   p.writeHalfEdges(out);
00575 
00576   return out;
00577 }
00578 

Generated on Wed Apr 9 19:22:37 2008 for HalfEdge library by  doxygen 1.5.3