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,
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
00141
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
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
00235
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
00261 forall_named(const junction& j, T.S, junctions)
00262 {
00263 if(T.S.iValence(j) < 3)
00264 {
00265
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
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
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
00301
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
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
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
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
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
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
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