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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2018 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "OBJsurfaceFormat.H"
30 #include "clock.H"
31 #include "Fstream.H"
32 #include "stringOps.H"
33 #include "faceTraits.H"
34 
35 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
36 
37 template<class Face>
39 (
40  const fileName& filename
41 )
42 {
43  read(filename);
44 }
45 
46 
47 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
48 
49 template<class Face>
51 (
52  const fileName& filename
53 )
54 {
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  // Place faces without a group in zone0.
67  // zoneId = -1 to signal uninitialized
68  label zoneId = -1;
69  bool sorted = true;
70 
71  DynamicList<point> dynPoints;
72  DynamicList<label> dynVerts;
73  DynamicList<Face> dynFaces;
74 
75  DynamicList<word> dynNames;
76  DynamicList<label> dynZones;
77  DynamicList<label> dynSizes;
78 
79  HashTable<label> groupLookup;
80 
81  while (is.good())
82  {
83  string line = this->getLineNoComment(is);
84 
85  // Line continuations
86  while (line.removeEnd('\\'))
87  {
88  line += this->getLineNoComment(is);
89  }
90 
92 
93  // Require command and some arguments
94  if (tokens.size() < 2)
95  {
96  continue;
97  }
98 
99  const word cmd = word::validate(tokens[0]);
100 
101  if (cmd == "v")
102  {
103  // Vertex
104  // v x y z
105 
106  dynPoints.append
107  (
108  point
109  (
110  readScalar(tokens[1]),
111  readScalar(tokens[2]),
112  readScalar(tokens[3])
113  )
114  );
115  }
116  else if (cmd == "g")
117  {
118  // Grouping
119  // g name
120 
121  const word groupName = word::validate(tokens[1]);
122  const auto iterGroup = groupLookup.cfind(groupName);
123 
124  if (iterGroup.found())
125  {
126  if (zoneId != *iterGroup)
127  {
128  sorted = false; // group appeared out of order
129  }
130  zoneId = *iterGroup;
131  }
132  else
133  {
134  zoneId = dynSizes.size();
135  groupLookup.insert(groupName, zoneId);
136  dynNames.append(groupName);
137  dynSizes.append(0);
138  }
139  }
140  else if (cmd == "f")
141  {
142  // Face
143  // f v1 v2 v3 ...
144  // OR
145  // f v1/vt1 v2/vt2 v3/vt3 ...
146 
147  // Ensure it has as valid grouping
148  if (zoneId < 0)
149  {
150  zoneId = 0;
151  groupLookup.insert("zone0", 0);
152  dynNames.append("zone0");
153  dynSizes.append(0);
154  }
155 
156  dynVerts.clear();
157 
158  bool first = true;
159  for (const auto& tok : tokens)
160  {
161  if (first)
162  {
163  // skip initial "f" or "l"
164  first = false;
165  continue;
166  }
167 
168  const string vrtSpec(tok);
169  const auto slash = vrtSpec.find('/');
170 
171  const label vertId =
172  (
173  slash != string::npos
174  ? readLabel(vrtSpec.substr(0, slash))
175  : readLabel(vrtSpec)
176  );
177 
178  dynVerts.append(vertId - 1);
179  }
180 
181  const labelUList& f = dynVerts;
182 
183  if (faceTraits<Face>::isTri() && f.size() > 3)
184  {
185  // simple face triangulation about f[0]
186  // points may be incomplete
187  for (label fp1 = 1; fp1 < f.size() - 1; fp1++)
188  {
189  const label fp2 = f.fcIndex(fp1);
190 
191  dynFaces.append(Face{f[0], f[fp1], f[fp2]});
192  dynZones.append(zoneId);
193  dynSizes[zoneId]++;
194  }
195  }
196  else if (f.size() >= 3)
197  {
198  dynFaces.append(Face(f));
199  dynZones.append(zoneId);
200  dynSizes[zoneId]++;
201  }
202  }
203  }
204 
205 
206  // Transfer to normal lists
207  this->storedPoints().transfer(dynPoints);
208 
209  this->sortFacesAndStore(dynFaces, dynZones, sorted);
210 
211  // Add zones (retaining empty ones)
212  this->addZones(dynSizes, dynNames);
213  this->addZonesToFaces(); // for labelledTri
214 
215  return true;
216 }
217 
218 
219 template<class Face>
221 (
222  const fileName& filename,
223  const MeshedSurfaceProxy<Face>& surf,
224  const dictionary& options
225 )
226 {
227  const UList<point>& pointLst = surf.points();
228  const UList<Face>& faceLst = surf.surfFaces();
229  const UList<label>& faceMap = surf.faceMap();
230 
231  // for no zones, suppress the group name
232  const surfZoneList zones =
233  (
234  surf.surfZones().empty()
235  ? surfaceFormatsCore::oneZone(faceLst, "")
236  : surf.surfZones()
237  );
238 
239  const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
240 
241  OFstream os(filename);
242  if (!os.good())
243  {
245  << "Cannot open file for writing " << filename
246  << exit(FatalError);
247  }
248 
249 
250  os << "# Wavefront OBJ file written " << clock::dateTime().c_str() << nl
251  << "o " << os.name().nameLessExt() << nl
252  << nl
253  << "# points : " << pointLst.size() << nl
254  << "# faces : " << faceLst.size() << nl
255  << "# zones : " << zones.size() << nl;
256 
257  // Print zone names as comment
258  forAll(zones, zonei)
259  {
260  os << "# " << zonei << " " << zones[zonei].name()
261  << " (nFaces: " << zones[zonei].size() << ")" << nl;
262  }
263 
264  os << nl
265  << "# <points count=\"" << pointLst.size() << "\">" << nl;
266 
267  // Write vertex coords
268  for (const point& pt : pointLst)
269  {
270  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
271  }
272 
273  os << "# </points>" << nl
274  << nl
275  << "# <faces count=\"" << faceLst.size() << "\">" << nl;
276 
277 
278  label faceIndex = 0;
279  for (const surfZone& zone : zones)
280  {
281  if (zone.name().size())
282  {
283  os << "g " << zone.name() << nl;
284  }
285 
286  const label nLocalFaces = zone.size();
287 
288  if (useFaceMap)
289  {
290  for (label i=0; i<nLocalFaces; ++i)
291  {
292  const Face& f = faceLst[faceMap[faceIndex++]];
293 
294  os << 'f';
295  for (const label verti : f)
296  {
297  os << ' ' << verti + 1;
298  }
299  os << nl;
300  }
301  }
302  else
303  {
304  for (label i=0; i<nLocalFaces; ++i)
305  {
306  const Face& f = faceLst[faceIndex++];
307 
308  os << 'f';
309  for (const label verti : f)
310  {
311  os << ' ' << verti + 1;
312  }
313  os << nl;
314  }
315  }
316  }
317  os << "# </faces>" << nl;
318 }
319 
320 
321 // ************************************************************************* //
Foam::faceMap
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Definition: blockMeshMergeFast.C:94
Foam::fileName::nameLessExt
static std::string nameLessExt(const std::string &str)
Return basename, without extension.
Definition: fileName.C:402
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::OFstream::name
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:91
Foam::MeshedSurfaceProxy::useFaceMap
bool useFaceMap() const
Use faceMap?
Definition: MeshedSurfaceProxy.H:186
Foam::IFstream
Input from file stream, using an ISstream.
Definition: IFstream.H:97
Foam::DynamicList< point >
validate
thermo validate(args.executable(), "h")
Foam::zone
Base class for mesh zones.
Definition: zone.H:63
Foam::HashTable::insert
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:168
Foam::MeshedSurfaceProxy::points
const pointField & points() const
Return const access to the points.
Definition: MeshedSurfaceProxy.H:160
Foam::stringOps::splitSpace
Foam::SubStrings< StringType > splitSpace(const StringType &str)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC)
Definition: stringOpsTemplates.C:180
Foam::SubStrings
Sub-ranges of a string with a structure similar to std::match_results, but without the underlying reg...
Definition: CStringList.H:63
Foam::MeshedSurfaceProxy
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats.
Definition: MeshedSurface.H:78
Foam::fileFormats::OBJsurfaceFormat::write
static void write(const fileName &filename, const MeshedSurfaceProxy< Face > &surf, const dictionary &options=dictionary::null)
Write surface mesh components by proxy.
Definition: OBJsurfaceFormat.C:221
Foam::MeshedSurfaceProxy::faceMap
const labelUList & faceMap() const
Const access to the faceMap, zero-sized when unused.
Definition: MeshedSurfaceProxy.H:180
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
Foam::fileFormats::OBJsurfaceFormat::OBJsurfaceFormat
OBJsurfaceFormat(const fileName &filename)
Construct from file name.
Definition: OBJsurfaceFormat.C:39
OBJsurfaceFormat.H
Foam::faceTraits
Traits class for faces.
Definition: faceTraits.H:50
Foam::label
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:62
clock.H
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:472
Foam::DynamicList::clear
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:348
Foam::blockMeshTools::read
void read(Istream &, label &, const dictionary &)
In-place read with dictionary lookup.
Definition: blockMeshTools.C:33
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::zone::name
const word & name() const
Return name.
Definition: zone.H:158
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:99
Foam::HashTable< label >
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::HashTable::cfind
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:141
clear
patchWriters clear()
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Fstream.H
Input/output from file streams.
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::readLabel
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition: label.H:70
Foam::List< surfZone >
Foam::surfZone
A surface zone on a MeshedSurface.
Definition: surfZone.H:65
Foam::UList< label >
Foam::DynamicList::transfer
void transfer(List< T > &lst)
Transfer contents of the argument List into this.
Definition: DynamicListI.H:426
Foam::fileFormats::OBJsurfaceFormat::read
virtual bool read(const fileName &filename)
Read from file.
Definition: OBJsurfaceFormat.C:51
Foam::line
A line primitive.
Definition: line.H:59
Foam::UList::size
void size(const label n) noexcept
Override size to be inconsistent with allocated storage.
Definition: UListI.H:360
Foam::MeshedSurfaceProxy::surfFaces
const UList< Face > & surfFaces() const
Return const access to the faces.
Definition: MeshedSurfaceProxy.H:166
Foam::IOstream::good
bool good() const
Return true if next operation might succeed.
Definition: IOstream.H:216
faceTraits.H
stringOps.H
Foam::MeshedSurfaceProxy::surfZones
const UList< surfZone > & surfZones() const
Const access to the surface zones.
Definition: MeshedSurfaceProxy.H:174