FreeFOAM The Cross-Platform CFD Toolkit
STLsurfaceFormat.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "STLsurfaceFormat.H"
27 #include <OpenFOAM/ListOps.H>
28 #include <OpenFOAM/triPointRef.H>
29 
30 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
31 
32 template<class Face>
34 (
35  Ostream& os,
36  const pointField& pointLst,
37  const Face& f
38 )
39 {
40  // calculate the normal ourselves, for flexibility and speed
41  vector norm = triPointRef
42  (
43  pointLst[f[0]],
44  pointLst[f[1]],
45  pointLst[f[2]]
46  ).normal();
47  norm /= mag(norm) + VSMALL;
48 
49  // simple triangulation about f[0].
50  // better triangulation should have been done before
51  const point& p0 = pointLst[f[0]];
52  for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
53  {
54  label fp2 = f.fcIndex(fp1);
55 
56  const point& p1 = pointLst[f[fp1]];
57  const point& p2 = pointLst[f[fp2]];
58 
59  // write STL triangle
60  os << " facet normal "
61  << norm.x() << ' ' << norm.y() << ' ' << norm.z() << nl
62  << " outer loop\n"
63  << " vertex " << p0.x() << ' ' << p0.y() << ' ' << p0.z() << nl
64  << " vertex " << p1.x() << ' ' << p1.y() << ' ' << p1.z() << nl
65  << " vertex " << p2.x() << ' ' << p2.y() << ' ' << p2.z() << nl
66  << " endloop\n"
67  << " endfacet" << endl;
68  }
69 }
70 
71 
72 template<class Face>
74 (
75  ostream& os,
76  const pointField& pointLst,
77  const Face& f,
78  const label zoneI
79 )
80 {
81  // calculate the normal ourselves, for flexibility and speed
82  vector norm = triPointRef
83  (
84  pointLst[f[0]],
85  pointLst[f[1]],
86  pointLst[f[2]]
87  ).normal();
88  norm /= mag(norm) + VSMALL;
89 
90  // simple triangulation about f[0].
91  // better triangulation should have been done before
92  const point& p0 = pointLst[f[0]];
93  for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
94  {
95  label fp2 = f.fcIndex(fp1);
96 
97  STLtriangle stlTri
98  (
99  norm,
100  p0,
101  pointLst[f[fp1]],
102  pointLst[f[fp2]],
103  zoneI
104  );
105 
106  stlTri.write(os);
107  }
108 }
109 
110 
111 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
112 
113 template<class Face>
115 (
116  const fileName& filename
117 )
118 {
119  read(filename);
120 }
121 
122 
123 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
124 
125 template<class Face>
127 (
128  const fileName& filename
129 )
130 {
131  this->clear();
132 
133  // read in the values
134  STLsurfaceFormatCore reader(filename);
135 
136  // transfer points
137  this->storedPoints().transfer(reader.points());
138 
139  // retrieve the original zone information
140  List<word> names(reader.names().xfer());
141  List<label> sizes(reader.sizes().xfer());
142  List<label> zoneIds(reader.zoneIds().xfer());
143 
144  // generate the (sorted) faces
145  List<Face> faceLst(zoneIds.size());
146 
147  if (reader.sorted())
148  {
149  // already sorted - generate directly
150  forAll(faceLst, faceI)
151  {
152  const label startPt = 3*faceI;
153  faceLst[faceI] = triFace(startPt, startPt+1, startPt+2);
154  }
155  }
156  else
157  {
158  // unsorted - determine the sorted order:
159  // avoid SortableList since we discard the main list anyhow
160  List<label> faceMap;
161  sortedOrder(zoneIds, faceMap);
162 
163  // generate sorted faces
164  forAll(faceMap, faceI)
165  {
166  const label startPt = 3*faceMap[faceI];
167  faceLst[faceI] = triFace(startPt, startPt+1, startPt+2);
168  }
169  }
170  zoneIds.clear();
171 
172  // transfer:
173  this->storedFaces().transfer(faceLst);
174 
175  if (names.size())
176  {
177  this->addZones(sizes, names);
178  }
179  else
180  {
181  this->addZones(sizes);
182  }
183 
184  this->stitchFaces(SMALL);
185  return true;
186 }
187 
188 
189 
190 template<class Face>
192 (
193  const fileName& filename,
194  const MeshedSurfaceProxy<Face>& surf
195 )
196 {
197  OFstream os(filename);
198  if (!os.good())
199  {
201  (
202  "fileFormats::STLsurfaceFormat::writeAscii"
203  "(const fileName&, const MeshedSurfaceProxy<Face>&)"
204  )
205  << "Cannot open file for writing " << filename
206  << exit(FatalError);
207  }
208 
209  const pointField& pointLst = surf.points();
210  const List<Face>& faceLst = surf.faces();
211  const List<label>& faceMap = surf.faceMap();
212 
213  const List<surfZone>& zones =
214  (
215  surf.surfZones().size() > 1
216  ? surf.surfZones()
217  : oneZone(faceLst)
218  );
219 
220  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
221 
222  label faceIndex = 0;
223  forAll(zones, zoneI)
224  {
225  // Print all faces belonging to this zone
226  const surfZone& zone = zones[zoneI];
227 
228  os << "solid " << zone.name() << nl;
229 
230  if (useFaceMap)
231  {
232  forAll(zone, localFaceI)
233  {
234  const label faceI = faceMap[faceIndex++];
235  writeShell(os, pointLst, faceLst[faceI]);
236  }
237  }
238  else
239  {
240  forAll(zone, localFaceI)
241  {
242  writeShell(os, pointLst, faceLst[faceIndex++]);
243  }
244  }
245  os << "endsolid " << zone.name() << endl;
246  }
247 }
248 
249 
250 template<class Face>
252 (
253  const fileName& filename,
254  const MeshedSurfaceProxy<Face>& surf
255 )
256 {
257  std::ofstream os(filename.c_str(), std::ios::binary);
258  if (!os.good())
259  {
261  (
262  "fileFormats::STLsurfaceFormat::writeBinary"
263  "(const fileName&, const MeshedSurfaceProxy<Face>&)"
264  )
265  << "Cannot open file for writing " << filename
266  << exit(FatalError);
267  }
268 
269 
270  const pointField& pointLst = surf.points();
271  const List<Face>& faceLst = surf.faces();
272  const List<label>& faceMap = surf.faceMap();
273 
274  const List<surfZone>& zones =
275  (
276  surf.surfZones().size() > 1
277  ? surf.surfZones()
278  : oneZone(faceLst)
279  );
280 
281  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
282 
283 
284  unsigned int nTris = 0;
286  {
287  nTris = faceLst.size();
288  }
289  else
290  {
291  // count triangles for on-the-fly triangulation
292  forAll(faceLst, faceI)
293  {
294  nTris += faceLst[faceI].size() - 2;
295  }
296  }
297 
298  // Write the STL header
299  STLsurfaceFormatCore::writeHeaderBINARY(os, nTris);
300 
301  label faceIndex = 0;
302  forAll(zones, zoneI)
303  {
304  const surfZone& zone = zones[zoneI];
305 
306  if (useFaceMap)
307  {
308  forAll(zone, localFaceI)
309  {
310  writeShell
311  (
312  os,
313  pointLst,
314  faceLst[faceMap[faceIndex++]],
315  zoneI
316  );
317  }
318  }
319  else
320  {
321  forAll(zone, localFaceI)
322  {
323  writeShell
324  (
325  os,
326  pointLst,
327  faceLst[faceIndex++],
328  zoneI
329  );
330  }
331  }
332  }
333 }
334 
335 
336 template<class Face>
338 (
339  const fileName& filename,
340  const UnsortedMeshedSurface<Face>& surf
341 )
342 {
343  OFstream os(filename);
344  if (!os.good())
345  {
347  (
348  "fileFormats::STLsurfaceFormat::writeAscii"
349  "(const fileName&, const UnsortedMeshedSurface<Face>&)"
350  )
351  << "Cannot open file for writing " << filename
352  << exit(FatalError);
353  }
354 
355  // a single zone - we can skip sorting
356  if (surf.zoneToc().size() == 1)
357  {
358  const pointField& pointLst = surf.points();
359  const List<Face>& faceLst = surf.faces();
360 
361  os << "solid " << surf.zoneToc()[0].name() << endl;
362  forAll(faceLst, faceI)
363  {
364  writeShell(os, pointLst, faceLst[faceI]);
365  }
366  os << "endsolid " << surf.zoneToc()[0].name() << endl;
367  }
368  else
369  {
370  labelList faceMap;
371  List<surfZone> zoneLst = surf.sortedZones(faceMap);
372 
373  writeAscii
374  (
375  filename,
377  (
378  surf.points(),
379  surf.faces(),
380  zoneLst,
381  faceMap
382  )
383  );
384  }
385 }
386 
387 
388 template<class Face>
390 (
391  const fileName& filename,
392  const UnsortedMeshedSurface<Face>& surf
393 )
394 {
395  std::ofstream os(filename.c_str(), std::ios::binary);
396  if (!os.good())
397  {
399  (
400  "fileFormats::STLsurfaceFormat::writeBinary"
401  "(const fileName&, const UnsortedMeshedSurface<Face>&)"
402  )
403  << "Cannot open file for writing " << filename
404  << exit(FatalError);
405  }
406 
407  const pointField& pointLst = surf.points();
408  const List<Face>& faceLst = surf.faces();
409  const List<label>& zoneIds = surf.zoneIds();
410 
411  unsigned int nTris = 0;
413  {
414  nTris = faceLst.size();
415  }
416  else
417  {
418  // count triangles for on-the-fly triangulation
419  forAll(faceLst, faceI)
420  {
421  nTris += faceLst[faceI].size() - 2;
422  }
423  }
424 
425  // Write the STL header
426  STLsurfaceFormatCore::writeHeaderBINARY(os, nTris);
427 
428  // always write unsorted
429  forAll(faceLst, faceI)
430  {
431  writeShell
432  (
433  os,
434  pointLst,
435  faceLst[faceI],
436  zoneIds[faceI]
437  );
438  }
439 }
440 
441 
442 template<class Face>
444 (
445  const fileName& filename,
446  const MeshedSurfaceProxy<Face>& surf
447 )
448 {
449  const word ext = filename.ext();
450 
451  // handle 'stlb' as binary directly
452  if (ext == "stlb")
453  {
454  writeBinary(filename, surf);
455  }
456  else
457  {
458  writeAscii(filename, surf);
459  }
460 }
461 
462 
463 template<class Face>
465 (
466  const fileName& filename,
467  const UnsortedMeshedSurface<Face>& surf
468 )
469 {
470  word ext = filename.ext();
471 
472  // handle 'stlb' as binary directly
473  if (ext == "stlb")
474  {
475  writeBinary(filename, surf);
476  }
477  else
478  {
479  writeAscii(filename, surf);
480  }
481 }
482 
483 
484 // ************************ vim: set sw=4 sts=4 et: ************************ //