polyhedron.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 <algorithm>
00022 #include <float.h>
00023 #include "polyhedron.h"
00024 #include "polyhedron_gl.h"
00025 #include "util.h"
00026 
00027 using namespace std;
00028 using namespace HE;
00029 using namespace Geometry;
00030 
00031 Polyhedron::Polyhedron(const char* filename)
00032   : _gl(0), _type(FT_OFF)
00033 {
00034   if (!load(filename))
00035     throw HE_exception("Cannot load input file", filename);
00036 }
00037 
00038 Polyhedron::Polyhedron()
00039    : _gl(0), _type(FT_OFF)
00040 {
00041 }
00042 
00043 Polyhedron::Polyhedron(const std::vector<Vertex*>& verts, const std::vector<std::vector<int> >& faces)
00044    : _gl(0), _type(FT_OFF)
00045 {
00046   _vertices.resize(verts.size());
00047   for (unsigned v=0 ; v<verts.size() ; v++)
00048     _vertices[v] = new Vertex(verts[v]->position(), v);
00049   loadFaces( faces );
00050 }
00051 
00052 Polyhedron::~Polyhedron()
00053 {
00054         for (face_iterator fit=fBegin() ; fit!=fEnd() ; ++fit)
00055                 delete *fit;
00056         _faces.clear();
00057 
00058         for (edge_iterator eit=eBegin() ; eit!=eEnd() ; ++eit)
00059                 delete *eit;
00060         _halfEdges.clear();
00061 
00062         for (vertex_iterator vit=vBegin() ; vit!=vEnd() ; ++vit)
00063                 delete *vit;
00064         _vertices.clear();
00065 }
00066 
00067 
00072 Polyhedron* Polyhedron::refine() const
00073 {
00074   Polyhedron* P = new Polyhedron;
00075   cerr << P->numFaces() << " faces in initial mesh\n";
00076   P->_vertices.reserve(_vertices.size() + _halfEdges.size()/2 + 1);
00077   for (unsigned i=0 ; i<_vertices.size() ; i++)
00078      P->_vertices.push_back( new Vertex(_vertices[i]->position(), _vertices[i]->index()) );
00079 
00080   map<const HalfEdge*, const Vertex*> edge2midpoints;
00081   for (const_face_iterator it=fBegin() ; it!=fEnd() ; ++it)
00082   {
00083     const Face* f = *it;
00084     //cerr << "***\nFace " << *f << "\n***\n";
00085     if (f->hole())
00086       continue;
00087     const HalfEdge* sentinel = f->edge();
00088     const HalfEdge* he = sentinel;
00089     const Vertex* V(0), *V2(0);
00090     vector<int> verts;
00091     //cerr << "[ Entering the loop...\n";
00092     do
00093     {
00094       if (edge2midpoints.end() == edge2midpoints.find(he))
00095       {
00096         V2 = P->addVertex(he->midpoint());
00097         edge2midpoints[he] = edge2midpoints[he->twin()] = V2;
00098       }
00099       else
00100       {
00101         V2 = edge2midpoints[he];
00102       }
00103       verts.push_back(V2->index());
00104 
00105       // Is this NOT the first halfedge we traverse in the face?
00106       if (V)
00107       {
00108         Face* f2 = P->addFace(V->index(), he->src()->index(), V2->index());
00109         f2->hole(f->hole());
00110       }
00111 
00112       V = V2;
00113       he = he->next();
00114     } while (he != sentinel) ;
00115     //cerr << "] Leaving the loop...\n";
00116     assert(verts.size() >= 3);
00117     Face* f2 = P->addFace(verts.back(), sentinel->src()->index(), verts.front());
00118     f2->hole(f->hole());
00119     f2 = P->addFace(verts);
00120     f2->hole(f->hole());
00121   }
00122 
00123   cerr << P->numFaces() << " in new Polyhedron\n";
00124   P->finalize();
00125   cerr << P->numFaces() << " in refined Polyhedron\n";
00126   cerr << numVertices() << " vertices in original Polyhedron\n";
00127   cerr << P->numVertices() << " vertices in refined Polyhedron\n";
00128   return P;
00129 }
00130 
00131 
00132 Vertex* Polyhedron::addVertex(const Vector3Df& v)
00133 {
00134         Vertex* V = new Vertex(v, _vertices.size());
00135         _vertices.push_back(V);
00136         return V;
00137 }
00138 
00139 void Polyhedron::clearData()
00140 {
00141    _faces.clear();
00142    _holes.clear();
00143    _halfEdges.clear();
00144    _vertices.clear();
00145 }
00146 
00147 bool Polyhedron::load(const char* filename)
00148 {
00149         filetype_e format = fileFormat(filename);
00150 
00151    clearData();
00152         bool success = false;
00153         switch( format )
00154         {
00155                 case FT_PLY_ASCII:
00156                         success = readPly(filename);
00157                         type(FT_PLY_ASCII);
00158                         break;
00159 
00160     case FT_OFF:
00161       success = readOff(filename);
00162       type(FT_OFF);
00163       break;
00164 
00165     case FT_TRI:
00166       success = readTri(filename);
00167       type(FT_TRI);
00168       break;
00169 
00170     case FT_PLY_BIN:
00171                         throw HE_exception("Cannot read binary PLY format yet", filename);
00172                         type(FT_PLY_BIN);
00173                         break;
00174 
00175                 case FT_OBJ:
00176                         throw HE_exception("Cannot read OBJ format yet", filename);
00177                         type(FT_OBJ);
00178                         break;
00179 
00180                 case FT_NONE:
00181                         throw HE_exception("Unknown input file format", filename);
00182                         type(FT_NONE);
00183                         break;
00184         }
00185 
00186         packVertices();
00187         return success;
00188 }
00189 
00190 
00191 void Polyhedron::finalize()
00192 {
00193   assert(check(false));
00194 
00195   // First, find the connections that need finalization. During construction, this is all of them.
00196   map<pair<int,int>, HalfEdge*> connections;
00197   for (edge_iterator it=eBegin() ; it!=eEnd() ; ++it)
00198   {
00199     HalfEdge* he = *it;
00200     if (!he->twin())
00201     {
00202       int a = he->prev()->dst()->index();
00203       int b = he->dst()->index();
00204       pair<int,int> idx(a, b);
00205       if (connections.end() != connections.find(idx))
00206          throw HE_exception("Repeated half-edge: This is a non-manifold mesh, not supported by half-edge data structures.");
00207 
00208       pair<int,int> idx2(b, a);
00209       map<pair<int,int>, HalfEdge*>::iterator cit = connections.find(idx2);
00210       if (connections.end() == cit)
00211       {
00212          connections[idx] = he;
00213       }
00214       else
00215       {
00216          HalfEdge*& he2 = cit->second;
00217          he->twin(he2);
00218          he2->twin(he);
00219          connections.erase(cit);
00220       }
00221       //connections[make_pair(b, a)] = he;
00222     }
00223     else
00224     {
00225        assert(he->twin()->twin() == he);
00226     }
00227   }
00228 
00229   assert(check(false));
00230   closeSurface(connections);
00231   assert(check());
00232 }
00233 
00234 
00239 void Polyhedron::closeSurface(map<pair<int,int>, HalfEdge*>& connections)
00240 {
00241   //cerr << "closeSurface\n";
00242    map<pair<int,int>, HalfEdge*>& endPoints = connections; // Which vertex points are connected by which halfedge?
00243    map<int,vector<pair<int,int> > >v2e;    // Which edges point to each vertex?
00244    for (map<pair<int,int>, HalfEdge*>::const_iterator it=endPoints.begin() ; it!=endPoints.end() ; ++it)
00245    {
00246       HalfEdge* e = it->second;
00247       assert(!e->twin());
00248 
00249       int src = e->prev()->dst()->index();
00250       int dst = e->dst()->index();
00251       pair<int,int> pts(src, dst);
00252       v2e[dst].push_back(pts);
00253       assert(find(v2e[pts.second].begin(), v2e[pts.second].end(), pts) != v2e[pts.second].end());
00254       //if (v2e[dst].size() > 1)
00255          //throw HE_exception("This mesh has a pinched vertex, which we do not support yet.");
00256    }
00257 
00258         // Add half-edges around the detected boundaries, each connected set being assigned to a face/hole
00259    while (!endPoints.empty())
00260    {
00261       map<pair<int,int>, HalfEdge*>::iterator pit = endPoints.begin();
00262       pair<int,int> pts = pit->first;
00263       HalfEdge* e = pit->second;
00264       HalfEdge* e2;
00265       Face* f = new Face(0, true);
00266       _faces.push_back(f);
00267       _holes.insert(f);
00268 
00269       //cerr << "processing edge <" << pts.first << ',' << pts.second << ">\n";
00270       int start = pts.second; // pts.second is the dst() of a surface half-edge
00271       int v = start;
00272       vector<HalfEdge*> bdry;
00273       do
00274       {
00275          e2 = new HalfEdge(_vertices[pts.first], f, e, 0);
00276          _halfEdges.push_back(e2);
00277          e->twin(e2);
00278          assert(e2->twin() == e);
00279          assert(e->dst() == e2->src());
00280          assert(e->src() == e2->dst());
00281          bdry.push_back(e2);
00282          assert(endPoints.end() != endPoints.find(pts));
00283          endPoints.erase(pit);
00284          assert(endPoints.end() == endPoints.find(pts));
00285          //assert(! v2e[pts.first].empty() );
00286 
00287          // Move on to the next halfedge in the boundary sequence.
00288          // Notice here that due to the edge shift, pts.first becomes pts.second... This caused a bug!
00289          int idx = pts.first;
00290          pts = v2e[idx].back();
00291          v2e[idx].pop_back();
00292          assert(pts.second == idx);
00293          //cerr << "trying to move to edge <" << pts.first << ',' << pts.second << ">\n";
00294          pit = endPoints.find(pts);
00295          if(endPoints.end() == pit)
00296             break;
00297          assert(pit->first == pts);
00298          //cerr << "moved to edge <" << pts.first << ',' << pts.second << ">\n";
00299          e = pit->second;
00300          v = pts.second;
00301          assert(start != v);
00302       } while(start != v);
00303       f->edge(e2);
00304 
00305                 // Connect each new half-edge with its immediately next around the hole
00306       //cerr << "closing a loop w/ " << bdry.size() << " elements:\n";
00307       for (unsigned i=0 ; i<bdry.size() ; i++)
00308       {
00309         //cerr << '<' << bdry[i]->src()->index() << ',' << bdry[i]->dst()->index() << "> is followed by <"
00310           //  << bdry[(i+1)%bdry.size()]->src()->index() << ',' << bdry[(i+1)%bdry.size()]->dst()->index() << ">\n";
00311          bdry[i]->next( bdry[(i+1)%bdry.size()] );
00312       }
00313 
00314       // Check the connections
00315 #ifndef NDEBUG
00316       for (unsigned i=0 ; i<bdry.size() ; i++)
00317       {
00318          const HalfEdge* e = bdry[i];
00319          const HalfEdge* e2 = e->twin();
00320          assert(e->prev()->dst() == e->src());
00321          assert(e2->prev()->dst() == e2->src());
00322       }
00323 #endif
00324    }
00325 }
00326 
00327 
00328 
00329 HalfEdge* Polyhedron::edge(int from, int to) const
00330 {
00331         return _vertices[from]->edgeTo(to);
00332 }
00333 
00334 
00335 void Polyhedron::boundingBox(Geometry::Vector3Df& m, Geometry::Vector3Df& M) const
00336 {
00337         m = Vector3Df(FLT_MAX, FLT_MAX, FLT_MAX);
00338         M = -m;
00339 
00340         // Find the bounding min and max values for each coordinate, each point
00341         for (const_vertex_iterator vit=vBegin() ; vit!=vEnd() ; ++vit)
00342         {
00343                 const Vector3Df& v = (*vit)->position();
00344                 for (int i=0 ; i<3 ; i++)
00345                 {
00346                         if (v[i] > M[i])
00347                                 M[i] = v[i];
00348                         if (v[i] < m[i])
00349                                 m[i] = v[i];
00350                 }
00351         }
00352 }
00353 
00354 
00355 void Polyhedron::scaleAndCenter(float radius)
00356 {
00357         Geometry::Vector3Df m, M;
00358         boundingBox(m, M);
00359         Geometry::Vector3Df ctr = (m+M) / 2;
00360         float diff = 0;
00361         for (int i=0 ; i<3 ; i++)
00362         {
00363                 assert(M[i] >= m[i]);
00364                 if (diff < M[i]-m[i])
00365                         diff = M[i]-m[i];
00366         }
00367 
00368         for (vertex_iterator vit=vBegin() ; vit!=vEnd() ; ++vit)
00369         {
00370                 Vector3Df v = (*vit)->position() - ctr;
00371                 v *= radius / diff;
00372                 (*vit)->position(v);
00373         }
00374 
00375         if (_gl)
00376                 _gl->recomputeNormals();
00377 }
00378 
00379 
00380 void Polyhedron::invertNormals()
00381 {
00382         // Invert the order of the edges around the faces
00383         map<const HalfEdge*, HalfEdge*> next;
00384         map<const HalfEdge*, Vertex*> dst;
00385         for (edge_iterator eit=eBegin() ; eit!=eEnd() ; ++eit)
00386         {
00387                 HalfEdge* e = *eit;
00388 
00389                 assert(next.end() == next.find(e->next()));
00390                 next[e->next()] = e;
00391 
00392                 assert(dst.end() == dst.find(e));
00393                 dst[e] = e->src();
00394         }
00395 
00396         // Apply such changes
00397         for (edge_iterator eit=eBegin() ; eit!=eEnd() ; ++eit)
00398         {
00399                 HalfEdge* e = *eit;
00400                 e->next( next[e] );
00401 
00402                 Vertex* v = e->dst();
00403                 e->dst( dst[e] );
00404                 v->edge(e);
00405         }
00406 
00407         if (_gl)
00408                 _gl->recomputeNormals();
00409 
00410         assert(check());
00411 }
00412 
00413 
00414 bool faceIsHole(const Face* f) { return f->hole(); }
00415 
00416 int Polyhedron::numHoles() const
00417 {
00418         return count_if(fBegin(), fEnd(), faceIsHole);
00419 }
00420 
00421 
00422 bool Polyhedron::check(bool holesFilled) const
00423 {
00424 #if 0
00425         for (Polyhedron::const_vertex_iterator it=vBegin() ; it!=vEnd() ; ++it)
00426         {
00427                 assert((*it)->edge() != 0);
00428         }
00429 #endif
00430 
00431         for (Polyhedron::const_edge_iterator it=eBegin() ; it!=eEnd() ; ++it)
00432         {
00433                 if (holesFilled)
00434                 {
00435                         assert((*it)->twin() != 0);
00436                         assert((*it)->twin()->twin() == (*it));
00437                 }
00438                 assert((*it)->next() != 0);
00439                 assert((*it)->face() != 0);
00440       assert((*it)->dst() != 0);
00441       assert(!(*(*it)->dst() == *(*it)->prev()->dst()));
00442                 
00443                 // Make sure the half edge is correctly linked in a face
00444                 {
00445                         set<const HalfEdge*> visited;
00446                         const HalfEdge* e = *it;
00447                         const HalfEdge* sentinel = e;
00448                         do
00449                         {
00450                                 assert(visited.end() == visited.find(e));
00451                                 visited.insert(e);
00452                                 e = e->next();
00453                         } while(e != sentinel);
00454                 }
00455 
00456                 assert((*it)->prev()->next() == *it);
00457                 if (holesFilled)
00458       {
00459         assert((*it)->prev()->dst() == (*it)->src());
00460       }
00461         }
00462 
00463         for (Polyhedron::const_face_iterator it=fBegin() ; it!=fEnd() ; ++it)
00464         {
00465                 set<const HalfEdge*> visited;
00466                 const Face* f = *it;
00467                 Face::const_edge_circulator eit = f->begin();
00468                 Face::const_edge_circulator sentinel = eit;
00469                 do
00470                 {
00471                         assert(visited.end() == visited.find(*eit));
00472                         visited.insert(*eit);
00473                         ++eit;
00474                 } while(eit != sentinel);
00475         }
00476 
00477         return true;
00478 }
00479 
00480 
00481 void Polyhedron::packVertices()
00482 {
00483         int n = 0;
00484         for (int v=0 ; v<numVertices() ; v++)
00485         {
00486                 if (_vertices[v]->edge())
00487                 {
00488                         _vertices[v]->index(n);
00489                         _vertices[n++] = _vertices[v];
00490                 }
00491         }
00492 
00493         //cerr << (numVertices()-n) << " vertices have been eliminated\n";
00494         _vertices.resize(n);
00495 }
00496 
00497 
00498 bool Polyhedron::adjacent(const Vertex* v1, const Vertex* v2) const
00499 {
00500    Vertex::const_edge_circulator eit = v1->begin();
00501    Vertex::const_edge_circulator sentinel = eit;
00502    do
00503    {
00504       if ((*eit)->dst() == v2)
00505          return true;
00506       ++eit;
00507    } while(eit != sentinel);
00508    return false;
00509 }
00510 
00511 bool Polyhedron::adjacent(const Face* f1, const Face* f2) const
00512 {
00513    Face::const_edge_circulator eit = f1->begin();
00514    Face::const_edge_circulator sentinel = eit;
00515    do
00516    {
00517       if ((*eit)->twin()->face() == f2)
00518          return true;
00519       ++eit;
00520    } while(eit != sentinel);
00521    return false;
00522 }
00523 

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