MeshTopologyLoader.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                              SOFA :: Framework                              *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 #include <sofa/helper/io/MeshTopologyLoader.h>
00028 #include <sofa/helper/io/Mesh.h>
00029 #include <sofa/helper/system/FileRepository.h>
00030 #include <sofa/defaulttype/Vec.h>
00031 
00032 #include <iostream>
00033 #include <vector>
00034 #include <string> 
00035  #include <cstring>
00036 
00037 #include <set>
00038 
00039 namespace sofa
00040 {
00041 
00042 namespace helper
00043 {
00044 
00045 namespace io
00046 {
00047 
00048 using namespace sofa::defaulttype;
00049 
00050 static void skipToEOL(FILE* f)
00051 {
00052     int ch;
00053     while ((ch = fgetc(f)) != EOF && ch != '\n') ;
00054 }
00055 
00056 static bool readLine(char* buf, int size, FILE* f)
00057 {
00058     buf[0] = '\0';
00059     if (fgets(buf, size, f) == NULL)
00060         return false;
00061     if ((int)strlen(buf)==size-1 && buf[size-1] != '\n')
00062         skipToEOL(f);
00063     return true;
00064 }
00065 
00066 bool MeshTopologyLoader::loadObj(const char *filename)
00067 {
00068     helper::io::Mesh* mesh = helper::io::Mesh::Create(filename);
00069     if (mesh==NULL) 
00070         return false;
00071     
00072     setNbPoints(mesh->getVertices().size());
00073     for (unsigned int i=0; i<mesh->getVertices().size(); i++)
00074     {
00075         addPoint((double)mesh->getVertices()[i][0],
00076                 (double)mesh->getVertices()[i][1],
00077                 (double)mesh->getVertices()[i][2]);
00078     }
00079     
00080     const vector< vector < vector <int> > > & facets = mesh->getFacets();
00081     for (unsigned int i=0; i<facets.size(); i++)
00082     {
00083         const vector<int>& facet = facets[i][0];
00084         if (facet.size()==2)
00085         { // Line
00086             if (facet[0]<facet[1])
00087                 addLine(facet[0],facet[1]);
00088             else
00089                 addLine(facet[1],facet[0]);
00090         }
00091         else if (facet.size()==4)
00092         { // Quad
00093             addQuad(facet[0],facet[1],facet[2],facet[3]);
00094         }
00095         // else if (facet.size()==8)
00096         // { // Quadralize
00097         //     addQuad(facet[0],facet[3],facet[2],facet[1]);
00098         //     addQuad(facet[4],facet[5],facet[6],facet[7]);
00099         //     addQuad(facet[0],facet[1],facet[5],facet[4]);
00100         //     addQuad(facet[1],facet[2],facet[6],facet[5]);
00101         //     addQuad(facet[2],facet[3],facet[7],facet[6]);
00102         //     addQuad(facet[3],facet[0],facet[4],facet[7]);
00103         // }
00104         else
00105         { // Triangularize
00106             for (unsigned int j=2; j<facet.size(); j++)
00107                 addTriangle(facet[0],facet[j-1],facet[j]);
00108         }
00109 
00110         std::set< std::pair<int,int> > edges;
00111         // Add edges
00112         if (facet.size()>2)
00113         {
00114             for (unsigned int j=0; j<facet.size(); j++)
00115             {
00116                 int i1 = facet[j];
00117                 int i2 = facet[(j+1)%facet.size()];
00118                 if (edges.count(std::make_pair(i1,i2))!=0)
00119                 {
00120                     /*  std::cerr << "ERROR: Duplicate edge.\n";*/
00121                 }
00122                 else if (edges.count(std::make_pair(i2,i1))==0)
00123                 {
00124                     if (i1>i2)
00125                         addLine(i1,i2);
00126                     else
00127                         addLine(i2,i1);
00128                     edges.insert(std::make_pair(i1,i2));
00129                 }
00130             }
00131         }
00132     }
00133 
00134     delete mesh;
00135     return true;
00136 }
00137 
00138 bool MeshTopologyLoader::loadGmsh(FILE *file, const int gmshFormat)
00139 {
00140     char cmd[1024];
00141     int npoints = 0;
00142     int nlines = 0;
00143     int ntris = 0;
00144     int nquads = 0;
00145     int ntetras = 0;
00146     int ncubes = 0;
00147 
00148 //  std::cout << "Loading Gmsh topology '" << filename << "'" << std::endl;
00149     fscanf(file, "%d\n", &npoints);
00150     setNbPoints(npoints);
00151     std::vector<int> pmap;
00152     for (int i=0; i<npoints; ++i)
00153     {
00154         int index = i;
00155         double x,y,z;
00156         fscanf(file, "%d %lf %lf %lf\n", &index, &x, &y, &z);
00157         addPoint(x, y, z);
00158         if ((int)pmap.size() <= index) pmap.resize(index+1);
00159         pmap[index] = i;
00160         //std::cout << "pmap[" << index << "] = " << pmap[index] << std::endl;
00161     }
00162     
00163     readLine(cmd, sizeof(cmd), file);
00164     //std::cout << cmd << std::endl;
00165     if (strncmp(cmd,"$ENDNOD",7) && strncmp(cmd,"$EndNodes",9))
00166     {
00167         std::cerr << "'$ENDNOD' or '$EndNodes' expected, found '" << cmd << "'" << std::endl;
00168         fclose(file);
00169         return false;
00170     }
00171 
00172     readLine(cmd, sizeof(cmd), file);
00173     //std::cout << cmd << std::endl;
00174     if (strncmp(cmd,"$ELM",4) && strncmp(cmd,"$Elements",9))
00175     {
00176         std::cerr << "'$ELM' or '$Elements' expected, found '" << cmd << "'" << std::endl;
00177         fclose(file);
00178         return false;
00179     }
00180 
00181     int nelems = 0;
00182     fscanf(file, "%d\n", &nelems);
00183     for (int i=0; i<nelems; ++i)
00184     {
00185         int index, etype, rphys, relem, nnodes, ntags, tag;
00186         if (gmshFormat==1) 
00187         {
00188             // version 1.0 format is 
00189             // elm-number elm-type reg-phys reg-elem number-of-nodes <node-number-list ...>
00190             fscanf(file, "%d %d %d %d %d", &index, &etype, &rphys, &relem, &nnodes);
00191         }
00192         else if (gmshFormat == 2) 
00193         {
00194             // version 2.0 format is
00195             // elm-number elm-type number-of-tags < tag > ... node-number-list
00196             fscanf(file, "%d %d %d", &index, &etype, &ntags);
00197             for (int t=0; t<ntags; t++)
00198                 fscanf(file, "%d", &tag); // read the tag but don't use it
00199 
00200             switch (etype)
00201             {
00202             case 1: // Line
00203                 nnodes = 2;
00204                 break;
00205             case 2: // Triangle
00206                 nnodes = 3;
00207                 break;
00208             case 3: // Quad
00209                 nnodes = 4;
00210                 break;
00211             case 4: // Tetra
00212                 nnodes = 4;
00213                 break;
00214             case 5: // Hexa
00215                 nnodes = 8;
00216                 break;
00217             default:
00218                 std::cerr << "Elements of type 1, 2, 3, 4, 5, or 6 expected. Element of type " << etype << " found." << std::endl;
00219                 //fclose(file);
00220                 //return false;
00221                 nnodes = 0;
00222             }
00223         }
00224 
00225         std::vector<int> nodes;
00226         nodes.resize(nnodes);
00227         for (int n=0; n<nnodes; ++n) 
00228         {
00229             int t = 0;
00230             fscanf(file, "%d",&t);
00231             nodes[n] = (((unsigned int)t)<pmap.size())?pmap[t]:0;
00232             //std::cout << "nodes[" << n << "] = " << nodes[n] << std::endl;
00233         }
00234         switch (etype)
00235         {
00236         case 1: // Line
00237             addLine(nodes[0], nodes[1]);
00238             ++nlines;
00239             break;
00240         case 2: // Triangle
00241             addTriangle(nodes[0], nodes[1], nodes[2]);
00242             //std::cout << "Adding triangle (" << nodes[0] << ", " << nodes[1] << ", " << nodes[2] << ")" << std::endl;
00243             ++ntris;
00244             break;
00245         case 3: // Quad
00246             addQuad(nodes[0], nodes[1], nodes[2], nodes[3]);
00247             ++nquads;
00248             break;
00249         case 4: // Tetra
00250             addTetra(nodes[0], nodes[1], nodes[2], nodes[3]);
00251             ++ntetras;
00252             break;
00253         case 5: // Hexa
00254             addCube(nodes[0], nodes[1], nodes[2], nodes[3],nodes[4], nodes[5], nodes[6], nodes[7]);         
00255             ++ncubes;
00256             break;
00257         }
00258         skipToEOL(file);
00259     }
00260     readLine(cmd, sizeof(cmd), file);
00261     if (strncmp(cmd,"$ENDELM",7) && strncmp(cmd,"$EndElements",12))
00262     {
00263         std::cerr << "'$ENDELM' or '$EndElements' expected, found '" << cmd << "'" << std::endl;
00264         fclose(file);
00265         return false;
00266     }
00267     else 
00268     {
00269 //          std::cout << "Done parsing Gmsh file." << std::endl;
00270     }
00271 //  std::cout << "Loading topology complete:";
00272 //  if (npoints>0) std::cout << ' ' << npoints << " points";
00273 //  if (nlines>0)  std::cout << ' ' << nlines  << " lines";
00274 //  if (ntris>0)   std::cout << ' ' << ntris   << " triangles";
00275 //  if (nquads>0)  std::cout << ' ' << nquads  << " quads";
00276 //  if (ntetras>0) std::cout << ' ' << ntetras << " tetrahedra";
00277 //  if (ncubes>0)  std::cout << ' ' << ncubes  << " cubes";
00278 //  std::cout << std::endl;
00279 
00280     return true;
00281 }
00282 
00283 bool MeshTopologyLoader::loadXsp(FILE *file, bool vector_spring)
00284 {
00285     char cmd[1024];
00286     int npoints = 0;
00287     int nlines = 0;
00288 //  int ntris = 0;
00289 //  int nquads = 0;
00290 //  int ntetras = 0;
00291 //  int ncubes = 0;
00292 
00293     int totalNumMasses;
00294     int totalNumSprings;
00295 
00296     //      skipToEOL(file);
00297 
00298     // then find out number of masses and springs
00299     if (fscanf(file, "%s", cmd) != EOF && !strcmp(cmd,"numm"))
00300     {
00301         fscanf(file, "%d", &totalNumMasses);
00302         setNbPoints(totalNumMasses);
00303         npoints=totalNumMasses;
00304     }
00305 
00306     if (fscanf(file, "%s", cmd) != EOF && !strcmp(cmd,"nums"))
00307     {
00308         fscanf(file, "%d", &totalNumSprings);
00309         setNbLines(totalNumSprings);
00310         nlines=totalNumSprings;
00311         //      setNumSprings(totalNumSprings);
00312     }
00313 
00314 //      std::cout << "Model contains "<< totalNumMasses <<" masses and "<< totalNumSprings <<" springs"<<std::endl;
00315 
00316     while (fscanf(file, "%s", cmd) != EOF)
00317     {
00318         if (!strcmp(cmd,"mass"))
00319         {
00320             int index;
00321             char location;
00322             double px,py,pz,vx,vy,vz,mass=0.0,elastic=0.0;
00323             bool fixed=false;
00324             fscanf(file, "%d %c %lf %lf %lf %lf %lf %lf %lf %lf\n",
00325                 &index, &location,
00326                 &px, &py, &pz, &vx, &vy, &vz,
00327                 &mass, &elastic);
00328 
00329             if (mass < 0)
00330             {
00331                 // fixed point initialization                       
00332                 mass = -mass;
00333                 fixed = true;
00334             }
00335             addPoint(px,py,pz);
00336         }
00337         else if (!strcmp(cmd,"lspg"))   // linear springs connector
00338         {
00339             int index;
00340             int m1,m2;
00341             double ks=0.0,kd=0.0,initpos=-1;
00342             double restx=0.0,resty=0.0,restz=0.0;
00343             if (vector_spring)
00344                 fscanf(file, "%d %d %d %lf %lf %lf %lf %lf %lf\n",
00345                     &index,&m1,&m2,&ks,&kd,&initpos, &restx,&resty,&restz);
00346             else 
00347                 fscanf(file, "%d %d %d %lf %lf %lf\n",
00348                     &index,&m1,&m2,&ks,&kd,&initpos);
00349             --m1;
00350             --m2;
00351 
00352             addLine(m1,m2);
00353         }
00354         else if (!strcmp(cmd,"grav"))
00355         {
00356             double gx,gy,gz;
00357             fscanf(file, "%lf %lf %lf\n", &gx, &gy, &gz);
00358         }
00359         else if (!strcmp(cmd,"visc"))
00360         {
00361             double viscosity;
00362             fscanf(file, "%lf\n", &viscosity);
00363         }
00364         else if (!strcmp(cmd,"step"))
00365         {
00366             //fscanf(file, "%lf\n", &(MSparams.default_dt));
00367             skipToEOL(file);
00368         }
00369         else if (!strcmp(cmd,"frce"))
00370         {
00371             skipToEOL(file);
00372         }
00373         else if (cmd[0] == '#') // it's a comment
00374         {
00375             skipToEOL(file);
00376         }
00377         else        // it's an unknown keyword
00378         {
00379             printf("Unknown MassSpring keyword: %s\n", cmd);
00380             skipToEOL(file);
00381             return false;
00382         }
00383     }
00384 //  std::cout << "Loading topology complete:";
00385 //  if (npoints>0) std::cout << ' ' << npoints << " points";
00386 //  if (nlines>0)  std::cout << ' ' << nlines  << " lines";
00387 //  if (ntris>0)   std::cout << ' ' << ntris   << " triangles";
00388 //  if (nquads>0)  std::cout << ' ' << nquads  << " quads";
00389 //  if (ntetras>0) std::cout << ' ' << ntetras << " tetrahedra";
00390 //  if (ncubes>0)  std::cout << ' ' << ncubes  << " cubes";
00391 //  std::cout << std::endl;
00392 
00393     return true;
00394 }
00395 
00396 bool MeshTopologyLoader::loadMesh(FILE *file)
00397 {
00398     char cmd[1024];
00399     int npoints = 0;
00400     int nlines = 0;
00401     int ntris = 0;
00402     int nquads = 0;
00403     int ntetras = 0;
00404     int ncubes = 0;
00405 
00406 //  std::cout << "Loading mesh topology '" << filename << "'" << std::endl;
00407     while (fscanf(file, "%s", cmd) != EOF)
00408     {
00409         if (!strcmp(cmd,"line"))
00410         {
00411             int p1,p2;
00412             fscanf(file, "%d %d\n",
00413                     &p1, &p2);
00414             addLine(p1, p2);
00415             ++nlines;
00416         }
00417         else if (!strcmp(cmd,"triangle"))
00418         {
00419             int p1,p2,p3;
00420             fscanf(file, "%d %d %d\n",
00421                     &p1, &p2, &p3);
00422             addTriangle(p1, p2, p3);
00423             ++ntris;
00424         }
00425         else if (!strcmp(cmd,"quad"))
00426         {
00427             int p1,p2,p3,p4;
00428             fscanf(file, "%d %d %d %d\n",
00429                     &p1, &p2, &p3, &p4);
00430             addQuad(p1, p2, p3, p4);
00431             ++nquads;
00432         }
00433         else if (!strcmp(cmd,"tetra"))
00434         {
00435             int p1,p2,p3,p4;
00436             fscanf(file, "%d %d %d %d\n",
00437                     &p1, &p2, &p3, &p4);
00438             addTetra(p1, p2, p3, p4);
00439             ++ntetras;
00440         }
00441         else if (!strcmp(cmd,"cube"))
00442         {
00443             int p1,p2,p3,p4,p5,p6,p7,p8;
00444             fscanf(file, "%d %d %d %d %d %d %d %d\n",
00445                     &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8);
00446             addCube(p1, p2, p3, p4, p5, p6, p7, p8);
00447             ++ncubes;
00448         }
00449         else if (!strcmp(cmd,"point"))
00450         {
00451             double px,py,pz;
00452             fscanf(file, "%lf %lf %lf\n",
00453                     &px, &py, &pz);
00454             addPoint(px, py, pz);
00455             ++npoints;
00456         }
00457         else if (!strcmp(cmd,"v"))
00458         {
00459             double px,py,pz;
00460             fscanf(file, "%lf %lf %lf\n",
00461                     &px, &py, &pz);
00462             addPoint(px, py, pz);
00463             ++npoints;
00464         }
00465         else if (!strcmp(cmd,"f"))
00466         {
00467             int p1,p2,p3,p4=0;
00468             fscanf(file, "%d %d %d %d\n",
00469                     &p1, &p2, &p3, &p4);
00470             if (p4)
00471             {
00472                 addQuad(p1-1, p2-1, p3-1, p4-1);
00473                 ++nquads;
00474             }
00475             else
00476             {
00477                 addTriangle(p1-1, p2-1, p3-1);
00478                 ++ntris;
00479             }
00480         }
00481         else if (!strcmp(cmd,"mass"))
00482         {
00483             int index;
00484             char location;
00485             double px,py,pz,vx,vy,vz,mass=0.0,elastic=0.0;
00486             fscanf(file, "%d %c %lf %lf %lf %lf %lf %lf %lf %lf\n",
00487                     &index, &location,
00488                     &px, &py, &pz, &vx, &vy, &vz,
00489                     &mass, &elastic);
00490             addPoint(px, py, pz);
00491             ++npoints;
00492         }
00493         else if (!strcmp(cmd,"lspg"))
00494         {
00495             int index;
00496             int m1,m2;
00497             double ks=0.0,kd=0.0,initpos=-1;
00498             fscanf(file, "%d %d %d %lf %lf %lf\n", &index,
00499                     &m1,&m2,&ks,&kd,&initpos);
00500             --m1;
00501             --m2;
00502             addLine(m1,m2);
00503             ++nlines;
00504         }
00505         else if (cmd[0] == '#') // it's a comment
00506         {
00507             skipToEOL(file);
00508         }
00509         else        // it's an unknown keyword
00510         {
00511             printf("Unknown Mesh keyword: %s\n", cmd);
00512             skipToEOL(file);
00513             return false;
00514         }
00515     }
00516 //  std::cout << "Loading topology complete:";
00517 //  if (npoints>0) std::cout << ' ' << npoints << " points";
00518 //  if (nlines>0)  std::cout << ' ' << nlines  << " lines";
00519 //  if (ntris>0)   std::cout << ' ' << ntris   << " triangles";
00520 //  if (nquads>0)  std::cout << ' ' << nquads  << " quads";
00521 //  if (ntetras>0) std::cout << ' ' << ntetras << " tetrahedra";
00522 //  if (ncubes>0)  std::cout << ' ' << ncubes  << " cubes";
00523 //  std::cout << std::endl;
00524 
00525     return true;
00526 }
00527 
00528 bool MeshTopologyLoader::loadMeshFile(const char *filename)
00529 {
00530     FILE* file;
00531     char cmd[1024];
00532     bool fileLoaded = false;
00533 
00534     if ((file = fopen(filename, "r")) == NULL)
00535     {
00536         std::cout << "ERROR: cannot read file '" << filename << "'. Exiting..." << std::endl;
00537         return false;
00538     }
00539 
00540     // Check first line 
00541     if (!readLine(cmd, sizeof(cmd), file))
00542     {
00543         fclose(file);
00544         return false;
00545     }
00546 
00547 //  std::cout << "Loading Gmsh topology '" << filename << "' - ";
00548 
00549     int gmshFormat = 0;
00550     if (!strncmp(cmd,"$MeshFormat",11)) // Reading gmsh 2.0 file
00551     {
00552         gmshFormat = 2;
00553 //      std::cout << "Gmsh format 2.0" << std::endl;
00554         readLine(cmd, sizeof(cmd), file); // we don't care about this line
00555         readLine(cmd, sizeof(cmd), file); 
00556         if (strncmp(cmd,"$EndMeshFormat",14)) // it should end with $EndMeshFormat
00557         {
00558             fclose(file);
00559             return false;
00560         }
00561         else 
00562             readLine(cmd, sizeof(cmd), file); 
00563     }
00564     else 
00565     {
00566         gmshFormat = 1;
00567 //      std::cout << "Gmsh format 1.0" << std::endl;
00568     }
00569 
00570     if (!strncmp(cmd,"$NOD",4) || !strncmp(cmd,"$Nodes",6)) // Gmsh format
00571     {
00572         fileLoaded = loadGmsh(file, gmshFormat);
00573     }
00574     else if (!strncmp(cmd,"Xsp",3)) 
00575     {
00576         float version = 0.0f;
00577         sscanf(cmd, "Xsp %f", &version);
00578 
00579         if (version == 3.0) 
00580             fileLoaded = loadXsp(file, false);
00581         else if (version == 4.0) 
00582             fileLoaded = loadXsp(file, true);
00583     }
00584     else
00585     {
00586         fileLoaded = loadMesh(file);
00587     }
00588 
00589     fclose(file);
00590     return  fileLoaded;
00591 }
00592 
00593 bool MeshTopologyLoader::load(const char *filename)
00594 {
00595     std::string fname(filename);
00596     if (!sofa::helper::system::DataRepository.findFile(fname)) 
00597     {
00598         printf("Cannot find file: %s \n", filename);
00599         return false;
00600     }
00601 
00602     bool fileLoaded;
00603 
00604     if ((strlen(filename)>4 && !strcmp(filename+strlen(filename)-4,".obj"))
00605         || (strlen(filename)>6 && !strcmp(filename+strlen(filename)-6,".trian")))
00606     {
00607         fileLoaded = loadObj(fname.c_str());
00608     }
00609     else 
00610         fileLoaded = loadMeshFile(fname.c_str());
00611 
00612     if(!fileLoaded)
00613         printf("Error loading mesh file: %s \n", fname.c_str());
00614 
00615     return fileLoaded;
00616 }
00617 
00618 } // namespace io
00619 
00620 } // namespace helper
00621 
00622 } // namespace sofa
00623 

Generated on Sun Nov 23 02:29:30 2008 for Sofa by  doxygen 1.5.7.1