initial commit for version 1.6.x patch release
[OpenFOAM-1.6.x.git] / src / surfMesh / surfaceFormats / obj / OBJsurfaceFormat.C
blobdf10f47d43d51c3e6074e92d66bccfc8131da177
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 "OBJsurfaceFormat.H"
28 #include "clock.H"
29 #include "IFstream.H"
30 #include "IStringStream.H"
31 #include "Ostream.H"
32 #include "OFstream.H"
33 #include "ListOps.H"
35 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
37 template<class Face>
38 Foam::fileFormats::OBJsurfaceFormat<Face>::OBJsurfaceFormat
40     const fileName& filename
43     read(filename);
47 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
49 template<class Face>
50 bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
52     const fileName& filename
55     const bool mustTriangulate = this->isTri();
56     this->clear();
58     IFstream is(filename);
59     if (!is.good())
60     {
61         FatalErrorIn
62         (
63             "fileFormats::OBJsurfaceFormat::read(const fileName&)"
64         )
65             << "Cannot read file " << filename
66             << exit(FatalError);
67     }
69     // assume that the groups are not intermixed
70     bool sorted = true;
72     DynamicList<point> dynPoints;
73     DynamicList<Face>  dynFaces;
74     DynamicList<label> dynZones;
75     DynamicList<word>  dynNames;
76     DynamicList<label> dynSizes;
77     HashTable<label>   lookup;
79     // place faces without a group in zone0
80     label zoneI = 0;
81     lookup.insert("zone0", zoneI);
82     dynNames.append("zone0");
83     dynSizes.append(0);
85     while (is.good())
86     {
87         string line = this->getLineNoComment(is);
89         // handle continuations
90         if (line[line.size()-1] == '\\')
91         {
92             line.substr(0, line.size()-1);
93             line += this->getLineNoComment(is);
94         }
96         // Read first word
97         IStringStream lineStream(line);
98         word cmd;
99         lineStream >> cmd;
101         if (cmd == "v")
102         {
103             scalar x, y, z;
104             lineStream >> x >> y >> z;
105             dynPoints.append(point(x, y, z));
106         }
107         else if (cmd == "g")
108         {
109             word name;
110             lineStream >> name;
112             HashTable<label>::const_iterator fnd = lookup.find(name);
113             if (fnd != lookup.end())
114             {
115                 if (zoneI != fnd())
116                 {
117                     // group appeared out of order
118                     sorted = false;
119                 }
120                 zoneI = fnd();
121             }
122             else
123             {
124                 zoneI = dynSizes.size();
125                 lookup.insert(name, zoneI);
126                 dynNames.append(name);
127                 dynSizes.append(0);
128             }
129         }
130         else if (cmd == "f")
131         {
132             DynamicList<label> dynVertices;
134             // Assume 'f' is followed by space.
135             string::size_type endNum = 1;
137             while (true)
138             {
139                 string::size_type startNum =
140                     line.find_first_not_of(' ', endNum);
142                 if (startNum == string::npos)
143                 {
144                     break;
145                 }
147                 endNum = line.find(' ', startNum);
149                 string vertexSpec;
150                 if (endNum != string::npos)
151                 {
152                     vertexSpec = line.substr(startNum, endNum-startNum);
153                 }
154                 else
155                 {
156                     vertexSpec = line.substr(startNum, line.size() - startNum);
157                 }
159                 string::size_type slashPos = vertexSpec.find('/');
161                 label vertI = 0;
162                 if (slashPos != string::npos)
163                 {
164                     IStringStream intStream(vertexSpec.substr(0, slashPos));
166                     intStream >> vertI;
167                 }
168                 else
169                 {
170                     IStringStream intStream(vertexSpec);
172                     intStream >> vertI;
173                 }
174                 dynVertices.append(vertI - 1);
175             }
176             dynVertices.shrink();
178             UList<label>& f = static_cast<UList<label>&>(dynVertices);
180             if (mustTriangulate && f.size() > 3)
181             {
182                 // simple face triangulation about f[0]
183                 // points may be incomplete
184                 for (label fp1 = 1; fp1 < f.size() - 1; fp1++)
185                 {
186                     label fp2 = f.fcIndex(fp1);
188                     dynFaces.append(triFace(f[0], f[fp1], f[fp2]));
189                     dynZones.append(zoneI);
190                     dynSizes[zoneI]++;
191                 }
192             }
193             else
194             {
195                 dynFaces.append(Face(f));
196                 dynZones.append(zoneI);
197                 dynSizes[zoneI]++;
198             }
199         }
200     }
203     // transfer to normal lists
204     this->storedPoints().transfer(dynPoints);
206     sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
208     // add zones, culling empty ones
209     this->addZones(dynSizes, dynNames, true);
210     return true;
214 template<class Face>
215 void Foam::fileFormats::OBJsurfaceFormat<Face>::write
217     const fileName& filename,
218     const MeshedSurfaceProxy<Face>& surf
221     const pointField& pointLst = surf.points();
222     const List<Face>&  faceLst = surf.faces();
223     const List<label>& faceMap = surf.faceMap();
225     // for no zones, suppress the group name
226     const List<surfZone>& zones =
227     (
228         surf.surfZones().size() > 1
229       ? surf.surfZones()
230       : oneZone(faceLst, "")
231     );
233     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
235     OFstream os(filename);
236     if (!os.good())
237     {
238         FatalErrorIn
239         (
240             "fileFormats::OBJsurfaceFormat::write"
241             "(const fileName&, const MeshedSurfaceProxy<Face>&)"
242         )
243             << "Cannot open file for writing " << filename
244             << exit(FatalError);
245     }
248     os  << "# Wavefront OBJ file written " << clock::dateTime().c_str() << nl
249         << "o " << os.name().lessExt().name() << nl
250         << nl
251         << "# points : " << pointLst.size() << nl
252         << "# faces  : " << faceLst.size() << nl
253         << "# zones  : " << zones.size() << nl;
255     // Print zone names as comment
256     forAll(zones, zoneI)
257     {
258         os  << "#   " << zoneI << "  " << zones[zoneI].name()
259             << "  (nFaces: " << zones[zoneI].size() << ")" << nl;
260     }
262     os  << nl
263         << "# <points count=\"" << pointLst.size() << "\">" << nl;
265     // Write vertex coords
266     forAll(pointLst, ptI)
267     {
268         const point& pt = pointLst[ptI];
270         os  << "v " << pt.x() << ' '  << pt.y() << ' '  << pt.z() << nl;
271     }
273     os  << "# </points>" << nl
274         << nl
275         << "# <faces count=\"" << faceLst.size() << "\">" << endl;
278     label faceIndex = 0;
279     forAll(zones, zoneI)
280     {
281         const surfZone& zone = zones[zoneI];
283         if (zone.name().size())
284         {
285             os << "g " << zone.name() << endl;
286         }
288         if (useFaceMap)
289         {
290             forAll(zone, localFaceI)
291             {
292                 const Face& f = faceLst[faceMap[faceIndex++]];
294                 os << 'f';
295                 forAll(f, fp)
296                 {
297                     os << ' ' << f[fp] + 1;
298                 }
299                 os << endl;
300             }
301         }
302         else
303         {
304             forAll(zone, localFaceI)
305             {
306                 const Face& f = faceLst[faceIndex++];
308                 os << 'f';
309                 forAll(f, fp)
310                 {
311                     os << ' ' << f[fp] + 1;
312                 }
313                 os << endl;
314             }
315         }
316     }
317     os << "# </faces>" << endl;
321 // ************************************************************************* //