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) 2011 OpenFOAM Foundation
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 "clock.H"
28 #include "IFstream.H"
29 #include "IStringStream.H"
30 #include "Ostream.H"
31 #include "OFstream.H"
32 #include "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;
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  labelUList& f = static_cast<labelUList&>(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  this->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().empty()
228  ? surfaceFormatsCore::oneZone(faceLst, "")
229  : surf.surfZones()
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 // ************************************************************************* //
Input from memory buffer stream.
Definition: IStringStream.H:49
Output to file stream.
Definition: OFstream.H:81
void transfer(List< T > &)
Transfer contents of the argument List into this.
Definition: DynamicListI.H:277
word name() const
Return file name (part beyond last /)
Definition: fileName.C:206
vector point
Point is a vector.
Definition: point.H:41
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
bool useFaceMap() const
Use faceMap?
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
labelList f(nPoints)
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats...
Definition: MeshedSurface.H:73
A class for handling words, derived from string.
Definition: word.H:59
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:310
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
Various functions to operate on Lists.
face triFace(3)
const pointField & points() const
Return const access to the points.
Input from file stream.
Definition: IFstream.H:81
A line primitive.
Definition: line.H:56
const List< Face > & faces() const
Return const access to the faces.
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
static const char nl
Definition: Ostream.H:260
const Cmpt & y() const
Definition: VectorI.H:71
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
stressControl lookup("compactNormalStress") >> compactNormalStress
Base class for zones.
Definition: zone.H:57
const List< surfZone > & surfZones() const
Const access to the surface zones.
Xfer< List< T > > xfer()
Transfer contents to the Xfer container as a plain List.
Definition: DynamicListI.H:301
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:118
#define forAll(list, i)
Definition: UList.H:421
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:258
const Cmpt & x() const
Definition: VectorI.H:65
label size() const
Return the number of elements in the UList.
Definition: UListI.H:299
const Cmpt & z() const
Definition: VectorI.H:77
A surface zone on a MeshedSurface.
Definition: surfZone.H:62
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
const word & name() const
Return name.
Provide a means of reading/writing Alias/Wavefront OBJ format.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
error FatalError
scalar y
A class for handling file names.
Definition: fileName.H:69
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
virtual bool read(const fileName &)
Read from file.
const List< label > & faceMap() const
Const access to the faceMap, zero-sized when unused.
fileName lessExt() const
Return file name without extension (part before last .)
Definition: fileName.C:307
bool read(const char *, int32_t &)
Definition: int32IO.C:87
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:106
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:139
UEqn clear()
static void write(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy.