STLsurfaceFormat.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2019 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  const vector norm = triPointRef
42  (
43  pointLst[f[0]],
44  pointLst[f[1]],
45  pointLst[f[2]]
46  ).normal();
47 
48  // simple triangulation about f[0].
49  // better triangulation should have been done before
50  const point& p0 = pointLst[f[0]];
51  for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
52  {
53  label fp2 = f.fcIndex(fp1);
54 
55  const point& p1 = pointLst[f[fp1]];
56  const point& p2 = pointLst[f[fp2]];
57 
58  // write STL triangle
59  os << " facet normal "
60  << norm.x() << ' ' << norm.y() << ' ' << norm.z() << nl
61  << " outer loop\n"
62  << " vertex " << p0.x() << ' ' << p0.y() << ' ' << p0.z() << nl
63  << " vertex " << p1.x() << ' ' << p1.y() << ' ' << p1.z() << nl
64  << " vertex " << p2.x() << ' ' << p2.y() << ' ' << p2.z() << nl
65  << " endloop\n"
66  << " endfacet" << endl;
67  }
68 }
69 
70 
71 template<class Face>
73 (
74  ostream& os,
75  const pointField& pointLst,
76  const Face& f,
77  const label zoneI
78 )
79 {
80  // calculate the normal ourselves, for flexibility and speed
81  const vector norm = triPointRef
82  (
83  pointLst[f[0]],
84  pointLst[f[1]],
85  pointLst[f[2]]
86  ).normal();
87 
88  // simple triangulation about f[0].
89  // better triangulation should have been done before
90  const point& p0 = pointLst[f[0]];
91  for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
92  {
93  label fp2 = f.fcIndex(fp1);
94 
95  STLtriangle stlTri
96  (
97  norm,
98  p0,
99  pointLst[f[fp1]],
100  pointLst[f[fp2]],
101  zoneI
102  );
103 
104  stlTri.write(os);
105  }
106 }
107 
108 
109 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
110 
111 template<class Face>
113 (
114  const fileName& filename
115 )
116 {
117  read(filename);
118 }
119 
120 
121 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
122 
123 template<class Face>
125 (
126  const fileName& filename
127 )
128 {
129  this->clear();
130 
131  // read in the values
132  STLsurfaceFormatCore reader(filename);
133 
134  // transfer points
135  this->storedPoints().transfer(reader.points());
136 
137  // retrieve the original zone information
138  List<word> names(move(reader.names()));
139  List<label> sizes(move(reader.sizes()));
140  List<label> zoneIds(move(reader.zoneIds()));
141 
142  // generate the (sorted) faces
143  List<Face> faceLst(zoneIds.size());
144 
145  if (reader.sorted())
146  {
147  // already sorted - generate directly
148  forAll(faceLst, facei)
149  {
150  const label startPt = 3*facei;
151  faceLst[facei] = triFace(startPt, startPt+1, startPt+2);
152  }
153  }
154  else
155  {
156  // unsorted - determine the sorted order:
157  // avoid SortableList since we discard the main list anyhow
159  sortedOrder(zoneIds, faceMap);
160 
161  // generate sorted faces
162  forAll(faceMap, facei)
163  {
164  const label startPt = 3*faceMap[facei];
165  faceLst[facei] = triFace(startPt, startPt+1, startPt+2);
166  }
167  }
168  zoneIds.clear();
169 
170  // transfer:
171  this->storedFaces().transfer(faceLst);
172 
173  if (names.size())
174  {
175  this->addZones(sizes, names);
176  }
177  else
178  {
179  this->addZones(sizes);
180  }
181 
182  this->stitchFaces(small);
183  return true;
184 }
185 
186 
187 
188 template<class Face>
190 (
191  const fileName& filename,
192  const MeshedSurfaceProxy<Face>& surf
193 )
194 {
195  OFstream os(filename);
196  if (!os.good())
197  {
199  << "Cannot open file for writing " << filename
200  << exit(FatalError);
201  }
202 
203  const pointField& pointLst = surf.points();
204  const List<Face>& faceLst = surf.faces();
205  const List<label>& faceMap = surf.faceMap();
206 
207  const List<surfZone>& zones =
208  (
209  surf.surfZones().empty()
210  ? surfaceFormatsCore::oneZone(faceLst)
211  : surf.surfZones()
212  );
213 
214  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
215 
216  label faceIndex = 0;
217  forAll(zones, zoneI)
218  {
219  // Print all faces belonging to this zone
220  const surfZone& zone = zones[zoneI];
221 
222  os << "solid " << zone.name() << nl;
223 
224  if (useFaceMap)
225  {
226  forAll(zone, localFacei)
227  {
228  const label facei = faceMap[faceIndex++];
229  writeShell(os, pointLst, faceLst[facei]);
230  }
231  }
232  else
233  {
234  forAll(zone, localFacei)
235  {
236  writeShell(os, pointLst, faceLst[faceIndex++]);
237  }
238  }
239  os << "endsolid " << zone.name() << endl;
240  }
241 }
242 
243 
244 template<class Face>
246 (
247  const fileName& filename,
248  const MeshedSurfaceProxy<Face>& surf
249 )
250 {
251  std::ofstream os(filename.c_str(), std::ios::binary);
252  if (!os.good())
253  {
255  << "Cannot open file for writing " << filename
256  << exit(FatalError);
257  }
258 
259 
260  const pointField& pointLst = surf.points();
261  const List<Face>& faceLst = surf.faces();
262  const List<label>& faceMap = surf.faceMap();
263 
264  const List<surfZone>& zones =
265  (
266  surf.surfZones().size() > 1
267  ? surf.surfZones()
268  : surfaceFormatsCore::oneZone(faceLst)
269  );
270 
271  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
272 
273 
274  unsigned int nTris = 0;
276  {
277  nTris = faceLst.size();
278  }
279  else
280  {
281  // count triangles for on-the-fly triangulation
282  forAll(faceLst, facei)
283  {
284  nTris += faceLst[facei].size() - 2;
285  }
286  }
287 
288  // Write the STL header
289  STLsurfaceFormatCore::writeHeaderBINARY(os, nTris);
290 
291  label faceIndex = 0;
292  forAll(zones, zoneI)
293  {
294  const surfZone& zone = zones[zoneI];
295 
296  if (useFaceMap)
297  {
298  forAll(zone, localFacei)
299  {
300  writeShell
301  (
302  os,
303  pointLst,
304  faceLst[faceMap[faceIndex++]],
305  zoneI
306  );
307  }
308  }
309  else
310  {
311  forAll(zone, localFacei)
312  {
313  writeShell
314  (
315  os,
316  pointLst,
317  faceLst[faceIndex++],
318  zoneI
319  );
320  }
321  }
322  }
323 }
324 
325 
326 template<class Face>
328 (
329  const fileName& filename,
330  const UnsortedMeshedSurface<Face>& surf
331 )
332 {
333  OFstream os(filename);
334  if (!os.good())
335  {
337  << "Cannot open file for writing " << filename
338  << exit(FatalError);
339  }
340 
341  // a single zone - we can skip sorting
342  if (surf.zoneToc().size() == 1)
343  {
344  const pointField& pointLst = surf.points();
345  const List<Face>& faceLst = surf.faces();
346 
347  os << "solid " << surf.zoneToc()[0].name() << endl;
348  forAll(faceLst, facei)
349  {
350  writeShell(os, pointLst, faceLst[facei]);
351  }
352  os << "endsolid " << surf.zoneToc()[0].name() << endl;
353  }
354  else
355  {
357  List<surfZone> zoneLst = surf.sortedZones(faceMap);
358 
359  writeAscii
360  (
361  filename,
363  (
364  surf.points(),
365  surf.faces(),
366  zoneLst,
367  faceMap
368  )
369  );
370  }
371 }
372 
373 
374 template<class Face>
376 (
377  const fileName& filename,
378  const UnsortedMeshedSurface<Face>& surf
379 )
380 {
381  std::ofstream os(filename.c_str(), std::ios::binary);
382  if (!os.good())
383  {
385  << "Cannot open file for writing " << filename
386  << exit(FatalError);
387  }
388 
389  const pointField& pointLst = surf.points();
390  const List<Face>& faceLst = surf.faces();
391  const List<label>& zoneIds = surf.zoneIds();
392 
393  unsigned int nTris = 0;
395  {
396  nTris = faceLst.size();
397  }
398  else
399  {
400  // count triangles for on-the-fly triangulation
401  forAll(faceLst, facei)
402  {
403  nTris += faceLst[facei].size() - 2;
404  }
405  }
406 
407  // Write the STL header
408  STLsurfaceFormatCore::writeHeaderBINARY(os, nTris);
409 
410  // always write unsorted
411  forAll(faceLst, facei)
412  {
413  writeShell
414  (
415  os,
416  pointLst,
417  faceLst[facei],
418  zoneIds[facei]
419  );
420  }
421 }
422 
423 
424 template<class Face>
426 (
427  const fileName& filename,
428  const MeshedSurfaceProxy<Face>& surf
429 )
430 {
431  const word ext = filename.ext();
432 
433  // handle 'stlb' as binary directly
434  if (ext == "stlb")
435  {
436  writeBinary(filename, surf);
437  }
438  else
439  {
440  writeAscii(filename, surf);
441  }
442 }
443 
444 
445 template<class Face>
447 (
448  const fileName& filename,
449  const UnsortedMeshedSurface<Face>& surf
450 )
451 {
452  word ext = filename.ext();
453 
454  // handle 'stlb' as binary directly
455  if (ext == "stlb")
456  {
457  writeBinary(filename, surf);
458  }
459  else
460  {
461  writeAscii(filename, surf);
462  }
463 }
464 
465 
466 // ************************************************************************* //
A surface geometry mesh, in which the surface zone information is conveyed by the &#39;zoneId&#39; associated...
Definition: MeshedSurface.H:74
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
tUEqn clear()
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 sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
A class for handling file names.
Definition: fileName.H:79
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
Provide a means of reading/writing STL files (ASCII and binary).
const word & name() const
Return name.
A surface geometry mesh with zone information, not to be confused with the similarly named surfaceMes...
Definition: MeshedSurface.H:72
Output to file stream.
Definition: OFstream.H:82
A surface zone on a MeshedSurface.
Definition: surfZone.H:62
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
const List< label > & zoneIds() const
Return const access to the zone ids.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
static void write(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy.
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
List< label > & sizes()
The list of solid sizes in the order of their first appearance.
Internal class used by the STLsurfaceFormat.
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
word ext() const
Return file name extension (part after last .)
Definition: fileName.C:287
List< word > & names()
The list of solid names in the order of their first appearance.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Various functions to operate on Lists.
bool useFaceMap() const
Use faceMap?
static void writeAscii(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy (as ASCII)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
pointField & points()
Return full access to the points.
Base class for zones.
Definition: zone.H:57
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
const List< Face > & faces() const
Return const access to the faces.
A class for handling words, derived from string.
Definition: word.H:59
face triFace(3)
const Field< PointType > & points() const
Return reference to global points.
STLsurfaceFormat(const fileName &)
Construct from file name.
const List< surfZone > & surfZones() const
Const access to the surface zones.
const Cmpt & x() const
Definition: VectorI.H:75
static const char nl
Definition: Ostream.H:260
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats...
Definition: MeshedSurface.H:73
virtual bool read(const fileName &)
Read from file.
List< label > & zoneIds()
Return full access to the zoneIds.
static void writeBinary(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy (as BINARY)
bool sorted() const
File read was already sorted.
const List< Face > & faces() const
Return const access to the faces.
const List< surfZoneIdentifier > & zoneToc() const
Return const access to the zone table-of-contents.
surfZoneList sortedZones(labelList &faceMap) const
Sort faces according to zoneIds.
vector point
Point is a vector.
Definition: point.H:41
const pointField & points() const
Return const access to the points.
const List< label > & faceMap() const
Const access to the faceMap, zero-sized when unused.
triangle< point, const point & > triPointRef
Definition: triPointRef.H:44