AC3DsurfaceFormat.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 "AC3DsurfaceFormat.H"
27 #include "clock.H"
28 #include "IStringStream.H"
29 #include "tensor.H"
30 #include "primitivePatch.H"
31 
32 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
33 
34 template<class Face>
36 (
37  const fileName& filename
38 )
39 {
40  read(filename);
41 }
42 
43 
44 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
45 
46 template<class Face>
48 (
49  const fileName& filename
50 )
51 {
52  const bool mustTriangulate = this->isTri();
53  this->clear();
54 
55  IFstream is(filename);
56  if (!is.good())
57  {
59  << "Cannot read file " << filename
60  << exit(FatalError);
61  }
62 
63  string line, cmd, args;
64 
65  is.getLine(line);
66 
67  string version = line.substr(4);
68 
69  if (version != "b")
70  {
72  << "When reading AC3D file " << filename
73  << " read header " << line << " with version "
74  << version << endl
75  << "Only tested reading with version 'b'."
76  << " This might give problems" << endl;
77  }
78 
79 
80  if (!cueTo(is, "OBJECT", args) || (args != "world"))
81  {
83  << "Cannot find \"OBJECT world\" in file " << filename
84  << exit(FatalError);
85  }
86 
87  // # of kids is the # of zones
88  args = cueToOrDie(is, "kids");
89  label nZones = parse<int>(args);
90 
91  // Start of vertices for object/zones
92  label vertexOffset = 0;
93 
94  DynamicList<point> dynPoints;
95  DynamicList<Face> dynFaces;
96  List<word> names(nZones);
97  List<label> sizes(nZones, 0);
98 
99  for (label zoneI = 0; zoneI < nZones; ++zoneI)
100  {
101  names[zoneI] = word("zone") + Foam::name(zoneI);
102 
103  args = cueToOrDie(is, "OBJECT", "while reading " + names[zoneI]);
104 
105  // number of vertices for this zone
106  label nZonePoints = 0;
107  vector location(Zero);
108  // tensor rotation(I);
109 
110  // Read all info for current zone
111  while (is.good())
112  {
113  // Read line and get first word. If end of file break since
114  // zone should always end with 'kids' command ?not sure.
115  if (!readCmd(is, cmd, args))
116  {
118  << "Did not read up to \"kids 0\" while reading zone "
119  << zoneI << " from file " << filename
120  << exit(FatalError);
121  }
122 
123  if (cmd == "name")
124  {
125  // name %s
126  string str = parse<string>(args);
127  string::stripInvalid<word>(str);
128 
129  names[zoneI] = str;
130  }
131  else if (cmd == "rot")
132  {
133  // rot %f %f %f %f %f %f %f %f %f
134 
135  // IStringStream lineStream(args);
136  //
137  // lineStream
138  // >> rotation.xx() >> rotation.xy() >> rotation.xz()
139  // >> rotation.yx() >> rotation.yy() >> rotation.yz()
140  // >> rotation.zx() >> rotation.zy() >> rotation.zz();
141 
143  << "rot (rotation tensor) command not implemented"
144  << "Line:" << cmd << ' ' << args << endl
145  << "while reading zone " << zoneI << endl;
146  }
147  else if (cmd == "loc")
148  {
149  // loc %f %f %f
150  IStringStream lineStream(args);
151 
152  lineStream
153  >> location.x()
154  >> location.y()
155  >> location.z();
156  }
157  else if (cmd == "numvert")
158  {
159  // numvert %d
160  nZonePoints = parse<int>(args);
161 
162  for (label vertI = 0; vertI < nZonePoints; ++vertI)
163  {
164  is.getLine(line);
165  IStringStream lineStream(line);
166 
167  point pt;
168  lineStream
169  >> pt.x() >> pt.y() >> pt.z();
170 
171  // Offset with current translation vector
172  dynPoints.append(location + pt);
173  }
174  }
175  else if (cmd == "numsurf")
176  {
177  label nFaces = parse<int>(args);
178 
179  for (label facei = 0; facei < nFaces; ++facei)
180  {
181  static string errorMsg =
182  string(" while reading face ")
183  + Foam::name(facei) + " on zone "
184  + Foam::name(zoneI)
185  + " from file " + filename;
186 
187  cueToOrDie(is, "SURF", errorMsg);
188  cueToOrDie(is, "mat", errorMsg);
189  args = cueToOrDie(is, "refs", errorMsg);
190 
191  label nVert = parse<int>(args);
192 
193  List<label> verts(nVert);
194  forAll(verts, vertI)
195  {
196  is.getLine(line);
197  verts[vertI] = parse<int>(line) + vertexOffset;
198  }
199 
200  labelUList& f = static_cast<labelUList&>(verts);
201 
202  if (mustTriangulate && f.size() > 3)
203  {
204  // simple face triangulation about f[0]
205  // points may be incomplete
206  for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
207  {
208  label fp2 = f.fcIndex(fp1);
209 
210  dynFaces.append(triFace(f[0], f[fp1], f[fp2]));
211  sizes[zoneI]++;
212  }
213  }
214  else
215  {
216  dynFaces.append(Face(f));
217  sizes[zoneI]++;
218  }
219  }
220 
221  // Done the current zone.
222  // Increment the offset vertices are stored at
223  vertexOffset += nZonePoints;
224  }
225  else if (cmd == "kids")
226  {
227  // 'kids' denotes the end of the current zone.
228  label nKids = parse<int>(args);
229 
230  if (nKids != 0)
231  {
233  << "Can only read objects without kids."
234  << " Encountered " << nKids << " kids when"
235  << " reading zone " << zoneI
236  << exit(FatalError);
237  }
238 
239  // Done reading current zone
240  break;
241  }
242  }
243  }
244 
245  // transfer to normal lists
246  this->storedPoints().transfer(dynPoints);
247  this->storedFaces().transfer(dynFaces);
248 
249  // add zones, culling empty ones
250  this->addZones(sizes, names, true);
251  this->stitchFaces(small);
252  return true;
253 }
254 
255 
256 template<class Face>
258 (
259  const fileName& filename,
260  const MeshedSurfaceProxy<Face>& surf
261 )
262 {
263  const pointField& pointLst = surf.points();
264  const List<Face>& faceLst = surf.faces();
265 
266  const List<surfZone>& zones =
267  (
268  surf.surfZones().size()
269  ? surf.surfZones()
270  : surfaceFormatsCore::oneZone(faceLst)
271  );
272 
273  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
274 
275  if (useFaceMap)
276  {
278  << "output with faceMap is not supported " << filename
279  << exit(FatalError);
280  }
281 
282 
283  OFstream os(filename);
284  if (!os.good())
285  {
287  << "Cannot open file for writing " << filename
288  << exit(FatalError);
289  }
290 
291  writeHeader(os, zones);
292 
293  forAll(zones, zoneI)
294  {
295  const surfZone& zone = zones[zoneI];
296 
297  os << "OBJECT poly" << nl
298  << "name \"" << zone.name() << "\"\n";
299 
300  // Temporary PrimitivePatch to calculate compact points & faces
301  // use 'UList' to avoid allocations!
303  (
305  (
306  faceLst,
307  zone.size(),
308  zone.start()
309  ),
310  pointLst
311  );
312 
313  os << "numvert " << patch.nPoints() << endl;
314 
315  forAll(patch.localPoints(), ptI)
316  {
317  const point& pt = patch.localPoints()[ptI];
318 
319  os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
320  }
321 
322  os << "numsurf " << patch.localFaces().size() << endl;
323 
324  forAll(patch.localFaces(), localFacei)
325  {
326  const Face& f = patch.localFaces()[localFacei];
327 
328  os << "SURF 0x20" << nl // polygon
329  << "mat " << zoneI << nl
330  << "refs " << f.size() << nl;
331 
332  forAll(f, fp)
333  {
334  os << f[fp] << " 0 0" << nl;
335  }
336  }
337 
338  os << "kids 0" << endl;
339  }
340 }
341 
342 
343 template<class Face>
345 (
346  const fileName& filename,
347  const UnsortedMeshedSurface<Face>& surf
348 )
349 {
351  List<surfZone> zoneLst = surf.sortedZones(faceMap);
352 
353  if (zoneLst.size() <= 1)
354  {
355  write
356  (
357  filename,
359  (
360  surf.points(),
361  surf.faces(),
362  zoneLst
363  )
364  );
365  }
366  else
367  {
368  OFstream os(filename);
369  if (!os.good())
370  {
372  << "Cannot open file for writing " << filename
373  << exit(FatalError);
374  }
375 
376  writeHeader(os, zoneLst);
377 
378  label faceIndex = 0;
379  forAll(zoneLst, zoneI)
380  {
381  const surfZone& zone = zoneLst[zoneI];
382 
383  os << "OBJECT poly" << nl
384  << "name \"" << zone.name() << "\"\n";
385 
386  // Create zone with only zone faces included for ease of addressing
387  labelHashSet include(surf.size());
388 
389  forAll(zone, localFacei)
390  {
391  const label facei = faceMap[faceIndex++];
392  include.insert(facei);
393  }
394 
395  UnsortedMeshedSurface<Face> subm = surf.subsetMesh(include);
396 
397  // Now we have isolated surface for this patch alone. Write it.
398  os << "numvert " << subm.nPoints() << endl;
399 
400  forAll(subm.localPoints(), ptI)
401  {
402  const point& pt = subm.localPoints()[ptI];
403 
404  os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
405  }
406 
407  os << "numsurf " << subm.localFaces().size() << endl;
408 
409  forAll(subm.localFaces(), localFacei)
410  {
411  const Face& f = subm.localFaces()[localFacei];
412 
413  os << "SURF 0x20" << nl // polygon
414  << "mat " << zoneI << nl
415  << "refs " << f.size() << nl;
416 
417  forAll(f, fp)
418  {
419  os << f[fp] << " 0 0" << nl;
420  }
421  }
422 
423  os << "kids 0" << endl;
424  }
425  }
426 }
427 
428 
429 // ************************************************************************* //
A surface geometry mesh, in which the surface zone information is conveyed by the &#39;zoneId&#39; associated...
Definition: MeshedSurface.H:74
label nPoints() const
Return number of points supporting patch faces.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
tUEqn clear()
A line primitive.
Definition: line.H:56
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:306
const word & name() const
Return name.
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
label size() const
Return size of this zone in the face list.
Definition: surfZone.H:141
const Cmpt & z() const
Definition: VectorI.H:87
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:330
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
const Cmpt & y() const
Definition: VectorI.H:81
label size() const
The surface size is the number of faces.
A list of faces which address into the list of points.
bool useFaceMap() const
Use faceMap?
UnsortedMeshedSurface subsetMesh(const labelHashSet &include, labelList &pointMap, labelList &faceMap) const
Return new surface.
A List obtained as a section of another List.
Definition: SubList.H:53
void writeHeader(std::ostream &, const bool isBinary, const std::string &title)
Write header.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
Base class for zones.
Definition: zone.H:57
virtual bool read(const fileName &)
Read from file.
const List< Face > & faces() const
Return const access to the faces.
A class for handling words, derived from string.
Definition: word.H:59
static bool readCmd(IFstream &ACfile, string &cmd, string &args)
Definition: readAC.C:56
face triFace(3)
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
const Field< PointType > & points() const
Return reference to global points.
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
static const zero Zero
Definition: zero.H:97
const List< surfZone > & surfZones() const
Const access to the surface zones.
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
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
Input from file stream.
Definition: IFstream.H:81
labelList f(nPoints)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
const List< Face > & faces() const
Return const access to the faces.
surfZoneList sortedZones(labelList &faceMap) const
Sort faces according to zoneIds.
AC3DsurfaceFormat(const fileName &)
Construct from file name.
label start() const
Return start label of this zone in the face list.
Definition: surfZone.H:129
ISstream & getLine(string &, const bool continuation=true)
Read line into a string.
Definition: ISstream.C:692
#define WarningInFunction
Report a warning using Foam::Warning.
const pointField & points() const
Return const access to the points.
Input from memory buffer stream.
Definition: IStringStream.H:49
const List< FaceType > & localFaces() const
Return patch faces addressing into local point list.
Foam::argList args(argc, argv)
A class for handling character strings derived from std::string.
Definition: string.H:76
static void write(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy.