objreader.h

Go to the documentation of this file.
00001 #ifndef VVELIB_FACTORY_OBJREADER_H
00002 #define VVELIB_FACTORY_OBJREADER_H
00003 
00009 #include <config.h>
00010 #include <string>
00011 #include <util/vector.h>
00012 #include <QIODevice>
00013 #include <QTextStream>
00014 #include <QString>
00015 #include <QFile>
00016 #include <iostream>
00017 #include <algorithms/complex.h>
00018 
00019 namespace complex_factory
00020 {
00021   typedef util::Vector<3,double> Point3d;
00022   using std::cerr;
00023   using std::endl;
00024 
00030   class ObjReaderError
00031   {
00032   public:
00036       enum Type
00037       {
00038         NO_ERRORS, // Due to windows crap, NO_ERROR is not usable (but equivalent?)
00039         BAD_NUMBER_OF_DIMENSIONS,
00040         FILE_FORMAT,
00041         DOUBLE_EXPECTED,
00042         INTEGER_EXPECTED,
00043         INVALID_FACE,
00044         CANNOT_OPEN_FILE
00045       };
00046 
00047       ObjReaderError() {}
00048       ObjReaderError(Type t);
00049       ObjReaderError(Type t, QString msg);
00050       ObjReaderError(const ObjReaderError& copy)
00051         : _string(copy._string)
00052         , _type(copy._type)
00053       {}
00054 
00058       virtual QString string() { return _string; }
00059 
00063       virtual int type() { return _type; }
00064 
00068       operator bool() { return _type != NO_ERRORS; }
00069 
00070   protected:
00071       void initFromType();
00072 
00073       QString _string;
00074       Type _type;
00075   };
00076 
00125   template <class CellComplex, class Model>
00126   ObjReaderError objreader(QTextStream& content, CellComplex& T, Model& model)
00127   {
00128     IMPORT_COMPLEX_TYPES(CellComplex);
00129 
00130     std::vector<Point3d> vertices_pos;
00131     std::vector<Point3d> normals;
00132     std::vector<std::vector<int> > faces_idx;
00133 
00134     QString token;
00135 
00136     while(!content.atEnd())
00137     {
00138       content >> token;
00139       QString buffer = content.readLine();
00140 //      cerr << "Reading token '" << token.toStdString() << "'" << endl;
00141 //      cerr << "Buffer: '" << buffer.toStdString() << "'" << endl;
00142       if(token == QString("v"))
00143       {
00144         QList<QString> pos = buffer.split(' ', QString::SkipEmptyParts);
00145         if(pos.size() != 3)
00146         {
00147           QString msg = "Error, vertex " + QString::number(vertices_pos.size()) +
00148             " has " + QString::number(pos.size()) +  " dimensions instead of 3";
00149           return ObjReaderError(ObjReaderError::BAD_NUMBER_OF_DIMENSIONS, msg);
00150         }
00151         Point3d p;
00152         bool ok, ok_tmp;
00153         p.x() = pos[0].toDouble(&ok);
00154         p.y() = pos[1].toDouble(&ok_tmp);
00155         ok &= ok_tmp;
00156         p.z() = pos[2].toDouble(&ok_tmp);
00157         ok &= ok_tmp;
00158         if(!ok)
00159         {
00160           QString msg = "Error on vertex " + QString::number(vertices_pos.size()) +
00161             ": double value expected";
00162           return ObjReaderError(ObjReaderError::DOUBLE_EXPECTED, msg);
00163         }
00164         vertices_pos.push_back(p);
00165       }
00166       else if(token == QString("vn"))
00167       {
00168         QList<QString> pos = buffer.split(' ');
00169         if(pos.size() != 3)
00170         {
00171           QString msg = "Error, normal " + QString::number(normals.size()) + " has " +
00172             QString::number(pos.size()) + " dimensions instead of 3";
00173           return ObjReaderError(ObjReaderError::BAD_NUMBER_OF_DIMENSIONS, msg);
00174         }
00175         Point3d p;
00176         bool ok, ok_tmp;
00177         p.x() = pos[0].toDouble(&ok);
00178         p.y() = pos[1].toDouble(&ok_tmp);
00179         ok &= ok_tmp;
00180         p.z() = pos[2].toDouble(&ok_tmp);
00181         ok &= ok_tmp;
00182         if(!ok)
00183         {
00184           QString msg = "Error on normal " + QString::number(vertices_pos.size()) + ": double value expected";
00185           return ObjReaderError(ObjReaderError::DOUBLE_EXPECTED, msg);
00186         }
00187         normals.push_back(p);
00188       }
00189       else if(token == QString("f"))
00190       {
00191         std::vector<int> f;
00192         QList<QString> face = buffer.split(' ', QString::SkipEmptyParts);
00193         if(face.size() < 3)
00194         {
00195           QString msg = "Error, face " + QString::number(faces_idx.size()) + " has less than 3 vertices.";
00196           return ObjReaderError(ObjReaderError::INVALID_FACE, msg);
00197         }
00198         bool ok = true;
00199         forall(QString& value, face)
00200         {
00201           int vn = value.toInt(&ok);
00202           if(!ok)
00203           {
00204             QString msg = "Error on face " + QString::number(faces_idx.size()) + ": integer values expected";
00205             return ObjReaderError(ObjReaderError::INTEGER_EXPECTED, msg);
00206           }
00207           f.push_back(vn);
00208         }
00209         faces_idx.push_back(f);
00210       }
00211     }
00212     if(normals.size() > vertices_pos.size())
00213     {
00214       cerr << "Warning: more normals than vertices" << endl;
00215     }
00216     if(!normals.empty() and normals.size() < vertices_pos.size())
00217     {
00218       cerr << "Warning: not all vertices have a normal, ignoring the specified normals." << endl;
00219       normals.clear();
00220     }
00221     // First, add the vertices
00222     std::vector<junction> vertices;
00223     std::vector<cell> faces;
00224     int id = 0;
00225     forall(const Point3d& pos, vertices_pos)
00226     {
00227       junction v;
00228       T.S.insert(v);
00229       T.W.insert(v);
00230       model.setPosition(v, pos);
00231       vertices.push_back(v);
00232       model.setVertexId(v, ++id);
00233     }
00234     // Then add the faces and connect the center to the junctions (in the 
00235     // correct order)
00236     id = 0;
00237     forall(const std::vector<int>& face_idx, faces_idx)
00238     {
00239       cell face;
00240       junction pf(0);
00241       T.S.insert(face);
00242       T.C.insert(face);
00243       Point3d center;
00244       forall(int i, face_idx)
00245       {
00246         center += vertices_pos[i-1];
00247         junction current = vertices[i-1];
00248         if(pf)
00249         {
00250           T.S.spliceAfter(face, pf, current);
00251         }
00252         else
00253           T.S.insertEdge(face, current);
00254         pf = current;
00255       }
00256       center /= face_idx.size();
00257       model.setPosition(face, center);
00258       model.setFaceId(face, ++id);
00259     }
00260     // Connect the vertices to the faces
00261     forall_named(const junction& j, T.S, junctions)
00262     {
00263       if(T.S.iValence(j) < 3)
00264       {
00265         // There is nothing to sort ...
00266         forall(const cell& f, T.S.iNeighbors(j))
00267         {
00268           T.S.insertEdge(j, f);
00269         }
00270       }
00271       else
00272       {
00273         const cell& f_init = T.S.iAnyIn(j);
00274         cell pf = f_init;
00275         T.S.insertEdge(j, f_init);
00276         do
00277         {
00278           cell f(0);
00279           const junction& m = T.S.prevTo(pf, j);
00280           // Now, find the face that contains also m
00281           forall(const cell& of, T.S.iNeighbors(j))
00282           {
00283             if(of == pf)
00284               continue;
00285             if(T.S.edge(of, m))
00286             {
00287               f = of;
00288               break;
00289             }
00290           }
00291           if(!f or f == f_init)
00292           {
00293             break;
00294           }
00295           // Insert f after pf in j
00296           T.S.spliceAfter(j, pf, f);
00297           pf = f;
00298         } while( T.S.iValence(j) != T.S.valence(j));
00299         pf = f_init;
00300         // If we didn't find all the neighbors, it means we have to go the 
00301         // other way around
00302         while(T.S.iValence(j) != T.S.valence(j))
00303         {
00304           cell f(0);
00305           const junction& m = T.S.nextTo(pf, j);
00306           forall(const cell& of, T.S.iNeighbors(j))
00307           {
00308             if(of == pf)
00309               continue;
00310             if(T.S.edge(of, m))
00311             {
00312               f = of;
00313               break;
00314             }
00315           }
00316           if(!f)
00317             break;
00318           T.S.spliceBefore(j, pf, f);
00319           pf = f;
00320         }
00321         if(T.S.valence(j) != T.S.iValence(j))
00322         {
00323           cerr << "Error, vertex " << model.vertexId(j) << " was not properly connected to the faces" << endl;
00324         }
00325       }
00326     }
00327     // Connect the junctions
00328     forall_named(const junction& j, T.S, junctions)
00329     {
00330       junction prev(0);
00331       forall(const cell& c, T.S.neighbors(j))
00332       {
00333         const junction& jn = T.S.nextTo(c, j);
00334         const junction& jp = T.S.prevTo(c, j);
00335         if(prev.isNull())
00336         {
00337           T.W.insertEdge(j, jn);
00338           prev = jn;
00339         }
00340         else if(prev != jn)
00341         {
00342           T.W.spliceAfter(j, prev, jn);
00343         }
00344         T.W.spliceAfter(j, jn, jp);
00345         prev = jp;
00346       }
00347     }
00348     // if the normals aren't specified, then compute them
00349     if(normals.empty())
00350     {
00351       forall_named(const junction& v, T.S, junctions)
00352       {
00353         Point3d pos = model.position(v);
00354         Point3d normal;
00355         if(T.border(v))
00356         {
00357           // If this is a border index, first find the border
00358           forall(const junction& n, T.W.neighbors(v))
00359           {
00360             const junction& m = T.W.nextTo(v,n);
00361             if(T.border(v, m) and T.border(v, n))
00362             {
00363               junction n1 = m;
00364               do
00365               {
00366                 const junction& n2 = T.W.nextTo(v, n1);
00367                 Point3d p1 = model.position(n1) - pos;
00368                 Point3d p2 = model.position(n2) - pos;
00369                 normal += p1^p2;
00370                 n1 = n2;
00371               } while(n1 != n);
00372               break;
00373             }
00374           }
00375         }
00376         else
00377         {
00378           // If this is an inside vertex
00379           forall(const junction& n, T.W.neighbors(v))
00380           {
00381             Point3d p1 = model.position(n) - pos;
00382             Point3d p2 = model.position(T.W.nextTo(v, n)) - pos;
00383             normal += p1^p2;
00384           }
00385         }
00386         normal.normalize();
00387         model.setNormal(v, normal);
00388       }
00389     }
00390     else
00391     {
00392       int k = 0;
00393       forall(const Point3d& n, normals)
00394       {
00395         junction v = vertices[k++];
00396         model.setNormal(v, n);
00397       }
00398     }
00399     // Compute normals for the faces
00400     forall_named(const cell& f, T.S, cells)
00401     {
00402       Point3d pos = model.position(f);
00403       Point3d normal;
00404       forall(const junction& v, T.S.neighbors(f))
00405       {
00406         const junction& v1 = T.S.nextTo(f, v);
00407         Point3d p1 = model.position(v) - pos;
00408         Point3d p2 = model.position(v1) - pos;
00409         normal += p1^p2;
00410       }
00411       normal.normalize();
00412       model.setNormal(f, normal);
00413     }
00414     // At last, connect the cell graph
00415     forall_named(const cell& f, T.S, cells)
00416     {
00417       cell pf(0);
00418       forall(const junction& j, T.S.neighbors(f))
00419       {
00420         const cell& f2 = T.adjacentCell(f, j);
00421         if(f2)
00422         {
00423           if(pf)
00424           {
00425             T.C.spliceAfter(f, pf, f2);
00426           }
00427           else
00428           {
00429             T.C.insertEdge(f, f2);
00430           }
00431           pf = f2;
00432         }
00433       }
00434     }
00435     return ObjReaderError(ObjReaderError::NO_ERRORS);
00436   }
00437 
00443   template <class CellComplex, class Model>
00444   ObjReaderError objreader(const QString& filename, CellComplex& T, Model& model)
00445   {
00446     QFile f(filename);
00447     if(!f.open(QIODevice::ReadOnly))
00448     {
00449       return ObjReaderError(ObjReaderError::CANNOT_OPEN_FILE, f.errorString());
00450     }
00451     QTextStream ts(&f);
00452     return objreader(ts, T, model);
00453   }
00454 
00460   template <class CellComplex, class Model>
00461   ObjReaderError objreader(std::string filename, CellComplex& T, Model& model)
00462   {
00463     QString fn = QString::fromLocal8Bit(filename.c_str());
00464     return objreader(fn, T, model);
00465   }
00466 
00467 }
00468 #endif // VVELIB_FACTORY_OBJREADER_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Fri May 31 15:37:50 2013 for VVE by  doxygen 1.6.3