FreeFOAM The Cross-Platform CFD Toolkit
OBJsurfaceFormat.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 "OBJsurfaceFormat.H"
27 #include <OpenFOAM/clock.H>
28 #include <OpenFOAM/IFstream.H>
29 #include <OpenFOAM/IStringStream.H>
30 #include <OpenFOAM/Ostream.H>
31 #include <OpenFOAM/OFstream.H>
32 #include <OpenFOAM/ListOps.H>
33 
34 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
35 
36 template<class Face>
38 (
39  const fileName& filename
40 )
41 {
42  read(filename);
43 }
44 
45 
46 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
47 
48 template<class Face>
50 (
51  const fileName& filename
52 )
53 {
54  const bool mustTriangulate = this->isTri();
55  this->clear();
56 
57  IFstream is(filename);
58  if (!is.good())
59  {
61  (
62  "fileFormats::OBJsurfaceFormat::read(const fileName&)"
63  )
64  << "Cannot read file " << filename
65  << exit(FatalError);
66  }
67 
68  // assume that the groups are not intermixed
69  bool sorted = true;
70 
71  DynamicList<point> dynPoints;
72  DynamicList<Face> dynFaces;
73  DynamicList<label> dynZones;
74  DynamicList<word> dynNames;
75  DynamicList<label> dynSizes;
76  HashTable<label> lookup;
77 
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);
83 
84  while (is.good())
85  {
86  string line = this->getLineNoComment(is);
87 
88  // handle continuations
89  if (line[line.size()-1] == '\\')
90  {
91  line.substr(0, line.size()-1);
92  line += this->getLineNoComment(is);
93  }
94 
95  // Read first word
96  IStringStream lineStream(line);
97  word cmd;
98  lineStream >> cmd;
99 
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;
110 
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  DynamicList<label> dynVertices;
132 
133  // Assume 'f' is followed by space.
134  string::size_type endNum = 1;
135 
136  while (true)
137  {
138  string::size_type startNum =
139  line.find_first_not_of(' ', endNum);
140 
141  if (startNum == string::npos)
142  {
143  break;
144  }
145 
146  endNum = line.find(' ', startNum);
147 
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  }
157 
158  string::size_type slashPos = vertexSpec.find('/');
159 
160  label vertI = 0;
161  if (slashPos != string::npos)
162  {
163  IStringStream intStream(vertexSpec.substr(0, slashPos));
164 
165  intStream >> vertI;
166  }
167  else
168  {
169  IStringStream intStream(vertexSpec);
170 
171  intStream >> vertI;
172  }
173  dynVertices.append(vertI - 1);
174  }
175  dynVertices.shrink();
176 
177  UList<label>& f = static_cast<UList<label>&>(dynVertices);
178 
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);
186 
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  }
200 
201 
202  // transfer to normal lists
203  this->storedPoints().transfer(dynPoints);
204 
205  sortFacesAndStore(dynFaces.xfer(), dynZones.xfer(), sorted);
206 
207  // add zones, culling empty ones
208  this->addZones(dynSizes, dynNames, true);
209  return true;
210 }
211 
212 
213 template<class Face>
215 (
216  const fileName& filename,
217  const MeshedSurfaceProxy<Face>& surf
218 )
219 {
220  const pointField& pointLst = surf.points();
221  const List<Face>& faceLst = surf.faces();
222  const List<label>& faceMap = surf.faceMap();
223 
224  // for no zones, suppress the group name
225  const List<surfZone>& zones =
226  (
227  surf.surfZones().size() > 1
228  ? surf.surfZones()
229  : oneZone(faceLst, "")
230  );
231 
232  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
233 
234  OFstream os(filename);
235  if (!os.good())
236  {
238  (
239  "fileFormats::OBJsurfaceFormat::write"
240  "(const fileName&, const MeshedSurfaceProxy<Face>&)"
241  )
242  << "Cannot open file for writing " << filename
243  << exit(FatalError);
244  }
245 
246 
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;
253 
254  // Print zone names as comment
255  forAll(zones, zoneI)
256  {
257  os << "# " << zoneI << " " << zones[zoneI].name()
258  << " (nFaces: " << zones[zoneI].size() << ")" << nl;
259  }
260 
261  os << nl
262  << "# <points count=\"" << pointLst.size() << "\">" << nl;
263 
264  // Write vertex coords
265  forAll(pointLst, ptI)
266  {
267  const point& pt = pointLst[ptI];
268 
269  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
270  }
271 
272  os << "# </points>" << nl
273  << nl
274  << "# <faces count=\"" << faceLst.size() << "\">" << endl;
275 
276 
277  label faceIndex = 0;
278  forAll(zones, zoneI)
279  {
280  const surfZone& zone = zones[zoneI];
281 
282  if (zone.name().size())
283  {
284  os << "g " << zone.name() << endl;
285  }
286 
287  if (useFaceMap)
288  {
289  forAll(zone, localFaceI)
290  {
291  const Face& f = faceLst[faceMap[faceIndex++]];
292 
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++];
306 
307  os << 'f';
308  forAll(f, fp)
309  {
310  os << ' ' << f[fp] + 1;
311  }
312  os << endl;
313  }
314  }
315  }
316  os << "# </faces>" << endl;
317 }
318 
319 
320 // ************************ vim: set sw=4 sts=4 et: ************************ //