AC3DsurfaceFormat.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-2020 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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 "AC3DsurfaceFormat.H"
30#include "StringStream.H"
31#include "PrimitivePatch.H"
32#include "faceTraits.H"
33
34// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
35
36template<class Face>
38(
39 const fileName& filename
40)
41{
42 read(filename);
43}
44
45
46// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
47
48template<class Face>
50(
51 const fileName& filename
52)
53{
54 // Clear everything
55 this->clear();
56
57 IFstream is(filename);
58 if (!is.good())
59 {
61 << "Cannot read file " << filename << nl
62 << exit(FatalError);
63 }
64
65 string line, cmd, args;
66
67 is.getLine(line);
68
69 // Verify version
70 {
71 const string version = line.substr(4);
72
73 if (version != "b")
74 {
76 << "When reading AC3D file " << filename
77 << " read header " << line << " with version "
78 << version << endl
79 << "Only tested reading with version 'b'."
80 << " This might give problems" << endl;
81 }
82 }
83
84
85 if (!cueTo(is, "OBJECT", args) || args != "world")
86 {
88 << "Cannot find 'OBJECT world' in file " << filename << nl
89 << exit(FatalError);
90 }
91
92 // Number of kids is the number of zones
93 args = cueToOrDie(is, "kids");
94 const label nZones = parse<int>(args);
95
96 // Start of vertices for object/zones
97 label vertexOffset = 0;
98
99 DynamicList<point> dynPoints;
100 DynamicList<Face> dynFaces;
101 List<word> names(nZones);
102 List<label> sizes(nZones, Zero);
103
104 for (label zoneI = 0; zoneI < nZones; ++zoneI)
105 {
106 names[zoneI] = surfZone::defaultName(zoneI);
107
108 args = cueToOrDie(is, "OBJECT", "while reading " + names[zoneI]);
109
110 // number of vertices for this zone
111 label nZonePoints = 0;
112 vector location(Zero);
113 // tensor rotation(I);
114
115 // Read all info for current zone
116 while (is.good())
117 {
118 // Read line and get first word. If end of file break since
119 // zone should always end with 'kids' command ?not sure.
120 if (!readCmd(is, cmd, args))
121 {
123 << "Did not read up to 'kids 0' while reading zone "
124 << zoneI << " from file " << filename << nl
125 << exit(FatalError);
126 }
127
128 if (cmd == "name")
129 {
130 // name %s
131 const string str = parse<string>(args);
132 names[zoneI] = word::validate(str);
133 }
134 else if (cmd == "rot")
135 {
136 // rot %f %f %f %f %f %f %f %f %f
137
138 // IStringStream lineStream(args);
139 //
140 // lineStream
141 // >> rotation.xx() >> rotation.xy() >> rotation.xz()
142 // >> rotation.yx() >> rotation.yy() >> rotation.yz()
143 // >> rotation.zx() >> rotation.zy() >> rotation.zz();
144
146 << "rot (rotation tensor) command not implemented"
147 << "Line:" << cmd << ' ' << args << endl
148 << "while reading zone " << zoneI << endl;
149 }
150 else if (cmd == "loc")
151 {
152 // loc %f %f %f
153 IStringStream lineStream(args);
154
155 lineStream
156 >> location.x()
157 >> location.y()
158 >> location.z();
159 }
160 else if (cmd == "numvert")
161 {
162 // numvert %d
163 nZonePoints = parse<int>(args);
164
165 for (label vertI = 0; vertI < nZonePoints; ++vertI)
166 {
167 is.getLine(line);
168 IStringStream lineStream(line);
169
170 point pt;
171 lineStream
172 >> pt.x() >> pt.y() >> pt.z();
173
174 // Offset with current translation vector
175 dynPoints.append(location + pt);
176 }
177 }
178 else if (cmd == "numsurf")
179 {
180 const label nFaces = parse<int>(args);
181
182 for (label facei = 0; facei < nFaces; ++facei)
183 {
184 const string errorMsg =
185 string(" while reading face ")
186 + Foam::name(facei) + " on zone "
187 + Foam::name(zoneI)
188 + " from file " + filename;
189
190 cueToOrDie(is, "SURF", errorMsg);
191 cueToOrDie(is, "mat", errorMsg);
192 args = cueToOrDie(is, "refs", errorMsg);
193
194 const label nVert = parse<int>(args);
195
196 List<label> verts(nVert);
197 forAll(verts, vertI)
198 {
199 is.getLine(line);
200 verts[vertI] = vertexOffset + parse<int>(line);
201 }
202
203 const labelUList& f = static_cast<const labelUList&>(verts);
204
205 if (faceTraits<Face>::isTri() && f.size() > 3)
206 {
207 // simple face triangulation about f[0]
208 // points may be incomplete
209 for (label fp1 = 1; fp1 < f.size() - 1; ++fp1)
210 {
211 label fp2 = f.fcIndex(fp1);
212
213 dynFaces.append(Face{f[0], f[fp1], f[fp2]});
214 sizes[zoneI]++;
215 }
216 }
217 else
218 {
219 dynFaces.append(Face(f));
220 sizes[zoneI]++;
221 }
222 }
223
224 // Done the current zone.
225 // Increment the offset vertices are stored at
226 vertexOffset += nZonePoints;
227 }
228 else if (cmd == "kids")
229 {
230 // 'kids' denotes the end of the current zone.
231 const label nKids = parse<int>(args);
232
233 if (nKids != 0)
234 {
236 << "Can only read objects without kids."
237 << " Encountered " << nKids << " kids when"
238 << " reading zone " << zoneI
239 << exit(FatalError);
240 }
241
242 // Done reading current zone
243 break;
244 }
245 }
246 }
247
248 // transfer to normal lists
249 this->storedPoints().transfer(dynPoints);
250 this->storedFaces().transfer(dynFaces);
251
252 // Add zones (retaining empty ones)
253 this->addZones(sizes, names);
254 this->addZonesToFaces(); // for labelledTri
255 this->stitchFaces(SMALL);
256
257 return true;
258}
259
260
261namespace Foam
262{
263// file-scope writing of a patch of faces
264template<class Patch>
265static void writeZone
266(
267 Ostream& os,
268 const Patch& patch,
269 const word& name,
270 const label zoneI
271)
272{
273 // An isolated surface region (patch).
274 os << "OBJECT poly" << nl
275 << "name \"" << name << "\"" << nl;
276
277 os << "numvert " << patch.nPoints() << nl;
278
279 for (const point& pt : patch.localPoints())
280 {
281 os << pt.x() << ' ' << pt.y() << ' ' << pt.z() << nl;
282 }
283
284 os << "numsurf " << patch.size() << nl;
285
286 for (const auto& f : patch.localFaces())
287 {
288 os << "SURF 0x20" << nl // polygon
289 << "mat " << zoneI << nl
290 << "refs " << f.size() << nl;
291
292 for (const label verti : f)
293 {
294 os << verti << " 0 0" << nl;
295 }
296 }
297
298 os << "kids 0" << endl;
299}
300}
301
302template<class Face>
304(
305 const fileName& filename,
306 const MeshedSurfaceProxy<Face>& surf,
307 IOstreamOption streamOpt,
308 const dictionary&
309)
310{
311 // ASCII only, allow output compression
312 streamOpt.format(IOstream::ASCII);
313
314 const pointField& pointLst = surf.points();
315 const UList<Face>& faceLst = surf.surfFaces();
316
317 const surfZoneList zones =
318 (
319 surf.surfZones().size()
320 ? surf.surfZones()
321 : surfaceFormatsCore::oneZone(faceLst)
322 );
323
324 const bool useFaceMap = (surf.useFaceMap() && zones.size() > 1);
325
326 OFstream os(filename, streamOpt);
327 if (!os.good())
328 {
330 << "Cannot write file " << filename << nl
331 << exit(FatalError);
332 }
333
334 writeHeader(os, zones);
335
336 if (zones.size() == 1)
337 {
339 (
340 faceLst, pointLst
341 );
342
343 writeZone(os, patch, zones[0].name(), 0);
344 return;
345 }
346
347 label zoneIndex = 0;
348 for (const surfZone& zone : zones)
349 {
350 if (useFaceMap)
351 {
353
354 SubList<label> zoneMap(surf.faceMap(), zone.range());
355
357 (
358 FaceListType(faceLst, zoneMap),
359 pointLst
360 );
361
362 writeZone(os, patch, zone.name(), zoneIndex);
363 }
364 else
365 {
367
369 (
370 FaceListType(faceLst, zone.range()),
371 pointLst
372 );
373
374 writeZone(os, patch, zone.name(), zoneIndex);
375 }
376
377 ++zoneIndex;
378 }
379}
380
381
382template<class Face>
384(
385 const fileName& filename,
386 const UnsortedMeshedSurface<Face>& surf,
387 IOstreamOption streamOpt,
388 const dictionary&
389)
390{
391 // ASCII only, allow output compression
392 streamOpt.format(IOstream::ASCII);
393
394 OFstream os(filename, streamOpt);
395 if (!os.good())
396 {
398 << "Cannot write file " << filename << nl
399 << exit(FatalError);
400 }
401
403 List<surfZone> zoneLst = surf.sortedZones(faceMap);
404
405 if (zoneLst.size() <= 1)
406 {
407 const surfZoneList zones =
408 (
409 zoneLst.size()
410 ? zoneLst
411 : surfaceFormatsCore::oneZone(surf.surfFaces())
412 );
413
414 writeHeader(os, zones);
415 writeZone(os, surf, zones[0].name(), 0);
416 return;
417 }
418
419 writeHeader(os, zoneLst);
420
421 label zoneIndex = 0;
422 for (const surfZone& zone : zoneLst)
423 {
425
426 SubList<label> zoneMap(faceMap, zone.range());
427
429 (
430 FaceListType(surf.surfFaces(), zoneMap),
431 surf.points()
432 );
433
434 writeZone(os, patch, zone.name(), zoneIndex);
435
436 ++zoneIndex;
437 }
438}
439
440
441// ************************************************************************* //
Input/output from string buffers.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
Input from file stream, using an ISstream.
Definition: IFstream.H:57
The IOstreamOption is a simple container for options an IOstream can normally have.
streamFormat format() const noexcept
Get the current stream format.
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:233
ISstream & getLine(std::string &str, char delim='\n')
Raw, low-level getline (until delimiter) into a string.
Definition: ISstreamI.H:76
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:112
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats.
const UList< surfZone > & surfZones() const
Const access to the surface zones.
const UList< Face > & surfFaces() const
Return const access to the faces.
bool useFaceMap() const
Can/should use faceMap?
const pointField & points() const
Return const access to the points.
const labelUList & faceMap() const
Const access to the faceMap, zero-sized when unused.
const List< Face > & surfFaces() const
Return const access to the faces.
Output to file stream, using an OSstream.
Definition: OFstream.H:57
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
A list of faces which address into the list of points.
const Field< point_type > & points() const noexcept
Return reference to global points.
virtual bool read()
Re-read model coefficients if they have changed.
A List obtained as a section of another List.
Definition: SubList.H:70
A List with indirect addressing. Like IndirectList but does not store addressing.
Definition: IndirectList.H:79
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A surface geometry mesh, in which the surface zone information is conveyed by the 'zoneId' associated...
surfZoneList sortedZones(labelList &faceMap) const
Sort faces according to zoneIds.
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:85
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:79
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:73
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
Traits class for faces.
Definition: faceTraits.H:51
A class for handling file names.
Definition: fileName.H:76
virtual bool write()
Write the output fields.
A line primitive.
Definition: line.H:68
A class for handling character strings derived from std::string.
Definition: string.H:79
A surface zone on a MeshedSurface.
Definition: surfZone.H:59
A class for handling words, derived from Foam::string.
Definition: word.H:68
const word & name() const noexcept
The zone name.
Base class for mesh zones.
Definition: zone.H:67
patchWriters clear()
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
label nZones
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
static void writeZone(Ostream &os, const Patch &patch, const word &name, const label zoneI)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
labelList f(nPoints)
Foam::argList args(argc, argv)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333