diff --git a/applications/test/colourTables/Make/files b/applications/test/colourTables/Make/files
new file mode 100644
index 0000000000..4ab74f8a9d
--- /dev/null
+++ b/applications/test/colourTables/Make/files
@@ -0,0 +1,3 @@
+Test-colourTables.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-colourTables
diff --git a/applications/test/colourTables/Make/options b/applications/test/colourTables/Make/options
new file mode 100644
index 0000000000..7ce182425d
--- /dev/null
+++ b/applications/test/colourTables/Make/options
@@ -0,0 +1,5 @@
+EXE_INC = \
+ -I$(LIB_SRC)/fileFormats/lnInclude
+
+EXE_LIBS = \
+ -lfileFormats
diff --git a/applications/test/colourTables/Test-colourTables.C b/applications/test/colourTables/Test-colourTables.C
new file mode 100644
index 0000000000..4bb53ceabd
--- /dev/null
+++ b/applications/test/colourTables/Test-colourTables.C
@@ -0,0 +1,66 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "colourTable.H"
+#include "IOstreams.H"
+
+using namespace Foam;
+
+void dumpTable(const colourTable& tbl, const label n=128)
+{
+ Info<< tbl.table(n) << nl;
+}
+
+
+void dumpTable(const colourTable* tbl, const label n=128)
+{
+ if (tbl)
+ {
+ Info<< tbl->table(n) << nl;
+ }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main()
+{
+ // dumpTable(colourTable::ptr(colourTable::RAINBOW));
+ dumpTable(colourTable::ptr(colourTable::COOL_WARM));
+
+// forAllConstIters(colourTable::tables(), iter)
+// {
+// Info<< nl << iter.key() << nl;
+// dumpTable(iter.val());
+// }
+
+ Info<< "\nDone\n";
+
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/etc/colourTables b/etc/colourTables
new file mode 100644
index 0000000000..8466eab299
--- /dev/null
+++ b/etc/colourTables
@@ -0,0 +1,96 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| ========= | |
+| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
+| \\ / O peration | Version: v1812 |
+| \\ / A nd | Web: www.OpenFOAM.com |
+| \\/ M anipulation | |
+\*---------------------------------------------------------------------------*/
+
+// An OpenFOAM dictionary of colourTables.
+// The names should match those in the colourTables class.
+
+6
+(
+
+coolToWarm
+{
+ // ParaView: "Cool To Warm"
+ interpolate diverging;
+
+ table
+ (
+ ( 0.0 ( 0.231372 0.298039 0.752941 ) )
+ ( 0.5 ( 0.865003 0.865003 0.865003 ) )
+ ( 1.0 ( 0.705882 0.0156863 0.14902 ) )
+ );
+}
+
+coldAndHot
+{
+ // ParaView : "Cold and Hot"
+ interpolate diverging;
+
+ table
+ (
+ ( 0 ( 0 1 1 ) )
+ ( 0.45 ( 0 0 1 ) )
+ ( 0.5 ( 0 0 0.5019608) )
+ ( 0.55 ( 1 0 0 ) )
+ ( 1 ( 1 1 0 ) )
+ );
+}
+
+
+fire
+{
+ // ParaView: Black-Body Radiation
+ interpolate rbg;
+
+ table
+ (
+ ( 0 ( 0 0 0 ) )
+ ( 0.4 ( 0.901961 0 0 ) )
+ ( 0.8 ( 0.901961 0.901961 0 ) )
+ ( 1 ( 1 1 1 ) )
+ );
+}
+
+rainbow
+{
+ interpolate hsv;
+
+ table
+ (
+ ( 0 ( 0 0 1 ) )
+ ( 0.5 ( 0 1 0 ) )
+ ( 1 ( 1 0 0 ) )
+ );
+}
+
+greyscale
+{
+ // ParaView: grayscale
+ interpolate rbg;
+
+ table
+ (
+ ( 0 ( 0 0 0 ) )
+ ( 1 ( 1 1 1 ) )
+ );
+}
+
+xray
+{
+ // ParaView: "X ray"
+ interpolate rbg;
+
+ table
+ (
+ ( 0 ( 1 1 1 ) )
+ ( 1 ( 0 0 0 ) )
+ );
+}
+
+)
+
+// ************************************************************************* //
diff --git a/src/fileFormats/Make/files b/src/fileFormats/Make/files
index 3bf374c8ff..103b0235a6 100644
--- a/src/fileFormats/Make/files
+++ b/src/fileFormats/Make/files
@@ -1,3 +1,7 @@
+colours/colourTable.C
+colours/colourTables.C
+colours/colourTools.C
+
ensight/file/ensightCase.C
ensight/file/ensightCaseOptions.C
ensight/file/ensightFile.C
diff --git a/src/fileFormats/colours/colourTable.C b/src/fileFormats/colours/colourTable.C
new file mode 100644
index 0000000000..6ddd674411
--- /dev/null
+++ b/src/fileFormats/colours/colourTable.C
@@ -0,0 +1,182 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "colourTable.H"
+#include "colourTools.H"
+#include "ListOps.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::Enum
+<
+ Foam::colourTable::interpolationType
+>
+Foam::colourTable::interpolationTypeNames
+({
+ { interpolationType::RGB, "rgb" },
+ { interpolationType::HSV, "hsv" },
+ { interpolationType::DIVERGING, "diverging" },
+});
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::colourTable::colourTable
+(
+ const List>& values,
+ const interpolationType interp
+)
+:
+ table_(values),
+ interp_(interp)
+{}
+
+
+Foam::colourTable::colourTable
+(
+ List>&& values,
+ const interpolationType interp
+)
+:
+ table_(std::move(values)),
+ interp_(interp)
+{}
+
+
+Foam::colourTable::colourTable
+(
+ const dictionary& dict,
+ const interpolationType interp
+)
+:
+ table_(),
+ interp_(interp)
+{
+ dict.readEntry("table", table_);
+ interpolationTypeNames.readIfPresent("interpolate", dict, interp_);
+}
+
+
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+Foam::autoPtr Foam::colourTable::New(Istream& is)
+{
+ return autoPtr::New(dictionary(is));
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+Foam::vector Foam::colourTable::value(const scalar x) const
+{
+ if (x <= 0)
+ {
+ return table_.first().second();
+ }
+
+ if (x >= 1)
+ {
+ return table_.last().second();
+ }
+
+
+ label idx = findLower
+ (
+ table_, x, 0,
+ [](const pair_type& pr, const scalar& val)
+ {
+ // Test first element
+ return (pr.first() <= val);
+ }
+ );
+
+ if (idx == -1)
+ {
+ // Use first element only
+ return table_.first().second();
+ }
+ else if (idx == table_.size()-1)
+ {
+ // Use last element only
+ return table_.last().second();
+ }
+
+ const scalar t0 = table_[idx].first();
+ const scalar t1 = table_[idx+1].first();
+
+ const scalar s = (x - t0)/(t1 - t0);
+
+ const vector& rgb0 = table_[idx].second();
+ const vector& rgb1 = table_[idx+1].second();
+
+ if (interp_ == DIVERGING)
+ {
+ return colourTools::interpolateDiverging(s, rgb0, rgb1);
+ }
+ else if (interp_ == HSV)
+ {
+ return colourTools::interpolateHSV(s, rgb0, rgb1);
+ }
+
+ return colourTools::interpolateRGB(s, rgb0, rgb1);
+}
+
+
+Foam::List>
+Foam::colourTable::table(const label nColours) const
+{
+ List> lut(nColours);
+
+ for (label i=0; i < nColours; ++i)
+ {
+ const scalar x = scalar(i)/scalar(nColours-1);
+
+ lut[i] = pair_type(x, value(x));
+ }
+
+ return lut;
+}
+
+
+Foam::Ostream& Foam::colourTable::writeDict(Ostream& os) const
+{
+ os.beginBlock();
+ os.writeEntry("interpolate", interpolationTypeNames[interp_]);
+ os.writeEntry("table", table_);
+ os.endBlock();
+
+ return os;
+}
+
+
+Foam::Ostream& Foam::operator<<(Ostream& os, const colourTable& tbl)
+{
+ tbl.writeDict(os);
+
+ return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/colours/colourTable.H b/src/fileFormats/colours/colourTable.H
new file mode 100644
index 0000000000..e92d76f3e1
--- /dev/null
+++ b/src/fileFormats/colours/colourTable.H
@@ -0,0 +1,207 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Class
+ Foam::colourTable
+
+Description
+ Base class for generating a colour table from node points.
+
+ Dictionary definition
+ \table
+ Property | Description | Required | Default
+ interpolate | rgb/hsv/diverging | no | rgb
+ table | Node points for the colour table | yes |
+ \endtable
+
+Predefined colour tables (in "etc/colourTables") include
+"coolToWarm", "coldAndHot", "fire", "rainbow", "greyscale", "xray".
+
+SourceFiles
+ colourTable.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef colourTable_H
+#define colourTable_H
+
+#include "Enum.H"
+#include "List.H"
+#include "Tuple2.H"
+#include "vector.H"
+#include "HashPtrTable.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+ Class colourTable Declaration
+\*---------------------------------------------------------------------------*/
+
+class colourTable
+{
+public:
+
+ //- Internal interpolation type
+ enum interpolationType
+ {
+ RGB,
+ HSV,
+ DIVERGING
+ };
+
+ //- Enumeration of commonly used colour tables.
+ // The indices must match those in "etc/colourTables"
+ enum predefinedType
+ {
+ COOL_WARM, //!< "coolToWarm"
+ COLD_HOT, //!< "coldAndHot"
+ FIRE, //!< "fire" - ParaView "Black-Body Radiation"
+ RAINBOW, //!< "rainbow"
+ GREYSCALE, //!< greyscale - ParaView "Grayscale"
+ XRAY //!< "xray" - ParaView "X Ray"
+ };
+
+
+ //- Enumeration names for interpolationType
+ static const Enum interpolationTypeNames;
+
+ //- Enumeration names for predefinedType
+ static const Enum predefinedNames;
+
+ //- The data lookup type
+ typedef Tuple2 pair_type;
+
+
+ // Lookup Colour Tables
+
+ //- Look up pointer to colourTable by name, or nullptr on failure.
+ static const colourTable* ptr(const word& tableName);
+
+ //- Look up pointer to colourTable by type, or nullptr on failure.
+ static const colourTable* ptr(const predefinedType tbl);
+
+ //- Look up pointer to colourTable by name. Fatal on failure
+ static const colourTable& ref(const word& tableName);
+
+ //- Look up pointer to colourTable by type. Fatal on failure
+ static const colourTable& ref(const predefinedType tbl);
+
+
+private:
+
+ // Private Static Data
+
+ //- Predefined tables
+ static HashPtrTable tables_;
+
+
+ // Private Data
+
+ //- The table control points
+ List table_;
+
+ //- Interpolator type
+ interpolationType interp_;
+
+
+ // Private Member Functions
+
+ //- Construct from central "etc/colourTables" file.
+ static void constructTables();
+
+
+public:
+
+ // Constructors
+
+ //- Copy construct from table values
+ explicit colourTable
+ (
+ const List>& values,
+ const interpolationType interp = interpolationType::RGB
+ );
+
+ //- Copy construct from table values
+ explicit colourTable
+ (
+ List>&& values,
+ const interpolationType interp = interpolationType::RGB
+ );
+
+ //- Read construct from dictionary
+ explicit colourTable
+ (
+ const dictionary& dict,
+ const interpolationType interp = interpolationType::RGB
+ );
+
+
+ // Selectors
+
+ //- Read as dictionary content
+ static autoPtr New(Istream& is);
+
+
+ //- Destructor
+ virtual ~colourTable() = default;
+
+
+ // Member Functions
+
+ // Access
+
+ //- Predefined tables
+ static const HashPtrTable& tables();
+
+ //- Return the colour at x (within 0-1 range)
+ vector value(const scalar x) const;
+
+ //- Return a discrete lookup table of colours
+ List> table(const label nColours) const;
+
+
+ // IO
+
+ //- Write as dictionary format
+ Ostream& writeDict(Ostream& os) const;
+};
+
+
+//- Write as dictionary format
+Ostream& operator<<(Ostream& os, const colourTable& tbl);
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/fileFormats/colours/colourTables.C b/src/fileFormats/colours/colourTables.C
new file mode 100644
index 0000000000..e0679ec140
--- /dev/null
+++ b/src/fileFormats/colours/colourTables.C
@@ -0,0 +1,132 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "colourTable.H"
+#include "etcFiles.H"
+#include "IFstream.H"
+#include "HashSet.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+Foam::HashPtrTable Foam::colourTable::tables_;
+
+
+
+const Foam::Enum
+<
+ Foam::colourTable::predefinedType
+>
+Foam::colourTable::predefinedNames
+({
+ { predefinedType::COOL_WARM, "coolToWarm" },
+ { predefinedType::COLD_HOT, "coldAndHot" },
+ { predefinedType::FIRE, "fire" },
+ { predefinedType::RAINBOW, "rainbow" },
+ { predefinedType::GREYSCALE, "greyscale" },
+ { predefinedType::XRAY, "xray" },
+});
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+void Foam::colourTable::constructTables()
+{
+ if (tables_.size())
+ {
+ FatalErrorInFunction
+ << "attempt to re-construct colourTables when they already exist"
+ << exit(FatalError);
+ }
+
+ IFstream is(findEtcFile("colourTables", true)); // Mandatory file
+
+ HashPtrTable newEntries(is);
+ tables_.swap(newEntries);
+
+ Info<< "loaded " << tables_.sortedToc()
+ << " from etc/colourTable" << endl;
+
+ Info<< "== " << tables_ << nl;
+}
+
+
+const Foam::HashPtrTable& Foam::colourTable::tables()
+{
+ if (tables_.empty())
+ {
+ constructTables();
+ }
+
+ return tables_;
+}
+
+
+const Foam::colourTable* Foam::colourTable::ptr(const word& tableName)
+{
+ if (tables_.empty())
+ {
+ constructTables();
+ }
+
+ const auto iter = tables_.cfind(tableName);
+
+ if (iter.good())
+ {
+ const colourTable* p = iter.val();
+ return p;
+ }
+
+ return nullptr;
+}
+
+
+const Foam::colourTable* Foam::colourTable::ptr(const predefinedType tbl)
+{
+ return ptr(predefinedNames[tbl]);
+}
+
+
+const Foam::colourTable& Foam::colourTable::ref(const word& tableName)
+{
+ const colourTable* p = ptr(tableName);
+
+ if (!p)
+ {
+ FatalErrorInFunction
+ << "No such colourTable: " << tableName
+ << exit(FatalError);
+ }
+
+ return *p;
+}
+
+
+const Foam::colourTable& Foam::colourTable::ref(const predefinedType tbl)
+{
+ return ref(predefinedNames[tbl]);
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/colours/colourTools.C b/src/fileFormats/colours/colourTools.C
new file mode 100644
index 0000000000..db27ecaa96
--- /dev/null
+++ b/src/fileFormats/colours/colourTools.C
@@ -0,0 +1,501 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Note
+ Some implementation details from VTK vtkColorTransferFunction.cxx
+ vtkMath.cxx
+
+\*---------------------------------------------------------------------------*/
+
+#include "colourTools.H"
+#include "mathematicalConstants.H"
+
+using namespace Foam::constant;
+
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+static constexpr scalar oneThird = 1.0 / 3.0;
+static constexpr scalar oneSixth = 1.0 / 6.0;
+static constexpr scalar twoThird = 2.0 / 3.0;
+static constexpr scalar fiveSixth = 5.0 / 6.0;
+
+
+// Compute HSV from RGB
+static inline void RGB_to_HSV
+(
+ const scalar r, const scalar g, const scalar b,
+ scalar& h, scalar& s, scalar& v
+)
+{
+ scalar cmin = r, cmax = r;
+
+ if (g > cmax)
+ {
+ cmax = g;
+ }
+ else if (g < cmin)
+ {
+ cmin = g;
+ }
+ if (b > cmax)
+ {
+ cmax = b;
+ }
+ else if (b < cmin)
+ {
+ cmin = b;
+ }
+
+ v = cmax;
+ s = (v > 0.0) ? ((cmax - cmin) / cmax) : 0.0;
+
+ if (s > 0.0)
+ {
+ if (r == cmax)
+ {
+ h = oneSixth * (g - b) / (cmax - cmin);
+ }
+ else if (g == cmax)
+ {
+ h = oneThird + oneSixth * (b - r) / (cmax - cmin);
+ }
+ else
+ {
+ h = twoThird + oneSixth * (r - g) / (cmax - cmin);
+ }
+
+ if (h < 0.0)
+ {
+ h += 1.0;
+ }
+ }
+ else
+ {
+ h = 0.0;
+ }
+}
+
+
+// Compute HSV to RGB
+static inline void HSV_to_RGB
+(
+ const scalar h, const scalar s, const scalar v,
+ scalar& r, scalar& g, scalar& b
+)
+{
+ if (h > oneSixth && h <= oneThird)
+ {
+ // green/red
+ g = 1.0;
+ r = (oneThird - h) / oneSixth;
+ b = 0.0;
+ }
+ else if (h > oneThird && h <= 0.5)
+ {
+ // green/blue
+ g = 1.0;
+ b = (h - oneThird) / oneSixth;
+ r = 0.0;
+ }
+ else if (h > 0.5 && h <= twoThird)
+ {
+ // blue/green
+ b = 1.0;
+ g = (twoThird - h) / oneSixth;
+ r = 0.0;
+ }
+ else if (h > twoThird && h <= fiveSixth)
+ {
+ // blue/red
+ b = 1.0;
+ r = (h - twoThird) / oneSixth;
+ g = 0.0;
+ }
+ else if (h > fiveSixth && h <= 1.0)
+ {
+ // red/blue
+ r = 1.0;
+ b = (1.0 - h) / oneSixth;
+ g = 0.0;
+ }
+ else
+ {
+ // red/green
+ r = 1.0;
+ g = h / oneSixth;
+ b = 0.0;
+ }
+
+ // Add saturation
+ r = (s * r + (1.0 - s));
+ g = (s * g + (1.0 - s));
+ b = (s * b + (1.0 - s));
+
+ r *= v;
+ g *= v;
+ b *= v;
+}
+
+
+// Intermediate calculation to XYZ
+static inline scalar to_XYZ(scalar val)
+{
+ const scalar p3 = pow3(val);
+ return (p3 > 0.008856 ? p3 : (val - 16.0 / 116.0) / 7.787);
+}
+
+
+// Intermediate calculation from XYZ
+static inline scalar from_XYZ(scalar val)
+{
+ return (val > 0.008856) ? cbrt(val) : (7.787 * val) + (16.0 / 116.0);
+}
+
+// Observer= 2 deg Illuminant= D65
+static constexpr scalar ref_X = 0.9505;
+static constexpr scalar ref_Y = 1.000;
+static constexpr scalar ref_Z = 1.089;
+
+static inline void LAB_to_XYZ
+(
+ const scalar L, const scalar a, const scalar b,
+ scalar& x, scalar& y, scalar& z
+)
+{
+ const scalar var_Y = (L + 16.0) / 116.0;
+ const scalar var_X = a / 500 + var_Y;
+ const scalar var_Z = var_Y - b / 200;
+
+ x = ref_X * to_XYZ(var_X);
+ y = ref_Y * to_XYZ(var_Y);
+ z = ref_Z * to_XYZ(var_Z);
+}
+
+
+static inline void XYZ_to_LAB
+(
+ const scalar x, const scalar y, const scalar z,
+ scalar& L, scalar& a, scalar& b
+)
+{
+ const scalar var_X = from_XYZ(x / ref_X);
+ const scalar var_Y = from_XYZ(y / ref_Y);
+ const scalar var_Z = from_XYZ(z / ref_Z);
+
+ L = (116 * var_Y) - 16;
+ a = 500 * (var_X - var_Y);
+ b = 200 * (var_Y - var_Z);
+}
+
+
+
+// "Gamma correction" specified by the sRGB color space.
+
+static inline scalar gamma_from_xyz(const scalar val)
+{
+ return
+ (
+ val > 0.0031308
+ ? (1.055 * (pow(val, 1.0/2.4)) - 0.055)
+ : 12.92 * val
+ );
+}
+
+
+static inline scalar gamma_to_xyz(const scalar val)
+{
+ return
+ (
+ val > 0.04045
+ ? (pow((val + 0.055) / 1.055, 2.4))
+ : val / 12.92
+ );
+}
+
+
+
+static inline void XYZ_to_RGB
+(
+ const scalar x, const scalar y, const scalar z,
+ scalar& r, scalar& g, scalar& b
+)
+{
+ r = gamma_from_xyz(x * 3.2406 + y * -1.5372 + z * -0.4986);
+ g = gamma_from_xyz(x * -0.9689 + y * 1.8758 + z * 0.0415);
+ b = gamma_from_xyz(x * 0.0557 + y * -0.2040 + z * 1.0570);
+
+ // Clip colour range
+ scalar cmax = r;
+ if (cmax < g) cmax = g;
+ if (cmax < b) cmax = b;
+ if (cmax > 1.0)
+ {
+ r /= cmax;
+ g /= cmax;
+ b /= cmax;
+ }
+
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+}
+
+
+static inline void RGB_to_XYZ
+(
+ scalar r, scalar g, scalar b,
+ scalar& x, scalar& y, scalar& z
+)
+{
+ r = gamma_to_xyz(r);
+ g = gamma_to_xyz(g);
+ b = gamma_to_xyz(b);
+
+ x = r * 0.4124 + g * 0.3576 + b * 0.1805;
+ y = r * 0.2126 + g * 0.7152 + b * 0.0722;
+ z = r * 0.0193 + g * 0.1192 + b * 0.9505;
+}
+
+
+
+//- Convert to special polar version of CIELAB
+// (for creating continuous diverging color maps).
+inline void labToMsh(const vector& lab, vector& msh)
+{
+ const scalar& L = lab[0];
+ const scalar& a = lab[1];
+ const scalar& b = lab[2];
+
+ msh[0] = sqrt(L*L + a*a + b*b);
+ msh[1] = (msh[0] > 0.001) ? acos(L / msh[0]) : 0.0;
+ msh[2] = (msh[1] > 0.001) ? atan2(b,a) : 0.0;
+}
+
+
+//- Convert from special polar version of CIELAB
+inline void mshToLab(const vector& msh, vector& lab)
+{
+ lab[0] = msh[0]*cos(msh[1]);
+ lab[1] = msh[0]*sin(msh[1])*cos(msh[2]);
+ lab[2] = msh[0]*sin(msh[1])*sin(msh[2]);
+}
+
+
+// Return the smallest angle between the two
+static inline scalar angleDiff(scalar angle1, scalar angle2)
+{
+ scalar adiff = angle1 - angle1;
+ if (adiff < 0.0) adiff = -adiff;
+
+ while (adiff >= mathematical::twoPi) adiff -= mathematical::twoPi;
+ if (adiff > mathematical::pi) adiff = (mathematical::twoPi - adiff);
+ return adiff;
+}
+
+
+// For the case when interpolating from a saturated color to an unsaturated
+// color, find a hue for the unsaturated color that makes sense.
+static inline scalar adjustHue(const vector& msh, scalar unsatM)
+{
+ if (msh[0] >= unsatM - 0.1)
+ {
+ // The best we can do is hold hue constant.
+ return msh[2];
+ }
+
+ // This equation is designed to make the perceptual change of the
+ // interpolation to be close to constant.
+ const scalar hueSpin =
+ msh[1]*sqrt(unsatM*unsatM - msh[0]*msh[0]) / (msh[0]*sin(msh[1]));
+
+ // Spin hue away from 0 except in purple hues.
+ if (msh[2] > -0.3*mathematical::pi)
+ {
+ return msh[2] + hueSpin;
+ }
+ else
+ {
+ return msh[2] - hueSpin;
+ }
+}
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+void Foam::colourTools::rgbToHsv(const vector& rgb, vector& hsv)
+{
+ RGB_to_HSV(rgb[0], rgb[1], rgb[2], hsv[0], hsv[1], hsv[2]);
+}
+
+void Foam::colourTools::hsvToRgb(const vector& hsv, vector& rgb)
+{
+ HSV_to_RGB(hsv[0], hsv[1], hsv[2], rgb[0], rgb[1], rgb[2]);
+}
+
+
+void Foam::colourTools::rgbToXyz(const vector& rgb, vector& xyz)
+{
+ RGB_to_XYZ(rgb[0], rgb[1], rgb[2], xyz[0], xyz[1], xyz[2]);
+}
+
+void Foam::colourTools::xyzToRgb(const vector& xyz, vector& rgb)
+{
+ XYZ_to_RGB(xyz[0], xyz[1], xyz[2], rgb[0], rgb[1], rgb[2]);
+}
+
+
+void Foam::colourTools::labToXyz(const vector& lab, vector& xyz)
+{
+ LAB_to_XYZ(lab[0], lab[1], lab[2], xyz[0], xyz[1], xyz[2]);
+}
+
+
+void Foam::colourTools::xyzToLab(const vector& xyz, vector& lab)
+{
+ XYZ_to_LAB(xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
+}
+
+
+void Foam::colourTools::rgbToLab(const vector& rgb, vector& lab)
+{
+ vector xyz;
+ RGB_to_XYZ(rgb[0], rgb[1], rgb[2], xyz[0], xyz[1], xyz[2]);
+ XYZ_to_LAB(xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
+}
+
+
+void Foam::colourTools::labToRgb(const vector& lab, vector& rgb)
+{
+ vector xyz;
+ labToXyz(lab, xyz);
+ xyzToRgb(xyz, rgb);
+}
+
+
+void Foam::colourTools::interpolateDiverging
+(
+ scalar s,
+ const vector& rgb1,
+ const vector& rgb2,
+ vector& result
+)
+{
+ vector lab1, lab2;
+ rgbToLab(rgb1, lab1);
+ rgbToLab(rgb2, lab2);
+
+ vector msh1, msh2;
+ labToMsh(lab1, msh1);
+ labToMsh(lab2, msh2);
+
+ // If the endpoints are distinct saturated colors,
+ // then place white in between them.
+ if
+ (
+ msh1[1] > 0.05
+ && msh2[1] > 0.05
+ && angleDiff(msh1[2], msh2[2]) > mathematical::pi/3.0
+ )
+ {
+ // Insert the white midpoint by setting one end to white and
+ // adjusting the scalar value.
+
+ scalar Mmid = std::max(msh1[0], msh2[0]);
+ Mmid = std::max(88.0, Mmid);
+ if (s < 0.5)
+ {
+ msh2[0] = Mmid; msh2[1] = 0; msh2[2] = 0;
+ s = 2.0*s;
+ }
+ else
+ {
+ msh1[0] = Mmid; msh1[1] = 0; msh1[2] = 0;
+ s = 2.0*s - 1.0;
+ }
+ }
+
+ // If one color has no saturation, then its hue value is invalid.
+ // In this case, we want to set it to something logical so the
+ // interpolation of hue makes sense.
+ if ((msh1[1] < 0.05) && (msh2[1] > 0.05))
+ {
+ msh1[2] = adjustHue(msh2, msh1[0]);
+ }
+ else if ((msh2[1] < 0.05) && (msh1[1] > 0.05))
+ {
+ msh2[2] = adjustHue(msh1, msh2[0]);
+ }
+
+ // Msh tmp
+ vector mshTmp((1-s)*msh1 + s*msh2);
+
+ // Convert back to RGB
+ vector lab;
+ mshToLab(mshTmp, lab);
+ labToRgb(lab, result);
+}
+
+
+void Foam::colourTools::interpolateHSV
+(
+ scalar s,
+ const vector& rgb1,
+ const vector& rgb2,
+ vector& result
+)
+{
+ vector hsv1, hsv2;
+ rgbToHsv(rgb1, hsv1);
+ rgbToHsv(rgb2, hsv2);
+
+ // Wrap HSV?
+ if (hsv1[0] - hsv2[0] > 0.5 || hsv2[0] - hsv1[0] > 0.5)
+ {
+ if (hsv1[0] > hsv2[0])
+ {
+ hsv1[0] -= 1.0;
+ }
+ else
+ {
+ hsv2[0] -= 1.0;
+ }
+ }
+
+ vector hsvTmp((1-s)*hsv1 + s*hsv2);
+
+ if (hsvTmp[0] < 0.0)
+ {
+ hsvTmp[0] += 1.0;
+ }
+
+ // Convert back to RGB
+ hsvToRgb(hsvTmp, result);
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/colours/colourTools.H b/src/fileFormats/colours/colourTools.H
new file mode 100644
index 0000000000..e2040dca50
--- /dev/null
+++ b/src/fileFormats/colours/colourTools.H
@@ -0,0 +1,214 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Namespace
+ Foam::colourTools
+
+Description
+ Utility methods for colours and colour spaces
+
+SourceFiles
+ colourTools.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef colourTools_H
+#define colourTools_H
+
+#include "vector.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace colourTools
+{
+
+/*---------------------------------------------------------------------------*\
+ Namespace colourTools
+\*---------------------------------------------------------------------------*/
+
+//- Convert RGB to HSV
+void rgbToHsv(const vector& rgb, vector& hsv);
+
+//- Convert RGB to HSV
+inline vector rgbToHsv(const vector& rgb)
+{
+ vector hsv;
+ rgbToHsv(rgb, hsv);
+ return hsv;
+}
+
+
+//- Convert HSV to RGB
+void hsvToRgb(const vector& hsv, vector& rgb);
+
+//- Convert HSV to RGB
+inline vector hsvToRgb(const vector& hsv)
+{
+ vector rgb;
+ hsvToRgb(hsv, rgb);
+ return rgb;
+}
+
+
+//- Convert RGB to XYZ
+void rgbToXyz(const vector& rgb, vector& xyz);
+
+//- Convert RGB to XYZ
+inline vector rgbToXyz(const vector& rgb)
+{
+ vector xyz;
+ rgbToXyz(rgb, xyz);
+ return xyz;
+}
+
+//- Convert XYZ to RGB
+void xyzToRgb(const vector& xyz, vector& rgb);
+
+//- Convert XYZ to RGB
+inline vector xyzToRgb(const vector& xyz)
+{
+ vector rgb;
+ xyzToRgb(xyz, rgb);
+ return rgb;
+}
+
+
+//- Convert LAB to XYZ
+void labToXyz(const vector& lab, vector& xyz);
+
+//- Convert LAB to XYZ
+inline vector labToXyz(const vector& lab)
+{
+ vector xyz;
+ labToXyz(lab, xyz);
+ return xyz;
+}
+
+
+//- Convert XYZ to LAB
+void xyzToLab(const vector& xyz, vector& lab);
+
+//- Convert XYZ to LAB
+inline vector xyzToLab(const vector& xyz)
+{
+ vector lab;
+ xyzToLab(xyz, lab);
+ return lab;
+}
+
+
+//- Convert RGB to LAB
+void rgbToLab(const vector& rgb, vector& lab);
+
+//- Convert RGB to LAB
+inline vector rgbToLab(const vector& rgb)
+{
+ vector lab;
+ rgbToLab(rgb, lab);
+ return lab;
+}
+
+
+//- Convert LAB to RGB
+void labToRgb(const vector& lab, vector& rgb);
+
+//- Convert LAB to RGB
+inline vector labToRgb(const vector& lab)
+{
+ vector rgb;
+ labToRgb(lab, rgb);
+ return rgb;
+}
+
+
+//- Interpolate RGB values with diverging color map
+void interpolateDiverging
+(
+ scalar s,
+ const vector& rgb1,
+ const vector& rgb2,
+ vector& result
+);
+
+//- Interpolate RGB values with diverging color map
+inline vector interpolateDiverging
+(
+ scalar s,
+ const vector& rgb1,
+ const vector& rgb2
+)
+{
+ vector result;
+ interpolateDiverging(s, rgb1, rgb2, result);
+ return result;
+}
+
+
+//- Interpolate RGB values in HSV colourspace
+void interpolateHSV
+(
+ scalar s,
+ const vector& rgb1,
+ const vector& rgb2,
+ vector& result
+);
+
+//- Interpolate RGB values in HSV colourspace
+inline vector interpolateHSV
+(
+ scalar s,
+ const vector& rgb1,
+ const vector& rgb2
+)
+{
+ vector result;
+ interpolateHSV(s, rgb1, rgb2, result);
+ return result;
+}
+
+
+//- Interpolate RGB values in RGB colourspace
+inline vector interpolateRGB
+(
+ scalar s,
+ const vector& rgb1,
+ const vector& rgb2
+)
+{
+ return ((1-s)*rgb1 + s*rgb2);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace colourTools
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/surfMesh/Make/files b/src/surfMesh/Make/files
index 4891715e49..d629b1ccd2 100644
--- a/src/surfMesh/Make/files
+++ b/src/surfMesh/Make/files
@@ -70,7 +70,7 @@ $(writers)/proxy/proxySurfaceWriter.C
$(writers)/raw/rawSurfaceWriter.C
$(writers)/starcd/starcdSurfaceWriter.C
$(writers)/vtk/vtkSurfaceWriter.C
-/* $(writers)/x3d/x3dSurfaceWriter.C */
+$(writers)/x3d/x3dSurfaceWriter.C
LIB = $(FOAM_LIBBIN)/libsurfMesh
diff --git a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C
index 66e2173719..75cbc22c1c 100644
--- a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C
+++ b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C
@@ -61,14 +61,9 @@ void Foam::fileFormats::X3DsurfaceFormat::write
}
writeHeader(os);
-
- os << "\n"
- "\n"
- " \n";
-
+ beginGroup(os);
writeAppearance(os);
-
// NOTE: we could provide an optimized IndexedTriangleSet output for
// triangulated surfaces too
@@ -108,21 +103,16 @@ void Foam::fileFormats::X3DsurfaceFormat::write
}
}
- os <<
- "' >\n"
- " \n";
- for (const point& p : pointLst)
- {
- os << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
- }
+ writePoints(os, pointLst);
os <<
- "' />\n" // end Coordinate
- " \n"
- " \n"
- " \n"
- "\n";
+ " \n";
+
+ endGroup(os);
+ writeFooter(os);
}
diff --git a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.C b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.C
index beb5bb1f1d..6b3caa6462 100644
--- a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.C
+++ b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.C
@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
- \\ / A nd |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
| Copyright (C) 2011-2016 OpenFOAM Foundation
@@ -26,7 +26,7 @@ License
\*---------------------------------------------------------------------------*/
#include "X3DsurfaceFormatCore.H"
-#include "clock.H"
+#include "Ostream.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
@@ -49,6 +49,38 @@ void Foam::fileFormats::X3DsurfaceFormatCore::writeHeader
}
+void Foam::fileFormats::X3DsurfaceFormatCore::writeFooter
+(
+ Ostream& os
+)
+{
+ os <<
+ "\n";
+}
+
+
+void Foam::fileFormats::X3DsurfaceFormatCore::beginGroup
+(
+ Ostream& os
+)
+{
+ os <<
+ "\n"
+ " \n";
+}
+
+
+void Foam::fileFormats::X3DsurfaceFormatCore::endGroup
+(
+ Ostream& os
+)
+{
+ os <<
+ " \n"
+ " \n";
+}
+
+
void Foam::fileFormats::X3DsurfaceFormatCore::writeAppearance
(
Ostream& os
@@ -57,13 +89,34 @@ void Foam::fileFormats::X3DsurfaceFormatCore::writeAppearance
os <<
" \n"
" \n" // end material
+ " ambientIntensity='0'"
+ " diffuseColor='1 1 1'" // Default: '0.8 0.8 0.8'
+ // Default: " emissiveColor='0 0 0'"
+ // Default: " specularColor='0 0 0'"
+ " shininess='0.8'" // Default: 0.2
+ " transparency='0'"
+ " />\n" // Material
" \n";
}
+void Foam::fileFormats::X3DsurfaceFormatCore::writePoints
+(
+ Ostream& os,
+ const UList& pts
+)
+{
+ os <<
+ " \n";
+}
+
+
// ************************************************************************* //
diff --git a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.H b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.H
index d777f076ac..dd7624f3a0 100644
--- a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.H
+++ b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.H
@@ -37,7 +37,7 @@ SourceFiles
#ifndef X3DsurfaceFormatCore_H
#define X3DsurfaceFormatCore_H
-#include "Ostream.H"
+#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -59,9 +59,20 @@ protected:
//- Write file header
static void writeHeader(Ostream& os);
+ //- Write file header
+ static void writeFooter(Ostream& os);
+
+ //- Begin Group/Shape node
+ static void beginGroup(Ostream& os);
+
+ //- End Group/Shape node
+ static void endGroup(Ostream& os);
+
//- Write appearance node
static void writeAppearance(Ostream& os);
+ //- Write points (Coordinate)
+ static void writePoints(Ostream& os, const UList& pts);
};
diff --git a/src/surfMesh/writers/x3d/x3dSurfaceWriter.C b/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
new file mode 100644
index 0000000000..534c744b25
--- /dev/null
+++ b/src/surfMesh/writers/x3d/x3dSurfaceWriter.C
@@ -0,0 +1,342 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+#include "x3dSurfaceWriter.H"
+#include "OFstream.H"
+#include "OSspecific.H"
+#include "MeshedSurfaceProxy.H"
+#include "surfaceWriterMethods.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace surfaceWriters
+{
+ defineTypeName(x3dWriter);
+ addToRunTimeSelectionTable(surfaceWriter, x3dWriter, word);
+ addToRunTimeSelectionTable(surfaceWriter, x3dWriter, wordDict);
+}
+}
+
+
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+//- A (0-1) range for colouring
+template
+static inline scalar rangex(const scalarMinMax& range, const Type& val)
+{
+ scalar x = Foam::mag(val);
+
+ return (x - range.min()) / (range.max() - range.min());
+}
+
+
+//- A (0-1) range for colouring
+template<>
+inline scalar rangex(const scalarMinMax& range, const scalar& val)
+{
+ scalar x = val;
+ return (x - range.min()) / (range.max() - range.min());
+}
+
+
+//- A (0-1) range for colouring
+template<>
+inline scalar rangex(const scalarMinMax& range, const label& val)
+{
+ scalar x = val;
+ return (x - range.min()) / (range.max() - range.min());
+}
+
+
+static inline void printColour(Ostream& os, const vector& rgb)
+{
+ os << rgb[0] << ' ' << rgb[1] << ' ' << rgb[2] << ',' << nl;
+}
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::surfaceWriters::x3dWriter::x3dWriter()
+:
+ surfaceWriter(),
+ range_(),
+ colourTablePtr_(nullptr)
+{}
+
+
+Foam::surfaceWriters::x3dWriter::x3dWriter
+(
+ const dictionary& options
+)
+:
+ surfaceWriter(options),
+ range_(),
+ colourTablePtr_(nullptr)
+{
+ verbose_ = true;
+
+ options.readIfPresent("range", range_);
+
+ word tableName;
+ if (options.readIfPresent("colourMap", tableName))
+ {
+ colourTablePtr_ = colourTable::ptr(tableName);
+ if (!colourTablePtr_)
+ {
+ WarningInFunction
+ << "No colourMap " << tableName << " using default" << nl;
+ }
+ }
+
+ if (!colourTablePtr_)
+ {
+ tableName = colourTable::predefinedNames[colourTable::COOL_WARM];
+ colourTablePtr_ = colourTable::ptr(colourTable::COOL_WARM);
+ }
+
+ if (verbose_)
+ {
+ Info<< "X3D with colourMap '" << tableName << "' and range ";
+
+ if (range_.valid())
+ {
+ Info<< range_;
+ }
+ else
+ {
+ Info<< "auto";
+ }
+ Info<< nl;
+ }
+}
+
+
+Foam::surfaceWriters::x3dWriter::x3dWriter
+(
+ const meshedSurf& surf,
+ const fileName& outputPath,
+ bool parallel,
+ const dictionary& options
+)
+:
+ x3dWriter(options)
+{
+ open(surf, outputPath, parallel);
+}
+
+
+Foam::surfaceWriters::x3dWriter::x3dWriter
+(
+ const pointField& points,
+ const faceList& faces,
+ const fileName& outputPath,
+ bool parallel,
+ const dictionary& options
+)
+:
+ x3dWriter(options)
+{
+ open(points, faces, outputPath, parallel);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+Foam::fileName Foam::surfaceWriters::x3dWriter::write()
+{
+ checkOpen();
+
+ // Geometry: rootdir/