FreeFOAM The Cross-Platform CFD Toolkit
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) 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 "AC3DsurfaceFormat.H"
27 #include <OpenFOAM/clock.H>
28 #include <OpenFOAM/IStringStream.H>
29 #include <OpenFOAM/tensor.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  UList<label>& f = static_cast<UList<label>&>(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  : 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 {
377  labelList faceMap;
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 // ************************ vim: set sw=4 sts=4 et: ************************ //