24 FILE *fp =
Fopen(name.c_str(),
"rb");
26 Msg::Error(
"Unable to open file '%s'", name.c_str());
31 std::vector<std::vector<SPoint3> > points;
33 std::vector<std::string> names;
37 if(!fgets(buffer,
sizeof(buffer), fp)) {
44 bool binary = strncmp(buffer,
"solid", 5) && strncmp(buffer,
"SOLID", 5);
48 if(strlen(buffer) > 6)
49 names.push_back(&buffer[6]);
55 if(!fgets(buffer,
sizeof(buffer), fp))
break;
56 if(!strncmp(buffer,
"endsolid", 8) || !strncmp(buffer,
"ENDSOLID", 8)) {
58 if(!fgets(buffer,
sizeof(buffer), fp))
break;
59 if(!strncmp(buffer,
"solid", 5) || !strncmp(buffer,
"SOLID", 5)) {
60 if(strlen(buffer) > 6)
61 names.push_back(&buffer[6]);
64 points.resize(points.size() + 1);
66 if(!fgets(buffer,
sizeof(buffer), fp))
break;
70 if(!fgets(buffer,
sizeof(buffer), fp))
break;
72 for(
int i = 0; i < 3; i++) {
73 if(!fgets(buffer,
sizeof(buffer), fp))
break;
76 if(sscanf(buffer,
"%s %lf %lf %lf", s1, &x, &y, &
z) != 4)
break;
79 points.back().push_back(p);
83 if(!fgets(buffer,
sizeof(buffer), fp))
break;
85 if(!fgets(buffer,
sizeof(buffer), fp))
break;
91 for(std::size_t i = 0; i < points.size(); i++) {
92 if(points[i].size()) {
97 if(
empty) points.clear();
101 if(binary ||
empty) {
105 Msg::Info(
"Wrong ASCII header or empty file: trying binary read");
109 if(!fread(header,
sizeof(
char), 80, fp))
break;
110 unsigned int nfacets = 0;
111 size_t ret = fread(&nfacets,
sizeof(
unsigned int), 1, fp);
113 if(nfacets > 100000000) {
114 Msg::Info(
"Swapping bytes from binary file");
116 SwapBytes((
char *)&nfacets,
sizeof(
unsigned int), 1);
119 names.push_back(header);
120 points.resize(points.size() + 1);
121 char *data =
new char[nfacets * 50 *
sizeof(char)];
122 ret = fread(data,
sizeof(
char), nfacets * 50, fp);
123 if(ret == nfacets * 50) {
124 for(std::size_t i = 0; i < nfacets; i++) {
125 float *xyz = (
float *)&data[i * 50 *
sizeof(
char)];
127 for(
int j = 0; j < 3; j++) {
128 SPoint3 p(xyz[3 + 3 * j], xyz[3 + 3 * j + 1], xyz[3 + 3 * j + 2]);
130 points.back().push_back(p);
141 if(names.size() != points.size()) {
142 Msg::Debug(
"Invalid number of names in STL file - should never happen");
143 names.resize(points.size());
145 for(std::size_t i = 0; i < names.size(); i++) {
146 names[i].erase(remove_if(names[i].begin(), names[i].end(),
invalidChar),
150 std::vector<GFace *>
faces;
151 for(std::size_t i = 0; i < points.size(); i++) {
152 if(points[i].
empty()) {
153 Msg::Error(
"No facets found in STL file for solid %d %s", i,
158 if(points[i].size() % 3) {
159 Msg::Error(
"Wrong number of points (%d) in STL file for solid %d %s",
160 points[i].size(), i, names[i].c_str());
164 Msg::Info(
"%d facets in solid %d %s", points[i].size() / 3, i,
168 faces.push_back(face);
176 for(std::size_t i = 0; i < points.size(); i++)
177 for(std::size_t j = 0; j < points[i].size(); j++)
179 new MVertex(points[i][j].x(), points[i][j].y(), points[i][j].
z()));
183 std::set<MFace, MFaceLessThan> unique;
184 int nbDuplic = 0, nbDegen = 0;
185 for(std::size_t i = 0; i < points.size(); i++) {
186 for(std::size_t j = 0; j < points[i].size(); j += 3) {
188 for(
int k = 0; k < 3; k++) {
189 double x = points[i][j + k].
x();
190 double y = points[i][j + k].y();
191 double z = points[i][j + k].z();
192 v[k] = pos.
find(x, y,
z);
194 Msg::Error(
"Could not find node at position (%.16g, %.16g, %.16g) "
198 if(!v[0] || !v[1] || !v[2]) {
201 else if(v[0] == v[1] || v[0] == v[2] || v[1] == v[2]) {
202 Msg::Debug(
"Skipping degenerated triangle %lu %lu %lu", v[0]->getNum(),
203 v[1]->getNum(), v[2]->getNum());
207 MFace mf(v[0], v[1], v[2]);
208 if(unique.find(mf) == unique.end()) {
221 if(nbDuplic || nbDegen)
222 Msg::Warning(
"%d duplicate/%d degenerate triangles in STL file", nbDuplic,
234 double scalingFactor,
const std::string &name)
236 bool useGeoSTL =
false;
237 unsigned int nfacets = 0;
238 for(
auto it =
faces.begin(); it !=
faces.end(); ++it) {
239 nfacets += (*it)->triangles.size() + 2 * (*it)->quadrangles.size();
243 for(
auto it =
faces.begin(); it !=
faces.end(); ++it) {
244 (*it)->buildSTLTriangulation();
245 nfacets += (*it)->stl_triangles.size() / 3;
249 if(!binary) { fprintf(fp,
"solid %s\n", name.c_str()); }
252 strncpy(header, name.c_str(), 79);
254 fwrite(header,
sizeof(
char), 80, fp);
255 fwrite(&nfacets,
sizeof(
unsigned int), 1, fp);
258 for(
auto it =
faces.begin(); it !=
faces.end(); ++it) {
259 if(useGeoSTL && (*it)->stl_vertices_uv.size()) {
260 for(std::size_t i = 0; i < (*it)->stl_triangles.size(); i += 3) {
261 SPoint2 &p1((*it)->stl_vertices_uv[(*it)->stl_triangles[i]]);
262 SPoint2 &p2((*it)->stl_vertices_uv[(*it)->stl_triangles[i + 1]]);
263 SPoint2 &p3((*it)->stl_vertices_uv[(*it)->stl_triangles[i + 2]]);
264 GPoint gp1 = (*it)->point(p1);
265 GPoint gp2 = (*it)->point(p2);
266 GPoint gp3 = (*it)->point(p3);
267 double x[3] = {gp1.
x(), gp2.
x(), gp3.
x()};
268 double y[3] = {gp1.
y(), gp2.
y(), gp3.
y()};
269 double z[3] = {gp1.
z(), gp2.
z(), gp3.
z()};
273 fprintf(fp,
"facet normal %g %g %g\n", n[0], n[1], n[2]);
274 fprintf(fp,
" outer loop\n");
275 for(
int j = 0; j < 3; j++)
276 fprintf(fp,
" vertex %.16g %.16g %.16g\n", x[j] * scalingFactor,
277 y[j] * scalingFactor,
z[j] * scalingFactor);
278 fprintf(fp,
" endloop\n");
279 fprintf(fp,
"endfacet\n");
283 float *coords = (
float *)data;
284 coords[0] = (float)n[0];
285 coords[1] = (float)n[1];
286 coords[2] = (float)n[2];
287 for(
int j = 0; j < 3; j++) {
288 coords[3 + 3 * j] = (float)(x[j] * scalingFactor);
289 coords[3 + 3 * j + 1] = (float)(y[j] * scalingFactor);
290 coords[3 + 3 * j + 2] = (float)(
z[j] * scalingFactor);
292 data[48] = data[49] = 0;
293 fwrite(data,
sizeof(
char), 50, fp);
298 for(std::size_t i = 0; i < (*it)->triangles.size(); i++)
299 (*it)->triangles[i]->writeSTL(fp, binary, scalingFactor);
300 for(std::size_t i = 0; i < (*it)->quadrangles.size(); i++)
301 (*it)->quadrangles[i]->writeSTL(fp, binary, scalingFactor);
305 if(!binary) fprintf(fp,
"endsolid %s\n", name.c_str());
309 double scalingFactor,
int oneSolidPerSurface)
311 FILE *fp =
Fopen(name.c_str(), binary ?
"wb" :
"w");
313 Msg::Error(
"Unable to open file '%s'", name.c_str());
319 if(oneSolidPerSurface == 1) {
321 if(saveAll || (*it)->physicals.size()) {
322 std::vector<GFace *>
faces(1, *it);
325 std::ostringstream s;
326 s <<
"Gmsh Surface " << (*it)->tag();
333 else if(oneSolidPerSurface == 2) {
334 std::map<int, std::vector<GEntity *> > phys;
336 for(
auto it = phys.begin(); it != phys.end(); it++) {
337 std::vector<GFace *>
faces;
338 for(std::size_t i = 0; i < it->second.size(); i++) {
339 faces.push_back(
static_cast<GFace *
>(it->second[i]));
343 std::ostringstream s;
344 s <<
"Gmsh Physical Surface " << it->first;
351 std::vector<GFace *>
faces;
353 if(saveAll || (*it)->physicals.size()) {
faces.push_back(*it); }
355 std::string name =
"Created by Gmsh";