initial commit for version 1.6.x patch release
[OpenFOAM-1.6.x.git] / src / surfMesh / surfaceFormats / ac3d / AC3DsurfaceFormat.C
blobf7c63278f5868291ac1be28610b0b4b4eb3228fd
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
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 the
13     Free Software Foundation; either version 2 of the License, or (at your
14     option) any later version.
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.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "AC3DsurfaceFormat.H"
28 #include "clock.H"
29 #include "IStringStream.H"
30 #include "tensor.H"
31 #include "primitivePatch.H"
33 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
35 template<class Face>
36 Foam::fileFormats::AC3DsurfaceFormat<Face>::AC3DsurfaceFormat
38     const fileName& filename
41     read(filename);
45 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
47 template<class Face>
48 bool Foam::fileFormats::AC3DsurfaceFormat<Face>::read
50     const fileName& filename
53     const bool mustTriangulate = this->isTri();
54     this->clear();
56     IFstream is(filename);
57     if (!is.good())
58     {
59         FatalErrorIn
60         (
61             "fileFormats::AC3DsurfaceFormat::read(const fileName&)"
62         )
63             << "Cannot read file " << filename
64             << exit(FatalError);
65     }
67     string line, cmd, args;
69     is.getLine(line);
71     string version = line.substr(4);
73     if (version != "b")
74     {
75         WarningIn
76         (
77             "fileFormats::AC3DsurfaceFormat::read(const fileName&)"
78         )
79             << "When reading AC3D file " << filename
80             << " read header " << line << " with version "
81             << version << endl
82             << "Only tested reading with version 'b'."
83             << " This might give problems" << endl;
84     }
87     if (!cueTo(is, "OBJECT", args) || (args != "world"))
88     {
89         FatalErrorIn
90         (
91             "fileFormats::AC3DsurfaceFormat::read(const fileName&)"
92         )
93             << "Cannot find \"OBJECT world\" in file " << filename
94             << exit(FatalError);
95     }
97     // # of kids is the # of zones
98     args = cueToOrDie(is, "kids");
99     label nZones = parse<int>(args);
101     // Start of vertices for object/zones
102     label vertexOffset = 0;
104     DynamicList<point> dynPoints;
105     DynamicList<Face>  dynFaces;
106     List<word>         names(nZones);
107     List<label>        sizes(nZones, 0);
109     for (label zoneI = 0; zoneI < nZones; ++zoneI)
110     {
111         names[zoneI] = word("zone") + Foam::name(zoneI);
113         args = cueToOrDie(is, "OBJECT", "while reading " + names[zoneI]);
115         // number of vertices for this zone
116         label  nZonePoints = 0;
117         vector location(pTraits<vector>::zero);
118         // tensor rotation(I);
120         // Read all info for current zone
121         while (is.good())
122         {
123             // Read line and get first word. If end of file break since
124             // zone should always end with 'kids' command ?not sure.
125             if (!readCmd(is, cmd, args))
126             {
127                 FatalErrorIn
128                 (
129                     "fileFormats::AC3DsurfaceFormat::read(const fileName&)"
130                 )
131                     << "Did not read up to \"kids 0\" while reading zone "
132                     << zoneI << " from file " << filename
133                     << exit(FatalError);
134             }
136             if (cmd == "name")
137             {
138                 // name %s
139                 string str = parse<string>(args);
140                 string::stripInvalid<word>(str);
142                 names[zoneI] = str;
143             }
144             else if (cmd == "rot")
145             {
146                 // rot  %f %f %f  %f %f %f  %f %f %f
148                 // IStringStream lineStream(args);
149                 //
150                 // lineStream
151                 //     >> rotation.xx() >> rotation.xy() >> rotation.xz()
152                 //     >> rotation.yx() >> rotation.yy() >> rotation.yz()
153                 //     >> rotation.zx() >> rotation.zy() >> rotation.zz();
155                 WarningIn
156                 (
157                     "fileFormats::AC3DsurfaceFormat::read"
158                     "(const fileName&)"
159                 )
160                     << "rot (rotation tensor) command not implemented"
161                     << "Line:" << cmd << ' ' << args << endl
162                     << "while reading zone " << zoneI << endl;
163             }
164             else if (cmd == "loc")
165             {
166                 // loc  %f %f %f
167                 IStringStream lineStream(args);
169                 lineStream
170                     >> location.x()
171                     >> location.y()
172                     >> location.z();
173             }
174             else if (cmd == "numvert")
175             {
176                 // numvert  %d
177                 nZonePoints = parse<int>(args);
179                 for (label vertI = 0; vertI < nZonePoints; ++vertI)
180                 {
181                     is.getLine(line);
182                     IStringStream lineStream(line);
184                     point pt;
185                     lineStream
186                         >> pt.x() >> pt.y() >> pt.z();
188                     // Offset with current translation vector
189                     dynPoints.append(location + pt);
190                 }
191             }
192             else if (cmd == "numsurf")
193             {
194                 label nFaces = parse<int>(args);
196                 for (label faceI = 0; faceI < nFaces; ++faceI)
197                 {
198                     static string errorMsg =
199                         string(" while reading face ")
200                             + Foam::name(faceI) + " on zone "
201                             + Foam::name(zoneI)
202                             + " from file " + filename;
204                     cueToOrDie(is, "SURF", errorMsg);
205                     cueToOrDie(is, "mat", errorMsg);
206                     args = cueToOrDie(is, "refs", errorMsg);
208                     label nVert = parse<int>(args);
210                     List<label> verts(nVert);
211                     forAll(verts, vertI)
212                     {
213                         is.getLine(line);
214                         verts[vertI] = parse<int>(line) + vertexOffset;
215                     }
217                     UList<label>& f = static_cast<UList<label>&>(verts);
219                     if (mustTriangulate && f.size() > 3)
220                     {
221                         // simple face triangulation about f[0]
222                         // points may be incomplete
223                         for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
224                         {
225                             label fp2 = f.fcIndex(fp1);
227                             dynFaces.append(triFace(f[0], f[fp1], f[fp2]));
228                             sizes[zoneI]++;
229                         }
230                     }
231                     else
232                     {
233                         dynFaces.append(Face(f));
234                         sizes[zoneI]++;
235                     }
236                 }
238                 // Done the current zone.
239                 // Increment the offset vertices are stored at
240                 vertexOffset += nZonePoints;
241             }
242             else if (cmd == "kids")
243             {
244                 // 'kids' denotes the end of the current zone.
245                 label nKids = parse<int>(args);
247                 if (nKids != 0)
248                 {
249                     FatalErrorIn
250                     (
251                         "fileFormats::AC3DsurfaceFormat::read(const fileName&)"
252                     )
253                         << "Can only read objects without kids."
254                         << " Encountered " << nKids << " kids when"
255                         << " reading zone " << zoneI
256                         << exit(FatalError);
257                 }
259                 // Done reading current zone
260                 break;
261             }
262         }
263     }
265     // transfer to normal lists
266     this->storedPoints().transfer(dynPoints);
267     this->storedFaces().transfer(dynFaces);
269     // add zones, culling empty ones
270     this->addZones(sizes, names, true);
271     this->stitchFaces(SMALL);
272     return true;
276 template<class Face>
277 void Foam::fileFormats::AC3DsurfaceFormat<Face>::write
279     const fileName& filename,
280     const MeshedSurfaceProxy<Face>& surf
283     const pointField& pointLst = surf.points();
284     const List<Face>&  faceLst = surf.faces();
286     const List<surfZone>& zones =
287     (
288         surf.surfZones().size()
289       ? surf.surfZones()
290       : oneZone(faceLst)
291     );
293     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
295     if (useFaceMap)
296     {
297         FatalErrorIn
298         (
299             "fileFormats::AC3DsurfaceFormat::write"
300             "(const fileName&, const MeshedSurfaceProxy<Face>&)"
301         )
302             << "output with faceMap is not supported " << filename
303             << exit(FatalError);
304     }
307     OFstream os(filename);
308     if (!os.good())
309     {
310         FatalErrorIn
311         (
312             "fileFormats::AC3DsurfaceFormat::write"
313             "(const fileName&, const MeshedSurfaceProxy<Face>&)"
314         )
315             << "Cannot open file for writing " << filename
316             << exit(FatalError);
317     }
319     writeHeader(os, zones);
321     forAll(zones, zoneI)
322     {
323         const surfZone& zone = zones[zoneI];
325         os  << "OBJECT poly" << nl
326             << "name \"" << zone.name() << "\"\n";
328         // Temporary PrimitivePatch to calculate compact points & faces
329         // use 'UList' to avoid allocations!
330         PrimitivePatch<Face, UList, const pointField&> patch
331         (
332             SubList<Face>
333             (
334                 faceLst,
335                 zone.size(),
336                 zone.start()
337             ),
338             pointLst
339         );
341         os << "numvert " << patch.nPoints() << endl;
343         forAll(patch.localPoints(), ptI)
344         {
345             const point& pt = patch.localPoints()[ptI];
347             os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
348         }
350         os << "numsurf " << patch.localFaces().size() << endl;
352         forAll(patch.localFaces(), localFaceI)
353         {
354             const Face& f = patch.localFaces()[localFaceI];
356             os  << "SURF 0x20" << nl          // polygon
357                 << "mat " << zoneI << nl
358                 << "refs " << f.size() << nl;
360             forAll(f, fp)
361             {
362                 os << f[fp] << " 0 0" << nl;
363             }
364         }
366         os << "kids 0" << endl;
367     }
371 template<class Face>
372 void Foam::fileFormats::AC3DsurfaceFormat<Face>::write
374     const fileName& filename,
375     const UnsortedMeshedSurface<Face>& surf
378     labelList faceMap;
379     List<surfZone> zoneLst = surf.sortedZones(faceMap);
381     if (zoneLst.size() <= 1)
382     {
383         write
384         (
385             filename,
386             MeshedSurfaceProxy<Face>
387             (
388                 surf.points(),
389                 surf.faces(),
390                 zoneLst
391             )
392         );
393     }
394     else
395     {
396         OFstream os(filename);
397         if (!os.good())
398         {
399             FatalErrorIn
400             (
401                 "fileFormats::AC3DsurfaceFormat::write"
402                 "(const fileName&, const MeshedSurfaceProxy<Face>&)"
403             )
404                 << "Cannot open file for writing " << filename
405                 << exit(FatalError);
406         }
408         writeHeader(os, zoneLst);
410         label faceIndex = 0;
411         forAll(zoneLst, zoneI)
412         {
413             const surfZone& zone = zoneLst[zoneI];
415             os  << "OBJECT poly" << nl
416                 << "name \"" << zone.name() << "\"\n";
418             // Create zone with only zone faces included for ease of addressing
419             labelHashSet include(surf.size());
421             forAll(zone, localFaceI)
422             {
423                 const label faceI = faceMap[faceIndex++];
424                 include.insert(faceI);
425             }
427             UnsortedMeshedSurface<Face> subm = surf.subsetMesh(include);
429             // Now we have isolated surface for this patch alone. Write it.
430             os << "numvert " << subm.nPoints() << endl;
432             forAll(subm.localPoints(), ptI)
433             {
434                 const point& pt = subm.localPoints()[ptI];
436                 os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
437             }
439             os << "numsurf " << subm.localFaces().size() << endl;
441             forAll(subm.localFaces(), localFaceI)
442             {
443                 const Face& f = subm.localFaces()[localFaceI];
445                 os  << "SURF 0x20" << nl          // polygon
446                     << "mat " << zoneI << nl
447                     << "refs " << f.size() << nl;
449                 forAll(f, fp)
450                 {
451                     os << f[fp] << " 0 0" << nl;
452                 }
453             }
455             os << "kids 0" << endl;
456         }
457     }
461 // ************************************************************************* //