OBJsurfaceFormat.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2019 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  << "Cannot read file " << filename
62  << exit(FatalError);
63  }
64 
65  // assume that the groups are not intermixed
66  bool sorted = true;
67 
68  DynamicList<point> dynPoints;
69  DynamicList<Face> dynFaces;
70  DynamicList<label> dynZones;
71  DynamicList<word> dynNames;
72  DynamicList<label> dynSizes;
74 
75  // place faces without a group in zone0
76  label zoneI = 0;
77  lookup.insert("zone0", zoneI);
78  dynNames.append("zone0");
79  dynSizes.append(0);
80 
81  while (is.good())
82  {
83  string line = this->getLineNoComment(is);
84 
85  // handle continuations
86  if (line[line.size()-1] == '\\')
87  {
88  line.substr(0, line.size()-1);
89  line += this->getLineNoComment(is);
90  }
91 
92  // Read first word
93  IStringStream lineStream(line);
94  word cmd;
95  lineStream >> cmd;
96 
97  if (cmd == "v")
98  {
99  scalar x, y, z;
100  lineStream >> x >> y >> z;
101  dynPoints.append(point(x, y, z));
102  }
103  else if (cmd == "g")
104  {
105  word name;
106  lineStream >> name;
107 
108  HashTable<label>::const_iterator fnd = lookup.find(name);
109  if (fnd != lookup.end())
110  {
111  if (zoneI != fnd())
112  {
113  // group appeared out of order
114  sorted = false;
115  }
116  zoneI = fnd();
117  }
118  else
119  {
120  zoneI = dynSizes.size();
121  lookup.insert(name, zoneI);
122  dynNames.append(name);
123  dynSizes.append(0);
124  }
125  }
126  else if (cmd == "f")
127  {
128  DynamicList<label> dynVertices;
129 
130  // Assume 'f' is followed by space.
131  string::size_type endNum = 1;
132 
133  while (true)
134  {
135  string::size_type startNum =
136  line.find_first_not_of(' ', endNum);
137 
138  if (startNum == string::npos)
139  {
140  break;
141  }
142 
143  endNum = line.find(' ', startNum);
144 
145  string vertexSpec;
146  if (endNum != string::npos)
147  {
148  vertexSpec = line.substr(startNum, endNum-startNum);
149  }
150  else
151  {
152  vertexSpec = line.substr(startNum, line.size() - startNum);
153  }
154 
155  string::size_type slashPos = vertexSpec.find('/');
156 
157  label vertI = 0;
158  if (slashPos != string::npos)
159  {
160  IStringStream intStream(vertexSpec.substr(0, slashPos));
161 
162  intStream >> vertI;
163  }
164  else
165  {
166  IStringStream intStream(vertexSpec);
167 
168  intStream >> vertI;
169  }
170  dynVertices.append(vertI - 1);
171  }
172  dynVertices.shrink();
173 
174  labelUList& f = static_cast<labelUList&>(dynVertices);
175 
176  if (mustTriangulate && f.size() > 3)
177  {
178  // simple face triangulation about f[0]
179  // points may be incomplete
180  for (label fp1 = 1; fp1 < f.size() - 1; fp1++)
181  {
182  label fp2 = f.fcIndex(fp1);
183 
184  dynFaces.append(triFace(f[0], f[fp1], f[fp2]));
185  dynZones.append(zoneI);
186  dynSizes[zoneI]++;
187  }
188  }
189  else
190  {
191  dynFaces.append(Face(f));
192  dynZones.append(zoneI);
193  dynSizes[zoneI]++;
194  }
195  }
196  }
197 
198 
199  // transfer to normal lists
200  this->storedPoints().transfer(dynPoints);
201 
202  this->sortFacesAndStore(move(dynFaces), move(dynZones), sorted);
203 
204  // add zones, culling empty ones
205  this->addZones(dynSizes, dynNames, true);
206  return true;
207 }
208 
209 
210 template<class Face>
212 (
213  const fileName& filename,
214  const MeshedSurfaceProxy<Face>& surf
215 )
216 {
217  const pointField& pointLst = surf.points();
218  const List<Face>& faceLst = surf.faces();
219  const List<label>& faceMap = surf.faceMap();
220 
221  // for no zones, suppress the group name
222  const List<surfZone>& zones =
223  (
224  surf.surfZones().empty()
225  ? surfaceFormatsCore::oneZone(faceLst, "")
226  : surf.surfZones()
227  );
228 
229  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
230 
231  OFstream os(filename);
232  if (!os.good())
233  {
235  << "Cannot open file for writing " << filename
236  << exit(FatalError);
237  }
238 
239 
240  os << "# Wavefront OBJ file written " << clock::dateTime().c_str() << nl
241  << "o " << os.name().lessExt().name() << nl
242  << nl
243  << "# points : " << pointLst.size() << nl
244  << "# faces : " << faceLst.size() << nl
245  << "# zones : " << zones.size() << nl;
246 
247  // Print zone names as comment
248  forAll(zones, zoneI)
249  {
250  os << "# " << zoneI << " " << zones[zoneI].name()
251  << " (nFaces: " << zones[zoneI].size() << ")" << nl;
252  }
253 
254  os << nl
255  << "# <points count=\"" << pointLst.size() << "\">" << nl;
256 
257  // Write vertex coords
258  forAll(pointLst, ptI)
259  {
260  const point& pt = pointLst[ptI];
261 
262  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
263  }
264 
265  os << "# </points>" << nl
266  << nl
267  << "# <faces count=\"" << faceLst.size() << "\">" << endl;
268 
269 
270  label faceIndex = 0;
271  forAll(zones, zoneI)
272  {
273  const surfZone& zone = zones[zoneI];
274 
275  if (zone.name().size())
276  {
277  os << "g " << zone.name() << endl;
278  }
279 
280  if (useFaceMap)
281  {
282  forAll(zone, localFacei)
283  {
284  const Face& f = faceLst[faceMap[faceIndex++]];
285 
286  os << 'f';
287  forAll(f, fp)
288  {
289  os << ' ' << f[fp] + 1;
290  }
291  os << endl;
292  }
293  }
294  else
295  {
296  forAll(zone, localFacei)
297  {
298  const Face& f = faceLst[faceIndex++];
299 
300  os << 'f';
301  forAll(f, fp)
302  {
303  os << ' ' << f[fp] + 1;
304  }
305  os << endl;
306  }
307  }
308  }
309  os << "# </faces>" << endl;
310 }
311 
312 
313 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
A line primitive.
Definition: line.H:56
A class for handling file names.
Definition: fileName.H:79
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:112
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
tUEqn clear()
const word & name() const
Return name.
Output to file stream.
Definition: OFstream.H:82
A surface zone on a MeshedSurface.
Definition: surfZone.H:62
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
OBJsurfaceFormat(const fileName &)
Construct from file name.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
const Cmpt & z() const
Definition: VectorI.H:87
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:120
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
const Cmpt & y() const
Definition: VectorI.H:81
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Various functions to operate on Lists.
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:142
scalar y
virtual bool read(const fileName &)
Read from file.
bool useFaceMap() const
Use faceMap?
stressControl lookup("compactNormalStress") >> compactNormalStress
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
Base class for zones.
Definition: zone.H:57
const List< Face > & faces() const
Return const access to the faces.
A class for handling words, derived from string.
Definition: word.H:59
face triFace(3)
word name() const
Return file name (part beyond last /)
Definition: fileName.C:183
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
const List< surfZone > & surfZones() const
Const access to the surface zones.
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
const Cmpt & x() const
Definition: VectorI.H:75
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:252
static const char nl
Definition: Ostream.H:265
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats...
Definition: MeshedSurface.H:73
Input from file stream.
Definition: IFstream.H:81
labelList f(nPoints)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
static void write(const fileName &, const MeshedSurfaceProxy< Face > &)
Write surface mesh components by proxy.
vector point
Point is a vector.
Definition: point.H:41
const pointField & points() const
Return const access to the points.
const List< label > & faceMap() const
Const access to the faceMap, zero-sized when unused.
Input from memory buffer stream.
Definition: IStringStream.H:49
fileName lessExt() const
Return file name without extension (part before last .)
Definition: fileName.C:272
label size() const
Return the number of elements in the UList.
Definition: UListI.H:299
void transfer(List< T > &)
Transfer contents of the argument List into this.
Definition: DynamicListI.H:285