// $Id: Print_Mesh.cpp,v 1.72 2006-03-24 21:37:14 geuzaine Exp $ // // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // // Please report all bugs and problems to <gmsh@geuz.org>. #include "Gmsh.h" #include "Numeric.h" #include "Geo.h" #include "CAD.h" #include "Mesh.h" #include "Create.h" #include "Context.h" #include <list> #include <map> extern Context_T CTX; extern Mesh *THEM; // Write mesh in native MSH format #define LINE 1 #define TRIANGLE 2 #define QUADRANGLE 3 #define TETRAHEDRON 4 #define HEXAHEDRON 5 #define PRISM 6 #define PYRAMID 7 #define LINE_2 8 #define TRIANGLE_2 9 #define QUADRANGLE_2 10 #define TETRAHEDRON_2 11 #define HEXAHEDRON_2 12 #define PRISM_2 13 #define PYRAMID_2 14 #define POINT 15 static int MSH_VOL_NUM, MSH_SUR_NUM, MSH_LIN_NUM; static int MSH_NODE_NUM, MSH_ELEMENT_NUM, MSH_ADD; static int MSH_PHYSICAL_NUM, MSH_PHYSICAL_ORI; static FILE *MSHFILE; static void _msh_print_node(void *a, void *b) { Vertex *V = *(Vertex **) a; fprintf(MSHFILE, "%d %.16g %.16g %.16g\n", V->Num, V->Pos.X * CTX.mesh.scaling_factor, V->Pos.Y * CTX.mesh.scaling_factor, V->Pos.Z * CTX.mesh.scaling_factor); } static void _msh_process_nodes(Mesh *M) { int i, j, Num; PhysicalGroup *p; Vertex *pv, **ppv, v; for(i = 0; i < List_Nbr(M->PhysicalGroups); i++) { List_Read(M->PhysicalGroups, i, &p); if(p->Typ == MSH_PHYSICAL_POINT) { for(j = 0; j < List_Nbr(p->Entities); j++) { List_Read(p->Entities, j, &Num); pv = &v; pv->Num = abs(Num); if(!Tree_Search(M->Vertices, &pv)) { if((ppv = (Vertex **) Tree_PQuery(M->Points, &pv))) Tree_Add(M->Vertices, ppv); } } } } MSH_NODE_NUM = Tree_Nbr(M->Vertices); if(CTX.mesh.msh_file_version == 2.0) fprintf(MSHFILE, "$Nodes\n"); else fprintf(MSHFILE, "$NOD\n"); fprintf(MSHFILE, "%d\n", MSH_NODE_NUM); Tree_Action(M->Vertices, _msh_print_node); if(CTX.mesh.msh_file_version == 2.0) fprintf(MSHFILE, "$EndNodes\n"); else fprintf(MSHFILE, "$ENDNOD\n"); } int _get_partition(int index) { MeshPartition **part = (MeshPartition**)List_Pointer_Test(THEM->Partitions, index); if(!part) return -1; // OK, no partitions available else return (*part)->Num; // partition number } static void _msh_print_simplex(void *a, void *b) { int i, type, nbn, nbs = 0; SimplexBase *s = *(SimplexBase **) a; if(MSH_VOL_NUM && (MSH_VOL_NUM != s->iEnt)) return; if(MSH_SUR_NUM && (MSH_SUR_NUM != s->iEnt)) return; if(MSH_LIN_NUM && (MSH_LIN_NUM != s->iEnt)) return; if(!MSH_ADD) { MSH_ELEMENT_NUM++; return; } if(!s->V[2]) { nbn = 2; if(s->VSUP) { type = LINE_2; nbs = 1; } else type = LINE; } else if(!s->V[3]) { nbn = 3; if(s->VSUP) { type = TRIANGLE_2; nbs = 3; } else type = TRIANGLE; } else { nbn = 4; if(s->VSUP) { type = TETRAHEDRON_2; nbs = 6; if(s->Volume_Simplexe() < 0) { Vertex *temp; temp = s->V[0]; s->V[0] = s->V[1]; s->V[1] = temp; temp = s->VSUP[1]; s->VSUP[1] = s->VSUP[2]; s->VSUP[2] = temp; temp = s->VSUP[5]; s->VSUP[5] = s->VSUP[3]; s->VSUP[3] = temp; } } else{ type = TETRAHEDRON; if(s->Volume_Simplexe() < 0) { Vertex *temp; temp = s->V[0]; s->V[0] = s->V[1]; s->V[1] = temp; } } } if(CTX.mesh.msh_file_version == 2.0){ int part = _get_partition(s->iPart); fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, (part >= 0) ? 3 : 2, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : s->iEnt, s->iEnt); if(part >= 0) fprintf(MSHFILE, " %d", part); } else fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : s->iEnt, s->iEnt, nbn + nbs); if(MSH_PHYSICAL_ORI > 0) { for(i = 0; i < nbn; i++) fprintf(MSHFILE, " %d", s->V[i]->Num); for(i = 0; i < nbs; i++) fprintf(MSHFILE, " %d", s->VSUP[i]->Num); } else { for(i = 0; i < nbn; i++) fprintf(MSHFILE, " %d", s->V[nbn - i - 1]->Num); for(i = 0; i < nbs; i++) fprintf(MSHFILE, " %d", s->VSUP[nbs - i - 1]->Num); } fprintf(MSHFILE, "\n"); } static void _msh_print_quadrangle(void *a, void *b) { int i, type, nbn, nbs = 0; Quadrangle *q = *(Quadrangle **) a; if(MSH_SUR_NUM && (MSH_SUR_NUM != q->iEnt)) return; if(!MSH_ADD) { MSH_ELEMENT_NUM++; return; } nbn = 4; if(q->VSUP) { type = QUADRANGLE_2; nbs = 4 + 1; } else type = QUADRANGLE; if(CTX.mesh.msh_file_version == 2.0){ int part = _get_partition(q->iPart); fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, (part >= 0) ? 3 : 2, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : q->iEnt, q->iEnt); if(part >= 0) fprintf(MSHFILE, " %d", part); } else fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : q->iEnt, q->iEnt, nbn + nbs); if(MSH_PHYSICAL_ORI > 0) { for(i = 0; i < nbn; i++) fprintf(MSHFILE, " %d", q->V[i]->Num); for(i = 0; i < nbs; i++) fprintf(MSHFILE, " %d", q->VSUP[i]->Num); } else { for(i = 0; i < nbn; i++) fprintf(MSHFILE, " %d", q->V[nbn - i - 1]->Num); if(nbs){ for(i = 0; i < nbs - 1; i++) fprintf(MSHFILE, " %d", q->VSUP[nbs - i - 2]->Num); fprintf(MSHFILE, " %d", q->VSUP[nbs - 1]->Num); } } fprintf(MSHFILE, "\n"); } static void _msh_print_hexahedron(void *a, void *b) { int i, type, nbn, nbs = 0; Hexahedron *h = *(Hexahedron **) a; if(MSH_VOL_NUM && (MSH_VOL_NUM != h->iEnt)) return; if(!MSH_ADD) { MSH_ELEMENT_NUM++; return; } nbn = 8; if(h->VSUP) { type = HEXAHEDRON_2; nbs = 12 + 6 + 1; if(h->Orientation() < 0) { Vertex *temp; temp = h->V[0]; h->V[0] = h->V[2]; h->V[2] = temp; temp = h->V[4]; h->V[4] = h->V[6]; h->V[6] = temp; temp = h->VSUP[0]; h->VSUP[0] = h->VSUP[4]; h->VSUP[4] = temp; temp = h->VSUP[1]; h->VSUP[1] = h->VSUP[10]; h->VSUP[10] = temp; temp = h->VSUP[2]; h->VSUP[2] = h->VSUP[8]; h->VSUP[8] = temp; temp = h->VSUP[5]; h->VSUP[5] = h->VSUP[6]; h->VSUP[6] = temp; temp = h->VSUP[7]; h->VSUP[7] = h->VSUP[11]; h->VSUP[11] = temp; } } else { type = HEXAHEDRON; if(h->Orientation() < 0) { Vertex *temp; temp = h->V[0]; h->V[0] = h->V[2]; h->V[2] = temp; temp = h->V[4]; h->V[4] = h->V[6]; h->V[6] = temp; } } if(CTX.mesh.msh_file_version == 2.0){ int part = _get_partition(h->iPart); fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, (part >= 0) ? 3 : 2, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : h->iEnt, h->iEnt); if(part >= 0) fprintf(MSHFILE, " %d", part); } else fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : h->iEnt, h->iEnt, nbn + nbs); for(i = 0; i < nbn; i++) fprintf(MSHFILE, " %d", h->V[i]->Num); for(i = 0; i < nbs; i++) fprintf(MSHFILE, " %d", h->VSUP[i]->Num); fprintf(MSHFILE, "\n"); } static void _msh_print_prism(void *a, void *b) { int i, type, nbn, nbs = 0; Prism *p = *(Prism **) a; if(MSH_VOL_NUM && (MSH_VOL_NUM != p->iEnt)) return; if(!MSH_ADD) { MSH_ELEMENT_NUM++; return; } nbn = 6; if(p->VSUP) { type = PRISM_2; nbs = 9 + 3; if(p->Orientation() < 0) { Vertex *temp; temp = p->V[0]; p->V[0] = p->V[1]; p->V[1] = temp; temp = p->V[3]; p->V[3] = p->V[4]; p->V[4] = temp; temp = p->VSUP[1]; p->VSUP[1] = p->VSUP[3]; p->VSUP[3] = temp; temp = p->VSUP[2]; p->VSUP[2] = p->VSUP[4]; p->VSUP[4] = temp; temp = p->VSUP[7]; p->VSUP[7] = p->VSUP[8]; p->VSUP[8] = temp; } } else { type = PRISM; if(p->Orientation() < 0) { Vertex *temp; temp = p->V[0]; p->V[0] = p->V[1]; p->V[1] = temp; temp = p->V[3]; p->V[3] = p->V[4]; p->V[4] = temp; } } if(CTX.mesh.msh_file_version == 2.0){ int part = _get_partition(p->iPart); fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, (part >= 0) ? 3 : 2, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : p->iEnt, p->iEnt); if(part >= 0) fprintf(MSHFILE, " %d", part); } else fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : p->iEnt, p->iEnt, nbn + nbs); for(i = 0; i < nbn; i++) fprintf(MSHFILE, " %d", p->V[i]->Num); for(i = 0; i < nbs; i++) fprintf(MSHFILE, " %d", p->VSUP[i]->Num); fprintf(MSHFILE, "\n"); } static void _msh_print_pyramid(void *a, void *b) { int i, type, nbn, nbs = 0; Pyramid *p = *(Pyramid **) a; if(MSH_VOL_NUM && (MSH_VOL_NUM != p->iEnt)) return; if(!MSH_ADD) { MSH_ELEMENT_NUM++; return; } nbn = 5; if(p->VSUP) { type = PYRAMID_2; nbs = 8 + 1; if(p->Orientation() < 0) { Vertex *temp; temp = p->V[0]; p->V[0] = p->V[2]; p->V[2] = temp; temp = p->VSUP[0]; p->VSUP[0] = p->VSUP[3]; p->VSUP[3] = temp; temp = p->VSUP[1]; p->VSUP[1] = p->VSUP[5]; p->VSUP[5] = temp; temp = p->VSUP[2]; p->VSUP[2] = p->VSUP[6]; p->VSUP[6] = temp; } } else { type = PYRAMID; if(p->Orientation() < 0) { Vertex *temp; temp = p->V[0]; p->V[0] = p->V[2]; p->V[2] = temp; } } if(CTX.mesh.msh_file_version == 2.0){ int part = _get_partition(p->iPart); fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, (part >= 0) ? 3 : 2, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : p->iEnt, p->iEnt); if(part >= 0) fprintf(MSHFILE, " %d", part); } else fprintf(MSHFILE, "%d %d %d %d %d", MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : p->iEnt, p->iEnt, nbn + nbs); for(i = 0; i < nbn; i++) fprintf(MSHFILE, " %d", p->V[i]->Num); for(i = 0; i < nbs; i++) fprintf(MSHFILE, " %d", p->VSUP[i]->Num); fprintf(MSHFILE, "\n"); } static void _msh_print_point(Vertex *V) { if(!MSH_ADD) { MSH_ELEMENT_NUM++; return; } if(CTX.mesh.msh_file_version == 2.0) fprintf(MSHFILE, "%d %d 2 %d %d %d\n", MSH_ELEMENT_NUM++, POINT, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : V->Num, V->Num, V->Num); else fprintf(MSHFILE, "%d %d %d %d 1 %d\n", MSH_ELEMENT_NUM++, POINT, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : V->Num, V->Num, V->Num); } static void _msh_print_elements(Mesh *M) { int i, j, k, Num; PhysicalGroup *p; Volume *pV; Surface *ps; Curve *pc; Vertex *pv, v; List_T *ListCurves = Tree2List(M->Curves); List_T *ListSurfaces = Tree2List(M->Surfaces); List_T *ListVolumes = Tree2List(M->Volumes); for(i = 0; i < List_Nbr(M->PhysicalGroups); i++) { List_Read(M->PhysicalGroups, i, &p); MSH_PHYSICAL_NUM = p->Num; MSH_VOL_NUM = MSH_SUR_NUM = MSH_LIN_NUM = 0; switch (p->Typ) { case MSH_PHYSICAL_POINT: for(j = 0; j < List_Nbr(p->Entities); j++) { pv = &v; List_Read(p->Entities, j, &Num); pv->Num = abs(Num); MSH_PHYSICAL_ORI = sign(Num); if(Tree_Query(M->Vertices, &pv)) _msh_print_point(pv); } break; case MSH_PHYSICAL_LINE: if(CTX.mesh.oldxtrude) { //for old extrusion mesh generator for(k = 0; k < List_Nbr(ListVolumes); k++) { List_Read(ListVolumes, k, &pV); for(j = 0; j < List_Nbr(p->Entities); j++) { List_Read(p->Entities, j, &Num); MSH_LIN_NUM = abs(Num); MSH_PHYSICAL_ORI = sign(Num); Tree_Action(pV->Lin_Surf, _msh_print_simplex); } } } else{ for(k = 0; k < List_Nbr(ListCurves); k++) { List_Read(ListCurves, k, &pc); for(j = 0; j < List_Nbr(p->Entities); j++) { List_Read(p->Entities, j, &Num); MSH_LIN_NUM = abs(Num); MSH_PHYSICAL_ORI = sign(Num); Tree_Action(pc->Simplexes, _msh_print_simplex); Tree_Action(pc->SimplexesBase, _msh_print_simplex); } } } break; case MSH_PHYSICAL_SURFACE: if(CTX.mesh.oldxtrude) { //for old extrusion mesh generator for(k = 0; k < List_Nbr(ListVolumes); k++) { List_Read(ListVolumes, k, &pV); for(j = 0; j < List_Nbr(p->Entities); j++) { List_Read(p->Entities, j, &Num); MSH_SUR_NUM = abs(Num); MSH_PHYSICAL_ORI = sign(Num); Tree_Action(pV->Simp_Surf, _msh_print_simplex); Tree_Action(pV->Quad_Surf, _msh_print_quadrangle); } } } else{ for(k = 0; k < List_Nbr(ListSurfaces); k++) { List_Read(ListSurfaces, k, &ps); for(j = 0; j < List_Nbr(p->Entities); j++) { List_Read(p->Entities, j, &Num); MSH_SUR_NUM = abs(Num); MSH_PHYSICAL_ORI = sign(Num); Tree_Action(ps->Simplexes, _msh_print_simplex); Tree_Action(ps->SimplexesBase, _msh_print_simplex); Tree_Action(ps->Quadrangles, _msh_print_quadrangle); } } } break; case MSH_PHYSICAL_VOLUME: for(k = 0; k < List_Nbr(ListVolumes); k++) { List_Read(ListVolumes, k, &pV); for(j = 0; j < List_Nbr(p->Entities); j++) { List_Read(p->Entities, j, &Num); MSH_VOL_NUM = abs(Num); MSH_PHYSICAL_ORI = sign(Num); Tree_Action(pV->Simplexes, _msh_print_simplex); Tree_Action(pV->SimplexesBase, _msh_print_simplex); Tree_Action(pV->Hexahedra, _msh_print_hexahedron); Tree_Action(pV->Prisms, _msh_print_prism); Tree_Action(pV->Pyramids, _msh_print_pyramid); } } break; default: Msg(GERROR, "Unknown type of physical group"); break; } } List_Delete(ListCurves); List_Delete(ListSurfaces); List_Delete(ListVolumes); } static void _get_all_model_points ( std::list<Vertex*> &mp ) { List_T *curves = Tree2List(THEM->Curves); std::set<Vertex*> points; for(int i = 0; i < List_Nbr(curves); i++){ Curve *c; List_Read(curves, i, &c); if (c->Num >=0) { if (c->beg && points.find(c->beg) == points.end()) { points.insert(c->beg); mp.push_back(c->beg); } if (c->end && points.find(c->end) == points.end()) { points.insert(c->end); mp.push_back(c->end); } } } } static void _msh_print_all_modelpoints() { std::list<Vertex*> mp; _get_all_model_points ( mp ); std::list<Vertex*>::iterator it = mp.begin(); while (it != mp.end()) { Vertex *v = (*it); _msh_print_point(v); it++; } } static void _msh_print_all_curves(void *a, void *b) { Curve *c = *(Curve **) a; Tree_Action(c->Simplexes, _msh_print_simplex); Tree_Action(c->SimplexesBase, _msh_print_simplex); } static void _msh_print_all_surfaces(void *a, void *b) { Surface *s = *(Surface **) a; Tree_Action(s->Simplexes, _msh_print_simplex); Tree_Action(s->SimplexesBase, _msh_print_simplex); Tree_Action(s->Quadrangles, _msh_print_quadrangle); } static void _msh_print_all_simpsurf(void *a, void *b) { Volume *v = *(Volume **) a; Tree_Action(v->Simp_Surf, _msh_print_simplex); Tree_Action(v->Quad_Surf, _msh_print_quadrangle); } static void _msh_print_all_linsurf(void *a, void *b) { Volume *v = *(Volume **) a; Tree_Action(v->Lin_Surf, _msh_print_simplex); } static void _msh_print_all_volumes(void *a, void *b) { Volume *v = *(Volume **) a; Tree_Action(v->Simplexes, _msh_print_simplex); Tree_Action(v->SimplexesBase, _msh_print_simplex); Tree_Action(v->Hexahedra, _msh_print_hexahedron); Tree_Action(v->Prisms, _msh_print_prism); Tree_Action(v->Pyramids, _msh_print_pyramid); } static void _msh_print_all_elements(Mesh *M) { MSH_PHYSICAL_NUM = 0; MSH_PHYSICAL_ORI = 1; MSH_LIN_NUM = MSH_SUR_NUM = MSH_VOL_NUM = 0; _msh_print_all_modelpoints(); if(CTX.mesh.oldxtrude) { Tree_Action(M->Volumes, _msh_print_all_simpsurf); Tree_Action(M->Volumes, _msh_print_all_linsurf); } else { Tree_Action(M->Curves, _msh_print_all_curves); Tree_Action(M->Surfaces, _msh_print_all_surfaces); } Tree_Action(M->Volumes, _msh_print_all_volumes); } static void _msh_process_elements(Mesh *M) { MSH_ADD = 0; MSH_ELEMENT_NUM = 1; if(!List_Nbr(M->PhysicalGroups) || CTX.mesh.save_all) { Msg(INFO, "Saving all elements (discarding physical groups)"); _msh_print_all_elements(M); } else _msh_print_elements(M); if(CTX.mesh.msh_file_version == 2.0) fprintf(MSHFILE, "$Elements\n"); else fprintf(MSHFILE, "$ELM\n"); fprintf(MSHFILE, "%d\n", MSH_ELEMENT_NUM - 1); if(MSH_ELEMENT_NUM == 1) Msg(WARNING, "No elements to save"); MSH_ADD = 1; MSH_ELEMENT_NUM = 1; if(!List_Nbr(M->PhysicalGroups) || CTX.mesh.save_all) _msh_print_all_elements(M); else _msh_print_elements(M); if(CTX.mesh.msh_file_version == 2.0) fprintf(MSHFILE, "$EndElements\n"); else fprintf(MSHFILE, "$ENDELM\n"); } void Print_Mesh_MSH(Mesh *M, FILE *fp) { MSHFILE = fp; if(CTX.mesh.msh_file_version == 1.0){ // OK, no header } else if(CTX.mesh.msh_file_version == 2.0){ fprintf(MSHFILE, "$MeshFormat\n"); fprintf(MSHFILE, "%g %d %d\n", CTX.mesh.msh_file_version, LIST_FORMAT_ASCII, (int)sizeof(double)); fprintf(MSHFILE, "$EndMeshFormat\n"); } else{ Msg(GERROR, "Unknown MSH file version to generate (%g)", CTX.mesh.msh_file_version); return; } _msh_process_nodes(M); _msh_process_elements(M); Msg(INFO, "%d nodes", MSH_NODE_NUM); Msg(INFO, "%d elements", MSH_ELEMENT_NUM - 1); } // Write mesh in UNV format // IDEAS records #define HEADER 151 #define UNITS 164 #define NODES 2411 #define ELEMENTS 2412 #define RESNODE 55 #define RESELEM 56 #define RESVECT 57 #define GROUPOFNODES 790 // IDEAS elements #define BEAM 21 #define BEAM2 24 #define THINSHLL 91 #define THINSHLL2 92 #define QUAD 94 #define QUAD2 95 // Ca c'est une impro !!! #define SOLIDFEM 111 #define WEDGE 112 #define BRICK 115 #define SOLIDFEM2 118 static int ELEMENT_ID; static Tree_T *tree; static int UNV_VOL_NUM; static FILE *UNVFILE; static void _unv_process_nodes(Mesh *M) { Vertex *v; List_T *Nodes = Tree2List(M->Vertices); fprintf(UNVFILE, "%6d\n", -1); fprintf(UNVFILE, "%6d\n", NODES); int nbnod = List_Nbr(Nodes); for(int i = 0; i < nbnod; i++) { List_Read(Nodes, i, &v); int idnod = v->Num; double x = v->Pos.X * CTX.mesh.scaling_factor; double y = v->Pos.Y * CTX.mesh.scaling_factor; double z = v->Pos.Z * CTX.mesh.scaling_factor; fprintf(UNVFILE, "%10d%10d%10d%10d\n", idnod, 1, 1, 11); char tmp[128]; // ugly hack to print number with 'D+XX' exponents sprintf(tmp, "%25.16E%25.16E%25.16E\n", x, y, z); tmp[21] = 'D'; tmp[46] = 'D'; tmp[71] = 'D'; fprintf(UNVFILE, tmp); } List_Delete(Nodes); fprintf(UNVFILE, "%6d\n", -1); } static void _unv_print_record(int num, int fetyp, int geo, int n, int nsup, Vertex **v, Vertex **vsup) { fprintf(UNVFILE, "%10d%10d%10d%10d%10d%10d\n", num, fetyp, geo, geo, 7, n + nsup); if(fetyp == BEAM || fetyp == BEAM2) fprintf(UNVFILE, "%10d%10d%10d\n", 0, 0, 0); int ntot = 0; for(int k = 0; k < n; k++) { fprintf(UNVFILE, "%10d", v[k]->Num); if(ntot % 8 == 7) fprintf(UNVFILE, "\n"); ntot++; } for(int k = 0; k < nsup; k++) { fprintf(UNVFILE, "%10d", vsup[k]->Num); if(ntot % 8 == 7) fprintf(UNVFILE, "\n"); ntot++; } if(ntot - 1 % 8 != 7) fprintf(UNVFILE, "\n"); } static void _unv_process_1D_elements(Mesh *m) { List_T *ListCurves = Tree2List(m->Curves); List_T *Elements; SimplexBase *sx; Curve *c; for(int i = 0; i < List_Nbr(ListCurves); i++) { List_Read(ListCurves, i, &c); for(int simtype = 0; simtype < 2; simtype ++){ Elements = (!simtype) ? Tree2List(c->Simplexes) : Tree2List(c->SimplexesBase); for(int j = 0; j < List_Nbr(Elements); j++) { List_Read(Elements, j, &sx); if(sx->VSUP) _unv_print_record(sx->Num, BEAM2, c->Num, 2, 1, &sx->V[0], sx->VSUP); else _unv_print_record(sx->Num, BEAM, c->Num, 2, 0, &sx->V[0], NULL); } List_Delete(Elements); } } List_Delete(ListCurves); } static void _unv_process_2D_elements(Mesh *m) { List_T *ListSurfaces = Tree2List(m->Surfaces); List_T *Elements; Surface *s; SimplexBase *sx; Quadrangle *qx; for(int i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &s); // triangles for(int simtype = 0; simtype < 2; simtype++){ Elements = (!simtype) ? Tree2List(s->Simplexes) : Tree2List(s->SimplexesBase); for(int j = 0; j < List_Nbr(Elements); j++) { List_Read(Elements, j, &sx); if(sx->VSUP) _unv_print_record(abs(sx->Num), THINSHLL, s->Num, 3, 3, &sx->V[0], sx->VSUP); else _unv_print_record(abs(sx->Num), THINSHLL, s->Num, 3, 0, &sx->V[0], NULL); } List_Delete(Elements); } // quadrangles Elements = Tree2List(s->Quadrangles); for(int j = 0; j < List_Nbr(Elements); j++) { List_Read(Elements, j, &qx); if(qx->VSUP) _unv_print_record(abs(qx->Num), QUAD, s->Num, 4, 4+1, &qx->V[0], qx->VSUP); else _unv_print_record(abs(qx->Num), QUAD2, s->Num, 4, 0, &qx->V[0], NULL); } List_Delete(Elements); } List_Delete(ListSurfaces); } static void _unv_process_3D_elements(Mesh *m) { List_T *ListVolumes = Tree2List(m->Volumes); List_T *Elements; SimplexBase *sx; Hexahedron *hx; Prism *px; Volume *v; for(int i = 0; i < List_Nbr(ListVolumes); i++) { List_Read(ListVolumes, i, &v); // Tets for(int simtype = 0; simtype < 2; simtype++){ Elements = (!simtype) ? Tree2List(v->Simplexes) : Tree2List(v->SimplexesBase); for(int j = 0; j < List_Nbr(Elements); j++) { List_Read(Elements, j, &sx); if(sx->Volume_Simplexe() < 0) { Vertex *temp; temp = sx->V[0]; sx->V[0] = sx->V[1]; sx->V[1] = temp; if(sx->VSUP){ temp = sx->VSUP[1]; sx->VSUP[1] = sx->VSUP[2]; sx->VSUP[2] = temp; temp = sx->VSUP[5]; sx->VSUP[5] = sx->VSUP[3]; sx->VSUP[3] = temp; } } if(sx->VSUP) _unv_print_record(ELEMENT_ID++, SOLIDFEM, v->Num, 4, 6, &sx->V[0], sx->VSUP); else _unv_print_record(ELEMENT_ID++, SOLIDFEM, v->Num, 4, 0, &sx->V[0], NULL); } List_Delete(Elements); } // Prisms Elements = Tree2List(v->Prisms); for(int j = 0; j < List_Nbr(Elements); j++) { List_Read(Elements, j, &px); if(px->VSUP) _unv_print_record(ELEMENT_ID++, WEDGE, v->Num, 6, 9+3, &px->V[0], px->VSUP); else _unv_print_record(ELEMENT_ID++, WEDGE, v->Num, 6, 0, &px->V[0], NULL); } List_Delete(Elements); // Hexas Elements = Tree2List(v->Hexahedra); for(int j = 0; j < List_Nbr(Elements); j++) { List_Read(Elements, j, &hx); if(hx->VSUP) _unv_print_record(ELEMENT_ID++, BRICK, v->Num, 8, 12+6+1, &hx->V[0], hx->VSUP); else _unv_print_record(ELEMENT_ID++, BRICK, v->Num, 8, 0, &hx->V[0], NULL); } List_Delete(Elements); } List_Delete(ListVolumes); } static void _unv_add_vertex(void *a, void *b) { Vertex *v = *(Vertex **) a; if(Tree_Search(tree, &v->Num)) return; Tree_Add(tree, &v->Num); fprintf(UNVFILE, "%10d%10d%2d%2d%2d%2d%2d%2d\n", v->Num, 1, 0, 1, 0, 0, 0, 0); fprintf(UNVFILE, " 0.0000000000000000D+00 1.0000000000000000D+00 0.0000000000000000D+00\n"); fprintf(UNVFILE, " 0.0000000000000000D+00 0.0000000000000000D+00 0.0000000000000000D+00\n"); fprintf(UNVFILE, "%10d%10d%10d%10d%10d%10d\n", 0, 0, 0, 0, 0, 0); } static void _unv_add_simplex_vertices(void *a, void *b) { SimplexBase *s = *(SimplexBase **) a; if(s->iEnt != UNV_VOL_NUM) return; for(int i = 0; i < 4; i++) _unv_add_vertex(&s->V[i], NULL); } static void _unv_add_hexahedron_vertices(void *a, void *b) { Hexahedron *h = *(Hexahedron **) a; if(h->iEnt != UNV_VOL_NUM) return; for(int i = 0; i < 8; i++) _unv_add_vertex(&h->V[i], NULL); } static void _unv_add_prism_vertices(void *a, void *b) { Prism *p = *(Prism **) a; if(p->iEnt != UNV_VOL_NUM) return; for(int i = 0; i < 6; i++) _unv_add_vertex(&p->V[i], NULL); } static void _unv_add_pyramid_vertices(void *a, void *b) { Pyramid *p = *(Pyramid **) a; if(p->iEnt != UNV_VOL_NUM) return; for(int i = 0; i < 5; i++) _unv_add_vertex(&p->V[i], NULL); } static void _unv_process_groups(Mesh *m) { Volume *pV; Surface *ps, s; Curve *pc, c; Vertex *pv, v; PhysicalGroup *p; List_T *ListVolumes; for(int i = 0; i < List_Nbr(m->PhysicalGroups); i++) { List_Read(m->PhysicalGroups, i, &p); fprintf(UNVFILE, "%6d\n", -1); fprintf(UNVFILE, "%6d\n", GROUPOFNODES); fprintf(UNVFILE, "%10d%10d\n", p->Num, 1); fprintf(UNVFILE, "LOAD SET %2d\n", 1); tree = Tree_Create(sizeof(int), fcmp_absint); switch (p->Typ) { case MSH_PHYSICAL_VOLUME: ListVolumes = Tree2List(m->Volumes); for(int k = 0; k < List_Nbr(ListVolumes); k++) { List_Read(ListVolumes, k, &pV); for(int j = 0; j < List_Nbr(p->Entities); j++) { List_Read(p->Entities, j, &UNV_VOL_NUM); Tree_Action(pV->Simplexes, _unv_add_simplex_vertices); Tree_Action(pV->SimplexesBase, _unv_add_simplex_vertices); Tree_Action(pV->Hexahedra, _unv_add_hexahedron_vertices); Tree_Action(pV->Prisms, _unv_add_prism_vertices); Tree_Action(pV->Pyramids, _unv_add_pyramid_vertices); } } List_Delete(ListVolumes); break; case MSH_PHYSICAL_SURFACE: for(int j = 0; j < List_Nbr(p->Entities); j++) { ps = &s; List_Read(p->Entities, j, &ps->Num); if(Tree_Query(m->Surfaces, &ps)) Tree_Action(ps->Vertices, _unv_add_vertex); } break; case MSH_PHYSICAL_LINE: for(int j = 0; j < List_Nbr(p->Entities); j++) { pc = &c; List_Read(p->Entities, j, &pc->Num); if(Tree_Query(m->Curves, &pc)) for(int k = 0; k < List_Nbr(pc->Vertices); k++) _unv_add_vertex(List_Pointer(pc->Vertices, k), NULL); } break; case MSH_PHYSICAL_POINT: for(int j = 0; j < List_Nbr(p->Entities); j++) { pv = &v; List_Read(p->Entities, j, &pv->Num); if(Tree_Query(m->Vertices, &pv)) _unv_add_vertex(&pv, NULL); } break; } Tree_Delete(tree); fprintf(UNVFILE, "%6d\n", -1); } } void Print_Mesh_UNV(Mesh *M, FILE *fp) { UNVFILE = fp; _unv_process_nodes(M); fprintf(UNVFILE, "%6d\n", -1); fprintf(UNVFILE, "%6d\n", ELEMENTS); ELEMENT_ID = 1; _unv_process_3D_elements(M); _unv_process_2D_elements(M); _unv_process_1D_elements(M); fprintf(UNVFILE, "%6d\n", -1); _unv_process_groups(M); } // Write mesh in Gref format static FILE *GREFFILE; static void _gref_consecutive_nodes(Mesh *M, Tree_T *ConsecutiveNTree, Tree_T *ConsecutiveETree) { SimplexBase *sx; Quadrangle *qx; Surface *s; int nbnod, nbedges, nbdof; int newnum = 0; List_T *ListSurfaces = Tree2List(M->Surfaces); for(int i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &s); // triangles for(int simtype = 0; simtype < 2; simtype++){ List_T *Triangles = (!simtype) ? Tree2List(s->Simplexes) : Tree2List(s->SimplexesBase); for(int j = 0; j < List_Nbr(Triangles); j++) { List_Read(Triangles, j, &sx); for(int k = 0; k < 3; k++) { if(sx->V[k]->Frozen >= 0) { sx->V[k]->Frozen = --newnum; Tree_Insert(ConsecutiveNTree, &(sx->V[k])); } } } List_Delete(Triangles); } // quads List_T *Quadrangles = Tree2List(s->Quadrangles); for(int j = 0; j < List_Nbr(Quadrangles); j++) { List_Read(Quadrangles, j, &qx); for(int k = 0; k < 4; k++) { if(qx->V[k]->Frozen >= 0) { qx->V[k]->Frozen = --newnum; Tree_Insert(ConsecutiveNTree, &(qx->V[k])); } } } List_Delete(Quadrangles); } nbnod = -newnum; for(int i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &s); // triangles for(int simtype = 0; simtype < 2; simtype++){ List_T *Triangles = (!simtype) ? Tree2List(s->Simplexes) : Tree2List(s->SimplexesBase); for(int j = 0; j < List_Nbr(Triangles); j++) { List_Read(Triangles, j, &sx); for(int k = 0; k < 3; k++) { if(sx->VSUP[k]->Frozen >= 0) { sx->VSUP[k]->Frozen = --newnum; Tree_Insert(ConsecutiveETree, &(sx->VSUP[k])); } } } List_Delete(Triangles); } // quads List_T *Quadrangles = Tree2List(s->Quadrangles); for(int j = 0; j < List_Nbr(Quadrangles); j++) { List_Read(Quadrangles, j, &qx); for(int k = 0; k < 4; k++) { if(qx->VSUP[k]->Frozen >= 0) { qx->VSUP[k]->Frozen = --newnum; Tree_Insert(ConsecutiveETree, &(qx->VSUP[k])); } } } List_Delete(Quadrangles); } List_Delete(ListSurfaces); nbedges = -newnum - nbnod; nbdof = nbnod + nbedges; Msg(INFO, "%d Dofs", nbdof); } static void _gref_end_consecutive_nodes(Mesh *M) { SimplexBase *sx; Quadrangle *qx; Surface *s; List_T *ListSurfaces = Tree2List(M->Surfaces); for(int i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &s); // triangles for(int simtype = 0; simtype < 2; simtype++){ List_T *Triangles = (!simtype) ? Tree2List(s->Simplexes) : Tree2List(s->SimplexesBase); for(int j = 0; j < List_Nbr(Triangles); j++) { List_Read(Triangles, j, &sx); for(int k = 0; k < 3; k++) sx->V[k]->Frozen = 0; for(int k = 0; k < 3; k++) sx->VSUP[k]->Frozen = 0; } List_Delete(Triangles); } // quads List_T *Quadrangles = Tree2List(s->Quadrangles); for(int j = 0; j < List_Nbr(Quadrangles); j++) { List_Read(Quadrangles, j, &qx); for(int k = 0; k < 4; k++) qx->V[k]->Frozen = 0; for(int k = 0; k < 4; k++) qx->VSUP[k]->Frozen = 0; } List_Delete(Quadrangles); } List_Delete(ListSurfaces); } static int _gref_compare_frozen(const void *a, const void *b) { Vertex *q, *w; q = *(Vertex **) a; w = *(Vertex **) b; return w->Frozen - q->Frozen; } static int _gref_process_nodes(Mesh *M, Tree_T *ConsecutiveNTree, Tree_T *ConsecutiveETree) { int i, nbtriqua; Vertex *v; Surface *s; List_T *Nodes; Tree_Action(M->Curves, Degre2_Curve); Tree_Action(M->Surfaces, Degre2_Surface); List_T *ListSurfaces = Tree2List(M->Surfaces); nbtriqua = 0; for(i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &s); nbtriqua += Tree_Nbr(s->Simplexes) + Tree_Nbr(s->SimplexesBase); nbtriqua += Tree_Nbr(s->Quadrangles); } List_Delete(ListSurfaces); _gref_consecutive_nodes(M, ConsecutiveNTree, ConsecutiveETree); fprintf(GREFFILE, "%d %d %d\n", nbtriqua, Tree_Nbr(ConsecutiveNTree), Tree_Nbr(ConsecutiveNTree) + Tree_Nbr(ConsecutiveETree)); Nodes = Tree2List(ConsecutiveNTree); for(i = 0; i < List_Nbr(Nodes); i++) { List_Read(Nodes, i, &v); fprintf(GREFFILE, "%21.16e ", v->Pos.X * CTX.mesh.scaling_factor); if(i % 3 == 2) fprintf(GREFFILE, "\n"); } if((List_Nbr(Nodes) - 1) % 3 != 2) fprintf(GREFFILE, "\n"); for(i = 0; i < List_Nbr(Nodes); i++) { List_Read(Nodes, i, &v); fprintf(GREFFILE, "%21.16e ", v->Pos.Y * CTX.mesh.scaling_factor); if(i % 3 == 2) fprintf(GREFFILE, "\n"); } if((List_Nbr(Nodes) - 1) % 3 != 2) fprintf(GREFFILE, "\n"); i = Tree_Nbr(ConsecutiveNTree); List_Delete(Nodes); return i; } static int _gref_find_physical(Vertex *v, Mesh *m) { PhysicalGroup *p; Curve *c; int i, j; for(i = 0; i < List_Nbr(m->PhysicalGroups); i++) { List_Read(m->PhysicalGroups, i, &p); if(p->Typ == MSH_PHYSICAL_POINT) { if(List_Search(p->Entities, &v->Num, fcmp_absint)) { return p->Num; } } } if(v->ListCurves) { for(i = 0; i < List_Nbr(m->PhysicalGroups); i++) { List_Read(m->PhysicalGroups, i, &p); if(p->Typ == MSH_PHYSICAL_LINE) { for(j = 0; j < List_Nbr(v->ListCurves); j++) { List_Read(v->ListCurves, j, &c); if(List_Search(p->Entities, &c->Num, fcmp_absint)) { return p->Num; } } } } } return 0; } static void _gref_process_boundary_conditions(Mesh *M, Tree_T *TRN, Tree_T *TRE) { int i, ent; Vertex *v; List_T *Nodes = Tree2List(TRN); for(i = 0; i < List_Nbr(Nodes); i++) { List_Read(Nodes, i, &v); ent = _gref_find_physical(v, M); fprintf(GREFFILE, "%d %d ", ent, ent); if(i % 3 == 2) fprintf(GREFFILE, "\n"); } if((List_Nbr(Nodes) - 1) % 3 != 2) fprintf(GREFFILE, "\n"); List_Delete(Nodes); Nodes = Tree2List(TRE); for(i = 0; i < List_Nbr(Nodes); i++) { List_Read(Nodes, i, &v); ent = _gref_find_physical(v, M); fprintf(GREFFILE, "%d %d ", ent, ent); if(i % 3 == 2) fprintf(GREFFILE, "\n"); } if((List_Nbr(Nodes) - 1) % 3 != 2) fprintf(GREFFILE, "\n"); List_Delete(Nodes); } static void _gref_process_elements(Mesh *M, int nn) { SimplexBase *sx; Quadrangle *qx; Surface *s; List_T *ListSurfaces = Tree2List(M->Surfaces); for(int i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &s); // triangles for(int simtype = 0; simtype < 2; simtype++){ List_T *Triangles = (!simtype) ? Tree2List(s->Simplexes) : Tree2List(s->SimplexesBase); for(int j = 0; j < List_Nbr(Triangles); j++) { List_Read(Triangles, j, &sx); fprintf(GREFFILE, "%d %d %d\n", -sx->V[0]->Frozen, -sx->V[1]->Frozen, -sx->V[2]->Frozen); } List_Delete(Triangles); } // quads List_T *Quadrangles = Tree2List(s->Quadrangles); for(int j = 0; j < List_Nbr(Quadrangles); j++) { List_Read(Quadrangles, j, &qx); fprintf(GREFFILE, "%d %d %d %d\n", -qx->V[0]->Frozen, -qx->V[1]->Frozen, -qx->V[2]->Frozen, -qx->V[3]->Frozen); } List_Delete(Quadrangles); } // Degres de Liberte for(int i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &s); // triangles for(int simtype = 0; simtype < 2; simtype++){ List_T *Triangles = (!simtype) ? Tree2List(s->Simplexes) : Tree2List(s->SimplexesBase); for(int j = 0; j < List_Nbr(Triangles); j++) { List_Read(Triangles, j, &sx); fprintf(GREFFILE, "%d %d %d %d %d %d %d %d %d %d %d %d\n", -2 * sx->V[0]->Frozen - 1, -2 * sx->V[0]->Frozen, -2 * sx->VSUP[0]->Frozen - 1, -2 * sx->VSUP[0]->Frozen, -2 * sx->V[1]->Frozen - 1, -2 * sx->V[1]->Frozen, -2 * sx->VSUP[1]->Frozen - 1, -2 * sx->VSUP[1]->Frozen, -2 * sx->V[2]->Frozen - 1, -2 * sx->V[2]->Frozen, -2 * sx->VSUP[2]->Frozen - 1, -2 * sx->VSUP[2]->Frozen); } List_Delete(Triangles); } // quads List_T *Quadrangles = Tree2List(s->Quadrangles); for(int j = 0; j < List_Nbr(Quadrangles); j++) { List_Read(Quadrangles, j, &qx); fprintf(GREFFILE, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", -2 * qx->V[0]->Frozen - 1, -2 * qx->V[0]->Frozen, -2 * qx->VSUP[0]->Frozen - 1, -2 * qx->VSUP[0]->Frozen, -2 * qx->V[1]->Frozen - 1, -2 * qx->V[1]->Frozen, -2 * qx->VSUP[1]->Frozen - 1, -2 * qx->VSUP[1]->Frozen, -2 * qx->V[2]->Frozen - 1, -2 * qx->V[2]->Frozen, -2 * qx->VSUP[2]->Frozen - 1, -2 * qx->VSUP[2]->Frozen, -2 * qx->V[3]->Frozen - 1, -2 * qx->V[3]->Frozen, -2 * qx->VSUP[3]->Frozen - 1, -2 * qx->VSUP[3]->Frozen); } List_Delete(Quadrangles); } List_Delete(ListSurfaces); } void Print_Mesh_GREF(Mesh *M, FILE *fp) { GREFFILE = fp; Tree_T *TRN = Tree_Create(sizeof(Vertex *), _gref_compare_frozen); Tree_T *TRE = Tree_Create(sizeof(Vertex *), _gref_compare_frozen); _gref_process_nodes(M, TRN, TRE); _gref_process_elements(M, Tree_Nbr(TRN)); _gref_process_boundary_conditions(M, TRN, TRE); Tree_Delete(TRN); Tree_Delete(TRE); _gref_end_consecutive_nodes(M); } // Write mesh in VRML 1 format static List_T *wrlnodes = NULL; static FILE *WRLFILE; static void _wrl_print_node(void *a, void *b) { Vertex *V = *(Vertex **) a; fprintf(WRLFILE, "%.16g %.16g %.16g,\n", V->Pos.X * CTX.mesh.scaling_factor, V->Pos.Y * CTX.mesh.scaling_factor, V->Pos.Z * CTX.mesh.scaling_factor); List_Add(wrlnodes, &V->Num); } static void _wrl_process_nodes(Mesh *M) { if(!wrlnodes) wrlnodes = List_Create(Tree_Size(M->Vertices), 100, sizeof(int)); else List_Reset(wrlnodes); fprintf(WRLFILE, "#VRML V1.0 ascii\n"); fprintf(WRLFILE, "#created by Gmsh\n"); fprintf(WRLFILE, "Coordinate3 {\n"); fprintf(WRLFILE, " point [\n"); Tree_Action(M->Vertices, _wrl_print_node); fprintf(WRLFILE, " ]\n"); fprintf(WRLFILE, "}\n"); } static void _wrl_print_line(void *a, void *b) { SimplexBase *s = *(SimplexBase **) a; for(int i = 0; i < 2; i++){ if(s->V[i]){ int j = List_ISearch(wrlnodes, &s->V[i]->Num, fcmp_int); if(j < 0) Msg(GERROR, "Unknown node %d in line %d", s->V[i]->Num, s->Num); else fprintf(WRLFILE, "%d,", j); } } fprintf(WRLFILE, "-1,\n"); } static void _wrl_print_triangle(void *a, void *b) { SimplexBase *s = *(SimplexBase **) a; for(int i = 0; i < 3; i++){ if(s->V[i]){ int j = List_ISearch(wrlnodes, &s->V[i]->Num, fcmp_int); if(j < 0) Msg(GERROR, "Unknown node %d in triangle %d", s->V[i]->Num, s->Num); else fprintf(WRLFILE, "%d,", j); } } fprintf(WRLFILE, "-1,\n"); } static void _wrl_print_quadrangle(void *a, void *b) { Quadrangle *q = *(Quadrangle **) a; for(int i = 0; i < 4; i++){ if(q->V[i]){ int j = List_ISearch(wrlnodes, &q->V[i]->Num, fcmp_int); if(j < 0) Msg(GERROR, "Unknown node %d in quadrangle %d", q->V[i]->Num, q->Num); else fprintf(WRLFILE, "%d,", j); } } fprintf(WRLFILE, "-1,\n"); } static void _wrl_print_all_curves(void *a, void *b) { Curve *c = *(Curve **) a; if(c->Num < 0) return; fprintf(WRLFILE, "DEF Curve%d IndexedLineSet {\n", c->Num); fprintf(WRLFILE, " coordIndex [\n"); Tree_Action(c->Simplexes, _wrl_print_line); Tree_Action(c->SimplexesBase, _wrl_print_line); fprintf(WRLFILE, " ]\n"); fprintf(WRLFILE, "}\n"); } static void _wrl_print_all_surfaces(void *a, void *b) { Surface *s = *(Surface **) a; fprintf(WRLFILE, "DEF Surface%d IndexedFaceSet {\n", s->Num); fprintf(WRLFILE, " coordIndex [\n"); Tree_Action(s->Simplexes, _wrl_print_triangle); Tree_Action(s->SimplexesBase, _wrl_print_triangle); Tree_Action(s->Quadrangles, _wrl_print_quadrangle); fprintf(WRLFILE, " ]\n"); fprintf(WRLFILE, "}\n"); } static void _wrl_process_elements(Mesh *M) { if(!wrlnodes) Msg(GERROR, "VRML node list does not exist"); else { Tree_Action(M->Curves, _wrl_print_all_curves); Tree_Action(M->Surfaces, _wrl_print_all_surfaces); } } void Print_Mesh_WRL(Mesh *M, FILE *fp) { WRLFILE = fp; _wrl_process_nodes(M); _wrl_process_elements(M); } // Write surface mesh in STL format static FILE *STLFILE; static void _stl_print_triangle(void *a, void *b) { SimplexBase *s = *(SimplexBase **) a; if(!s->V[2]) return; double n[3]; normal3points(s->V[0]->Pos.X, s->V[0]->Pos.Y, s->V[0]->Pos.Z, s->V[1]->Pos.X, s->V[1]->Pos.Y, s->V[1]->Pos.Z, s->V[2]->Pos.X, s->V[2]->Pos.Y, s->V[2]->Pos.Z, n); fprintf(STLFILE, "facet normal %g %g %g\n", n[0], n[1], n[2]); fprintf(STLFILE, " outer loop\n"); fprintf(STLFILE, " vertex %g %g %g\n", s->V[0]->Pos.X, s->V[0]->Pos.Y, s->V[0]->Pos.Z); fprintf(STLFILE, " vertex %g %g %g\n", s->V[1]->Pos.X, s->V[1]->Pos.Y, s->V[1]->Pos.Z); fprintf(STLFILE, " vertex %g %g %g\n", s->V[2]->Pos.X, s->V[2]->Pos.Y, s->V[2]->Pos.Z); fprintf(STLFILE, " endloop\n"); fprintf(STLFILE, "endfacet\n"); } static void _stl_print_quadrangle(void *a, void *b) { Quadrangle *q = *(Quadrangle **) a; double n[3]; normal3points(q->V[0]->Pos.X, q->V[0]->Pos.Y, q->V[0]->Pos.Z, q->V[1]->Pos.X, q->V[1]->Pos.Y, q->V[1]->Pos.Z, q->V[2]->Pos.X, q->V[2]->Pos.Y, q->V[2]->Pos.Z, n); fprintf(STLFILE, "facet normal %g %g %g\n", n[0], n[1], n[2]); fprintf(STLFILE, " outer loop\n"); fprintf(STLFILE, " vertex %g %g %g\n", q->V[0]->Pos.X, q->V[0]->Pos.Y, q->V[0]->Pos.Z); fprintf(STLFILE, " vertex %g %g %g\n", q->V[1]->Pos.X, q->V[1]->Pos.Y, q->V[1]->Pos.Z); fprintf(STLFILE, " vertex %g %g %g\n", q->V[2]->Pos.X, q->V[2]->Pos.Y, q->V[2]->Pos.Z); fprintf(STLFILE, " endloop\n"); fprintf(STLFILE, "endfacet\n"); fprintf(STLFILE, "facet normal %g %g %g\n", n[0], n[1], n[2]); fprintf(STLFILE, " outer loop\n"); fprintf(STLFILE, " vertex %g %g %g\n", q->V[0]->Pos.X, q->V[0]->Pos.Y, q->V[0]->Pos.Z); fprintf(STLFILE, " vertex %g %g %g\n", q->V[2]->Pos.X, q->V[2]->Pos.Y, q->V[2]->Pos.Z); fprintf(STLFILE, " vertex %g %g %g\n", q->V[3]->Pos.X, q->V[3]->Pos.Y, q->V[3]->Pos.Z); fprintf(STLFILE, " endloop\n"); fprintf(STLFILE, "endfacet\n"); } static void _stl_print_all_surfaces(void *a, void *b) { Surface *s = *(Surface **) a; Tree_Action(s->Simplexes, _stl_print_triangle); Tree_Action(s->SimplexesBase, _stl_print_triangle); Tree_Action(s->Quadrangles, _stl_print_quadrangle); } void Print_Mesh_STL(Mesh *M, FILE *fp) { STLFILE = fp; fprintf(STLFILE, "solid Created by Gmsh\n"); Tree_Action(M->Surfaces, _stl_print_all_surfaces); fprintf(STLFILE, "endsolid Created by Gmsh\n"); } // Write mesh in DMG format static int _dmg_is_topologic(Vertex *v, List_T *curves) { Curve *c; for(int i = 0; i < List_Nbr(curves); i++) { List_Read(curves, i, &c); if(!compareVertex(&v, &c->beg)) return 1; } return 0; } void Print_Mesh_DMG(Mesh *m, FILE *fp) { int i, j; List_T *ll, *l; Vertex *v; Curve *c; Surface *s; int k; l = Tree2List(m->Points); ll = Tree2List(m->Curves); k = 0; for(i = 0; i < List_Nbr(l); i++) { List_Read(l, i, &v); if(_dmg_is_topologic(v, ll)) { k++; } } // write first the global infos fprintf(fp, "%d %d %d %d \n", Tree_Nbr(m->Volumes), Tree_Nbr(m->Surfaces), Tree_Nbr(m->Curves) / 2, // the 2 is for the reverse curves k); // then write the bounding box fprintf(fp, "%12.5E %12.5E %12.5E \n", CTX.min[0], CTX.min[1], CTX.min[2]); fprintf(fp, "%12.5E %12.5E %12.5E \n", CTX.max[0], CTX.max[1], CTX.max[2]); // write the points k = 0; for(i = 0; i < List_Nbr(l); i++) { List_Read(l, i, &v); if(_dmg_is_topologic(v, ll)) { v->Frozen = k++; fprintf(fp, "%d %12.5E %12.5E %12.5E \n", v->Frozen, v->Pos.X, v->Pos.Y, v->Pos.Z); } } List_Delete(l); // write the curves l = ll; k = 0; for(i = 0; i < List_Nbr(l); i++) { List_Read(l, i, &c); if(c->Num > 0) { c->ipar[3] = k; Curve *cinv = FindCurve(-c->Num, m); cinv->ipar[3] = k++; fprintf(fp, "%d %d %d \n", c->ipar[3], c->beg->Frozen, c->end->Frozen); } } List_Delete(l); // write the surfaces l = Tree2List(m->Surfaces); for(i = 0; i < List_Nbr(l); i++) { List_Read(l, i, &s); int numEdgeLoop[2000], iLoop = 0; Vertex *beg = NULL; numEdgeLoop[iLoop] = 0; int deb = 1; for(j = 0; j < List_Nbr(s->Generatrices); j++) { List_Read(s->Generatrices, j, &c); if(deb) { beg = c->beg; deb = 0; } Msg(INFO, "beg->%d end->%d", c->beg->Num, c->end->Num); (numEdgeLoop[iLoop])++; if(c->end == beg) { iLoop++; numEdgeLoop[iLoop] = 0; deb = 1; } } s->ipar[3] = i; fprintf(fp, "%d %d\n", i, iLoop); int iEdge = 0; for(k = 0; k < iLoop; k++) { fprintf(fp, "%d ", numEdgeLoop[k]); for(j = 0; j < numEdgeLoop[k]; j++) { List_Read(s->Generatrices, iEdge++, &c); fprintf(fp, "%d %d ", abs(c->ipar[3]), (c->Num > 0) ? 1 : -1); } fprintf(fp, "\n"); } } List_Delete(l); // write the volumes (2 b continued...) } // Write mesh in Plot3D format, ASCII structured, multi-zone // FIXME: still need to implement this for extruded grids static FILE *P3DFILE; int _p3d_cmp_entities(const void *a, const void *b) { Element **e1 = (Element **) a; Element **e2 = (Element **) b; return (*e1)->iEnt - (*e2)->iEnt; } int _p3d_cmp_surf_num(const void *a, const void *b) { Surface **e1 = (Surface **) a; Surface **e2 = (Surface **) b; return (*e1)->Num - (*e2)->Num; } int _p3d_cmp_vol_num(const void *a, const void *b) { Volume **e1 = (Volume **) a; Volume **e2 = (Volume **) b; return (*e1)->Num - (*e2)->Num; } void _p3d_print_quads(List_T *ListQuads, int Nu, int Nv) { int i = 0, j = 0, c = 1, curQuad = 0; double coord; Quadrangle *pQ; for (c = 0; c < 3; c++) { for (j = 0; j < (Nu - 1); j++) { for (i = 0; i < (Nv - 1); i++) { curQuad = i + (j * (Nv - 1)); List_Read(ListQuads, curQuad, &pQ); coord = (c==0) ? pQ->V[0]->Pos.X : ((c==1) ? pQ->V[0]->Pos.Y : pQ->V[0]->Pos.Z); fprintf(P3DFILE, "%g ", coord * CTX.mesh.scaling_factor); } coord = (c==0) ? pQ->V[3]->Pos.X : ((c==1) ? pQ->V[3]->Pos.Y : pQ->V[3]->Pos.Z); fprintf(P3DFILE, "%g\n", coord * CTX.mesh.scaling_factor); } j--; for (i = 0; i < (Nv - 1); i++) { curQuad = i + (j * (Nv - 1)); List_Read(ListQuads, curQuad, &pQ); coord = (c==0) ? pQ->V[1]->Pos.X : ((c==1) ? pQ->V[1]->Pos.Y : pQ->V[1]->Pos.Z); fprintf(P3DFILE, "%g ", coord * CTX.mesh.scaling_factor); } coord = (c==0) ? pQ->V[2]->Pos.X : ((c==1) ? pQ->V[2]->Pos.Y : pQ->V[2]->Pos.Z); fprintf(P3DFILE, "%g\n", coord * CTX.mesh.scaling_factor); } } void _p3d_print_hex(List_T *ListHex, int Nu, int Nv, int Nw) { int i = 0, j = 0, k = 0, c = 0, curHex = 0; double coord; Hexahedron *pH; for (c = 0; c < 3; c++) { for (k = 0; k < (Nu - 1); k++) { for (j = 0; j < (Nv - 1); j++) { for (i = 0; i < (Nw - 1); i++) { curHex = i + (j * (Nw - 1)) + (k * (Nw - 1) * (Nv - 1)); List_Read(ListHex, curHex, &pH); coord = (c==0) ? pH->V[0]->Pos.X : ((c==1) ? pH->V[0]->Pos.Y : pH->V[0]->Pos.Z); fprintf(P3DFILE, "%g ", coord * CTX.mesh.scaling_factor); } coord = (c==0) ? pH->V[4]->Pos.X : ((c==1) ? pH->V[4]->Pos.Y : pH->V[4]->Pos.Z); fprintf(P3DFILE, "%g\n", coord * CTX.mesh.scaling_factor); } j--; for (i = 0; i < (Nw - 1); i++) { curHex = i + (j * (Nw - 1)) + (k * (Nw - 1) * (Nv - 1)); List_Read(ListHex, curHex, &pH); coord = (c==0) ? pH->V[3]->Pos.X : ((c==1) ? pH->V[3]->Pos.Y : pH->V[3]->Pos.Z); fprintf(P3DFILE, "%g ", coord * CTX.mesh.scaling_factor); } coord = (c==0) ? pH->V[7]->Pos.X : ((c==1) ? pH->V[7]->Pos.Y : pH->V[7]->Pos.Z); fprintf(P3DFILE, "%g\n", coord * CTX.mesh.scaling_factor); } k--; for (j = 0; j < (Nv - 1); j++) { for (i = 0; i < (Nw - 1); i++) { curHex = i + (j * (Nw - 1)) + (k * (Nw - 1) * (Nv - 1)); List_Read(ListHex, curHex, &pH); coord = (c==0) ? pH->V[1]->Pos.X : ((c==1) ? pH->V[1]->Pos.Y : pH->V[1]->Pos.Z); fprintf(P3DFILE, "%g ", coord * CTX.mesh.scaling_factor); } coord = (c==0) ? pH->V[5]->Pos.X : ((c==1) ? pH->V[5]->Pos.Y : pH->V[5]->Pos.Z); fprintf(P3DFILE, "%g\n", coord * CTX.mesh.scaling_factor); } j--; for (i = 0; i < (Nw - 1); i++) { curHex = i + (j * (Nw - 1)) + (k * (Nw - 1) * (Nv - 1)); List_Read(ListHex, curHex, &pH); coord = (c==0) ? pH->V[2]->Pos.X : ((c==1) ? pH->V[2]->Pos.Y : pH->V[2]->Pos.Z); fprintf(P3DFILE, "%g ", coord * CTX.mesh.scaling_factor); } coord = (c==0) ? pH->V[6]->Pos.X : ((c==1) ? pH->V[6]->Pos.Y : pH->V[6]->Pos.Z); fprintf(P3DFILE, "%g\n", coord * CTX.mesh.scaling_factor); } } void _p3d_print_all_elements(Mesh *M) { int i, Nv, Nu, ElemCnt = 0; Volume *pV; Surface *pS; List_T *ListQuads; List_T *ListHex; List_T *ListSurfaces = Tree2List(M->Surfaces); List_T *ListVolumes = Tree2List(M->Volumes); List_T *ListStructSurf = List_Create(1,1,sizeof(Surface *)); List_T *ListStructVol = List_Create(1,1,sizeof(Volume *)); List_Sort(ListSurfaces, _p3d_cmp_surf_num); List_Sort(ListVolumes, _p3d_cmp_vol_num); for(i = 0; i < List_Nbr(ListSurfaces); i++) { List_Read(ListSurfaces, i, &pS); if (pS->Nu && pS->Nv && (Tree_Nbr(pS->Quadrangles) == (pS->Nu - 1) * (pS->Nv - 1))){ ElemCnt++; List_Add(ListStructSurf, &pS); } } for(i = 0; i < List_Nbr(ListVolumes); i++) { List_Read(ListVolumes, i, &pV); List_Read(pV->Surfaces, 0, &pS); Nu = pS->Nu; Nv = pS->Nv; List_Read(pV->Surfaces, 1, &pS); if (Nu && Nv && pS->Nv && (Tree_Nbr(pV->Hexahedra) == (Nu - 1) * (Nv - 1) * (pS->Nv - 1))){ ElemCnt++; List_Add(ListStructVol, &pV); } } fprintf(P3DFILE, "%d\n", ElemCnt); for(i = 0; i < List_Nbr(ListStructSurf); i++) { List_Read(ListStructSurf, i, &pS); fprintf(P3DFILE, "%d %d 1\n", pS->Nv, pS->Nu); } for(i = 0; i < List_Nbr(ListStructVol); i++) { List_Read(ListStructVol, i, &pV); List_Read(pV->Surfaces, 0, &pS); Nu = pS->Nu; Nv = pS->Nv; List_Read(pV->Surfaces, 1, &pS); fprintf(P3DFILE, "%d %d %d\n", pS->Nv, Nv, Nu); } for(i = 0; i < List_Nbr(ListStructSurf); i++) { List_Read(ListStructSurf, i, &pS); ListQuads = Tree2List(pS->Quadrangles); List_Sort(ListQuads, _p3d_cmp_entities); _p3d_print_quads(ListQuads, pS->Nu, pS->Nv); List_Delete(ListQuads); } for(i = 0; i < List_Nbr(ListStructVol); i++) { List_Read(ListStructVol, i, &pV); List_Read(pV->Surfaces, 0, &pS); Nu = pS->Nu; Nv = pS->Nv; List_Read(pV->Surfaces, 1, &pS); ListHex = Tree2List(pV->Hexahedra); List_Sort(ListHex, _p3d_cmp_entities); _p3d_print_hex(ListHex, Nu, Nv, pS->Nv); List_Delete(ListHex); } List_Delete(ListSurfaces); List_Delete(ListVolumes); List_Delete(ListStructSurf); List_Delete(ListStructVol); } void _p3d_print_elements(Mesh *M) { // FIXME: to do } void Print_Mesh_P3D(Mesh *M, FILE *fp) { P3DFILE = fp; if(!List_Nbr(M->PhysicalGroups) || CTX.mesh.save_all) { Msg(INFO, "Saving all elements (discarding physical groups)"); _p3d_print_all_elements(M); } else{ Msg(WARNING, "No Plot3d format of physicals yet, saving all elements!"); //_p3d_print_elements(M); _p3d_print_all_elements(M); } } // Public Print_Mesh routine void GetDefaultMeshFileName(Mesh *M, int Type, char *name) { char ext[10] = ""; strcpy(name, M->name); switch(Type){ case FORMAT_MSH: strcpy(ext, ".msh"); break; case FORMAT_VRML: strcpy(ext, ".wrl"); break; case FORMAT_UNV: strcpy(ext, ".unv"); break; case FORMAT_GREF: strcpy(ext, ".Gref"); break; case FORMAT_DMG: strcpy(ext, ".dmg"); break; case FORMAT_STL: strcpy(ext, ".stl"); break; case FORMAT_P3D: strcpy(ext, ".p3d"); break; default: Msg(GERROR, "Unknown mesh file format %d", Type); break; } strcat(name, ext); } void Print_Mesh(Mesh *M, char *filename, int Type) { char name[256]; if(CTX.threads_lock) { Msg(INFO, "I'm busy! Ask me that later..."); return; } CTX.threads_lock = 1; if(!filename) GetDefaultMeshFileName(M, Type, name); else strcpy(name, filename); Msg(INFO, "Writing mesh file '%s'", name); FILE *fp = fopen(name, "w"); if(!fp) { Msg(GERROR, "Unable to open file '%s'", name); CTX.threads_lock = 0; return; } switch(Type){ case FORMAT_MSH: Print_Mesh_MSH(M, fp); break; case FORMAT_VRML: Print_Mesh_WRL(M, fp); break; case FORMAT_UNV: Print_Mesh_UNV(M, fp); break; case FORMAT_GREF: Print_Mesh_GREF(M, fp); break; case FORMAT_DMG: Print_Mesh_DMG(M, fp); break; case FORMAT_STL: Print_Mesh_STL(M, fp); break; case FORMAT_P3D: Print_Mesh_P3D(M, fp); break; default: break; } fclose(fp); Msg(INFO, "Wrote mesh file '%s'", name); Msg(STATUS2N, "Wrote '%s'", name); CTX.threads_lock = 0; }