x3dSurfaceWriter.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) 2019-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "x3dSurfaceWriter.H"
29 #include "OFstream.H"
30 #include "OSspecific.H"
31 #include "MeshedSurfaceProxy.H"
32 #include "surfaceWriterMethods.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 namespace surfaceWriters
40 {
41  defineTypeName(x3dWriter);
42  addToRunTimeSelectionTable(surfaceWriter, x3dWriter, word);
43  addToRunTimeSelectionTable(surfaceWriter, x3dWriter, wordDict);
44 }
45 }
46 
47 
48 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
49 
50 namespace Foam
51 {
52 
53 //- A (0-1) range for colouring
54 inline scalar srange01(const scalarMinMax& range, scalar x)
55 {
56  if (x >= range.max())
57  {
58  return 1;
59  }
60 
61  x -= range.min();
62 
63  if (x < VSMALL)
64  {
65  return 0;
66  }
67 
68  return x / (range.max() - range.min());
69 }
70 
71 
72 //- A (0-1) range for colouring
73 template<class Type>
74 static inline scalar rangex(const scalarMinMax& range, const Type& val)
75 {
76  return srange01(range, Foam::mag(val));
77 }
78 
79 
80 //- A (0-1) range for colouring
81 template<>
82 inline scalar rangex(const scalarMinMax& range, const scalar& val)
83 {
84  return srange01(range, val);
85 }
86 
87 
88 //- A (0-1) range for colouring
89 template<>
90 inline scalar rangex(const scalarMinMax& range, const label& val)
91 {
92  return srange01(range, val);
93 }
94 
95 
96 static inline void printColour(Ostream& os, const vector& rgb)
97 {
98  os << rgb[0] << ' ' << rgb[1] << ' ' << rgb[2] << ',' << nl;
99 }
100 
101 } // End namespace Foam
102 
103 
104 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
105 
107 :
108  surfaceWriter(),
109  streamOpt_(),
110  range_(),
111  colourTablePtr_(nullptr)
112 {}
113 
114 
116 (
117  const dictionary& options
118 )
119 :
120  surfaceWriter(options),
121  streamOpt_
122  (
123  IOstreamOption::ASCII,
124  IOstreamOption::compressionEnum("compression", options)
125  ),
126  range_(),
127  colourTablePtr_(nullptr)
128 {
129  verbose_ = true;
130 
131  options.readIfPresent("range", range_);
132 
133  word tableName;
134  if (options.readIfPresent("colourMap", tableName))
135  {
136  colourTablePtr_ = colourTable::ptr(tableName);
137  if (!colourTablePtr_)
138  {
140  << "No colourMap " << tableName << " using default" << nl;
141  }
142  }
143 
144  if (!colourTablePtr_)
145  {
147  colourTablePtr_ = colourTable::ptr(colourTable::COOL_WARM);
148  }
149 
150  if (verbose_)
151  {
152  Info<< "X3D with colourMap '" << tableName << "' and range ";
153 
154  if (range_.good())
155  {
156  Info<< range_;
157  }
158  else
159  {
160  Info<< "auto";
161  }
162  Info<< nl;
163  }
164 }
165 
166 
168 (
169  const meshedSurf& surf,
170  const fileName& outputPath,
171  bool parallel,
172  const dictionary& options
173 )
174 :
175  x3dWriter(options)
176 {
177  open(surf, outputPath, parallel);
178 }
179 
180 
182 (
184  const faceList& faces,
185  const fileName& outputPath,
186  bool parallel,
187  const dictionary& options
188 )
189 :
190  x3dWriter(options)
191 {
192  open(points, faces, outputPath, parallel);
193 }
194 
195 
196 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
197 
199 {
200  checkOpen();
201 
202  // Geometry: rootdir/<TIME>/surfaceName.x3d
203 
204  fileName outputFile = outputPath_;
205  if (useTimeDir() && !timeName().empty())
206  {
207  // Splice in time-directory
208  outputFile = outputPath_.path() / timeName() / outputPath_.name();
209  }
210  outputFile.ext("x3d");
211 
212  if (verbose_)
213  {
214  Info<< "Writing geometry to " << outputFile << endl;
215  }
216 
217  // const meshedSurf& surf = surface();
218  const meshedSurfRef& surf = adjustSurface();
219 
220  if (UPstream::master() || !parallel_)
221  {
222  if (!isDir(outputFile.path()))
223  {
224  mkDir(outputFile.path());
225  }
226 
228  (
229  outputFile,
230  "x3d",
231  streamOpt_
232  );
233  }
234 
235  wroteGeom_ = true;
236  return outputFile;
237 }
238 
239 
240 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
241 
242 template<class Type>
243 Foam::fileName Foam::surfaceWriters::x3dWriter::writeTemplate
244 (
245  const word& fieldName,
246  const Field<Type>& localValues
247 )
248 {
249  if (!colourTablePtr_)
250  {
251  // Write geometry only if there are no colours to use
253  << "No output colours set" << endl;
254 
255  return this->write();
256  }
257 
258  checkOpen();
259 
260  // Field: rootdir/<TIME>/<field>_surfaceName.x3d
261 
262  fileName outputFile = outputPath_.path();
263  if (useTimeDir() && !timeName().empty())
264  {
265  // Splice in time-directory
266  outputFile /= timeName();
267  }
268 
269  // Append <field>_surfaceName.x3d
270  outputFile /= fieldName + '_' + outputPath_.name();
271  outputFile.ext("x3d");
272 
273  // Implicit geometry merge()
274  tmp<Field<Type>> tfield = adjustField(fieldName, mergeField(localValues));
275 
276  if (verbose_)
277  {
278  Info<< " to " << outputFile << endl;
279  }
280 
281 
282  // const meshedSurf& surf = surface();
283  const meshedSurfRef& surf = adjustSurface();
284 
285  if (UPstream::master() || !parallel_)
286  {
287  const auto& values = tfield();
288 
289  scalarMinMax range(range_);
290 
291  if (!range.good())
292  {
294 
295  if (equal(range.mag(), 0))
296  {
297  range.add(range.centre());
298  }
299  }
300 
301  // Slight rounding
302  range.min() -= VSMALL;
303  range.max() += VSMALL;
304 
305  if (!isDir(outputFile.path()))
306  {
307  mkDir(outputFile.path());
308  }
309 
310  OFstream os(outputFile, streamOpt_);
311 
312  writeHeader(os);
313  beginGroup(os);
314  writeAppearance(os);
315 
316  // For point field: "colorPerVetex=true"
317  os << " <IndexedFaceSet"
318  << " colorPerVertex='" << Switch(this->isPointData()) << "'"
319  << " coordIndex='" << nl;
320 
321  for (const auto& f : surf.faces())
322  {
323  for (const label vrti : f)
324  {
325  os << vrti << ' ';
326  }
327  os << "-1\n";
328  }
329  os << "'";
330 
331  // Colour indices for face fields
332  if (!this->isPointData())
333  {
334  const label nFaces = surf.faces().size();
335 
336  os << " colorIndex='";
337 
338  for (label i=0; i < nFaces; ++i)
339  {
340  os << i << ' ';
341  }
342  os << "'";
343  }
344 
345  os << " >\n"; // IndexedFaceSet
346 
347  writePoints(os, surf.points());
348 
349  os << "<Color color='" << nl;
350 
351  // writeColours(os, values, range, colorBar);
352 
353  for (const Type& val : values)
354  {
355  const scalar x = rangex(range, val);
356  vector rgb = colourTablePtr_->value(x);
357  printColour(os, rgb);
358  }
359 
360  os << "' />" << nl; // Color
361 
362  os <<
363  " </IndexedFaceSet>\n";
364 
365  endGroup(os);
366  writeFooter(os);
367  }
368 
369  wroteGeom_ = true;
370  return outputFile;
371 }
372 
373 
374 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
375 
376 // Field writing methods
378 
379 
380 // ************************************************************************* //
static void printColour(Ostream &os, const vector &rgb)
virtual const pointField & points() const
The points used for the surface.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
A class for handling file names.
Definition: fileName.H:72
MinMax< scalar > scalarMinMax
A scalar min/max range.
Definition: MinMax.H:97
static const Enum< predefinedType > predefinedNames
Enumeration names for predefinedType.
Definition: colourTable.H:113
static void writeHeader(Ostream &os, const word &fieldName)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
bool equal(const T &a, const T &b)
Compare two values for equality.
Definition: label.H:164
virtual void open(const fileName &outputPath)
Open for output on specified path, using existing surface.
Output to file stream, using an OSstream.
Definition: OFstream.H:49
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
defineSurfaceWriterWriteFields(Foam::surfaceWriters::x3dWriter)
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, any/none. Also accepts 0/1 as a string and shortcuts t/f, y/n.
Definition: Switch.H:77
scalar srange01(const scalarMinMax &range, scalar x)
A (0-1) range for colouring.
A simple container for options an IOstream can normally have.
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:169
word ext() const
Return file name extension (part after last .)
Definition: fileNameI.H:211
Macros for easy insertion into run-time selection tables.
scalar range
bool good() const
Range is non-inverted.
Definition: MinMaxI.H:165
Abstract definition of a meshed surface defined by faces and points.
Definition: meshedSurf.H:43
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
word timeName
Definition: getTimeIndex.H:3
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
const pointField & points
Implements a meshed surface by referencing another meshed surface or faces/points components...
Definition: meshedSurfRef.H:47
A class for handling words, derived from Foam::string.
Definition: word.H:63
virtual fileName write()
Write surface geometry to file.
Vector< scalar > vector
Definition: vector.H:57
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
virtual const faceList & faces() const
The faces used for the surface.
OBJstream os(runTime.globalPath()/outputName)
A proxy for writing MeshedSurface, UnsortedMeshedSurface and surfMesh to various file formats...
Definition: MeshedSurface.H:75
labelList f(nPoints)
A surfaceWriter for X3D files.
Convenience macros for instantiating surfaceWriter methods.
defineTypeName(abaqusWriter)
dimensioned< scalarMinMax > minMaxMag(const DimensionedField< Type, GeoMesh > &f1)
#define WarningInFunction
Report a warning using Foam::Warning.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
messageStream Info
Information stream (stdout output on master, null elsewhere)
Base class for surface writers.
bool verbose_
Additional output verbosity.
A class for managing temporary objects.
Definition: HashPtrTable.H:50
addToRunTimeSelectionTable(surfaceWriter, abaqusWriter, word)
Namespace for OpenFOAM.
static const colourTable * ptr(const word &tableName)
Look up pointer to colourTable by name, or nullptr on failure.
Definition: colourTables.C:81
static scalar rangex(const scalarMinMax &range, const Type &val)
A (0-1) range for colouring.