diff --git a/applications/test/colourTables/Make/files b/applications/test/colourTables/Make/files new file mode 100644 index 0000000000000000000000000000000000000000..4ab74f8a9dae1a36e3ec49bbb04e2188ba177326 --- /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 0000000000000000000000000000000000000000..7ce182425d9bee4bef91ba2a36b6b8475fc1aeb2 --- /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 0000000000000000000000000000000000000000..4bb53ceabd0f5461a8a7382e43d27dbf87f2d912 --- /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 <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#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 0000000000000000000000000000000000000000..8466eab299e1d3234c6dfd0269e5237065a80b67 --- /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 3bf374c8ffcf803d826d8c2b3613c91505deb9e4..103b0235a6bc09449eab34f6889da45b3c7b9086 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 0000000000000000000000000000000000000000..6ddd674411f7313f94965c957cfb93c889a1f866 --- /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 <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#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<Tuple2<scalar, vector>>& values, + const interpolationType interp +) +: + table_(values), + interp_(interp) +{} + + +Foam::colourTable::colourTable +( + List<Tuple2<scalar, vector>>&& 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> Foam::colourTable::New(Istream& is) +{ + return autoPtr<colourTable>::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::Tuple2<Foam::scalar, Foam::vector>> +Foam::colourTable::table(const label nColours) const +{ + List<Tuple2<scalar, vector>> 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 0000000000000000000000000000000000000000..e92d76f3e115334ae522fc3d34c0e309b1076567 --- /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 <http://www.gnu.org/licenses/>. + +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<interpolationType> interpolationTypeNames; + + //- Enumeration names for predefinedType + static const Enum<predefinedType> predefinedNames; + + //- The data lookup type + typedef Tuple2<scalar, vector> 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<colourTable> tables_; + + + // Private Data + + //- The table control points + List<pair_type> 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<Tuple2<scalar, vector>>& values, + const interpolationType interp = interpolationType::RGB + ); + + //- Copy construct from table values + explicit colourTable + ( + List<Tuple2<scalar, vector>>&& 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<colourTable> New(Istream& is); + + + //- Destructor + virtual ~colourTable() = default; + + + // Member Functions + + // Access + + //- Predefined tables + static const HashPtrTable<colourTable>& tables(); + + //- Return the colour at x (within 0-1 range) + vector value(const scalar x) const; + + //- Return a discrete lookup table of colours + List<Tuple2<scalar, vector>> 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 0000000000000000000000000000000000000000..e0679ec140f0f1ed87531df73e6257c7cd0f6a16 --- /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 <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "colourTable.H" +#include "etcFiles.H" +#include "IFstream.H" +#include "HashSet.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +Foam::HashPtrTable<Foam::colourTable> 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<colourTable> newEntries(is); + tables_.swap(newEntries); + + Info<< "loaded " << tables_.sortedToc() + << " from etc/colourTable" << endl; + + Info<< "== " << tables_ << nl; +} + + +const Foam::HashPtrTable<Foam::colourTable>& 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 0000000000000000000000000000000000000000..db27ecaa963e94ae535c53adaeea5f5647ce7c55 --- /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 <http://www.gnu.org/licenses/>. + +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 0000000000000000000000000000000000000000..e2040dca50c196ec93ecc0d49671302f9a4e2f5e --- /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 <http://www.gnu.org/licenses/>. + +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 4891715e49de82e90f67fa0fd546e7fd6cf10c01..d629b1ccd2d9fc7ff01835e3651cebbd5bfe0513 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 99d975762538d92a22140b470044992cd7afa784..62caeba061c1154dc85f5a72efdc795faf3d4590 100644 --- a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C +++ b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormat.C @@ -61,14 +61,9 @@ void Foam::fileFormats::X3DsurfaceFormat<Face>::write } writeHeader(os); - - os << "\n" - "<Group>\n" - " <Shape>\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<Face>::write } } - os << - "' >\n" - " <Coordinate point='\n"; + os << + "' >\n"; - for (const point& p : pointLst) - { - os << p.x() << ' ' << p.y() << ' ' << p.z() << nl; - } + writePoints(os, pointLst); os << - "' />\n" // end Coordinate - " </IndexedFaceSet>\n" - " </Shape>\n" - " </Group>\n" - "</X3D>\n"; + " </IndexedFaceSet>\n"; + + endGroup(os); + writeFooter(os); } diff --git a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.C b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.C index 4bff32656e56c7b4084980aca8c278f47aa5e7f3..6d343377829baaa934cc5459f52d443aff52d81d 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 | Copyright (C) 2009-2010 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2009-2010, 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 << + "</X3D>\n"; +} + + +void Foam::fileFormats::X3DsurfaceFormatCore::beginGroup +( + Ostream& os +) +{ + os << + "<Group>\n" + " <Shape>\n"; +} + + +void Foam::fileFormats::X3DsurfaceFormatCore::endGroup +( + Ostream& os +) +{ + os << + " </Shape>\n" + " </Group>\n"; +} + + void Foam::fileFormats::X3DsurfaceFormatCore::writeAppearance ( Ostream& os @@ -57,13 +89,34 @@ void Foam::fileFormats::X3DsurfaceFormatCore::writeAppearance os << " <Appearance>\n" " <Material" - " diffuseColor='0.8 0.8 0.8'" - " specularColor='1.0 1.0 1.0'" - " shininess='0.5'" - " transparency='0.0'" - " />\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 " </Appearance>\n"; } +void Foam::fileFormats::X3DsurfaceFormatCore::writePoints +( + Ostream& os, + const UList<point>& pts +) +{ + os << + " <Coordinate point='\n"; + + for (const point& p : pts) + { + os << p.x() << ' ' << p.y() << ' ' << p.z() << ',' << nl; + } + + os << + "' />\n"; +} + + // ************************************************************************* // diff --git a/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.H b/src/surfMesh/surfaceFormats/x3d/X3DsurfaceFormatCore.H index b9fb256109bed0b24f0a2a2cf39de6208f4f92d2..d87332cf01662320eb8844f3f25509a11689e879 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<point>& pts); }; diff --git a/src/surfMesh/writers/x3d/x3dSurfaceWriter.C b/src/surfMesh/writers/x3d/x3dSurfaceWriter.C new file mode 100644 index 0000000000000000000000000000000000000000..534c744b252d90e32767db4ca3a384c4d475935a --- /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 <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#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<class Type> +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/<TIME>/surfaceName.x3d + + fileName outputFile = outputPath_; + if (useTimeDir() && !timeName().empty()) + { + // Splice in time-directory + outputFile = outputPath_.path() / timeName() / outputPath_.name(); + } + outputFile.ext("x3d"); + + if (verbose_) + { + Info<< "Writing geometry to " << outputFile << endl; + } + + const meshedSurf& surf = surface(); + + if (Pstream::master() || !parallel_) + { + if (!isDir(outputFile.path())) + { + mkDir(outputFile.path()); + } + + MeshedSurfaceProxy<face> + ( + surf.points(), + surf.faces() + ).write(outputFile, "x3d"); + } + + wroteGeom_ = true; + return outputFile; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +template<class Type> +Foam::fileName Foam::surfaceWriters::x3dWriter::writeTemplate +( + const word& fieldName, + const Field<Type>& localValues +) +{ + if (!colourTablePtr_) + { + // Write geometry only if there are no colours to use + WarningInFunction + << "No output colours set" << endl; + + return this->write(); + } + + checkOpen(); + + // Field: rootdir/<TIME>/<field>_surfaceName.x3d + + fileName outputFile = outputPath_.path(); + if (useTimeDir() && !timeName().empty()) + { + // Splice in time-directory + outputFile /= timeName(); + } + + // Append <field>_surfaceName.usr + outputFile /= fieldName + '_' + outputPath_.name(); + outputFile.ext("x3d"); + + if (verbose_) + { + Info<< "Writing field " << fieldName << " to " << outputFile << endl; + } + + const meshedSurf& surf = surface(); + + // geometry merge() implicit + tmp<Field<Type>> tfield = mergeField(localValues); + + if (Pstream::master() || !parallel_) + { + const auto& values = tfield(); + + scalarMinMax range(range_); + + if (!range.valid()) + { + range = minMaxMag(values); + } + + if (!isDir(outputFile.path())) + { + mkDir(outputFile.path()); + } + + OFstream os(outputFile); + + writeHeader(os); + beginGroup(os); + writeAppearance(os); + + // For point field: "colorPerVetex=true" + os << " <IndexedFaceSet" + << " colorPerVertex='" << Switch(this->isPointData()) << "'" + << " coordIndex='" << nl; + + for (const auto& f : surf.faces()) + { + for (const label vrti : f) + { + os << vrti << ' '; + } + os << "-1\n"; + } + os << "'"; + + // Colour indices for face fields + if (!this->isPointData()) + { + const label nFaces = surf.faces().size(); + + os << " colorIndex='"; + + for (label i=0; i < nFaces; ++i) + { + os << i << ' '; + } + os << "'"; + } + + os << " >\n"; // IndexedFaceSet + + writePoints(os, surf.points()); + + os << "<Color color='" << nl; + + // writeColours(os, values, range, colorBar); + + for (const Type& val : values) + { + const scalar x = rangex(range, val); + vector rgb = colourTablePtr_->value(x); + printColour(os, rgb); + } + + os << "' />" << nl; // Color + + os << + " </IndexedFaceSet>\n"; + + endGroup(os); + writeFooter(os); + } + + wroteGeom_ = true; + return outputFile; +} + + +// Field writing methods +defineSurfaceWriterWriteFields(Foam::surfaceWriters::x3dWriter); + + +// ************************************************************************* // diff --git a/src/surfMesh/writers/x3d/x3dSurfaceWriter.H b/src/surfMesh/writers/x3d/x3dSurfaceWriter.H new file mode 100644 index 0000000000000000000000000000000000000000..d12c90dfac2e6cf3a2a05059c19858904edbce49 --- /dev/null +++ b/src/surfMesh/writers/x3d/x3dSurfaceWriter.H @@ -0,0 +1,169 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 <http://www.gnu.org/licenses/>. + +Class + Foam::surfaceWriters::x3dWriter + +Description + A surfaceWriter for X3D files. + + The formatOptions for x3d: + \table + Property | Description | Required | Default + range | The min/max range for colour table | no | automatic + colourMap | The colour map for rendering | no | coolToWarm + \endtable + + \heading Output file locations + + The \c rootdir normally corresponds to something like + \c postProcessing/\<name\> + + \subheading Geometry + \verbatim + rootdir + `-- timeName + `-- surfaceName.x3d + \endverbatim + + \subheading Fields + \verbatim + rootdir + `-- timeName + |-- <field0>_surfaceName.x3d + `-- <field1>_surfaceName.x3d + \endverbatim + +SourceFiles + x3dSurfaceWriter.C + +\*---------------------------------------------------------------------------*/ + +#ifndef x3dSurfaceWriter_H +#define x3dSurfaceWriter_H + +#include "surfaceWriter.H" +#include "X3DsurfaceFormatCore.H" +#include "colourTable.H" +#include "MinMax.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace surfaceWriters +{ + +/*---------------------------------------------------------------------------*\ + Class x3dWriter Declaration +\*---------------------------------------------------------------------------*/ + +class x3dWriter +: + public surfaceWriter, + protected fileFormats::X3DsurfaceFormatCore +{ + // Private Data + + //- Range of values + // The lower/upper limits for the colour table output + // Undefined means calculate from the data + scalarMinMax range_; + + //- Selected colour table + const colourTable* colourTablePtr_; + + + // Private Member Functions + + //- Templated write operation + template<class Type> + fileName writeTemplate + ( + const word& fieldName, //!< Name of field + const Field<Type>& localValues //!< Local field values to write + ); + + +public: + + //- Runtime type information + TypeNameNoDebug("x3d"); + + + // Constructors + + //- Construct null + x3dWriter(); + + //- Construct with some output options + explicit x3dWriter(const dictionary& options); + + //- Construct from components + x3dWriter + ( + const meshedSurf& surf, + const fileName& outputPath, + bool parallel = Pstream::parRun(), + const dictionary& options = dictionary() + ); + + //- Construct from components + x3dWriter + ( + const pointField& points, + const faceList& faces, + const fileName& outputPath, + bool parallel = Pstream::parRun(), + const dictionary& options = dictionary() + ); + + + //- Destructor + virtual ~x3dWriter() = default; + + + // Member Functions + + //- Write surface geometry to file. + virtual fileName write(); // override + + declareSurfaceWriterWriteMethod(label); + declareSurfaceWriterWriteMethod(scalar); + declareSurfaceWriterWriteMethod(vector); + declareSurfaceWriterWriteMethod(sphericalTensor); + declareSurfaceWriterWriteMethod(symmTensor); + declareSurfaceWriterWriteMethod(tensor); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace surfaceWriters +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* //