Merge branch 'master' of ssh://git.code.sf.net/p/foam-extend/foam-extend-3.2
[foam-extend-3.2.git] / src / surfMesh / surfaceFormats / obj / OBJsurfaceFormat.C
blob56e05688f37bdefd90f530fb12790c67e8886b2e
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend 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 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "OBJsurfaceFormat.H"
27 #include "clock.H"
28 #include "IFstream.H"
29 #include "IStringStream.H"
30 #include "Ostream.H"
31 #include "OFstream.H"
32 #include "ListOps.H"
34 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
36 template<class Face>
37 Foam::fileFormats::OBJsurfaceFormat<Face>::OBJsurfaceFormat
39     const fileName& filename
42     this->read(filename);
46 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
48 template<class Face>
49 bool Foam::fileFormats::OBJsurfaceFormat<Face>::read
51     const fileName& filename
54     const bool mustTriangulate = this->isTri();
55     this->clear();
57     IFstream is(filename);
58     if (!is.good())
59     {
60         FatalErrorIn
61         (
62             "fileFormats::OBJsurfaceFormat::read(const fileName&)"
63         )
64             << "Cannot read file " << filename
65             << exit(FatalError);
66     }
68     // assume that the groups are not intermixed
69     bool sorted = true;
71     DynamicList<point> dynPoints;
72     DynamicList<Face>  dynFaces;
73     dynamicLabelList dynZones;
74     DynamicList<word>  dynNames;
75     dynamicLabelList dynSizes;
76     HashTable<label>   lookup;
78     // place faces without a group in zone0
79     label zoneI = 0;
80     lookup.insert("zone0", zoneI);
81     dynNames.append("zone0");
82     dynSizes.append(0);
84     while (is.good())
85     {
86         string line = this->getLineNoComment(is);
88         // handle continuations
89         if (line[line.size()-1] == '\\')
90         {
91             line.substr(0, line.size()-1);
92             line += this->getLineNoComment(is);
93         }
95         // Read first word
96         IStringStream lineStream(line);
97         word cmd;
98         lineStream >> cmd;
100         if (cmd == "v")
101         {
102             scalar x, y, z;
103             lineStream >> x >> y >> z;
104             dynPoints.append(point(x, y, z));
105         }
106         else if (cmd == "g")
107         {
108             word name;
109             lineStream >> name;
111             HashTable<label>::const_iterator fnd = lookup.find(name);
112             if (fnd != lookup.end())
113             {
114                 if (zoneI != fnd())
115                 {
116                     // group appeared out of order
117                     sorted = false;
118                 }
119                 zoneI = fnd();
120             }
121             else
122             {
123                 zoneI = dynSizes.size();
124                 lookup.insert(name, zoneI);
125                 dynNames.append(name);
126                 dynSizes.append(0);
127             }
128         }
129         else if (cmd == "f")
130         {
131             dynamicLabelList dynVertices;
133             // Assume 'f' is followed by space.
134             string::size_type endNum = 1;
136             while (true)
137             {
138                 string::size_type startNum =
139                     line.find_first_not_of(' ', endNum);
141                 if (startNum == string::npos)
142                 {
143                     break;
144                 }
146                 endNum = line.find(' ', startNum);
148                 string vertexSpec;
149                 if (endNum != string::npos)
150                 {
151                     vertexSpec = line.substr(startNum, endNum-startNum);
152                 }
153                 else
154                 {
155                     vertexSpec = line.substr(startNum, line.size() - startNum);
156                 }
158                 string::size_type slashPos = vertexSpec.find('/');
160                 label vertI = 0;
161                 if (slashPos != string::npos)
162                 {
163                     IStringStream intStream(vertexSpec.substr(0, slashPos));
165                     intStream >> vertI;
166                 }
167                 else
168                 {
169                     IStringStream intStream(vertexSpec);
171                     intStream >> vertI;
172                 }
173                 dynVertices.append(vertI - 1);
174             }
175             dynVertices.shrink();
177             UList<label>& f = static_cast<UList<label>&>(dynVertices);
179             if (mustTriangulate && f.size() > 3)
180             {
181                 // simple face triangulation about f[0]
182                 // points may be incomplete
183                 for (label fp1 = 1; fp1 < f.size() - 1; fp1++)
184                 {
185                     label fp2 = f.fcIndex(fp1);
187                     dynFaces.append(triFace(f[0], f[fp1], f[fp2]));
188                     dynZones.append(zoneI);
189                     dynSizes[zoneI]++;
190                 }
191             }
192             else
193             {
194                 dynFaces.append(Face(f));
195                 dynZones.append(zoneI);
196                 dynSizes[zoneI]++;
197             }
198         }
199     }
202     // transfer to normal lists
203     this->storedPoints().transfer(dynPoints);
205     this->sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
207     // add zones, culling empty ones
208     this->addZones(dynSizes, dynNames, true);
209     return true;
213 template<class Face>
214 void Foam::fileFormats::OBJsurfaceFormat<Face>::write
216     const fileName& filename,
217     const MeshedSurfaceProxy<Face>& surf
220     const pointField& pointLst = surf.points();
221     const List<Face>&  faceLst = surf.faces();
222     const List<label>& faceMap = surf.faceMap();
224     // for no zones, suppress the group name
225     const List<surfZone>& zones =
226     (
227         surf.surfZones().size() > 1
228       ? surf.surfZones()
229       : OBJsurfaceFormat::oneZone(faceLst, "")
230     );
232     const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
234     OFstream os(filename);
235     if (!os.good())
236     {
237         FatalErrorIn
238         (
239             "fileFormats::OBJsurfaceFormat::write"
240             "(const fileName&, const MeshedSurfaceProxy<Face>&)"
241         )
242             << "Cannot open file for writing " << filename
243             << exit(FatalError);
244     }
247     os  << "# Wavefront OBJ file written " << clock::dateTime().c_str() << nl
248         << "o " << os.name().lessExt().name() << nl
249         << nl
250         << "# points : " << pointLst.size() << nl
251         << "# faces  : " << faceLst.size() << nl
252         << "# zones  : " << zones.size() << nl;
254     // Print zone names as comment
255     forAll(zones, zoneI)
256     {
257         os  << "#   " << zoneI << "  " << zones[zoneI].name()
258             << "  (nFaces: " << zones[zoneI].size() << ")" << nl;
259     }
261     os  << nl
262         << "# <points count=\"" << pointLst.size() << "\">" << nl;
264     // Write vertex coords
265     forAll(pointLst, ptI)
266     {
267         const point& pt = pointLst[ptI];
269         os  << "v " << pt.x() << ' '  << pt.y() << ' '  << pt.z() << nl;
270     }
272     os  << "# </points>" << nl
273         << nl
274         << "# <faces count=\"" << faceLst.size() << "\">" << endl;
277     label faceIndex = 0;
278     forAll(zones, zoneI)
279     {
280         const surfZone& zone = zones[zoneI];
282         if (zone.name().size())
283         {
284             os << "g " << zone.name() << endl;
285         }
287         if (useFaceMap)
288         {
289             forAll(zone, localFaceI)
290             {
291                 const Face& f = faceLst[faceMap[faceIndex++]];
293                 os << 'f';
294                 forAll(f, fp)
295                 {
296                     os << ' ' << f[fp] + 1;
297                 }
298                 os << endl;
299             }
300         }
301         else
302         {
303             forAll(zone, localFaceI)
304             {
305                 const Face& f = faceLst[faceIndex++];
307                 os << 'f';
308                 forAll(f, fp)
309                 {
310                     os << ' ' << f[fp] + 1;
311                 }
312                 os << endl;
313             }
314         }
315     }
316     os << "# </faces>" << endl;
320 // ************************************************************************* //