Commit 70e10459 authored by Kenneth Moreland's avatar Kenneth Moreland

Update presets for ColorTable

The ParaView project went through a rigourous selection process
for a short list of color tables. Let's replicate that for our
presets.
parent 8497febf
......@@ -127,6 +127,7 @@ set(sources
CellSet.cxx
CellSetStructured.cxx
ColorTable.cxx
ColorTablePresets.cxx
DataSet.cxx
DataSetBuilderExplicit.cxx
DataSetBuilderRectilinear.cxx
......@@ -145,7 +146,6 @@ set(sources
internal/VirtualObjectTransfer.cxx
Logging.cxx
MultiBlock.cxx
PresetColorTables.cxx
RuntimeDeviceInformation.cxx
RuntimeDeviceTracker.cxx
StorageBasic.cxx
......
......@@ -18,6 +18,7 @@
// this software.
//============================================================================
#include <algorithm>
#include <cctype>
#include <memory>
#include <vtkm/cont/ColorTable.h>
......@@ -32,12 +33,12 @@ namespace vtkm
namespace cont
{
namespace detail
namespace internal
{
bool loadColorTablePreset(vtkm::cont::ColorTable::Preset preset, vtkm::cont::ColorTable& table);
std::set<std::string> GetPresetNames();
bool loadColorTablePreset(std::string name, vtkm::cont::ColorTable& table);
}
bool LoadColorTablePreset(vtkm::cont::ColorTable::Preset preset, vtkm::cont::ColorTable& table);
bool LoadColorTablePreset(std::string name, vtkm::cont::ColorTable& table);
} // namespace internal
//----------------------------------------------------------------------------
ColorTable::ColorTable(vtkm::cont::ColorTable::Preset preset)
......@@ -102,27 +103,55 @@ ColorTable::ColorTable(const vtkm::Range& range,
this->SetColorSpace(space);
}
//----------------------------------------------------------------------------
ColorTable::ColorTable(const std::string& name,
vtkm::cont::ColorSpace colorSpace,
const vtkm::Vec<double, 3>& nanColor,
const std::vector<double>& rgbPoints,
const std::vector<double>& alphaPoints)
: Impl(std::make_shared<detail::ColorTableInternals>())
{
this->SetName(name);
this->SetColorSpace(colorSpace);
this->SetNaNColor(nanColor);
this->FillColorTableFromDataPointer(static_cast<vtkm::Int32>(rgbPoints.size()), rgbPoints.data());
this->FillOpacityTableFromDataPointer(static_cast<vtkm::Int32>(alphaPoints.size()),
alphaPoints.data());
}
//----------------------------------------------------------------------------
ColorTable::~ColorTable()
{
}
//----------------------------------------------------------------------------
const std::string& ColorTable::GetName() const
{
return this->Impl->Name;
}
//----------------------------------------------------------------------------
void ColorTable::SetName(const std::string& name)
{
this->Impl->Name = name;
}
//----------------------------------------------------------------------------
bool ColorTable::LoadPreset(vtkm::cont::ColorTable::Preset preset)
{
return detail::loadColorTablePreset(preset, *this);
return internal::LoadColorTablePreset(preset, *this);
}
//----------------------------------------------------------------------------
std::set<std::string> ColorTable::GetPresets() const
std::set<std::string> ColorTable::GetPresets()
{
return detail::GetPresetNames();
return internal::GetPresetNames();
}
//----------------------------------------------------------------------------
bool ColorTable::LoadPreset(const std::string& name)
{
return detail::loadColorTablePreset(name, *this);
return internal::LoadColorTablePreset(name, *this);
}
//----------------------------------------------------------------------------
......@@ -358,8 +387,8 @@ vtkm::Int32 ColorTable::AddPoint(double x, const vtkm::Vec<float, 3>& rgb)
}
else
{
this->Impl->ColorNodePos.emplace(pos, x);
this->Impl->ColorRGB.emplace(this->Impl->ColorRGB.begin() + std::distance(begin, pos), rgb);
this->Impl->ColorNodePos.emplace(pos, x);
}
}
this->Impl->TableRange.Include(x); //update range to include x
......@@ -541,11 +570,11 @@ vtkm::Int32 ColorTable::AddPointAlpha(double x, float alpha, float midpoint, flo
}
else
{
this->Impl->OpacityNodePos.emplace(pos, x);
this->Impl->OpacityAlpha.emplace(this->Impl->OpacityAlpha.begin() + std::distance(begin, pos),
alpha);
this->Impl->OpacityMidSharp.emplace(
this->Impl->OpacityMidSharp.begin() + std::distance(begin, pos), midsharp);
this->Impl->OpacityNodePos.emplace(pos, x);
}
}
this->Impl->OpacityArraysChanged = true;
......@@ -749,7 +778,7 @@ bool ColorTable::FillOpacityTableFromDataPointer(vtkm::Int32 n, const double* pt
}
this->ClearAlpha();
std::size_t size = static_cast<std::size_t>(n / 2);
std::size_t size = static_cast<std::size_t>(n / 4);
this->Impl->OpacityNodePos.reserve(size);
this->Impl->OpacityAlpha.reserve(size);
this->Impl->OpacityMidSharp.reserve(size);
......@@ -774,7 +803,7 @@ bool ColorTable::FillOpacityTableFromDataPointer(vtkm::Int32 n, const float* ptr
this->ClearAlpha();
std::size_t size = static_cast<std::size_t>(n / 2);
std::size_t size = static_cast<std::size_t>(n / 4);
this->Impl->OpacityNodePos.reserve(size);
this->Impl->OpacityAlpha.reserve(size);
this->Impl->OpacityMidSharp.reserve(size);
......
......@@ -112,20 +112,23 @@ public:
enum struct Preset
{
DEFAULT,
VIRIDIS,
COOL_TO_WARM,
COOL_TO_WARN_EXTENDED,
COLD_AND_HOT,
COOL_TO_WARM_EXTENDED,
VIRIDIS,
INFERNO,
PLASMA,
BLACK_BODY_RADIATION,
SAMSEL_FIRE,
LINEAR_YGB,
BLACK_BLUE_AND_WHITE,
LINEAR_GREEN,
X_RAY,
GREEN,
BLACK_BLUE_WHITE,
BLUE_TO_ORANGE,
GRAY_TO_RED,
COLD_AND_HOT,
BLUE_GREEN_ORANGE,
YELLOW_GRAY_BLUE,
RAINBOW_UNIFORM,
JET,
RAINBOW_DESATURATED,
RAINBOW
RAINBOW_DESATURATED
};
/// \brief Construct a color table from a preset
......@@ -145,20 +148,24 @@ public:
/// Note: Names are case insensitive
/// Currently supports the following color tables:
///
/// "Default"
/// "Cool to Warm"
/// "Black-Body Radiation"
/// "Samsel Fire" [ known previously as "Black, Orange and White"]
/// "Cool to Warm Extended"
/// "Viridis"
/// "Inferno"
/// "Linear YGB"
/// "Cold and Hot"
/// "Rainbow Desaturated"
/// "Cool to Warm (Extended)"
/// "Plasma"
/// "Black-Body Radiation"
/// "X Ray"
/// "Black, Blue and White"
/// "Virdis"
/// "Linear Green"
/// "Green"
/// "Black - Blue - White"
/// "Blue to Orange"
/// "Gray to Red"
/// "Cold and Hot"
/// "Blue - Green - Orange"
/// "Yellow - Gray - Blue"
/// "Rainbow Uniform"
/// "Jet"
/// "Rainbow"
/// "Rainbow Desaturated"
///
explicit ColorTable(const std::string& name);
......@@ -192,9 +199,22 @@ public:
const vtkm::Vec<float, 4>& rgba2,
ColorSpace space = ColorSpace::LAB);
/// Construct a color table with a list of colors and alphas. For this version you must also
/// specify a name.
///
/// This constructor is mostly used for presets.
ColorTable(const std::string& name,
vtkm::cont::ColorSpace colorSpace,
const vtkm::Vec<double, 3>& nanColor,
const std::vector<double>& rgbPoints,
const std::vector<double>& alphaPoints = { 0.0, 1.0, 0.5, 0.0, 1.0, 1.0, 0.5, 0.0 });
~ColorTable();
const std::string& GetName() const;
void SetName(const std::string& name);
bool LoadPreset(vtkm::cont::ColorTable::Preset preset);
/// Returns the name of all preset color tables
......@@ -202,7 +222,7 @@ public:
/// This list will include all presets defined in vtkm::cont::ColorTable::Preset and could
/// include extras as well.
///
std::set<std::string> GetPresets() const;
static std::set<std::string> GetPresets();
/// Load a preset color table
///
......@@ -213,20 +233,25 @@ public:
/// Note: Names are case insensitive
///
/// Currently supports the following color tables:
/// "Default"
/// "Cool to Warm"
/// "Black-Body Radiation"
/// "Samsel Fire" [ known previously as "Black, Orange and White"]
/// "Cool to Warm Extended"
/// "Viridis"
/// "Inferno"
/// "Linear YGB"
/// "Cold and Hot"
/// "Rainbow Desaturated"
/// "Cool to Warm (Extended)"
/// "Plasma"
/// "Black-Body Radiation"
/// "X Ray"
/// "Black, Blue and White"
/// "Virdis"
/// "Linear Green"
/// "Green"
/// "Black - Blue - White"
/// "Blue to Orange"
/// "Gray to Red"
/// "Cold and Hot"
/// "Blue - Green - Orange"
/// "Yellow - Gray - Blue"
/// "Rainbow Uniform"
/// "Jet"
/// "Rainbow"
/// "Rainbow Desaturated"
///
bool LoadPreset(const std::string& name);
/// Make a deep copy of the current color table
......@@ -455,27 +480,31 @@ public:
/// Fill the Opacity table from a double pointer
///
/// The double pointer is required to have the layout out of [X1, A1,
/// X2, A2, ..., Xn, An] where n is the number of nodes. The midpoint
/// of each node will be set to 0.5 and the sharpness to 0.0 (linear).
/// The double pointer is required to have the layout out of [X1, A1, M1, S1, X2, A2, M2, S2,
/// ..., Xn, An, Mn, Sn] where n is the number of nodes. The Xi values represent the value to
/// map, the Ai values represent alpha (opacity) value, the Mi values represent midpoints, and
/// the Si values represent sharpness. Use 0.5 for midpoint and 0.0 for sharpness to have linear
/// interpolation of the alpha.
///
/// This will remove any existing opacity control points.
///
/// Note: n represents the length of the array, so ( n/2 == number of control points )
/// Note: n represents the length of the array, so ( n/4 == number of control points )
///
/// Note: This is provided as a interoperability method with VTK
/// Will return false and not modify anything if n is <= 0 or ptr == nullptr
bool FillOpacityTableFromDataPointer(vtkm::Int32 n, const double* ptr);
/// Fill the Opacity table from a float pointer
///
/// The double pointer is required to have the layout out of [X1, A1,
/// X2, A2, ..., Xn, An] where n is the number of nodes. The midpoint
/// of each node will be set to 0.5 and the sharpness to 0.0 (linear).
/// The float pointer is required to have the layout out of [X1, A1, M1, S1, X2, A2, M2, S2,
/// ..., Xn, An, Mn, Sn] where n is the number of nodes. The Xi values represent the value to
/// map, the Ai values represent alpha (opacity) value, the Mi values represent midpoints, and
/// the Si values represent sharpness. Use 0.5 for midpoint and 0.0 for sharpness to have linear
/// interpolation of the alpha.
///
/// This will remove any existing opacity control points.
///
/// Note: n represents the length of the array, so ( n/2 == number of control points )
/// Note: n represents the length of the array, so ( n/4 == number of control points )
///
/// Note: This is provided as a interoperability method with VTK
/// Will return false and not modify anything if n is <= 0 or ptr == nullptr
bool FillOpacityTableFromDataPointer(vtkm::Int32 n, const float* ptr);
......
This diff is collapsed.
......@@ -35,6 +35,7 @@ namespace detail
{
struct ColorTableInternals
{
std::string Name;
ColorSpace CSpace = ColorSpace::LAB;
vtkm::Range TableRange = { 1.0, 0.0 };
......
This diff is collapsed.
......@@ -88,46 +88,74 @@ public:
auto labspace = vtkm::cont::ColorSpace::LAB;
auto diverging = vtkm::cont::ColorSpace::DIVERGING;
vtkm::cont::ColorTable table(rgbspace);
VTKM_TEST_ASSERT(table.LoadPreset("Linear YGB"), "failed to find Linear YGB preset");
VTKM_TEST_ASSERT(table.GetColorSpace() == labspace,
"color space not switched when loading preset");
VTKM_TEST_ASSERT(table.GetRange() == range, "color range not correct after loading preset");
VTKM_TEST_ASSERT(table.GetNumberOfPoints() == 22,
"color range not correct after loading preset");
table.SetColorSpace(diverging);
VTKM_TEST_ASSERT(table.LoadPreset("inferno"), "failed to find inferno");
VTKM_TEST_ASSERT(table.GetColorSpace() == labspace,
"color space not switched when loading preset");
VTKM_TEST_ASSERT(table.GetRange() == range, "color range not correct after loading preset");
VTKM_TEST_ASSERT(table.GetNumberOfPoints() == 256,
"color range not correct after loading preset");
table.SetColorSpace(hsvspace);
VTKM_TEST_ASSERT((table.LoadPreset("no table with this name") == false),
"failed to error out on bad preset table name");
//verify that after a failure we still have the previous preset loaded
VTKM_TEST_ASSERT(table.GetColorSpace() == hsvspace,
"color space not switched when loading preset");
VTKM_TEST_ASSERT(table.GetRange() == range, "color range not correct after loading preset");
VTKM_TEST_ASSERT(table.GetNumberOfPoints() == 256,
"color range not correct after loading preset");
{
vtkm::cont::ColorTable table(rgbspace);
VTKM_TEST_ASSERT(table.LoadPreset("Cool to Warm"));
VTKM_TEST_ASSERT(table.GetColorSpace() == diverging,
"color space not switched when loading preset");
VTKM_TEST_ASSERT(table.GetRange() == range, "color range not correct after loading preset");
VTKM_TEST_ASSERT(table.GetNumberOfPoints() == 3);
VTKM_TEST_ASSERT(table.LoadPreset(vtkm::cont::ColorTable::Preset::COOL_TO_WARM_EXTENDED));
VTKM_TEST_ASSERT(table.GetColorSpace() == labspace,
"color space not switched when loading preset");
VTKM_TEST_ASSERT(table.GetRange() == range, "color range not correct after loading preset");
VTKM_TEST_ASSERT(table.GetNumberOfPoints() == 35);
table.SetColorSpace(hsvspace);
VTKM_TEST_ASSERT((table.LoadPreset("no table with this name") == false),
"failed to error out on bad preset table name");
//verify that after a failure we still have the previous preset loaded
VTKM_TEST_ASSERT(table.GetColorSpace() == hsvspace,
"color space not switched when loading preset");
VTKM_TEST_ASSERT(table.GetRange() == range, "color range not correct after failing preset");
VTKM_TEST_ASSERT(table.GetNumberOfPoints() == 35);
}
//verify that we can get the presets
std::set<std::string> names = table.GetPresets();
VTKM_TEST_ASSERT(names.size() == 15, "incorrect number of names in preset set");
std::set<std::string> names = vtkm::cont::ColorTable::GetPresets();
VTKM_TEST_ASSERT(names.size() == 18, "incorrect number of names in preset set");
VTKM_TEST_ASSERT(names.count("inferno") == 1, "names should contain inferno");
VTKM_TEST_ASSERT(names.count("black-body radiation") == 1,
VTKM_TEST_ASSERT(names.count("Inferno") == 1, "names should contain inferno");
VTKM_TEST_ASSERT(names.count("Black-Body Radiation") == 1,
"names should contain black-body radiation");
VTKM_TEST_ASSERT(names.count("viridis") == 1, "names should contain viridis");
VTKM_TEST_ASSERT(names.count("black, blue and white") == 1,
VTKM_TEST_ASSERT(names.count("Viridis") == 1, "names should contain viridis");
VTKM_TEST_ASSERT(names.count("Black - Blue - White") == 1,
"names should contain black, blue and white");
VTKM_TEST_ASSERT(names.count("samsel fire") == 1, "names should contain samsel fire");
VTKM_TEST_ASSERT(names.count("jet") == 1, "names should contain jet");
VTKM_TEST_ASSERT(names.count("Blue to Orange") == 1, "names should contain samsel fire");
VTKM_TEST_ASSERT(names.count("Jet") == 1, "names should contain jet");
// verify that we can load in all the listed color tables
for (auto&& name : names)
{
vtkm::cont::ColorTable table(name);
VTKM_TEST_ASSERT(table.GetNumberOfPoints() > 0, "Issue loading preset ", name);
}
auto presetEnum = { vtkm::cont::ColorTable::Preset::DEFAULT,
vtkm::cont::ColorTable::Preset::COOL_TO_WARM,
vtkm::cont::ColorTable::Preset::COOL_TO_WARM_EXTENDED,
vtkm::cont::ColorTable::Preset::VIRIDIS,
vtkm::cont::ColorTable::Preset::INFERNO,
vtkm::cont::ColorTable::Preset::PLASMA,
vtkm::cont::ColorTable::Preset::BLACK_BODY_RADIATION,
vtkm::cont::ColorTable::Preset::X_RAY,
vtkm::cont::ColorTable::Preset::GREEN,
vtkm::cont::ColorTable::Preset::BLACK_BLUE_WHITE,
vtkm::cont::ColorTable::Preset::BLUE_TO_ORANGE,
vtkm::cont::ColorTable::Preset::GRAY_TO_RED,
vtkm::cont::ColorTable::Preset::COLD_AND_HOT,
vtkm::cont::ColorTable::Preset::BLUE_GREEN_ORANGE,
vtkm::cont::ColorTable::Preset::YELLOW_GRAY_BLUE,
vtkm::cont::ColorTable::Preset::RAINBOW_UNIFORM,
vtkm::cont::ColorTable::Preset::JET,
vtkm::cont::ColorTable::Preset::RAINBOW_DESATURATED };
for (vtkm::cont::ColorTable::Preset preset : presetEnum)
{
vtkm::cont::ColorTable table(preset);
VTKM_TEST_ASSERT(table.GetNumberOfPoints() > 0, "Issue loading preset");
}
}
static void TestClamping()
......@@ -310,7 +338,7 @@ public:
//Verify that the opacity points have moved
vtkm::Vec<double, 4> opacityData;
table.GetPointAlpha(1, opacityData);
VTKM_TEST_ASSERT(opacityData[0] == range.Max, "rescale to range failed on opacity");
VTKM_TEST_ASSERT(test_equal(opacityData[0], range.Max), "rescale to range failed on opacity");
VTKM_TEST_ASSERT(opacityData[1] == 1.0, "rescale changed opacity values");
VTKM_TEST_ASSERT(opacityData[2] == 0.5, "rescale modified mid/sharp of opacity");
VTKM_TEST_ASSERT(opacityData[3] == 0.0, "rescale modified mid/sharp of opacity");
......@@ -449,14 +477,14 @@ public:
{
using namespace vtkm::worklet::colorconversion;
vtkm::cont::ColorTable table(vtkm::cont::ColorTable::Preset::LINEAR_GREEN);
vtkm::cont::ColorTable table(vtkm::cont::ColorTable::Preset::GREEN);
VTKM_TEST_ASSERT((table.GetRange() == vtkm::Range{ 0.0, 1.0 }),
"loading linear green table failed with wrong range");
VTKM_TEST_ASSERT((table.GetNumberOfPoints() == 21),
"loading linear green table failed with number of control points");
constexpr vtkm::Id nvals = 3;
constexpr double data[3] = { 0.0f, 0.5f, 1.0f };
constexpr double data[3] = { 0.0, 0.5, 1.0 };
auto samples = vtkm::cont::make_ArrayHandle(data, nvals);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> colors;
......@@ -481,7 +509,7 @@ public:
static void TestSampling()
{
vtkm::cont::ColorTable table(vtkm::cont::ColorTable::Preset::LINEAR_GREEN);
vtkm::cont::ColorTable table(vtkm::cont::ColorTable::Preset::GREEN);
VTKM_TEST_ASSERT((table.GetRange() == vtkm::Range{ 0.0, 1.0 }),
"loading linear green table failed with wrong range");
VTKM_TEST_ASSERT((table.GetNumberOfPoints() == 21),
......@@ -539,7 +567,6 @@ public:
}
}
struct TestAll
{
VTKM_CONT void operator()() const
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment