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