diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h index 3622e57623cc89f2883f0bdf2cd044af6979f3b7..5caff558e19b74c4755dfdb61d364e990bf48fba 100644 --- a/Common/GmshDefines.h +++ b/Common/GmshDefines.h @@ -27,10 +27,11 @@ #define FORMAT_PNGTEX 23 #define FORMAT_PDF 24 #define FORMAT_PDFTEX 25 -#define FORMAT_LC 26 +#define FORMAT_POS 26 #define FORMAT_STL 27 #define FORMAT_P3D 28 #define FORMAT_SVG 29 +#define FORMAT_MESH 30 // Element types in .msh file format #define LGN1 1 diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp index 71fe96964c4df986d00d99a212734cd425127411..34a1bc34c251e07cd15ff6f571f028cd1f9db3e0 100644 --- a/Fltk/Callbacks.cpp +++ b/Fltk/Callbacks.cpp @@ -1,4 +1,4 @@ -// $Id: Callbacks.cpp,v 1.424 2006-08-07 13:57:13 geuzaine Exp $ +// $Id: Callbacks.cpp,v 1.425 2006-08-07 21:04:05 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -593,8 +593,9 @@ static char *file_types = "*" "\tGmsh geometry (*.geo)" "\tGmsh mesh (*.msh)" - "\tGmsh post-processing view (*.pos)" - "\tSTL triangulation (*.stl)" + "\tGmsh post-processing (*.pos)" + "\tSTL mesh (*.stl)" + "\tINRIA mesh (*.mesh)" "\tJPEG (*.jpg)" "\tPNG (*.png)" "\tBMP (*.bmp)" @@ -643,9 +644,9 @@ int _save_msh(char *name) return msh_dialog(name); } -int _save_lc(char *name) +int _save_pos(char *name) { - CreateOutputFile(name, FORMAT_LC); + CreateOutputFile(name, FORMAT_POS); return 1; } @@ -655,6 +656,12 @@ int _save_unv(char *name) return 1; } +int _save_mesh(char *name) +{ + CreateOutputFile(name, CTX.mesh.format = FORMAT_MESH); + return 1; +} + int _save_vrml(char *name) { CreateOutputFile(name, CTX.mesh.format = FORMAT_VRML); @@ -773,35 +780,40 @@ void file_save_as_cb(CALLBACK_ARGS) static char *pat = NULL; static patXfunc formats[] = { {"Guess from extension (*.*)", _save_auto}, + {" ", _save_auto}, + {"Gmsh mesh (*.msh)", _save_msh}, + {"Gmsh mesh statistics (*.pos)", _save_pos}, {"Gmsh options (*.opt)", _save_options}, {"Gmsh unrolled geometry (*.geo)", _save_geo}, - {"Gmsh mesh (*.msh)", _save_msh}, - {"Gmsh mesh statistics (*.pos)", _save_lc}, + {" ", _save_auto}, {"I-DEAS universal mesh (*.unv)", _save_unv}, + {"INRIA mesh (*.mesh)", _save_mesh}, + {"STL mesh (*.stl)", _save_stl}, {"VRML surface mesh (*.wrl)", _save_vrml}, - {"STL surface mesh (*.stl)", _save_stl}, + {" ", _save_auto}, + {"Encapsulated PostScript (*.eps)", _save_eps}, {"GIF (*.gif)", _save_gif}, #if defined(HAVE_LIBJPEG) {"JPEG (*.jpg)", _save_jpeg}, #endif -#if defined(HAVE_LIBPNG) - {"PNG (*.png)", _save_png}, -#endif - {"PostScript (*.ps)", _save_ps}, - {"Encapsulated PostScript (*.eps)", _save_eps}, - {"PDF (*.pdf)", _save_pdf}, - {"SVG (*.svg)", _save_svg}, - {"PPM (*.ppm)", _save_ppm}, + {"LaTeX EPS part without text (*.eps)", _save_epstex}, #if defined(HAVE_LIBJPEG) {"LaTeX JPEG part without text (*.jpg)", _save_jpegtex}, #endif + {"LaTeX PDF part without text (*.pdf)", _save_pdftex}, #if defined(HAVE_LIBPNG) {"LaTeX PNG part without text (*.png)", _save_pngtex}, #endif - {"LaTeX EPS part without text (*.eps)", _save_epstex}, - {"LaTeX PDF part without text (*.pdf)", _save_pdftex}, {"LaTeX text part (*.tex)", _save_tex}, - {"YUV (*.yuv)", _save_yuv} + {"PDF (*.pdf)", _save_pdf}, +#if defined(HAVE_LIBPNG) + {"PNG (*.png)", _save_png}, +#endif + {"PostScript (*.ps)", _save_ps}, + {"PPM (*.ppm)", _save_ppm}, + {"SVG (*.svg)", _save_svg}, + {"YUV (*.yuv)", _save_yuv}, + {" ", _save_auto}, }; nbformats = sizeof(formats) / sizeof(formats[0]); @@ -829,7 +841,7 @@ void file_save_as_cb(CALLBACK_ARGS) if(!formats[i].func(name)) goto test; } - else // handle any additional automatic fltk filter + else // handle any additional automatic fltk filter _save_auto(name); } } diff --git a/Geo/GModel.h b/Geo/GModel.h index 1793db774a185831c3fe02ddd16397534ea568e8..1864c660f578786de0ec2042c14d8cf4fd36d576 100644 --- a/Geo/GModel.h +++ b/Geo/GModel.h @@ -89,6 +89,8 @@ class GModel int writeSTL(const std::string &name, double scalingFactor=1.0); int writeVRML(const std::string &name, double scalingFactor=1.0); int writeUNV(const std::string &name, double scalingFactor=1.0); + int readMESH(const std::string &name); + int writeMESH(const std::string &name, double scalingFactor=1.0); }; #endif diff --git a/Geo/GModelIO.cpp b/Geo/GModelIO.cpp index 96b66bc155dc42113f6d47ed0238fd0d1723cf0e..dadc841d6b51c6d47a6bd0f78ecd4c496662a2cd 100644 --- a/Geo/GModelIO.cpp +++ b/Geo/GModelIO.cpp @@ -31,14 +31,6 @@ static int getNumVerticesForElementTypeMSH(int type) } } -template<class T> -static void associateEntityWithVertices(GEntity *ge, std::vector<T*> &elements) -{ - for(unsigned int i = 0; i < elements.size(); i++) - for(int j = 0; j < elements[i]->getNumVertices(); j++) - elements[i]->getVertex(j)->setEntity(ge); -} - template<class T> void copyElements(std::vector<T*> &dst, const std::vector<MElement*> &src) { @@ -91,6 +83,52 @@ static void storeElementsInEntities(GModel *m, int type, } } +template<class T> +static void associateEntityWithVertices(GEntity *ge, std::vector<T*> &elements) +{ + for(unsigned int i = 0; i < elements.size(); i++) + for(int j = 0; j < elements[i]->getNumVertices(); j++) + elements[i]->getVertex(j)->setEntity(ge); +} + +static void associateEntityWithVertices(GModel *m) +{ + // loop on regions, then on faces, edges and vertices and store the + // entity pointer in the the elements' vertices (this way we + // associate the entity of lowest geometrical degree with each + // vertex) + for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){ + associateEntityWithVertices(*it, (*it)->tetrahedra); + associateEntityWithVertices(*it, (*it)->hexahedra); + associateEntityWithVertices(*it, (*it)->prisms); + associateEntityWithVertices(*it, (*it)->pyramids); + } + for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){ + associateEntityWithVertices(*it, (*it)->triangles); + associateEntityWithVertices(*it, (*it)->quadrangles); + } + for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it){ + associateEntityWithVertices(*it, (*it)->lines); + } + for(GModel::viter it = m->firstVertex(); it != m->lastVertex(); ++it){ + (*it)->mesh_vertices[0]->setEntity(*it); + } +} + +static void storeVerticesInEntities(std::map<int, MVertex*> &vertices) +{ + std::map<int, MVertex*>::const_iterator it = vertices.begin(); + std::map<int, MVertex*>::const_iterator ite = vertices.end(); + for(; it != ite; ++it){ + MVertex *v = it->second; + GEntity *ge = v->onWhat(); + if(ge) + ge->mesh_vertices.push_back(v); + else + delete v; // we delete all unused vertices + } +} + static void storePhysicalTagsInEntities(GModel *m, int dim, std::map<int, std::map<int, std::string> > &map) { @@ -297,44 +335,18 @@ int GModel::readMSH(const std::string &name) v->mesh_vertices.push_back(it->second[0]); } } - - // loop on regions, then on faces, edges and vertices and store the - // entity pointer in the the elements' vertices (this way we - // associate the entity of lowest geometrical degree with each - // vertex) - for(riter it = firstRegion(); it != lastRegion(); ++it){ - associateEntityWithVertices(*it, (*it)->tetrahedra); - associateEntityWithVertices(*it, (*it)->hexahedra); - associateEntityWithVertices(*it, (*it)->prisms); - associateEntityWithVertices(*it, (*it)->pyramids); - } - for(fiter it = firstFace(); it != lastFace(); ++it){ - associateEntityWithVertices(*it, (*it)->triangles); - associateEntityWithVertices(*it, (*it)->quadrangles); - } - for(eiter it = firstEdge(); it != lastEdge(); ++it){ - associateEntityWithVertices(*it, (*it)->lines); - } - for(viter it = firstVertex(); it != lastVertex(); ++it){ - // special case for points: the mesh vertex has been copied here - // so that we can assign the entity: - (*it)->mesh_vertices[0]->setEntity(*it); - // now that this is done, we reset mesh_vertices so that it can be - // filled again below + + // associate the correct geometrical entity with each mesh vertex + associateEntityWithVertices(this); + + // special case for geometry vertices: now that the correct + // geometrical entity has been associated with the vertices, we + // reset mesh_vertices so that it can be filled again below + for(viter it = firstVertex(); it != lastVertex(); ++it) (*it)->mesh_vertices.clear(); - } // store the vertices in their associated geometrical entity - std::map<int, MVertex*>::const_iterator it = vertices.begin(); - std::map<int, MVertex*>::const_iterator ite = vertices.end(); - for(; it != ite; ++it){ - MVertex *v = it->second; - GEntity *ge = v->onWhat(); - if(ge) - ge->mesh_vertices.push_back(v); - else - delete v; // we delete all unused vertices - } + storeVerticesInEntities(vertices); // store the physical tags for(int i = 0; i < 4; i++) @@ -836,3 +848,149 @@ int GModel::writeUNV(const std::string &name, double scalingFactor) fclose(fp); return 1; } + +int GModel::readMESH(const std::string &name) +{ + FILE *fp = fopen(name.c_str(), "r"); + if(!fp){ + Msg(GERROR, "Unable to open file '%s'", name.c_str()); + return 0; + } + + char buffer[256]; + fgets(buffer, sizeof(buffer), fp); + + char str[256]; + int format; + sscanf(buffer, "%s %d", str, &format); + + if(format != 1){ + Msg(GERROR, "Non-ASCII INRIA mesh import is not yet available"); + return 0; + } + + std::map<int, MVertex*> vertices; + int elementTypes[2] = {TRI1, QUA1}; + std::map<int, std::vector<MElement*> > elements[2]; + SBoundingBox3d bbox; + + while(!feof(fp)) { + fgets(buffer, sizeof(buffer), fp); + if(buffer[0] != '#'){ // skip comments + sscanf(buffer, "%s", str); + if(!strcmp(str, "Dimension")){ + fgets(buffer, sizeof(buffer), fp); + } + else if(!strcmp(str, "Vertices")){ + fgets(buffer, sizeof(buffer), fp); + int nbv; + sscanf(buffer, "%d", &nbv); + Msg(INFO, "%d vertices", nbv); + for(int i = 0; i < nbv; i++) { + fgets(buffer, sizeof(buffer), fp); + int cl; + double x, y, z; + sscanf(buffer, "%lf %lf %lf %d", &x, &y, &z, &cl); + bbox += SPoint3(x, y, z); + vertices[i + 1] = new MVertex(x, y, z); + } + } + else if(!strcmp(str, "Triangles")){ + fgets(buffer, sizeof(buffer), fp); + int nbt; + sscanf(buffer, "%d", &nbt); + Msg(INFO, "%d triangles", nbt); + for(int i = 0; i < nbt; i++) { + fgets(buffer, sizeof(buffer), fp); + int n1, n2, n3, cl; + sscanf(buffer, "%d %d %d %d", &n1, &n2, &n3, &cl); + elements[0][cl].push_back + (new MTriangle(vertices[n1], vertices[n2], vertices[n3])); + } + } + else if(!strcmp(str, "Quadrilaterals")) { + fgets(buffer, sizeof(buffer), fp); + int nbq; + sscanf(buffer, "%d", &nbq); + Msg(INFO, "%d quadrangles", nbq); + for(int i = 0; i < nbq; i++) { + fgets(buffer, sizeof(buffer), fp); + int n1, n2, n3, n4, cl; + sscanf(buffer, "%d %d %d %d %d", &n1, &n2, &n3, &n4, &cl); + elements[1][cl].push_back + (new MQuadrangle(vertices[n1], vertices[n2], vertices[n3], vertices[n4])); + } + } + } + } + + // store the elements in their associated elementary entity. If the + // entity does not exist, create a new one. + for(int i = 0; i < 2; i++) + storeElementsInEntities(this, elementTypes[i], elements[i]); + + // associate the correct geometrical entity with each mesh vertex + associateEntityWithVertices(this); + + // store the vertices in their associated geometrical entity + storeVerticesInEntities(vertices); + + boundingBox += bbox; + + fclose(fp); + return 1; +} + +int GModel::writeMESH(const std::string &name, double scalingFactor) +{ + FILE *fp = fopen(name.c_str(), "w"); + if(!fp){ + Msg(GERROR, "Unable to open file '%s'", name.c_str()); + return 0; + } + + fprintf(fp, " MeshVersionFormatted 1\n"); + fprintf(fp, " Dimension\n"); + fprintf(fp, " 3\n"); + + int numVertices = renumberMeshVertices(); + fprintf(fp, " Vertices\n"); + fprintf(fp, " %d\n", numVertices); + for(viter it = firstVertex(); it != lastVertex(); ++it) + for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++) + (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor); + for(eiter it = firstEdge(); it != lastEdge(); ++it) + for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++) + (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor); + for(fiter it = firstFace(); it != lastFace(); ++it) + for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++) + (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor); + for(riter it = firstRegion(); it != lastRegion(); ++it) + for(unsigned int i = 0; i < (*it)->mesh_vertices.size(); i++) + (*it)->mesh_vertices[i]->writeMESH(fp, scalingFactor); + + int numTriangles = 0, numQuadrangles = 0; + for(fiter it = firstFace(); it != lastFace(); ++it){ + numTriangles += (*it)->triangles.size(); + numQuadrangles += (*it)->quadrangles.size(); + } + if(numTriangles){ + fprintf(fp, " Triangles\n"); + fprintf(fp, " %d\n", numTriangles); + for(fiter it = firstFace(); it != lastFace(); ++it) + for(unsigned int i = 0; i < (*it)->triangles.size(); i++) + (*it)->triangles[i]->writeMESH(fp, (*it)->tag()); + } + if(numQuadrangles){ + fprintf(fp, " Quadrilaterals\n"); + fprintf(fp, " %d\n", numQuadrangles); + for(fiter it = firstFace(); it != lastFace(); ++it) + for(unsigned int i = 0; i < (*it)->triangles.size(); i++) + (*it)->quadrangles[i]->writeMESH(fp, (*it)->tag()); + } + + fprintf(fp, " End\n"); + + fclose(fp); + return 1; +} diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index 2e2625d02275166838fa127a0968e10ea6b6cb87..497f0e76d41951c25f5329616c928cd553c44701 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -192,3 +192,10 @@ void MElement::writeUNV(FILE *fp, int type, int elementary) if(n - 1 % 8 != 7) fprintf(fp, "\n"); } + +void MElement::writeMESH(FILE *fp, int elementary) +{ + for(int i = 0; i < getNumVertices(); i++) + fprintf(fp, " %d", getVertex(i)->getNum()); + fprintf(fp, " %d\n", elementary); +} diff --git a/Geo/MElement.h b/Geo/MElement.h index e464bb81859a2109e34bfa566a47b79d0b920968..4007a09b6d2f6a3bc37237214a3ab2cde38ae4a5 100644 --- a/Geo/MElement.h +++ b/Geo/MElement.h @@ -104,6 +104,7 @@ class MElement virtual void writeSTL(FILE *fp, double scalingFactor=1.0); virtual void writeVRML(FILE *fp); virtual void writeUNV(FILE *fp, int type, int elementary); + virtual void writeMESH(FILE *fp, int elementary); virtual char *getStringForPOS() = 0; virtual int getTypeForMSH() = 0; }; diff --git a/Geo/MVertex.cpp b/Geo/MVertex.cpp index d900baf5879d57edd7a77dfa65bb9bf8ab41cf98..ce6599de431410356e38d2ac55f5540027fcabdb 100644 --- a/Geo/MVertex.cpp +++ b/Geo/MVertex.cpp @@ -39,3 +39,9 @@ void MVertex::writeUNV(FILE *fp, double scalingFactor) tmp[71] = 'D'; fprintf(fp, tmp); } + +void MVertex::writeMESH(FILE *fp, double scalingFactor) +{ + fprintf(fp, " %20.14E %20.14E %20.14E %d\n", + x() * scalingFactor, y() * scalingFactor, z() * scalingFactor, 0); +} diff --git a/Geo/MVertex.h b/Geo/MVertex.h index b732f779a1ebaa4904185b518afd132d2a50f3a7..24ed0d86fabccab8723ad027d183404592ee634b 100644 --- a/Geo/MVertex.h +++ b/Geo/MVertex.h @@ -41,6 +41,7 @@ class MVertex{ void writeMSH(FILE *fp, double version, int num, int elementary, int physical); void writeVRML(FILE *fp, double scalingFactor=1.0); void writeUNV(FILE *fp, double scalingFactor=1.0); + void writeMESH(FILE *fp, double scalingFactor=1.0); }; class MEdgeVertex : public MVertex{ diff --git a/Graphics/CreateFile.cpp b/Graphics/CreateFile.cpp index f60bdc49c3e6b3ad4e4c66ad3aebc2c742af5016..f36beddce0c50426004536e39e0010278dc94eb4 100644 --- a/Graphics/CreateFile.cpp +++ b/Graphics/CreateFile.cpp @@ -1,4 +1,4 @@ -// $Id: CreateFile.cpp,v 1.88 2006-08-07 13:57:14 geuzaine Exp $ +// $Id: CreateFile.cpp,v 1.89 2006-08-07 21:04:05 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -56,7 +56,8 @@ int GuessFileFormatFromFileName(char *name) else if(!strcmp(ext, ".msh")) return FORMAT_MSH; else if(!strcmp(ext, ".unv")) return FORMAT_UNV; else if(!strcmp(ext, ".stl")) return FORMAT_STL; - else if(!strcmp(ext, ".pos")) return FORMAT_LC; + else if(!strcmp(ext, ".mesh")) return FORMAT_MESH; + else if(!strcmp(ext, ".pos")) return FORMAT_POS; else if(!strcmp(ext, ".gif")) return FORMAT_GIF; else if(!strcmp(ext, ".jpg")) return FORMAT_JPEG; else if(!strcmp(ext, ".jpeg")) return FORMAT_JPEG; @@ -72,6 +73,7 @@ int GuessFileFormatFromFileName(char *name) else if(!strcmp(ext, ".ppm")) return FORMAT_PPM; else if(!strcmp(ext, ".yuv")) return FORMAT_YUV; else if(!strcmp(ext, ".wrl")) return FORMAT_VRML; + else if(!strcmp(ext, ".vrml")) return FORMAT_VRML; else return -1; } @@ -84,6 +86,7 @@ void GetDefaultFileName(int format, char *name) case FORMAT_VRML: strcpy(ext, ".wrl"); break; case FORMAT_UNV: strcpy(ext, ".unv"); break; case FORMAT_STL: strcpy(ext, ".stl"); break; + case FORMAT_MESH: strcpy(ext, ".mesh"); break; default: break; } strcat(name, ext); @@ -141,7 +144,11 @@ void CreateOutputFile(char *filename, int format) GMODEL->writeUNV(name, CTX.mesh.scaling_factor); break; - case FORMAT_LC: + case FORMAT_MESH: + GMODEL->writeMESH(name, CTX.mesh.scaling_factor); + break; + + case FORMAT_POS: GMODEL->writePOS(name); break; diff --git a/Parser/OpenFile.cpp b/Parser/OpenFile.cpp index c012e09b0382f7b4c2c75c486aa1eb0974440626..52f0a33088f16e2684ccd4660c07492610a7e373 100644 --- a/Parser/OpenFile.cpp +++ b/Parser/OpenFile.cpp @@ -1,4 +1,4 @@ -// $Id: OpenFile.cpp,v 1.102 2006-08-07 19:08:13 geuzaine Exp $ +// $Id: OpenFile.cpp,v 1.103 2006-08-07 21:04:05 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // @@ -293,6 +293,10 @@ int MergeProblem(char *name, int warn_if_missing) if(!GMODEL) GMODEL = new gmshModel; status = GMODEL->readSTL(name, CTX.mesh.stl_distance_tol); } + else if(!strcmp(ext, ".mesh")){ + if(!GMODEL) GMODEL = new gmshModel; + status = GMODEL->readMESH(name); + } #if defined(HAVE_FLTK) else if(!strcmp(ext, ".pnm") || !strcmp(ext, ".PNM") || !strcmp(ext, ".pbm") || !strcmp(ext, ".PBM") ||