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) 2011 OpenFOAM Foundation
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 "ListOps.H"
28 #include "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
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().empty()
216  ? surfaceFormatsCore::oneZone(faceLst)
217  : surf.surfZones()
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  : surfaceFormatsCore::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  {
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 // ************************************************************************* //
Output to file stream.
Definition: OFstream.H:81
word ext() const
Return file name extension (part after last .)
Definition: fileName.C:323
const List< surfZoneIdentifier > & zoneToc() const
Return const access to the zone table-of-contents.
vector point
Point is a vector.
Definition: point.H:41
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
bool useFaceMap() const
Use faceMap?
dimensioned< scalar > mag(const dimensioned< Type > &)
virtual bool read(const fileName &)
Read from file.
Xfer< List< T > > xfer()
Transfer contents to the Xfer container.
Definition: ListI.H:90
List< label > & zoneIds()
Return full access to the zoneIds.
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats...
Definition: MeshedSurface.H:73
const List< label > & zoneIds() const
Return const access to the zone ids.
A class for handling words, derived from string.
Definition: word.H:59
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Various functions to operate on Lists.
face triFace(3)
List< label > & sizes()
The list of solid sizes in the order of their first appearance.
const pointField & points() const
Return const access to the points.
Internal class used by the STLsurfaceFormat.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
const List< Face > & faces() const
Return const access to the faces.
triangle< point, const point & > triPointRef
Definition: triPointRef.H:44
static const char nl
Definition: Ostream.H:260
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
const List< Face > & faces() const
Return const access to the faces.
static void write(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy.
Base class for zones.
Definition: zone.H:57
const List< surfZone > & surfZones() const
Const access to the surface zones.
static void writeBinary(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy (as BINARY)
List< word > & names()
The list of solid names in the order of their first appearance.
#define forAll(list, i)
Definition: UList.H:421
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
const Cmpt & x() const
Definition: VectorI.H:65
A surface zone on a MeshedSurface.
Definition: surfZone.H:62
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
const word & name() const
Return name.
A surface geometry mesh, in which the surface zone information is conveyed by the &#39;zoneId&#39; associated...
Definition: MeshedSurface.H:74
Provide a means of reading/writing STL files (ASCII and binary).
error FatalError
A class for handling file names.
Definition: fileName.H:69
A surface geometry mesh with zone information, not to be confused with the similarly named surfaceMes...
Definition: MeshedSurface.H:72
const List< label > & faceMap() const
Const access to the faceMap, zero-sized when unused.
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
bool read(const char *, int32_t &)
Definition: int32IO.C:87
static void writeAscii(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy (as ASCII)
bool sorted() const
File read was already sorted.
UEqn clear()
pointField & points()
Return full access to the points.
surfZoneList sortedZones(labelList &faceMap) const
Sort faces according to zoneIds.
const Field< point > & points() const
Return reference to global points.