OBJedgeFormat.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-2025 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 "OBJedgeFormat.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 
37 (
38  const fileName& filename
39 )
40 {
41  read(filename);
42 }
43 
44 
45 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
46 
47 void Foam::fileFormats::OBJedgeFormat::readVertices
48 (
49  const string& line,
50  string::size_type& endNum,
51  DynamicList<label>& dynVertices
52 )
53 {
54  dynVertices.clear();
55  while (true)
56  {
57  string::size_type startNum =
58  line.find_first_not_of(' ', endNum);
59 
60  if (startNum == string::npos)
61  {
62  break;
63  }
64 
65  endNum = line.find(' ', startNum);
66 
67  string vertexSpec;
68  if (endNum != string::npos)
69  {
70  vertexSpec = line.substr(startNum, endNum-startNum);
71  }
72  else
73  {
74  vertexSpec = line.substr(startNum, line.size() - startNum);
75  }
76 
77  string::size_type slashPos = vertexSpec.find('/');
78 
79  label vertI = 0;
80  if (slashPos != string::npos)
81  {
82  IStringStream intStream(vertexSpec.substr(0, slashPos));
83 
84  intStream >> vertI;
85  }
86  else
87  {
88  IStringStream intStream(vertexSpec);
89 
90  intStream >> vertI;
91  }
92  dynVertices.append(vertI - 1);
93  }
94 }
95 
96 
98 {
99  clear();
100 
101  IFstream is(filename);
102  if (!is.good())
103  {
105  << "Cannot read file " << filename
106  << exit(FatalError);
107  }
108 
109  DynamicList<point> dynPoints;
110  DynamicList<edge> dynEdges;
111  DynamicList<label> dynUsedPoints;
112 
113  DynamicList<label> dynVertices;
114 
115  while (is.good())
116  {
117  const string line = this->getLineNoComment(is);
118 
119  // Read first word
120  IStringStream lineStream(line);
121  word cmd;
122  lineStream >> cmd;
123 
124  if (cmd == "v")
125  {
126  scalar x, y, z;
127  lineStream >> x >> y >> z;
128 
129  dynPoints.append(point(x, y, z));
130  dynUsedPoints.append(-1);
131  }
132  else if (cmd == "l")
133  {
134  // Assume 'l' is followed by space.
135  string::size_type endNum = 1;
136 
137  readVertices
138  (
139  line,
140  endNum,
141  dynVertices
142  );
143 
144 
145  for (label i = 1; i < dynVertices.size(); i++)
146  {
147  edge edgeRead(dynVertices[i-1], dynVertices[i]);
148 
149  dynUsedPoints[edgeRead[0]] = edgeRead[0];
150  dynUsedPoints[edgeRead[1]] = edgeRead[1];
151 
152  dynEdges.append(edgeRead);
153  }
154  }
155  else if (cmd == "f")
156  {
157  // Support for faces with 2 vertices
158 
159  // Assume 'f' is followed by space.
160  string::size_type endNum = 1;
161 
162  readVertices
163  (
164  line,
165  endNum,
166  dynVertices
167  );
168 
169  if (dynVertices.size() == 2)
170  {
171  for (label i = 1; i < dynVertices.size(); i++)
172  {
173  edge edgeRead(dynVertices[i-1], dynVertices[i]);
174 
175  dynUsedPoints[edgeRead[0]] = edgeRead[0];
176  dynUsedPoints[edgeRead[1]] = edgeRead[1];
177 
178  dynEdges.append(edgeRead);
179  }
180  }
181  }
182  }
183 
184  // cull unused points
185  label nUsed = 0;
186 
187  forAll(dynPoints, pointi)
188  {
189  if (dynUsedPoints[pointi] >= 0)
190  {
191  if (nUsed != pointi)
192  {
193  dynPoints[nUsed] = dynPoints[pointi];
194  dynUsedPoints[pointi] = nUsed; // new position
195  }
196  ++nUsed;
197  }
198  }
199 
200  dynPoints.setSize(nUsed);
201 
202  // transfer to normal lists
203  storedPoints().transfer(dynPoints);
204 
205  // renumber edge vertices
206  if (nUsed != dynUsedPoints.size())
207  {
208  forAll(dynEdges, edgeI)
209  {
210  edge& e = dynEdges[edgeI];
211 
212  e[0] = dynUsedPoints[e[0]];
213  e[1] = dynUsedPoints[e[1]];
214  }
215  }
216  storedEdges().transfer(dynEdges);
217 
218  return true;
219 }
220 
221 
223 (
224  const fileName& filename,
225  const edgeMesh& mesh
226 )
227 {
228  const pointField& pointLst = mesh.points();
229  const edgeList& edgeLst = mesh.edges();
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  << "# lines : " << edgeLst.size() << nl;
245 
246  os << nl
247  << "# <points count=\"" << pointLst.size() << "\">" << nl;
248 
249  // Write vertex coords
250  forAll(pointLst, ptI)
251  {
252  const point& p = pointLst[ptI];
253 
254  os << "v " << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
255  }
256 
257  os << "# </points>" << nl
258  << nl
259  << "# <edges count=\"" << edgeLst.size() << "\">" << endl;
260 
261  // Write line connectivity
262  forAll(edgeLst, edgeI)
263  {
264  const edge& e = edgeLst[edgeI];
265 
266  os << "l " << (e[0] + 1) << " " << (e[1] + 1) << nl;
267  }
268  os << "# </edges>" << endl;
269 }
270 
271 
272 // ************************************************************************* //
scalar y
Various functions to operate on Lists.
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
void transfer(List< T > &)
Transfer contents of the argument List into this.
Definition: DynamicListI.H:285
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:236
void setSize(const label)
Alter the addressed list size.
Definition: DynamicListI.H:175
Input from file stream.
Definition: IFstream.H:85
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:333
Input from memory buffer stream.
Definition: IStringStream.H:52
bool good() const
Return true if next operation might succeed.
Definition: Istream.H:101
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Output to file stream.
Definition: OFstream.H:87
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:121
static string dateTime()
Return the current wall-clock date/time as a string.
Definition: clock.C:57
Points connected by edges.
Definition: edgeMesh.H:72
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:61
virtual bool read(const fileName &)
Read from file.
Definition: OBJedgeFormat.C:97
OBJedgeFormat(const fileName &)
Construct from file name.
Definition: OBJedgeFormat.C:37
static void write(const fileName &, const edgeMesh &)
Write surface mesh components by proxy.
A class for handling file names.
Definition: fileName.H:82
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
fileName lessExt() const
Return file name without extension (part before last .)
Definition: fileName.C:303
A line primitive.
Definition: line.H:71
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
A class for handling words, derived from string.
Definition: word.H:63
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
tUEqn clear()
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
error FatalError
static const char nl
Definition: Ostream.H:297
volScalarField & p