1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5
6 #include <stdio.h>
7 #include <string>
8 #include "GModel.h"
9 #include "MTriangle.h"
10 #include "MQuadrangle.h"
11 #include "OS.h"
12 #include "discreteFace.h"
13
readOFF(const std::string & name)14 int GModel::readOFF(const std::string &name)
15 {
16 FILE *fp = Fopen(name.c_str(), "r");
17 if(!fp) {
18 Msg::Error("Unable to open file '%s'", name.c_str());
19 return 0;
20 }
21
22 int numVertices, numFaces, numEdges;
23 if(fscanf(fp, "OFF %d %d %d", &numVertices, &numFaces, &numEdges) != 3) {
24 Msg::Error("Invalid OFF header");
25 return 0;
26 }
27
28 if(!numVertices || !numFaces) {
29 Msg::Info("Empty OFF mesh");
30 return 1;
31 }
32
33 GFace *gf = new discreteFace(this, getMaxElementaryNumber(2) + 1);
34 add(gf);
35
36 std::vector<MVertex*> vertices(numVertices);
37 for(int i = 0; i < numVertices; i++) {
38 double x, y, z;
39 if(fscanf(fp, "%lf %lf %lf", &x, &y, &z) != 3) {
40 Msg::Error("Could not read vertex");
41 return 0;
42 }
43 vertices[i] = new MVertex(x, y, z, gf);
44 }
45
46 for(int i = 0; i < numFaces; i++) {
47 int n;
48 if(fscanf(fp, "%d", &n) != 1) {
49 Msg::Error("Could not read face");
50 }
51 int v[4] = {-1, -1, -1, -1};
52 if(n == 3) {
53 if(fscanf(fp, "%d %d %d", &v[0], &v[1], &v[2]) != 3) {
54 Msg::Error("Could not read face");
55 return 0;
56 }
57 gf->triangles.push_back(new MTriangle(vertices[v[0]], vertices[v[1]],
58 vertices[v[2]]));
59 }
60 else if(n == 4) {
61 if(fscanf(fp, "%d %d %d %d", &v[0], &v[1], &v[2], &v[3]) != 4) {
62 Msg::Error("Could not read face");
63 return 0;
64 }
65 gf->quadrangles.push_back(new MQuadrangle(vertices[v[0]], vertices[v[1]],
66 vertices[v[2]], vertices[v[3]]));
67 }
68 else{
69 char buffer[4096];
70 if(!fgets(buffer, sizeof(buffer), fp))
71 Msg::Error("Could not read line");
72 Msg::Warning("Ignoring %d-node face", n);
73 continue;
74 }
75 }
76
77 _associateEntityWithMeshVertices();
78 _storeVerticesInEntities(vertices); // will delete unused vertices
79 fclose(fp);
80 return 1;
81 }
82
writeOFF(const std::string & name,bool saveAll,double scalingFactor)83 int GModel::writeOFF(const std::string &name, bool saveAll, double scalingFactor)
84 {
85 FILE *fp = Fopen(name.c_str(), "w");
86 if(!fp) {
87 Msg::Error("Unable to open file '%s'", name.c_str());
88 return 0;
89 }
90
91 if(noPhysicalGroups()) saveAll = true;
92 int numVertices = indexMeshVertices(saveAll);
93 int numFaces = 0;
94 for(auto it = faces.begin(); it != faces.end(); ++it) {
95 GFace *gf = *it;
96 if(saveAll || gf->physicals.size())
97 numFaces += gf->getNumMeshElements();
98 }
99
100 fprintf(fp, "OFF %d %d 0\n", numVertices, numFaces);
101
102 std::vector<GEntity *> entities;
103 getEntities(entities);
104 for(std::size_t i = 0; i < entities.size(); i++)
105 for(std::size_t j = 0; j < entities[i]->mesh_vertices.size(); j++)
106 entities[i]->mesh_vertices[j]->writeOFF(fp, scalingFactor);
107
108 for(auto it = faces.begin(); it != faces.end(); ++it) {
109 GFace *gf = *it;
110 if(saveAll || gf->physicals.size()) {
111 for(std::size_t i = 0; i < gf->triangles.size(); i++)
112 fprintf(fp, "3 %d %d %d\n",
113 (int)gf->triangles[i]->getVertex(0)->getIndex() - 1,
114 (int)gf->triangles[i]->getVertex(1)->getIndex() - 1,
115 (int)gf->triangles[i]->getVertex(2)->getIndex() - 1);
116 for(std::size_t i = 0; i < gf->quadrangles.size(); i++)
117 fprintf(fp, "4 %d %d %d %d\n",
118 (int)gf->triangles[i]->getVertex(0)->getIndex() - 1,
119 (int)gf->triangles[i]->getVertex(1)->getIndex() - 1,
120 (int)gf->triangles[i]->getVertex(2)->getIndex() - 1,
121 (int)gf->triangles[i]->getVertex(3)->getIndex() - 1);
122 }
123 }
124
125 fclose(fp);
126 return 1;
127 }
128