00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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];
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
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
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
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
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
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
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
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
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
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