Introduce vtkm::cont::ColorTable replacing vtkm::rendering::ColorTable

The new and improved vtkm::cont::ColorTable provides a more feature complete
color table implementation that is modeled after
vtkDiscretizableColorTransferFunction. This class therefore supports different
color spaces ( rgb, lab, hsv, diverging ) and supports execution across all
device adapters.
This commit is contained in:
Robert Maynard 2018-01-18 13:55:15 -05:00
parent 428f7568c4
commit 944bc3c0d6
68 changed files with 4687 additions and 1471 deletions

@ -153,7 +153,7 @@ camera.SetViewUp(vtkm::make_Vec(0.f, 1.f, 0.f));
camera.SetClippingRange(1.f, 100.f);
camera.SetFieldOfView(60.f);
camera.SetPosition(totalExtent*(mag * 2.f));
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
// Create a mapper, canvas and view that will be used to render the scene
vtkm::rendering::Scene scene;

@ -35,7 +35,7 @@
#include <iostream>
void makeScene(const vtkm::cont::DataSet& inputData,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const std::string& fieldName,
vtkm::rendering::Scene& scene)
{
@ -100,7 +100,7 @@ int main(int argc, char* argv[])
camera.SetClippingRange(1.f, 100.f);
camera.SetFieldOfView(60.f);
camera.SetPosition(totalExtent * (mag * 2.f));
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
// Create a scene for rendering the input data
vtkm::rendering::Scene scene;

@ -42,8 +42,8 @@
#include <GL/glut.h>
#endif
#include <vtkm/cont/ColorTable.h>
#include <vtkm/rendering/CanvasGL.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/MapperGL.h>
#include <vtkm/rendering/View3D.h>
@ -141,7 +141,7 @@ int main(int argc, char* argv[])
scene.AddActor(vtkm::rendering::Actor(ds.GetCellSet(),
ds.GetCoordinateSystem(),
ds.GetField("pointvar"),
vtkm::rendering::ColorTable("thermal")));
vtkm::cont::ColorTable("inferno")));
//Create vtkm rendering stuff.
view = new vtkm::rendering::View3D(scene, mapper, canvas, bg);

@ -348,7 +348,7 @@ void RenderRTTest(const vtkm::cont::DataSet& ds, int N)
using V3 = vtkm::rendering::View3D;
//std::cout<<"Render: "<<i<<std::endl;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
vtkm::rendering::testing::Render<M, C, V3>(ds, "scalar", colorTable);
}
}
@ -366,7 +366,7 @@ void RenderVolTest(const vtkm::cont::DataSet& ds, int N)
using V3 = vtkm::rendering::View3D;
//std::cout<<"Render: "<<i<<std::endl;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
vtkm::rendering::testing::Render<M, C, V3>(ds, "scalar", colorTable);
}
}

@ -79,8 +79,24 @@ struct BenchRayTracing
Tracer.SetData(Coords.GetData(), Indices, field, NumberOfTriangles, range, bounds);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> temp;
vtkm::cont::ColorTable table("cool to warm");
table.Sample(100, temp);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> colors;
vtkm::rendering::ColorTable("cool2warm").Sample(100, colors);
colors.Allocate(100);
auto portal = colors.GetPortalControl();
auto colorPortal = temp.GetPortalConstControl();
constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);
for (vtkm::Id i = 0; i < 100; ++i)
{
auto color = colorPortal.Get(i);
vtkm::Vec<vtkm::Float32, 4> t(color[0] * conversionToFloatSpace,
color[1] * conversionToFloatSpace,
color[2] * conversionToFloatSpace,
color[3] * conversionToFloatSpace);
portal.Set(i, t);
}
Tracer.SetColorMap(colors);
Tracer.Render(Rays);

@ -55,6 +55,8 @@ set(headers
CellSetSingleType.h
CellSetStructured.h
CellSetPermutation.h
ColorTable.h
ColorTableSamples.h
CoordinateSystem.h
DataSet.h
DataSetBuilderExplicit.h
@ -110,6 +112,7 @@ set(sources
internal/SimplePolymorphicContainer.cxx
internal/ArrayManagerExecutionShareWithControl.cxx
internal/ArrayHandleBasicImpl.cxx
PresetColorTables.cxx
StorageBasic.cxx
)
@ -118,6 +121,7 @@ set(sources
set(device_sources
ArrayRangeCompute.cxx
CellSetExplicit.cxx
ColorTable.cxx
CoordinateSystem.cxx
DataSet.cxx
MultiBlock.cxx
@ -162,6 +166,5 @@ if(VTKm_ENABLE_CUDA)
add_dependencies(vtkm_cont vtkm_cont_cuda)
endif()
#-----------------------------------------------------------------------------
add_subdirectory(testing)

880
vtkm/cont/ColorTable.cxx Normal file

@ -0,0 +1,880 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <algorithm>
#include <memory>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/ColorTable.hxx>
#include <vtkm/cont/ColorTablePrivate.hxx>
namespace vtkm
{
namespace cont
{
namespace detail
{
std::set<std::string> GetPresetNames();
bool loadColorTablePreset(std::string name, vtkm::cont::ColorTable& table);
}
//----------------------------------------------------------------------------
ColorTable::ColorTable(const std::string& name)
: Impl(std::make_shared<detail::ColorTableInternals>())
{
const bool loaded = this->LoadPreset(name);
if (!loaded)
{ //if we failed to load the requested color table, call SetColorSpace
//so that the internal host side cache is constructed and we leave
//the constructor in a valid state. We use RGB as it is the default
//when the no parameter constructor is called
this->SetColorSpace(ColorSpace::RGB);
}
this->AddSegmentAlpha(this->Impl->TableRange.Min, 1.0f, this->Impl->TableRange.Max, 1.0f);
}
//----------------------------------------------------------------------------
ColorTable::ColorTable(ColorSpace space)
: Impl(std::make_shared<detail::ColorTableInternals>())
{
this->SetColorSpace(space);
}
//----------------------------------------------------------------------------
ColorTable::ColorTable(const vtkm::Range& range,
const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
ColorSpace space)
: Impl(std::make_shared<detail::ColorTableInternals>())
{
this->AddSegment(range.Min, rgb1, range.Max, rgb2);
this->AddSegmentAlpha(range.Min, 1.0f, range.Max, 1.0f);
this->SetColorSpace(space);
}
//----------------------------------------------------------------------------
ColorTable::ColorTable(const vtkm::Range& range,
const vtkm::Vec<float, 4>& rgba1,
const vtkm::Vec<float, 4>& rgba2,
ColorSpace space)
: Impl(std::make_shared<detail::ColorTableInternals>())
{
vtkm::Vec<float, 3> rgb1(rgba1[0], rgba1[1], rgba1[2]);
vtkm::Vec<float, 3> rgb2(rgba2[0], rgba2[1], rgba2[2]);
this->AddSegment(range.Min, rgb1, range.Max, rgb2);
this->AddSegmentAlpha(range.Min, rgba1[3], range.Max, rgba2[3]);
this->SetColorSpace(space);
}
//----------------------------------------------------------------------------
ColorTable::~ColorTable()
{
}
//----------------------------------------------------------------------------
std::set<std::string> ColorTable::GetPresets() const
{
return detail::GetPresetNames();
}
//----------------------------------------------------------------------------
bool ColorTable::LoadPreset(const std::string& name)
{
return detail::loadColorTablePreset(name, *this);
}
//----------------------------------------------------------------------------
ColorTable ColorTable::MakeDeepCopy()
{
ColorTable dcopy(this->Impl->CSpace);
dcopy.Impl->TableRange = this->Impl->TableRange;
dcopy.Impl->HostSideCache->NaNColor = this->Impl->HostSideCache->NaNColor;
dcopy.Impl->HostSideCache->BelowRangeColor = this->Impl->HostSideCache->BelowRangeColor;
dcopy.Impl->HostSideCache->AboveRangeColor = this->Impl->HostSideCache->AboveRangeColor;
dcopy.Impl->HostSideCache->UseClamping = this->Impl->HostSideCache->UseClamping;
dcopy.Impl->ColorNodePos = this->Impl->ColorNodePos;
dcopy.Impl->ColorRGB = this->Impl->ColorRGB;
dcopy.Impl->OpacityNodePos = this->Impl->OpacityNodePos;
dcopy.Impl->OpacityAlpha = this->Impl->OpacityAlpha;
dcopy.Impl->OpacityMidSharp = this->Impl->OpacityMidSharp;
return dcopy;
}
//----------------------------------------------------------------------------
ColorSpace ColorTable::GetColorSpace() const
{
return this->Impl->CSpace;
}
//----------------------------------------------------------------------------
void ColorTable::SetColorSpace(ColorSpace space)
{
if (this->Impl->CSpace != space || this->Impl->HostSideCache == nullptr)
{
this->Impl->CSpace = space;
//Remove any existing host and execution data
delete this->Impl->HostSideCache;
delete this->Impl->ExecHandle;
using HandleType = vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>;
switch (space)
{
case vtkm::cont::ColorSpace::RGB:
{
auto* hostPortal = new vtkm::exec::ColorTableRGB();
this->Impl->ExecHandle = new HandleType(hostPortal, false);
this->Impl->HostSideCache = hostPortal;
break;
}
case vtkm::cont::ColorSpace::HSV:
{
auto* hostPortal = new vtkm::exec::ColorTableHSV();
this->Impl->ExecHandle = new HandleType(hostPortal, false);
this->Impl->HostSideCache = hostPortal;
break;
}
case vtkm::cont::ColorSpace::HSV_WRAP:
{
auto* hostPortal = new vtkm::exec::ColorTableHSVWrap();
this->Impl->ExecHandle = new HandleType(hostPortal, false);
this->Impl->HostSideCache = hostPortal;
break;
}
case vtkm::cont::ColorSpace::LAB:
{
auto* hostPortal = new vtkm::exec::ColorTableLab();
this->Impl->ExecHandle = new HandleType(hostPortal, false);
this->Impl->HostSideCache = hostPortal;
break;
}
case vtkm::cont::ColorSpace::DIVERGING:
{
auto* hostPortal = new vtkm::exec::ColorTableDiverging();
this->Impl->ExecHandle = new HandleType(hostPortal, false);
this->Impl->HostSideCache = hostPortal;
break;
}
default:
throw vtkm::cont::ErrorBadType("unkown vtkm::cont::ColorType requested");
}
}
}
//----------------------------------------------------------------------------
void ColorTable::SetClamping(bool state)
{
this->Impl->HostSideCache->UseClamping = state;
this->Impl->HostSideCache->Modified();
}
//----------------------------------------------------------------------------
bool ColorTable::GetClamping() const
{
return this->Impl->HostSideCache->UseClamping;
}
//----------------------------------------------------------------------------
void ColorTable::SetBelowRangeColor(const vtkm::Vec<float, 3>& c)
{
this->Impl->HostSideCache->BelowRangeColor = c;
this->Impl->HostSideCache->Modified();
}
//----------------------------------------------------------------------------
const vtkm::Vec<float, 3>& ColorTable::GetBelowRangeColor() const
{
return this->Impl->HostSideCache->BelowRangeColor;
}
//----------------------------------------------------------------------------
void ColorTable::SetAboveRangeColor(const vtkm::Vec<float, 3>& c)
{
this->Impl->HostSideCache->AboveRangeColor = c;
this->Impl->HostSideCache->Modified();
}
//----------------------------------------------------------------------------
const vtkm::Vec<float, 3>& ColorTable::GetAboveRangeColor() const
{
return this->Impl->HostSideCache->AboveRangeColor;
}
//----------------------------------------------------------------------------
void ColorTable::SetNaNColor(const vtkm::Vec<float, 3>& c)
{
this->Impl->HostSideCache->NaNColor = c;
this->Impl->HostSideCache->Modified();
}
//----------------------------------------------------------------------------
const vtkm::Vec<float, 3>& ColorTable::GetNaNColor() const
{
return this->Impl->HostSideCache->NaNColor;
}
//----------------------------------------------------------------------------
void ColorTable::Clear()
{
this->ClearColors();
this->ClearAlpha();
}
//---------------------------------------------------------------------------
void ColorTable::ClearColors()
{
this->Impl->ColorNodePos.clear();
this->Impl->ColorRGB.clear();
this->Impl->ColorArraysChanged = true;
}
//---------------------------------------------------------------------------
void ColorTable::ClearAlpha()
{
this->Impl->OpacityNodePos.clear();
this->Impl->OpacityAlpha.clear();
this->Impl->OpacityMidSharp.clear();
this->Impl->OpacityArraysChanged = true;
}
//---------------------------------------------------------------------------
void ColorTable::ReverseColors()
{
std::reverse(this->Impl->ColorRGB.begin(), this->Impl->ColorRGB.end());
this->Impl->ColorArraysChanged = true;
}
//---------------------------------------------------------------------------
void ColorTable::ReverseAlpha()
{
std::reverse(this->Impl->OpacityAlpha.begin(), this->Impl->OpacityAlpha.end());
//To keep the shape correct the mid and sharp values of the last node are not included in the reversal
std::reverse(this->Impl->OpacityMidSharp.begin(), this->Impl->OpacityMidSharp.end() - 1);
this->Impl->OpacityArraysChanged = true;
}
//---------------------------------------------------------------------------
const vtkm::Range& ColorTable::GetRange() const
{
return this->Impl->TableRange;
}
//---------------------------------------------------------------------------
void ColorTable::RescaleToRange(const vtkm::Range& r)
{
if (r == this->GetRange())
{
return;
}
//make sure range has space.
auto newRange = adjustRange(r);
//slam control points down to 0.0 - 1.0, and than rescale to new range
const double minv = this->GetRange().Min;
const double oldScale = this->GetRange().Length();
const double newScale = newRange.Length();
VTKM_ASSERT(oldScale > 0);
VTKM_ASSERT(newScale > 0);
for (auto i = this->Impl->ColorNodePos.begin(); i != this->Impl->ColorNodePos.end(); ++i)
{
const auto t = (*i - minv) / oldScale;
*i = (t * newScale) + newRange.Min;
}
for (auto i = this->Impl->OpacityNodePos.begin(); i != this->Impl->OpacityNodePos.end(); ++i)
{
const auto t = (*i - minv) / oldScale;
*i = (t * newScale) + newRange.Min;
}
this->Impl->ColorArraysChanged = true;
this->Impl->OpacityArraysChanged = true;
this->Impl->TableRange = newRange;
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::AddPoint(double x, const vtkm::Vec<float, 3>& rgb)
{
if (outside_range(rgb))
{
return -1;
}
std::size_t index = 0;
if (this->Impl->ColorNodePos.size() == 0 || this->Impl->ColorNodePos.back() < x)
{
this->Impl->ColorNodePos.emplace_back(x);
this->Impl->ColorRGB.emplace_back(rgb);
index = this->Impl->ColorNodePos.size();
}
else
{
auto begin = this->Impl->ColorNodePos.begin();
auto pos = std::lower_bound(begin, this->Impl->ColorNodePos.end(), x);
index = static_cast<std::size_t>(std::distance(begin, pos));
if (*pos == x)
{
this->Impl->ColorRGB[index] = rgb;
}
else
{
this->Impl->ColorNodePos.emplace(pos, x);
this->Impl->ColorRGB.emplace(this->Impl->ColorRGB.begin() + std::distance(begin, pos), rgb);
}
}
this->Impl->TableRange.Include(x); //update range to include x
this->Impl->ColorArraysChanged = true;
return static_cast<vtkm::Int32>(index);
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::AddPointHSV(double x, const vtkm::Vec<float, 3>& hsv)
{
return this->AddPoint(x, hsvTorgb(hsv));
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::AddSegment(double x1,
const vtkm::Vec<float, 3>& rgb1,
double x2,
const vtkm::Vec<float, 3>& rgb2)
{
if (outside_range(rgb1, rgb2))
{
return -1;
}
if (this->Impl->ColorNodePos.size() > 0)
{
//Todo:
// - This could be optimized so we do 2 less lower_bound calls when
// the table already exists
//When we add a segment we remove all points that are inside the line
auto nodeBegin = this->Impl->ColorNodePos.begin();
auto nodeEnd = this->Impl->ColorNodePos.end();
auto rgbBegin = this->Impl->ColorRGB.begin();
auto nodeStart = std::lower_bound(nodeBegin, nodeEnd, x1);
auto nodeStop = std::lower_bound(nodeBegin, nodeEnd, x2);
auto rgbStart = rgbBegin + std::distance(nodeBegin, nodeStart);
auto rgbStop = rgbBegin + std::distance(nodeBegin, nodeStop);
//erase is exclusive so if end->x == x2 it will be kept around, and
//than we will update it in AddPoint
this->Impl->ColorNodePos.erase(nodeStart, nodeStop);
this->Impl->ColorRGB.erase(rgbStart, rgbStop);
}
vtkm::Int32 pos = this->AddPoint(x1, rgb1);
this->AddPoint(x2, rgb2);
return pos;
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::AddSegmentHSV(double x1,
const vtkm::Vec<float, 3>& hsv1,
double x2,
const vtkm::Vec<float, 3>& hsv2)
{
return this->AddSegment(x1, hsvTorgb(hsv1), x2, hsvTorgb(hsv2));
}
//---------------------------------------------------------------------------
bool ColorTable::GetPoint(vtkm::Int32 index, vtkm::Vec<double, 4>& data) const
{
std::size_t i = static_cast<std::size_t>(index);
const std::size_t size = this->Impl->ColorNodePos.size();
if (index < 0 || i >= size)
{
return false;
}
const auto& pos = this->Impl->ColorNodePos[i];
const auto& rgb = this->Impl->ColorRGB[i];
data[0] = pos;
data[1] = rgb[0];
data[2] = rgb[1];
data[3] = rgb[2];
return true;
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::UpdatePoint(vtkm::Int32 index, const vtkm::Vec<double, 4>& data)
{
//skip data[0] as we don't care about position
if (outside_range(data[1], data[2], data[3]))
{
return -1;
}
std::size_t i = static_cast<std::size_t>(index);
const std::size_t size = this->Impl->ColorNodePos.size();
if (index < 0 || i >= size)
{
return -1;
}
//When updating the first question is has the relative position of the point changed?
//If it hasn't we can quickly just update the RGB value
auto oldPos = this->Impl->ColorNodePos.begin() + index;
auto newPos =
std::lower_bound(this->Impl->ColorNodePos.begin(), this->Impl->ColorNodePos.end(), data[0]);
if (oldPos == newPos)
{ //node's relative location hasn't changed
this->Impl->ColorArraysChanged = true;
auto& rgb = this->Impl->ColorRGB[i];
*newPos = data[0];
rgb[0] = static_cast<float>(data[1]);
rgb[1] = static_cast<float>(data[2]);
rgb[2] = static_cast<float>(data[3]);
return index;
}
else
{ //remove the point, and add the new values as the relative location is different
this->RemovePoint(index);
vtkm::Vec<float, 3> newrgb(
static_cast<float>(data[1]), static_cast<float>(data[2]), static_cast<float>(data[3]));
return this->AddPoint(data[0], newrgb);
}
}
//---------------------------------------------------------------------------
bool ColorTable::RemovePoint(double x)
{
auto begin = this->Impl->ColorNodePos.begin();
auto pos = std::lower_bound(begin, this->Impl->ColorNodePos.end(), x);
return this->RemovePoint(static_cast<vtkm::Int32>(std::distance(begin, pos)));
}
//---------------------------------------------------------------------------
bool ColorTable::RemovePoint(vtkm::Int32 index)
{
std::size_t i = static_cast<std::size_t>(index);
const std::size_t size = this->Impl->ColorNodePos.size();
if (index < 0 || i >= size)
{
return false;
}
this->Impl->ColorNodePos.erase(this->Impl->ColorNodePos.begin() + index);
this->Impl->ColorRGB.erase(this->Impl->ColorRGB.begin() + index);
this->Impl->ColorArraysChanged = true;
this->Impl->RecalculateRange();
return true;
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::GetNumberOfPoints() const
{
return static_cast<vtkm::Int32>(this->Impl->ColorNodePos.size());
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::AddPointAlpha(double x, float alpha, float midpoint, float sharpness)
{
if (outside_range(alpha, midpoint, sharpness))
{
return -1;
}
const vtkm::Vec<float, 2> midsharp(midpoint, sharpness);
std::size_t index = 0;
if (this->Impl->OpacityNodePos.size() == 0 || this->Impl->OpacityNodePos.back() < x)
{
this->Impl->OpacityNodePos.emplace_back(x);
this->Impl->OpacityAlpha.emplace_back(alpha);
this->Impl->OpacityMidSharp.emplace_back(midsharp);
index = this->Impl->OpacityNodePos.size();
}
else
{
auto begin = this->Impl->OpacityNodePos.begin();
auto pos = std::lower_bound(begin, this->Impl->OpacityNodePos.end(), x);
index = static_cast<std::size_t>(std::distance(begin, pos));
if (*pos == x)
{
this->Impl->OpacityAlpha[index] = alpha;
this->Impl->OpacityMidSharp[index] = midsharp;
}
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->OpacityArraysChanged = true;
this->Impl->TableRange.Include(x); //update range to include x
return static_cast<vtkm::Int32>(index);
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::AddSegmentAlpha(double x1,
float alpha1,
double x2,
float alpha2,
const vtkm::Vec<float, 2>& mid_sharp1,
const vtkm::Vec<float, 2>& mid_sharp2)
{
if (outside_range(alpha1, alpha2, mid_sharp1, mid_sharp2))
{
return -1;
}
if (this->Impl->OpacityNodePos.size() > 0)
{
//Todo:
// - This could be optimized so we do 2 less lower_bound calls when
// the table already exists
//When we add a segment we remove all points that are inside the line
auto nodeBegin = this->Impl->OpacityNodePos.begin();
auto nodeEnd = this->Impl->OpacityNodePos.end();
auto alphaBegin = this->Impl->OpacityAlpha.begin();
auto midBegin = this->Impl->OpacityMidSharp.begin();
auto nodeStart = std::lower_bound(nodeBegin, nodeEnd, x1);
auto nodeStop = std::lower_bound(nodeBegin, nodeEnd, x2);
auto alphaStart = alphaBegin + std::distance(nodeBegin, nodeStart);
auto alphaStop = alphaBegin + std::distance(nodeBegin, nodeStop);
auto midStart = midBegin + std::distance(nodeBegin, nodeStart);
auto midStop = midBegin + std::distance(nodeBegin, nodeStop);
//erase is exclusive so if end->x == x2 it will be kept around, and
//than we will update it in AddPoint
this->Impl->OpacityNodePos.erase(nodeStart, nodeStop);
this->Impl->OpacityAlpha.erase(alphaStart, alphaStop);
this->Impl->OpacityMidSharp.erase(midStart, midStop);
}
vtkm::Int32 pos = this->AddPointAlpha(x1, alpha1, mid_sharp1[0], mid_sharp1[1]);
this->AddPointAlpha(x2, alpha2, mid_sharp2[0], mid_sharp2[1]);
return pos;
}
//---------------------------------------------------------------------------
bool ColorTable::GetPointAlpha(vtkm::Int32 index, vtkm::Vec<double, 4>& data) const
{
std::size_t i = static_cast<std::size_t>(index);
const std::size_t size = this->Impl->OpacityNodePos.size();
if (index < 0 || i >= size)
{
return false;
}
const auto& pos = this->Impl->OpacityNodePos[i];
const auto& alpha = this->Impl->OpacityAlpha[i];
const auto& midsharp = this->Impl->OpacityMidSharp[i];
data[0] = pos;
data[1] = alpha;
data[2] = midsharp[0];
data[3] = midsharp[1];
return true;
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::UpdatePointAlpha(vtkm::Int32 index, const vtkm::Vec<double, 4>& data)
{
//skip data[0] as we don't care about position
if (outside_range(data[1], data[2], data[3]))
{
return -1;
}
std::size_t i = static_cast<std::size_t>(index);
const std::size_t size = this->Impl->OpacityNodePos.size();
if (index < 0 || i >= size)
{
return -1;
}
//When updating the first question is has the relative position of the point changed?
//If it hasn't we can quickly just update the RGB value
auto oldPos = this->Impl->OpacityNodePos.begin() + index;
auto newPos =
std::lower_bound(this->Impl->OpacityNodePos.begin(), this->Impl->OpacityNodePos.end(), data[0]);
if (oldPos == newPos)
{ //node's relative location hasn't changed
this->Impl->OpacityArraysChanged = true;
auto& alpha = this->Impl->OpacityAlpha[i];
auto& midsharp = this->Impl->OpacityMidSharp[i];
*newPos = data[0];
alpha = static_cast<float>(data[1]);
midsharp[0] = static_cast<float>(data[2]);
midsharp[1] = static_cast<float>(data[3]);
return index;
}
else
{ //remove the point, and add the new values as the relative location is different
this->RemovePointAlpha(index);
return this->AddPointAlpha(data[0],
static_cast<float>(data[1]),
static_cast<float>(data[2]),
static_cast<float>(data[3]));
}
}
//---------------------------------------------------------------------------
bool ColorTable::RemovePointAlpha(double x)
{
auto begin = this->Impl->OpacityNodePos.begin();
auto pos = std::lower_bound(begin, this->Impl->OpacityNodePos.end(), x);
return this->RemovePointAlpha(static_cast<vtkm::Int32>(std::distance(begin, pos)));
}
//---------------------------------------------------------------------------
bool ColorTable::RemovePointAlpha(vtkm::Int32 index)
{
std::size_t i = static_cast<std::size_t>(index);
const std::size_t size = this->Impl->OpacityNodePos.size();
if (index < 0 || i >= size)
{
return false;
}
this->Impl->OpacityNodePos.erase(this->Impl->OpacityNodePos.begin() + index);
this->Impl->OpacityAlpha.erase(this->Impl->OpacityAlpha.begin() + index);
this->Impl->OpacityMidSharp.erase(this->Impl->OpacityMidSharp.begin() + index);
this->Impl->OpacityArraysChanged = true;
this->Impl->RecalculateRange();
return true;
}
//---------------------------------------------------------------------------
vtkm::Int32 ColorTable::GetNumberOfPointsAlpha() const
{
return static_cast<vtkm::Int32>(this->Impl->OpacityNodePos.size());
}
//---------------------------------------------------------------------------
bool ColorTable::FillColorTableFromDataPointer(vtkm::Int32 n, const double* ptr)
{
if (n <= 0 || ptr == nullptr)
{
return false;
}
this->ClearColors();
std::size_t size = static_cast<std::size_t>(n / 4);
this->Impl->ColorNodePos.reserve(size);
this->Impl->ColorRGB.reserve(size);
for (std::size_t i = 0; i < size; ++i)
{ //allows us to support unsorted arrays
vtkm::Vec<float, 3> rgb(
static_cast<float>(ptr[1]), static_cast<float>(ptr[2]), static_cast<float>(ptr[3]));
this->AddPoint(ptr[0], rgb);
ptr += 4;
}
this->Impl->ColorArraysChanged = true;
return true;
}
//---------------------------------------------------------------------------
bool ColorTable::FillColorTableFromDataPointer(vtkm::Int32 n, const float* ptr)
{
if (n <= 0 || ptr == nullptr)
{
return false;
}
this->ClearColors();
std::size_t size = static_cast<std::size_t>(n / 4);
this->Impl->ColorNodePos.reserve(size);
this->Impl->ColorRGB.reserve(size);
for (std::size_t i = 0; i < size; ++i)
{ //allows us to support unsorted arrays
vtkm::Vec<float, 3> rgb(ptr[1], ptr[2], ptr[3]);
this->AddPoint(ptr[0], rgb);
ptr += 4;
}
this->Impl->ColorArraysChanged = true;
return true;
}
//---------------------------------------------------------------------------
bool ColorTable::FillOpacityTableFromDataPointer(vtkm::Int32 n, const double* ptr)
{
if (n <= 0 || ptr == nullptr)
{
return false;
}
this->ClearAlpha();
std::size_t size = static_cast<std::size_t>(n / 2);
this->Impl->OpacityNodePos.reserve(size);
this->Impl->OpacityAlpha.reserve(size);
this->Impl->OpacityMidSharp.reserve(size);
for (std::size_t i = 0; i < size; ++i)
{ //allows us to support unsorted arrays
this->AddPointAlpha(
ptr[0], static_cast<float>(ptr[1]), static_cast<float>(ptr[2]), static_cast<float>(ptr[3]));
ptr += 4;
}
this->Impl->OpacityArraysChanged = true;
return true;
}
//---------------------------------------------------------------------------
bool ColorTable::FillOpacityTableFromDataPointer(vtkm::Int32 n, const float* ptr)
{
if (n <= 0 || ptr == nullptr)
{
return false;
}
this->ClearAlpha();
std::size_t size = static_cast<std::size_t>(n / 2);
this->Impl->OpacityNodePos.reserve(size);
this->Impl->OpacityAlpha.reserve(size);
this->Impl->OpacityMidSharp.reserve(size);
for (std::size_t i = 0; i < size; ++i)
{ //allows us to support unsorted arrays
this->AddPointAlpha(ptr[0], ptr[1], ptr[2], ptr[3]);
ptr += 4;
}
this->Impl->OpacityArraysChanged = true;
return true;
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGBA& samples,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
samples.NumberOfSamples = numSamples;
samples.SampleRange = this->GetRange();
return sampleColorTable(this, numSamples, samples.Samples, tolerance, true);
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGB& samples,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
samples.NumberOfSamples = numSamples;
samples.SampleRange = this->GetRange();
return sampleColorTable(this, numSamples, samples.Samples, tolerance, true);
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& colors,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
return sampleColorTable(this, numSamples, colors, tolerance, false);
}
//---------------------------------------------------------------------------
bool ColorTable::Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& colors,
double tolerance) const
{
if (numSamples <= 1)
{
return false;
}
return sampleColorTable(this, numSamples, colors, tolerance, false);
}
//---------------------------------------------------------------------------
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* ColorTable::GetHandleForExecution()
const
{
//Only rebuild the array handles that have changed since the last time
//we have modified or color / opacity information
if (this->Impl->ColorArraysChanged)
{
this->Impl->ColorPosHandle = vtkm::cont::make_ArrayHandle(this->Impl->ColorNodePos);
this->Impl->ColorRGBHandle = vtkm::cont::make_ArrayHandle(this->Impl->ColorRGB);
}
if (this->Impl->OpacityArraysChanged)
{
this->Impl->OpacityPosHandle = vtkm::cont::make_ArrayHandle(this->Impl->OpacityNodePos);
this->Impl->OpacityAlphaHandle = vtkm::cont::make_ArrayHandle(this->Impl->OpacityAlpha);
this->Impl->OpacityMidSharpHandle = vtkm::cont::make_ArrayHandle(this->Impl->OpacityMidSharp);
}
if (this->Impl->ColorArraysChanged || this->Impl->OpacityArraysChanged)
{
vtkm::cont::TryExecute(
detail::transfer_color_table_to_device{}, this->Impl->HostSideCache, this->Impl.get());
this->Impl->HostSideCache->Modified();
}
this->Impl->ColorArraysChanged = false;
this->Impl->OpacityArraysChanged = false;
return this->Impl->ExecHandle;
}
/*
#define ColorTableExportMapFunctions(T) \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
const vtkm::cont::ColorTableSamplesRGBA&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>&) const; \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
const vtkm::cont::ColorTableSamplesRGB&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>&) const; \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>&) const; \
template VTKM_CONT_EXPORT bool ColorTable::Map( \
const vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>&, \
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>&) const;
ColorTableExportMapFunctions(char);
ColorTableExportMapFunctions(vtkm::UInt8);
ColorTableExportMapFunctions(vtkm::Int8);
ColorTableExportMapFunctions(vtkm::Float32);
ColorTableExportMapFunctions(vtkm::Float64);
#undef ColorTableExportMapFunctions
*/
}
} //namespace vtkm::cont

644
vtkm/cont/ColorTable.h Normal file

@ -0,0 +1,644 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_ColorTable_h
#define vtk_m_cont_ColorTable_h
#include <vtkm/Range.h>
#include <vtkm/Types.h>
#include <vtkm/cont/vtkm_cont_export.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ColorTableSamples.h>
#include <vtkm/cont/VirtualObjectHandle.h>
#include <set>
namespace vtkm
{
namespace exec
{
//forward declare exec objects
class ColorTableBase;
}
namespace cont
{
namespace detail
{
struct ColorTableInternals;
}
enum struct ColorSpace
{
RGB,
HSV,
HSV_WRAP,
LAB,
DIVERGING
};
/// \brief Color Table for coloring arbitrary fields
///
///
/// The vtkm::cont::ColorTable allows for color mapping in RGB or HSV space and
/// uses a piecewise hermite functions to allow opacity interpolation that can be
/// piecewise constant, piecewise linear, or somewhere in-between
/// (a modified piecewise hermite function that squishes the function
/// according to a sharpness parameter).
///
/// For colors interpolation is handled using a piecewise linear function.
///
/// For opacity we define a piecewise function mapping. This mapping allows the addition
/// of control points, and allows the user to control the function between
/// the control points. A piecewise hermite curve is used between control
/// points, based on the sharpness and midpoint parameters. A sharpness of
/// 0 yields a piecewise linear function and a sharpness of 1 yields a
/// piecewise constant function. The midpoint is the normalized distance
/// between control points at which the curve reaches the median Y value.
/// The midpoint and sharpness values specified when adding a node are used
/// to control the transition to the next node with the last node's values being
/// ignored.
///
/// When adding opacity nodes without an explicit midpoint and sharpness we
/// will default to to Midpoint = 0.5 (halfway between the control points) and
/// Sharpness = 0.0 (linear).
///
/// ColorTable also contains which ColorSpace should be used for interpolation
/// Currently the valid ColorSpaces are:
/// - RGB
/// - HSV
/// - HSV_WRAP
/// - LAB
/// - Diverging
///
/// In HSV_WRAP mode, it will take the shortest path
/// in Hue (going back through 0 if that is the shortest way around the hue
/// circle) whereas HSV will not go through 0 (in order the
/// match the current functionality of vtkLookupTable). In Lab mode,
/// it will take the shortest path in the Lab color space with respect to the
/// CIE Delta E 2000 color distance measure. Diverging is a special
/// mode where colors will pass through white when interpolating between two
/// saturated colors.
///
/// To map an vtkm::cont::ArrayHandle through the color and opacity transfer
/// functions and into a RGB or RGBA array you will need to use
/// vtkm::worklet::ColorTransferFunction. ColorTransferFunction has
/// controls if you want to modify which ColorSpace (RGB, HSV, LAB, Diverging) you want to
/// interpolate through.
///
class VTKM_CONT_EXPORT ColorTable
{
std::shared_ptr<detail::ColorTableInternals> Impl;
public:
/// Construct a color table from a preset color table
///
/// Constructs a color table from a given preset, which might include a NaN color.
/// The alpha table will have 2 entries of alpha = 1.0 with linear interpolation
///
/// Note: Names are case insensitive
/// Currently supports the following color tables:
///
/// "Cool to Warm"
/// "Black-Body Radiation"
/// "Samsel Fire" [ known previously as "Black, Orange and White"]
/// "Inferno"
/// "Linear YGB"
/// "Cold and Hot"
/// "Rainbow Desaturated"
/// "Cool to Warm (Extended)"
/// "X Ray"
/// "Black, Blue and White"
/// "Virdis"
/// "Linear Green"
/// "Jet"
/// "Rainbow"
///
ColorTable(const std::string& name);
/// Construct a color table with a zero positions, and an invalid range
///
/// Note: The color table will have 0 entries
/// Note: The alpha table will have 0 entries
ColorTable(ColorSpace space = ColorSpace::RGB);
/// Construct a color table with a 2 positions
///
/// Note: The color table will have 2 entries of rgb = {1.0,1.0,1.0}
/// Note: The alpha table will have 2 entries of alpha = 1.0 with linear
/// interpolation
ColorTable(const vtkm::Range& range, ColorSpace space = ColorSpace::RGB);
/// Construct a color table with 2 positions
//
/// Note: The alpha table will have 2 entries of alpha = 1.0 with linear
/// interpolation
ColorTable(const vtkm::Range& range,
const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
ColorSpace space = ColorSpace::RGB);
/// Construct color and alpha and table with 2 positions
///
/// Note: The alpha table will use linear interpolation
ColorTable(const vtkm::Range& range,
const vtkm::Vec<float, 4>& rgba1,
const vtkm::Vec<float, 4>& rgba2,
ColorSpace space = ColorSpace::RGB);
~ColorTable();
/// Returns the name of all preset color tables
///
std::set<std::string> GetPresets() const;
/// Load a preset color table
///
/// Removes all existing all values in both color and alpha tables,
/// and will reset the NaN Color if the color table has that information.
/// Will not modify clamping, below, and above range state.
///
/// Note: Names are case insensitive
///
/// Currently supports the following color tables:
/// "Cool to Warm"
/// "Black-Body Radiation"
/// "Samsel Fire" [ known previously as "Black, Orange and White"]
/// "Inferno"
/// "Linear YGB"
/// "Cold and Hot"
/// "Rainbow Desaturated"
/// "Cool to Warm (Extended)"
/// "X Ray"
/// "Black, Blue and White"
/// "Virdis"
/// "Linear Green"
/// "Jet"
/// "Rainbow"
bool LoadPreset(const std::string& name);
/// Make a deep copy of the current color table
///
/// The ColorTable is implemented so that all stack based copies are 'shallow'
/// copies. This means that they all alter the same internal instance. But
/// sometimes you need to make an actual fully independent copy.
ColorTable MakeDeepCopy();
///
ColorSpace GetColorSpace() const;
void SetColorSpace(ColorSpace space);
/// If clamping is disabled values that lay out side
/// the color table range are colored based on Below
/// and Above settings.
///
/// By default clamping is enabled
void SetClampingOn() { this->SetClamping(true); }
void SetClampingOff() { this->SetClamping(false); }
void SetClamping(bool state);
bool GetClamping() const;
/// Color to use when clamping is disabled for any value
/// that is below the given range
///
/// Default value is {0,0,0}
void SetBelowRangeColor(const vtkm::Vec<float, 3>& c);
const vtkm::Vec<float, 3>& GetBelowRangeColor() const;
/// Color to use when clamping is disabled for any value
/// that is above the given range
///
/// Default value is {0,0,0}
void SetAboveRangeColor(const vtkm::Vec<float, 3>& c);
const vtkm::Vec<float, 3>& GetAboveRangeColor() const;
///
void SetNaNColor(const vtkm::Vec<float, 3>& c);
const vtkm::Vec<float, 3>& GetNaNColor() const;
/// Remove all existing all values in both color and alpha tables
/// doesn't remove the clamping, below, and above range state or colors
void Clear();
/// Remove only color table values
void ClearColors();
/// Remove only alpha table values
void ClearAlpha();
/// Reverse the rgb values inside the color table
void ReverseColors();
/// Reverse the alpha, mid, and sharp values inside the opacity table.
///
/// Note: To keep the shape correct the mid and sharp values of the last
/// node are not included in the reversal
void ReverseAlpha();
/// Returns min and max position of all function points
const vtkm::Range& GetRange() const;
/// Rescale the color and opacity transfer functions to match the
/// input range.
void RescaleToRange(const vtkm::Range& range);
// Functions for Colors
/// Adds a point to the color function. If the point already exists, it
/// will be updated to the new value.
///
/// Note: rgb values need to be between 0 and 1.0 (inclusive).
/// Return the index of the point (0 based), or -1 osn error.
vtkm::Int32 AddPoint(double x, const vtkm::Vec<float, 3>& rgb);
/// Adds a point to the color function. If the point already exists, it
/// will be updated to the new value.
///
/// Note: hsv values need to be between 0 and 1.0 (inclusive).
/// Return the index of the point (0 based), or -1 on error.
vtkm::Int32 AddPointHSV(double x, const vtkm::Vec<float, 3>& hsv);
/// Add a line segment to the color function. All points which lay between x1 and x2
/// (inclusive) are removed from the function.
///
/// Note: rgb1, and rgb2 values need to be between 0 and 1.0 (inclusive).
/// Return the index of the point x1 (0 based), or -1 on error.
vtkm::Int32 AddSegment(double x1,
const vtkm::Vec<float, 3>& rgb1,
double x2,
const vtkm::Vec<float, 3>& rgb2);
/// Add a line segment to the color function. All points which lay between x1 and x2
/// (inclusive) are removed from the function.
///
/// Note: hsv1, and hsv2 values need to be between 0 and 1.0 (inclusive)
/// Return the index of the point x1 (0 based), or -1 on error
vtkm::Int32 AddSegmentHSV(double x1,
const vtkm::Vec<float, 3>& hsv1,
double x2,
const vtkm::Vec<float, 3>& hsv2);
/// Get the location, and rgb information for an existing point in the opacity function.
///
/// Note: components 1-3 are rgb and will have values between 0 and 1.0 (inclusive)
/// Return the index of the point (0 based), or -1 on error.
bool GetPoint(vtkm::Int32 index, vtkm::Vec<double, 4>&) const;
/// Update the location, and rgb information for an existing point in the color function.
/// If the location value for the index is modified the point is removed from
/// the function and re-inserted in the proper sorted location.
///
/// Note: components 1-3 are rgb and must have values between 0 and 1.0 (inclusive).
/// Return the new index of the updated point (0 based), or -1 on error.
vtkm::Int32 UpdatePoint(vtkm::Int32 index, const vtkm::Vec<double, 4>&);
/// Remove the Color function point that exists at exactly x
///
/// Return true if the point x exists and has been removed
bool RemovePoint(double x);
/// Remove the Color function point n
///
/// Return true if n >= 0 && n < GetNumberOfPoints
bool RemovePoint(vtkm::Int32 index);
/// Returns the number of points in the color function
vtkm::Int32 GetNumberOfPoints() const;
// Functions for Opacity
/// Adds a point to the opacity function. If the point already exists, it
/// will be updated to the new value. Uses a midpoint of 0.5 (halfway between the control points)
/// and sharpness of 0.0 (linear).
///
/// Note: alpha needs to be a value between 0 and 1.0 (inclusive).
/// Return the index of the point (0 based), or -1 on error.
vtkm::Int32 AddPointAlpha(double x, float alpha) { return AddPointAlpha(x, alpha, 0.5f, 0.0f); }
/// Adds a point to the opacity function. If the point already exists, it
/// will be updated to the new value.
///
/// Note: alpha, midpoint, and sharpness values need to be between 0 and 1.0 (inclusive)
/// Return the index of the point (0 based), or -1 on error.
vtkm::Int32 AddPointAlpha(double x, float alpha, float midpoint, float sharpness);
/// Add a line segment to the opacity function. All points which lay between x1 and x2
/// (inclusive) are removed from the function. Uses a midpoint of
/// 0.5 (halfway between the control points) and sharpness of 0.0 (linear).
///
/// Note: alpha values need to be between 0 and 1.0 (inclusive)
/// Return the index of the point x1 (0 based), or -1 on error
vtkm::Int32 AddSegmentAlpha(double x1, float alpha1, double x2, float alpha2)
{
vtkm::Vec<float, 2> mid_sharp(0.5f, 0.0f);
return AddSegmentAlpha(x1, alpha1, x2, alpha2, mid_sharp, mid_sharp);
}
/// Add a line segment to the opacity function. All points which lay between x1 and x2
/// (inclusive) are removed from the function.
///
/// Note: alpha, midpoint, and sharpness values need to be between 0 and 1.0 (inclusive)
/// Return the index of the point x1 (0 based), or -1 on error
vtkm::Int32 AddSegmentAlpha(double x1,
float alpha1,
double x2,
float alpha2,
const vtkm::Vec<float, 2>& mid_sharp1,
const vtkm::Vec<float, 2>& mid_sharp2);
/// Get the location, alpha, midpoint and sharpness information for an existing
/// point in the opacity function.
///
/// Note: alpha, midpoint, and sharpness values all will be between 0 and 1.0 (inclusive)
/// Return the index of the point (0 based), or -1 on error.
bool GetPointAlpha(vtkm::Int32 index, vtkm::Vec<double, 4>&) const;
/// Update the location, alpha, midpoint and sharpness information for an existing
/// point in the opacity function.
/// If the location value for the index is modified the point is removed from
/// the function and re-inserted in the proper sorted location
///
/// Note: alpha, midpoint, and sharpness values need to be between 0 and 1.0 (inclusive)
/// Return the new index of the updated point (0 based), or -1 on error.
vtkm::Int32 UpdatePointAlpha(vtkm::Int32 index, const vtkm::Vec<double, 4>&);
/// Remove the Opacity function point that exists at exactly x
///
/// Return true if the point x exists and has been removed
bool RemovePointAlpha(double x);
/// Remove the Opacity function point n
///
/// Return true if n >= 0 && n < GetNumberOfPointsAlpha
bool RemovePointAlpha(vtkm::Int32 index);
/// Returns the number of points in the alpha function
vtkm::Int32 GetNumberOfPointsAlpha() const;
/// Fill the Color table from a double pointer
///
/// The double pointer is required to have the layout out of [X1, R1,
/// G1, B1, X2, R2, G2, B2, ..., Xn, Rn, Gn, Bn] where n is the
/// number of nodes.
/// This will remove any existing color 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 FillColorTableFromDataPointer(vtkm::Int32 n, const double* ptr);
/// Fill the Color table from a float pointer
///
/// The double pointer is required to have the layout out of [X1, R1,
/// G1, B1, X2, R2, G2, B2, ..., Xn, Rn, Gn, Bn] where n is the
/// number of nodes.
/// This will remove any existing color 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 FillColorTableFromDataPointer(vtkm::Int32 n, const float* ptr);
/// 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).
/// This will remove any existing opacity control points.
///
/// Note: n represents the length of the array, so ( n/2 == 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).
/// This will remove any existing opacity control points.
///
/// Note: n represents the length of the array, so ( n/2 == 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);
/// \brief Sample each value through an intermediate lookup/sample table to generate RGBA colors
///
/// Each value in \c values is binned based on its value in relationship to the range
/// of the color table and will use the color value at that bin from the \c samples.
/// To generate the lookup table use \c Sample .
///
/// Here is a simple example.
/// \code{.cpp}
///
/// vtkm::cont::ColorTableSamplesRGBA samples;
/// vtkm::cont::ColorTable table("black-body radiation");
/// table.Sample(256, samples);
/// vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> colors;
/// table.Map(input, samples, colors);
///
/// \endcode
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Sample each value through an intermediate lookup/sample table to generate RGB colors
///
/// Each value in \c values is binned based on its value in relationship to the range
/// of the color table and will use the color value at that bin from the \c samples.
/// To generate the lookup table use \c Sample .
///
/// Here is a simple example.
/// \code{.cpp}
///
/// vtkm::cont::ColorTableSamplesRGB samples;
/// vtkm::cont::ColorTable table("black-body radiation");
/// table.Sample(256, samples);
/// vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
/// table.Map(input, samples, colors);
///
/// \endcode
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbaOut) const;
/// \brief Use magnitude of a vector with a sample table to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use magnitude of a vector with a sample table to generate RGB colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbaOut) const;
/// \brief Use a single component of a vector with a sample table to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use a single component of a vector with a sample table to generate RGB colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief Interpolate each value through the color table to generate RGBA colors
///
/// Each value in \c values will be sampled through the entire color table
/// to determine a color.
///
/// Note: This is more costly than using Sample/Map with the generated intermediate lookup table
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Interpolate each value through the color table to generate RGB colors
///
/// Each value in \c values will be sampled through the entire color table
/// to determine a color.
///
/// Note: This is more costly than using Sample/Map with the generated intermediate lookup table
template <typename T, typename S>
bool Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief Use magnitude of a vector to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use magnitude of a vector to generate RGB colors
///
template <typename T, int N, typename S>
bool MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief Use a single component of a vector to generate RGBA colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const;
/// \brief Use a single component of a vector to generate RGB colors
///
template <typename T, int N, typename S>
bool MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const;
/// \brief generate RGB colors using regular spaced samples along the range.
///
/// Will use the current range of the color table to generate evenly spaced
/// values using either vtkm::Float32 or vtkm::Float64 space.
/// Will use vtkm::Float32 space when the difference between the float and double
/// values when the range is withing float space and the following are within a tolerance:
///
/// - (max-min) / numSamples
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGBA& samples,
double tolerance = 0.002) const;
/// \brief generate a sample lookup table using regular spaced samples along the range.
///
/// Will use the current range of the color table to generate evenly spaced
/// values using either vtkm::Float32 or vtkm::Float64 space.
/// Will use vtkm::Float32 space when the difference between the float and double
/// values when the range is withing float space and the following are within a tolerance:
///
/// - (max-min) / numSamples
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ColorTableSamplesRGB& samples,
double tolerance = 0.002) const;
/// \brief generate RGBA colors using regular spaced samples along the range.
///
/// Will use the current range of the color table to generate evenly spaced
/// values using either vtkm::Float32 or vtkm::Float64 space.
/// Will use vtkm::Float32 space when the difference between the float and double
/// values when the range is withing float space and the following are within a tolerance:
///
/// - (max-min) / numSamples
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& colors,
double tolerance = 0.002) const;
/// \brief generate RGB colors using regular spaced samples along the range.
///
/// Will use the current range of the color table to generate evenly spaced
/// values using either vtkm::Float32 or vtkm::Float64 space.
/// Will use vtkm::Float32 space when the difference between the float and double
/// values when the range is withing float space and the following are within a tolerance:
///
/// - (max-min) / numSamples
/// - ((max-min) / numSamples) * numSamples
///
/// Note: This will return false if the number of samples is less than 2
bool Sample(vtkm::Int32 numSamples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& colors,
double tolerance = 0.002) const;
/// \brief returns a virtual object handle of the exec color table
///
/// This object is only valid as long as the ColorTable is unmodified
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* GetHandleForExecution() const;
//Todo:
//
// 1. Implement Preset Methods
};
}
} //namespace vtkm::cont
#endif //vtk_m_cont_ColorTable_h

229
vtkm/cont/ColorTable.hxx Normal file

@ -0,0 +1,229 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleTransform.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/colorconversion/LookupTable.h>
#include <vtkm/worklet/colorconversion/Portals.h>
#include <vtkm/worklet/colorconversion/TransferFunction.h>
#include <vtkm/exec/ColorTable.h>
namespace vtkm
{
namespace cont
{
namespace detail
{
struct map_color_table
{
template <typename DeviceAdapter, typename ColorTable, typename... Args>
bool operator()(DeviceAdapter device, ColorTable&& colors, Args&&... args) const
{
using namespace vtkm::worklet::colorconversion;
TransferFunction transfer(colors->PrepareForExecution(device));
vtkm::worklet::DispatcherMapField<TransferFunction, DeviceAdapter> dispatcher(transfer);
dispatcher.Invoke(std::forward<Args>(args)...);
return true;
}
};
struct map_color_table_with_samples
{
template <typename DeviceAdapter, typename... Args>
bool operator()(DeviceAdapter,
const vtkm::worklet::colorconversion::LookupTable& lookupTable,
Args&&... args) const
{
using namespace vtkm::worklet::colorconversion;
vtkm::worklet::DispatcherMapField<LookupTable, DeviceAdapter> dispatcher(lookupTable);
dispatcher.Invoke(std::forward<Args>(args)...);
return true;
}
};
struct transfer_color_table_to_device
{
template <typename DeviceAdapter, typename ColorTableInternals>
bool operator()(DeviceAdapter device,
vtkm::exec::ColorTableBase* portal,
ColorTableInternals* internals)
{
auto p1 = internals->ColorPosHandle.PrepareForInput(device);
auto p2 = internals->ColorRGBHandle.PrepareForInput(device);
auto p3 = internals->OpacityPosHandle.PrepareForInput(device);
auto p4 = internals->OpacityAlphaHandle.PrepareForInput(device);
auto p5 = internals->OpacityMidSharpHandle.PrepareForInput(device);
//The rest of the data member on portal are set when-ever the user
//modifies the ColorTable instance and don't need to specified here
portal->ColorSize = static_cast<vtkm::Int32>(internals->ColorPosHandle.GetNumberOfValues());
portal->OpacitySize = static_cast<vtkm::Int32>(internals->OpacityPosHandle.GetNumberOfValues());
#if !defined(VTKM_MSVC) || (defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL == 0)
portal->ColorNodes = vtkm::cont::ArrayPortalToIteratorBegin(p1);
portal->RGB = vtkm::cont::ArrayPortalToIteratorBegin(p2);
portal->ONodes = vtkm::cont::ArrayPortalToIteratorBegin(p3);
portal->Alpha = vtkm::cont::ArrayPortalToIteratorBegin(p4);
portal->MidSharp = vtkm::cont::ArrayPortalToIteratorBegin(p5);
#else
//ArrayPortalToIteratorBegin is returning a checked_array_iterator so
//we need to grab the underlying pointer
portal->ColorNodes = vtkm::cont::ArrayPortalToIteratorBegin(p1).base();
portal->RGB = vtkm::cont::ArrayPortalToIteratorBegin(p2).base();
portal->ONodes = vtkm::cont::ArrayPortalToIteratorBegin(p3).base();
portal->Alpha = vtkm::cont::ArrayPortalToIteratorBegin(p4).base();
portal->MidSharp = vtkm::cont::ArrayPortalToIteratorBegin(p5).base();
#endif
return true;
}
};
}
//---------------------------------------------------------------------------
template <typename T, typename S>
bool ColorTable::Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const
{
if (samples.NumberOfSamples <= 0)
{
return false;
}
vtkm::worklet::colorconversion::LookupTable lookupTable(samples);
return vtkm::cont::TryExecute(
detail::map_color_table_with_samples{}, lookupTable, values, samples.Samples, rgbaOut);
}
//---------------------------------------------------------------------------
template <typename T, typename S>
bool ColorTable::Map(const vtkm::cont::ArrayHandle<T, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const
{
if (samples.NumberOfSamples <= 0)
{
return false;
}
vtkm::worklet::colorconversion::LookupTable lookupTable(samples);
return vtkm::cont::TryExecute(
detail::map_color_table_with_samples{}, lookupTable, values, samples.Samples, rgbOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(
vtkm::cont::make_ArrayHandleTransform(values, MagnitudePortal()), samples, rgbaOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(
vtkm::cont::make_ArrayHandleTransform(values, MagnitudePortal()), samples, rgbOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGBA& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(
vtkm::cont::make_ArrayHandleTransform(values, ComponentPortal(comp)), samples, rgbaOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
const vtkm::cont::ColorTableSamplesRGB& samples,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(
vtkm::cont::make_ArrayHandleTransform(values, ComponentPortal(comp)), samples, rgbOut);
}
//---------------------------------------------------------------------------
template <typename T, typename S>
bool ColorTable::Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const
{
return vtkm::cont::TryExecute(
detail::map_color_table{}, this->GetHandleForExecution(), values, rgbaOut);
}
//---------------------------------------------------------------------------
template <typename T, typename S>
bool ColorTable::Map(const vtkm::cont::ArrayHandle<T, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const
{
return vtkm::cont::TryExecute(
detail::map_color_table{}, this->GetHandleForExecution(), values, rgbOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(vtkm::cont::make_ArrayHandleTransform(values, MagnitudePortal()), rgbaOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapMagnitude(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(vtkm::cont::make_ArrayHandleTransform(values, MagnitudePortal()), rgbOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& rgbaOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(vtkm::cont::make_ArrayHandleTransform(values, ComponentPortal(comp)), rgbaOut);
}
//---------------------------------------------------------------------------
template <typename T, int N, typename S>
bool ColorTable::MapComponent(const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, S>& values,
vtkm::IdComponent comp,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>>& rgbOut) const
{
using namespace vtkm::worklet::colorconversion;
return this->Map(vtkm::cont::make_ArrayHandleTransform(values, ComponentPortal(comp)), rgbOut);
}
}
}

@ -0,0 +1,375 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/Range.h>
#include <vtkm/Types.h>
#include <vtkm/cont/VirtualObjectHandle.h>
#include <vtkm/exec/ColorTable.h>
#include <limits>
#include <vector>
namespace vtkm
{
namespace cont
{
namespace detail
{
struct ColorTableInternals
{
ColorSpace CSpace = ColorSpace::RGB;
vtkm::Range TableRange = { 1.0, 0.0 };
//Host side version of the ColorTableBase. This holds data such as:
// NanColor
// BelowRangeColor
// AboveRangeColor
// UseClamping
// BelowRangeColor
// AboveRangeColor
//Note the pointers inside the host side portal are not valid, as they
//are execution
vtkm::exec::ColorTableBase* HostSideCache = nullptr;
//Execution side version of the ColorTableBase.
vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* ExecHandle = nullptr;
std::vector<double> ColorNodePos;
std::vector<vtkm::Vec<float, 3>> ColorRGB;
std::vector<double> OpacityNodePos;
std::vector<float> OpacityAlpha;
std::vector<vtkm::Vec<float, 2>> OpacityMidSharp;
vtkm::cont::ArrayHandle<double> ColorPosHandle;
vtkm::cont::ArrayHandle<vtkm::Vec<float, 3>> ColorRGBHandle;
vtkm::cont::ArrayHandle<double> OpacityPosHandle;
vtkm::cont::ArrayHandle<float> OpacityAlphaHandle;
vtkm::cont::ArrayHandle<vtkm::Vec<float, 2>> OpacityMidSharpHandle;
bool ColorArraysChanged = true;
bool OpacityArraysChanged = true;
void RecalculateRange()
{
vtkm::Range r;
if (this->ColorNodePos.size() > 0)
{
r.Include(this->ColorNodePos.front());
r.Include(this->ColorNodePos.back());
}
if (this->OpacityNodePos.size() > 0)
{
r.Include(this->OpacityNodePos.front());
r.Include(this->OpacityNodePos.back());
}
this->TableRange = r;
}
};
} //namespace detail
namespace
{
template <typename T>
struct MinDelta
{
};
// This value seems to work well for float ranges we have tested
template <>
struct MinDelta<float>
{
static constexpr int value = 2048;
};
template <>
struct MinDelta<double>
{
static constexpr vtkm::Int64 value = 2048L;
};
// Reperesents the following:
// T m = std::numeric_limits<T>::min();
// EquivSizeIntT im;
// std::memcpy(&im, &m, sizeof(T));
//
template <typename EquivSizeIntT>
struct MinRepresentable
{
};
template <>
struct MinRepresentable<float>
{
static constexpr int value = 8388608;
};
template <>
struct MinRepresentable<double>
{
static constexpr vtkm::Int64 value = 4503599627370496L;
};
bool rangeAlmostEqual(const vtkm::Range& r)
{
vtkm::Int64 irange[2];
// needs to be a memcpy to avoid strict aliasing issues, doing a count
// of 2*sizeof(T) to couple both values at the same time
std::memcpy(irange, &r.Min, sizeof(vtkm::Int64));
std::memcpy(irange, &r.Max, sizeof(vtkm::Int64));
// determine the absolute delta between these two numbers.
const vtkm::Int64 delta = std::abs(irange[1] - irange[0]);
// If the numbers are not nearly equal, we don't touch them. This avoids running into
// pitfalls like BUG PV #17152.
return (delta < 1024) ? true : false;
}
template <typename T>
double expandRange(T r[2])
{
constexpr bool is_float32_type = std::is_same<T, vtkm::Float32>::value;
using IRange = typename std::conditional<is_float32_type, vtkm::Int32, vtkm::Int64>::type;
IRange irange[2];
// needs to be a memcpy to avoid strict aliasing issues, doing a count
// of 2*sizeof(T) to couple both values at the same time
std::memcpy(irange, r, sizeof(T) * 2);
const bool denormal = !std::isnormal(r[0]);
const IRange minInt = MinRepresentable<T>::value;
const IRange minDelta = denormal ? minInt + MinDelta<T>::value : MinDelta<T>::value;
// determine the absolute delta between these two numbers.
const vtkm::Int64 delta = std::abs(irange[1] - irange[0]);
// if our delta is smaller than the min delta push out the max value
// so that it is equal to minRange + minDelta. When our range is entirely
// negative we should instead subtract from our max, to max a larger negative
// value
if (delta < minDelta)
{
if (irange[0] < 0)
{
irange[1] = irange[0] - minDelta;
}
else
{
irange[1] = irange[0] + minDelta;
}
T result;
std::memcpy(&result, irange + 1, sizeof(T));
return static_cast<double>(result);
}
return static_cast<double>(r[1]);
}
vtkm::Range adjustRange(const vtkm::Range& r)
{
const bool spans_zero_boundary = r.Min < 0 && r.Max > 0;
if (spans_zero_boundary)
{ // nothing needs to be done, but this check is required.
// if we convert into integer space the delta difference will overflow
// an integer
return r;
}
if (rangeAlmostEqual(r))
{
return r;
}
// range should be left untouched as much as possible to
// to avoid loss of precision whenever possible. That is why
// we only modify the Max value
vtkm::Range result = r;
if (r.Min > static_cast<double>(std::numeric_limits<float>::lowest()) &&
r.Max < static_cast<double>(std::numeric_limits<float>::max()))
{ //We've found it best to offset it in float space if the numbers
//lay inside that representable range
float frange[2] = { static_cast<float>(r.Min), static_cast<float>(r.Max) };
result.Max = expandRange(frange);
}
else
{
double drange[2] = { r.Min, r.Max };
result.Max = expandRange(drange);
}
return result;
}
template <typename T>
vtkm::cont::ArrayHandle<T> buildSampleHandle(std::vector<T>& samples,
vtkm::Int32 numSamples,
T start,
T end,
T inc,
bool appendNanAndRangeColors)
{
int extra_values = (appendNanAndRangeColors) ? 0 : 4;
samples.reserve(static_cast<std::size_t>(numSamples + extra_values));
//Insert the below range first
if (appendNanAndRangeColors)
{
samples.push_back(std::numeric_limits<T>::lowest()); //below
}
for (T i = start; i < end; i += inc)
{
samples.push_back(i);
}
samples.push_back(end);
if (appendNanAndRangeColors)
{
//push back the last value again so that when lookups near the max value
//occur we can
samples.push_back(end);
samples.push_back(std::numeric_limits<T>::max()); //above
samples.push_back(vtkm::Nan<T>()); //nan
}
return vtkm::cont::make_ArrayHandle(samples);
}
template <typename ColorTable, typename OutputColors>
bool sampleColorTable(const ColorTable* self,
vtkm::Int32 numSamples,
OutputColors& colors,
double tolerance,
bool appendNanAndRangeColors)
{
vtkm::Range r = self->GetRange();
//We want the samples to start at Min, and end at Max so that means
//we want actually to interpolate numSample - 1 values. For example
//for range 0 - 1, we want the values 0, 0.5, and 1.
const double d_samples = static_cast<double>(numSamples - 1);
const double d_delta = r.Length() / d_samples;
if (r.Min > static_cast<double>(std::numeric_limits<float>::lowest()) &&
r.Max < static_cast<double>(std::numeric_limits<float>::max()))
{
//we can try and see if float space has enough resolution
const float f_samples = static_cast<float>(numSamples - 1);
const float f_start = static_cast<float>(r.Min);
const float f_delta = static_cast<float>(r.Length()) / f_samples;
const float f_end = f_delta * f_samples;
if (vtkm::Abs(static_cast<double>(f_end) - r.Max) <= tolerance &&
vtkm::Abs(static_cast<double>(f_delta) - d_delta) <= tolerance)
{
std::vector<float> samples;
auto handle =
buildSampleHandle(samples, numSamples, f_start, f_end, f_delta, appendNanAndRangeColors);
return self->Map(handle, colors);
}
}
//otherwise we need to use double space
std::vector<double> samples;
auto handle =
buildSampleHandle(samples, numSamples, r.Min, r.Max, d_delta, appendNanAndRangeColors);
return self->Map(handle, colors);
}
vtkm::Vec<double, 3> hsvTorgb(const vtkm::Vec<double, 3>& hsv)
{
vtkm::Vec<double, 3> rgb;
constexpr double onethird = 1.0 / 3.0;
constexpr double onesixth = 1.0 / 6.0;
constexpr double twothird = 2.0 / 3.0;
constexpr double fivesixth = 5.0 / 6.0;
// compute RGB from HSV
if (hsv[0] > onesixth && hsv[0] <= onethird) // green/red
{
rgb[1] = 1.0;
rgb[0] = (onethird - hsv[0]) * 6;
rgb[2] = 0.0;
}
else if (hsv[0] > onethird && hsv[0] <= 0.5) // green/blue
{
rgb[1] = 1.0;
rgb[2] = (hsv[0] - onethird) * 6;
rgb[0] = 0.0;
}
else if (hsv[0] > 0.5 && hsv[0] <= twothird) // blue/green
{
rgb[2] = 1.0;
rgb[1] = (twothird - hsv[0]) * 6;
rgb[0] = 0.0;
}
else if (hsv[0] > twothird && hsv[0] <= fivesixth) // blue/red
{
rgb[2] = 1.0;
rgb[0] = (hsv[0] - twothird) * 6;
rgb[1] = 0.0;
}
else if (hsv[0] > fivesixth && hsv[0] <= 1.0) // red/blue
{
rgb[0] = 1.0;
rgb[2] = (1.0 - hsv[0]) * 6;
rgb[1] = 0.0;
}
else // red/green
{
rgb[0] = 1.0;
rgb[1] = hsv[0] * 6;
rgb[2] = 0.0;
}
// add Saturation to the equation.
rgb[0] = (hsv[1] * rgb[0] + (1.0 - hsv[1]));
rgb[1] = (hsv[1] * rgb[1] + (1.0 - hsv[1]));
rgb[2] = (hsv[1] * rgb[2] + (1.0 - hsv[1]));
rgb[0] *= hsv[2];
rgb[1] *= hsv[2];
rgb[2] *= hsv[2];
return rgb;
}
// clang-format off
bool outside_vrange(double x) { return x < 0.0 || x > 1.0; }
bool outside_vrange(const vtkm::Vec<double, 2>& x)
{ return x[0] < 0.0 || x[0] > 1.0 || x[1] < 0.0 || x[1] > 1.0; }
bool outside_vrange(const vtkm::Vec<double, 3>& x)
{ return x[0] < 0.0 || x[0] > 1.0 || x[1] < 0.0 || x[1] > 1.0 || x[2] < 0.0 || x[2] > 1.0; }
bool outside_range() { return false; }
template <typename T>
bool outside_range(T&& t) { return outside_vrange(t); }
template <typename T, typename U>
bool outside_range(T&& t, U&& u) { return outside_vrange(t) || outside_vrange(u); }
template <typename T, typename U, typename V, typename... Args>
bool outside_range(T&& t, U&& u, V&& v, Args&&... args)
{
return outside_vrange(t) || outside_vrange(u) || outside_vrange(v) ||
outside_range(std::forward<Args>(args)...);
}
// clang-format on
}
} //namespace cont
} //namespace vtkm

@ -0,0 +1,71 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_ColorTableSamples_h
#define vtk_m_cont_ColorTableSamples_h
#include <vtkm/Range.h>
#include <vtkm/cont/ArrayHandle.h>
namespace vtkm
{
namespace cont
{
/// \brief Color Sample Table used with vtkm::cont::ColorTable for fast coloring
///
/// Holds a special layout of sampled values with the pattern of
/// [Below Color, samples, last sample value again, Above Color, Nan Color ]
///
/// This layout has been chosen as it allows for efficient access for values
/// inside the range, and values outside the range. The last value being duplicated
/// a second time is an optimization for fast interpolation of values that are
/// very near to the Max value of the range.
///
///
class ColorTableSamplesRGBA
{
public:
vtkm::Range SampleRange = { 1.0, 0.0 };
vtkm::Int32 NumberOfSamples = 0; // this will not include end padding, NaN, Below or Above Range
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> Samples;
};
/// \brief Color Sample Table used with vtkm::cont::ColorTable for fast coloring
///
/// Holds a special layout of sampled values with the pattern of
/// [Below Color, samples, last sample value again, Above Color ]
///
/// This layout has been chosen as it allows for efficient access for values
/// inside the range, and values outside the range. The last value being duplicated
/// a second time is an optimization for fast interpolation of values that are
/// very near to the Max value of the range.
///
///
class ColorTableSamplesRGB
{
public:
vtkm::Range SampleRange = { 1.0, 0.0 };
vtkm::Int32 NumberOfSamples = 0; // this will not include end padding, NaN, Below or Above Range
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> Samples;
};
}
}
#endif

@ -0,0 +1,609 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/vtkm_cont_export.h>
#include <algorithm>
#include <cctype>
#include <set>
namespace
{
template <int Points>
struct ColorTable
{
static constexpr int points = Points;
static constexpr int size = points * 4;
const vtkm::cont::ColorSpace space;
const double values[size];
};
// clang-format off
static constexpr ColorTable<3> CoolToWarm = {
vtkm::cont::ColorSpace::DIVERGING,
{ 0, 0.23137254902, 0.298039215686, 0.752941176471,
0.5, 0.865, 0.865, 0.865,
1, 0.705882352941, 0.0156862745098, 0.149019607843
}
};
static constexpr ColorTable<4> BlackBody = {
vtkm::cont::ColorSpace::RGB,
{ 0, 0, 0, 0,
0.4, 0.901960784314, 0, 0,
0.8, 0.901960784314, 0.901960784314, 0,
1, 1, 1, 1
}
};
static constexpr ColorTable<4> SamselFire = {
vtkm::cont::ColorSpace::RGB,
{ 0, 0, 0, 0,
0.333, 0.501960784314, 0, 0,
0.666, 1, 0.501960784314, 0,
1, 1, 1, 1
}
};
static constexpr ColorTable<256> Inferno = {
vtkm::cont::ColorSpace::LAB,
{ 0.000000, 0.001462, 0.000466, 0.013866, 0.003922, 0.002267, 0.001270, 0.018570, 0.007843,
0.003299, 0.002249, 0.024239, 0.011765, 0.004547, 0.003392, 0.030909, 0.015686, 0.006006,
0.004692, 0.038558, 0.019608, 0.007676, 0.006136, 0.046836, 0.023529, 0.009561, 0.007713,
0.055143, 0.027451, 0.011663, 0.009417, 0.063460, 0.031373, 0.013995, 0.011225, 0.071862,
0.035294, 0.016561, 0.013136, 0.080282, 0.039216, 0.019373, 0.015133, 0.088767, 0.043137,
0.022447, 0.017199, 0.097327, 0.047059, 0.025793, 0.019331, 0.105930, 0.050980, 0.029432,
0.021503, 0.114621, 0.054902, 0.033385, 0.023702, 0.123397, 0.058824, 0.037668, 0.025921,
0.132232, 0.062745, 0.042253, 0.028139, 0.141141, 0.066667, 0.046915, 0.030324, 0.150164,
0.070588, 0.051644, 0.032474, 0.159254, 0.074510, 0.056449, 0.034569, 0.168414, 0.078431,
0.061340, 0.036590, 0.177642, 0.082353, 0.066331, 0.038504, 0.186962, 0.086275, 0.071429,
0.040294, 0.196354, 0.090196, 0.076637, 0.041905, 0.205799, 0.094118, 0.081962, 0.043328,
0.215289, 0.098039, 0.087411, 0.044556, 0.224813, 0.101961, 0.092990, 0.045583, 0.234358,
0.105882, 0.098702, 0.046402, 0.243904, 0.109804, 0.104551, 0.047008, 0.253430, 0.113725,
0.110536, 0.047399, 0.262912, 0.117647, 0.116656, 0.047574, 0.272321, 0.121569, 0.122908,
0.047536, 0.281624, 0.125490, 0.129285, 0.047293, 0.290788, 0.129412, 0.135778, 0.046856,
0.299776, 0.133333, 0.142378, 0.046242, 0.308553, 0.137255, 0.149073, 0.045468, 0.317085,
0.141176, 0.155850, 0.044559, 0.325338, 0.145098, 0.162689, 0.043554, 0.333277, 0.149020,
0.169575, 0.042489, 0.340874, 0.152941, 0.176493, 0.041402, 0.348111, 0.156863, 0.183429,
0.040329, 0.354971, 0.160784, 0.190367, 0.039309, 0.361447, 0.164706, 0.197297, 0.038400,
0.367535, 0.168627, 0.204209, 0.037632, 0.373238, 0.172549, 0.211095, 0.037030, 0.378563,
0.176471, 0.217949, 0.036615, 0.383522, 0.180392, 0.224763, 0.036405, 0.388129, 0.184314,
0.231538, 0.036405, 0.392400, 0.188235, 0.238273, 0.036621, 0.396353, 0.192157, 0.244967,
0.037055, 0.400007, 0.196078, 0.251620, 0.037705, 0.403378, 0.200000, 0.258234, 0.038571,
0.406485, 0.203922, 0.264810, 0.039647, 0.409345, 0.207843, 0.271347, 0.040922, 0.411976,
0.211765, 0.277850, 0.042353, 0.414392, 0.215686, 0.284321, 0.043933, 0.416608, 0.219608,
0.290763, 0.045644, 0.418637, 0.223529, 0.297178, 0.047470, 0.420491, 0.227451, 0.303568,
0.049396, 0.422182, 0.231373, 0.309935, 0.051407, 0.423721, 0.235294, 0.316282, 0.053490,
0.425116, 0.239216, 0.322610, 0.055634, 0.426377, 0.243137, 0.328921, 0.057827, 0.427511,
0.247059, 0.335217, 0.060060, 0.428524, 0.250980, 0.341500, 0.062325, 0.429425, 0.254902,
0.347771, 0.064616, 0.430217, 0.258824, 0.354032, 0.066925, 0.430906, 0.262745, 0.360284,
0.069247, 0.431497, 0.266667, 0.366529, 0.071579, 0.431994, 0.270588, 0.372768, 0.073915,
0.432400, 0.274510, 0.379001, 0.076253, 0.432719, 0.278431, 0.385228, 0.078591, 0.432955,
0.282353, 0.391453, 0.080927, 0.433109, 0.286275, 0.397674, 0.083257, 0.433183, 0.290196,
0.403894, 0.085580, 0.433179, 0.294118, 0.410113, 0.087896, 0.433098, 0.298039, 0.416331,
0.090203, 0.432943, 0.301961, 0.422549, 0.092501, 0.432714, 0.305882, 0.428768, 0.094790,
0.432412, 0.309804, 0.434987, 0.097069, 0.432039, 0.313725, 0.441207, 0.099338, 0.431594,
0.317647, 0.447428, 0.101597, 0.431080, 0.321569, 0.453651, 0.103848, 0.430498, 0.325490,
0.459875, 0.106089, 0.429846, 0.329412, 0.466100, 0.108322, 0.429125, 0.333333, 0.472328,
0.110547, 0.428334, 0.337255, 0.478558, 0.112764, 0.427475, 0.341176, 0.484789, 0.114974,
0.426548, 0.345098, 0.491022, 0.117179, 0.425552, 0.349020, 0.497257, 0.119379, 0.424488,
0.352941, 0.503493, 0.121575, 0.423356, 0.356863, 0.509730, 0.123769, 0.422156, 0.360784,
0.515967, 0.125960, 0.420887, 0.364706, 0.522206, 0.128150, 0.419549, 0.368627, 0.528444,
0.130341, 0.418142, 0.372549, 0.534683, 0.132534, 0.416667, 0.376471, 0.540920, 0.134729,
0.415123, 0.380392, 0.547157, 0.136929, 0.413511, 0.384314, 0.553392, 0.139134, 0.411829,
0.388235, 0.559624, 0.141346, 0.410078, 0.392157, 0.565854, 0.143567, 0.408258, 0.396078,
0.572081, 0.145797, 0.406369, 0.400000, 0.578304, 0.148039, 0.404411, 0.403922, 0.584521,
0.150294, 0.402385, 0.407843, 0.590734, 0.152563, 0.400290, 0.411765, 0.596940, 0.154848,
0.398125, 0.415686, 0.603139, 0.157151, 0.395891, 0.419608, 0.609330, 0.159474, 0.393589,
0.423529, 0.615513, 0.161817, 0.391219, 0.427451, 0.621685, 0.164184, 0.388781, 0.431373,
0.627847, 0.166575, 0.386276, 0.435294, 0.633998, 0.168992, 0.383704, 0.439216, 0.640135,
0.171438, 0.381065, 0.443137, 0.646260, 0.173914, 0.378359, 0.447059, 0.652369, 0.176421,
0.375586, 0.450980, 0.658463, 0.178962, 0.372748, 0.454902, 0.664540, 0.181539, 0.369846,
0.458824, 0.670599, 0.184153, 0.366879, 0.462745, 0.676638, 0.186807, 0.363849, 0.466667,
0.682656, 0.189501, 0.360757, 0.470588, 0.688653, 0.192239, 0.357603, 0.474510, 0.694627,
0.195021, 0.354388, 0.478431, 0.700576, 0.197851, 0.351113, 0.482353, 0.706500, 0.200728,
0.347777, 0.486275, 0.712396, 0.203656, 0.344383, 0.490196, 0.718264, 0.206636, 0.340931,
0.494118, 0.724103, 0.209670, 0.337424, 0.498039, 0.729909, 0.212759, 0.333861, 0.501961,
0.735683, 0.215906, 0.330245, 0.505882, 0.741423, 0.219112, 0.326576, 0.509804, 0.747127,
0.222378, 0.322856, 0.513725, 0.752794, 0.225706, 0.319085, 0.517647, 0.758422, 0.229097,
0.315266, 0.521569, 0.764010, 0.232554, 0.311399, 0.525490, 0.769556, 0.236077, 0.307485,
0.529412, 0.775059, 0.239667, 0.303526, 0.533333, 0.780517, 0.243327, 0.299523, 0.537255,
0.785929, 0.247056, 0.295477, 0.541176, 0.791293, 0.250856, 0.291390, 0.545098, 0.796607,
0.254728, 0.287264, 0.549020, 0.801871, 0.258674, 0.283099, 0.552941, 0.807082, 0.262692,
0.278898, 0.556863, 0.812239, 0.266786, 0.274661, 0.560784, 0.817341, 0.270954, 0.270390,
0.564706, 0.822386, 0.275197, 0.266085, 0.568627, 0.827372, 0.279517, 0.261750, 0.572549,
0.832299, 0.283913, 0.257383, 0.576471, 0.837165, 0.288385, 0.252988, 0.580392, 0.841969,
0.292933, 0.248564, 0.584314, 0.846709, 0.297559, 0.244113, 0.588235, 0.851384, 0.302260,
0.239636, 0.592157, 0.855992, 0.307038, 0.235133, 0.596078, 0.860533, 0.311892, 0.230606,
0.600000, 0.865006, 0.316822, 0.226055, 0.603922, 0.869409, 0.321827, 0.221482, 0.607843,
0.873741, 0.326906, 0.216886, 0.611765, 0.878001, 0.332060, 0.212268, 0.615686, 0.882188,
0.337287, 0.207628, 0.619608, 0.886302, 0.342586, 0.202968, 0.623529, 0.890341, 0.347957,
0.198286, 0.627451, 0.894305, 0.353399, 0.193584, 0.631373, 0.898192, 0.358911, 0.188860,
0.635294, 0.902003, 0.364492, 0.184116, 0.639216, 0.905735, 0.370140, 0.179350, 0.643137,
0.909390, 0.375856, 0.174563, 0.647059, 0.912966, 0.381636, 0.169755, 0.650980, 0.916462,
0.387481, 0.164924, 0.654902, 0.919879, 0.393389, 0.160070, 0.658824, 0.923215, 0.399359,
0.155193, 0.662745, 0.926470, 0.405389, 0.150292, 0.666667, 0.929644, 0.411479, 0.145367,
0.670588, 0.932737, 0.417627, 0.140417, 0.674510, 0.935747, 0.423831, 0.135440, 0.678431,
0.938675, 0.430091, 0.130438, 0.682353, 0.941521, 0.436405, 0.125409, 0.686275, 0.944285,
0.442772, 0.120354, 0.690196, 0.946965, 0.449191, 0.115272, 0.694118, 0.949562, 0.455660,
0.110164, 0.698039, 0.952075, 0.462178, 0.105031, 0.701961, 0.954506, 0.468744, 0.099874,
0.705882, 0.956852, 0.475356, 0.094695, 0.709804, 0.959114, 0.482014, 0.089499, 0.713725,
0.961293, 0.488716, 0.084289, 0.717647, 0.963387, 0.495462, 0.079073, 0.721569, 0.965397,
0.502249, 0.073859, 0.725490, 0.967322, 0.509078, 0.068659, 0.729412, 0.969163, 0.515946,
0.063488, 0.733333, 0.970919, 0.522853, 0.058367, 0.737255, 0.972590, 0.529798, 0.053324,
0.741176, 0.974176, 0.536780, 0.048392, 0.745098, 0.975677, 0.543798, 0.043618, 0.749020,
0.977092, 0.550850, 0.039050, 0.752941, 0.978422, 0.557937, 0.034931, 0.756863, 0.979666,
0.565057, 0.031409, 0.760784, 0.980824, 0.572209, 0.028508, 0.764706, 0.981895, 0.579392,
0.026250, 0.768627, 0.982881, 0.586606, 0.024661, 0.772549, 0.983779, 0.593849, 0.023770,
0.776471, 0.984591, 0.601122, 0.023606, 0.780392, 0.985315, 0.608422, 0.024202, 0.784314,
0.985952, 0.615750, 0.025592, 0.788235, 0.986502, 0.623105, 0.027814, 0.792157, 0.986964,
0.630485, 0.030908, 0.796078, 0.987337, 0.637890, 0.034916, 0.800000, 0.987622, 0.645320,
0.039886, 0.803922, 0.987819, 0.652773, 0.045581, 0.807843, 0.987926, 0.660250, 0.051750,
0.811765, 0.987945, 0.667748, 0.058329, 0.815686, 0.987874, 0.675267, 0.065257, 0.819608,
0.987714, 0.682807, 0.072489, 0.823529, 0.987464, 0.690366, 0.079990, 0.827451, 0.987124,
0.697944, 0.087731, 0.831373, 0.986694, 0.705540, 0.095694, 0.835294, 0.986175, 0.713153,
0.103863, 0.839216, 0.985566, 0.720782, 0.112229, 0.843137, 0.984865, 0.728427, 0.120785,
0.847059, 0.984075, 0.736087, 0.129527, 0.850980, 0.983196, 0.743758, 0.138453, 0.854902,
0.982228, 0.751442, 0.147565, 0.858824, 0.981173, 0.759135, 0.156863, 0.862745, 0.980032,
0.766837, 0.166353, 0.866667, 0.978806, 0.774545, 0.176037, 0.870588, 0.977497, 0.782258,
0.185923, 0.874510, 0.976108, 0.789974, 0.196018, 0.878431, 0.974638, 0.797692, 0.206332,
0.882353, 0.973088, 0.805409, 0.216877, 0.886275, 0.971468, 0.813122, 0.227658, 0.890196,
0.969783, 0.820825, 0.238686, 0.894118, 0.968041, 0.828515, 0.249972, 0.898039, 0.966243,
0.836191, 0.261534, 0.901961, 0.964394, 0.843848, 0.273391, 0.905882, 0.962517, 0.851476,
0.285546, 0.909804, 0.960626, 0.859069, 0.298010, 0.913725, 0.958720, 0.866624, 0.310820,
0.917647, 0.956834, 0.874129, 0.323974, 0.921569, 0.954997, 0.881569, 0.337475, 0.925490,
0.953215, 0.888942, 0.351369, 0.929412, 0.951546, 0.896226, 0.365627, 0.933333, 0.950018,
0.903409, 0.380271, 0.937255, 0.948683, 0.910473, 0.395289, 0.941176, 0.947594, 0.917399,
0.410665, 0.945098, 0.946809, 0.924168, 0.426373, 0.949020, 0.946392, 0.930761, 0.442367,
0.952941, 0.946403, 0.937159, 0.458592, 0.956863, 0.946903, 0.943348, 0.474970, 0.960784,
0.947937, 0.949318, 0.491426, 0.964706, 0.949545, 0.955063, 0.507860, 0.968627, 0.951740,
0.960587, 0.524203, 0.972549, 0.954529, 0.965896, 0.540361, 0.976471, 0.957896, 0.971003,
0.556275, 0.980392, 0.961812, 0.975924, 0.571925, 0.984314, 0.966249, 0.980678, 0.587206,
0.988235, 0.971162, 0.985282, 0.602154, 0.992157, 0.976511, 0.989753, 0.616760, 0.996078,
0.982257, 0.994109, 0.631017, 1.000000, 0.988362, 0.998364, 0.644924
}
};
static constexpr ColorTable<22> LinearYGB = {
vtkm::cont::ColorSpace::LAB,
{ 0, 1, 0.988235, 0.968627,
0.02, 1, 0.952941, 0.878431,
0.05, 0.968627, 0.905882, 0.776471,
0.1, 0.94902, 0.898039, 0.6470590000000001,
0.15, 0.901961, 0.878431, 0.556863,
0.2, 0.847059, 0.858824, 0.482353,
0.25, 0.690196, 0.819608, 0.435294,
0.3, 0.513725, 0.7686269999999999, 0.384314,
0.35, 0.337255, 0.721569, 0.337255,
0.4, 0.278431, 0.658824, 0.392157,
0.45, 0.231373, 0.639216, 0.435294,
0.5, 0.203922, 0.6, 0.486275,
0.55, 0.172549, 0.568627, 0.537255,
0.6, 0.141176, 0.517647, 0.54902,
0.65, 0.133333, 0.458824, 0.541176,
0.7, 0.12549, 0.396078, 0.529412,
0.75, 0.117647, 0.321569, 0.5215689999999999,
0.8, 0.121569, 0.258824, 0.509804,
0.85, 0.133333, 0.227451, 0.501961,
0.9, 0.145098, 0.192157, 0.490196,
0.95, 0.188235, 0.164706, 0.470588,
1, 0.258824, 0.196078, 0.439216
}
};
static constexpr ColorTable<5> ColdAndHot = {
vtkm::cont::ColorSpace::RGB,
{ 0, 0, 1, 1,
0.45, 0, 0, 1,
0.5, 0, 0, 0.501960784314,
0.55, 1, 0, 0,
1, 1, 1, 0
}
};
static constexpr ColorTable<8> RainbowDesaturated = {
vtkm::cont::ColorSpace::RGB,
{ 0, 0.278431372549, 0.278431372549, 0.858823529412,
0.143, 0, 0, 0.360784313725,
0.285, 0, 1, 1,
0.429, 0, 0.501960784314, 0,
0.571, 1, 1, 0,
0.714, 1, 0.380392156863, 0,
0.857, 0.419607843137, 0, 0,
1, 0.8784313725489999, 0.301960784314, 0.301960784314
}
};
static constexpr ColorTable<35> CoolToWarmExtended = {
vtkm::cont::ColorSpace::LAB,
{ 0, 0, 0, 0.34902,
0.03125, 0.039216, 0.062745, 0.380392,
0.0625, 0.062745, 0.117647, 0.411765,
0.09375, 0.090196, 0.184314, 0.45098,
0.125, 0.12549, 0.262745, 0.501961,
0.15625, 0.160784, 0.337255, 0.541176,
0.1875, 0.2, 0.396078, 0.568627,
0.21875, 0.239216, 0.454902, 0.6,
0.25, 0.286275, 0.5215689999999999, 0.65098,
0.28125, 0.337255, 0.592157, 0.7019609999999999,
0.3125, 0.388235, 0.654902, 0.74902,
0.34375, 0.466667, 0.737255, 0.819608,
0.375, 0.572549, 0.819608, 0.878431,
0.40625, 0.654902, 0.866667, 0.9098039999999999,
0.4375, 0.752941, 0.917647, 0.941176,
0.46875, 0.823529, 0.956863, 0.968627,
0.5, 0.988235, 0.960784, 0.901961,
0.5, 0.941176, 0.984314, 0.988235,
0.52, 0.988235, 0.945098, 0.85098,
0.54, 0.980392, 0.898039, 0.784314,
0.5625, 0.968627, 0.835294, 0.698039,
0.59375, 0.94902, 0.733333, 0.588235,
0.625, 0.929412, 0.65098, 0.509804,
0.65625, 0.9098039999999999, 0.564706, 0.435294,
0.6875, 0.878431, 0.458824, 0.352941,
0.71875, 0.839216, 0.388235, 0.286275,
0.75, 0.760784, 0.294118, 0.211765,
0.78125, 0.7019609999999999, 0.211765, 0.168627,
0.8125, 0.65098, 0.156863, 0.129412,
0.84375, 0.6, 0.09411799999999999, 0.09411799999999999,
0.875, 0.54902, 0.066667, 0.098039,
0.90625, 0.501961, 0.05098, 0.12549,
0.9375, 0.45098, 0.054902, 0.172549,
0.96875, 0.4, 0.054902, 0.192157,
1, 0.34902, 0.070588, 0.211765
}
};
static constexpr ColorTable<2> XRay = {
vtkm::cont::ColorSpace::RGB,
{ 0, 1, 1, 1,
1, 0, 0, 0
}
};
static constexpr ColorTable<4> BlackBlueWhite = {
vtkm::cont::ColorSpace::RGB,
{ 0, 0, 0, 0,
0.333, 0, 0, 0.501960784314,
0.666, 0, 0.501960784314, 1,
1, 1, 1, 1
}
};
static constexpr ColorTable<21> LinearGreen = {
vtkm::cont::ColorSpace::LAB,
{ 0, 0.054901999999999999, 0.109804, 0.121569, 0.050000000000000003,
0.074510000000000007, 0.17254900000000001, 0.180392, 0.10000000000000001,
0.086275000000000004, 0.231373, 0.219608, 0.14999999999999999,
0.094117999999999993, 0.27843099999999998, 0.25097999999999998,
0.20000000000000001, 0.109804, 0.34902, 0.27843099999999998, 0.25,
0.11372500000000001, 0.40000000000000002, 0.27843099999999998,
0.29999999999999999, 0.117647, 0.45097999999999999, 0.270588,
0.34999999999999998, 0.117647, 0.49019600000000002, 0.24313699999999999,
0.40000000000000002, 0.11372500000000001, 0.52156899999999995,
0.20392199999999999, 0.45000000000000001, 0.109804, 0.54901999999999995,
0.15294099999999999, 0.5, 0.082352999999999996, 0.58823499999999995,
0.082352999999999996, 0.55000000000000004, 0.109804, 0.63137299999999996,
0.050979999999999998, 0.59999999999999998, 0.21176500000000001,
0.67843100000000001, 0.082352999999999996, 0.65000000000000002,
0.31764700000000001, 0.72156900000000002, 0.11372500000000001,
0.69999999999999996, 0.43137300000000001, 0.76078400000000002,
0.16078400000000001, 0.75, 0.556863, 0.80000000000000004,
0.23921600000000001, 0.80000000000000004, 0.66666700000000001,
0.83921599999999996, 0.29411799999999999, 0.84999999999999998,
0.78431399999999996, 0.87843099999999996, 0.39607799999999999,
0.90000000000000002, 0.88627500000000003, 0.92156899999999997,
0.53333299999999995, 0.94999999999999996, 0.96078399999999997,
0.94901999999999997, 0.67058799999999996, 1, 1, 0.98431400000000002,
0.90196100000000001
}
};
static constexpr ColorTable<256> Virdis =
{
vtkm::cont::ColorSpace::LAB,
{ 0.000000, 0.267004, 0.004874, 0.329415, 0.003922, 0.268510, 0.009605, 0.335427, 0.007843,
0.269944, 0.014625, 0.341379, 0.011765, 0.271305, 0.019942, 0.347269, 0.015686, 0.272594,
0.025563, 0.353093, 0.019608, 0.273809, 0.031497, 0.358853, 0.023529, 0.274952, 0.037752,
0.364543, 0.027451, 0.276022, 0.044167, 0.370164, 0.031373, 0.277018, 0.050344, 0.375715,
0.035294, 0.277941, 0.056324, 0.381191, 0.039216, 0.278791, 0.062145, 0.386592, 0.043137,
0.279566, 0.067836, 0.391917, 0.047059, 0.280267, 0.073417, 0.397163, 0.050980, 0.280894,
0.078907, 0.402329, 0.054902, 0.281446, 0.084320, 0.407414, 0.058824, 0.281924, 0.089666,
0.412415, 0.062745, 0.282327, 0.094955, 0.417331, 0.066667, 0.282656, 0.100196, 0.422160,
0.070588, 0.282910, 0.105393, 0.426902, 0.074510, 0.283091, 0.110553, 0.431554, 0.078431,
0.283197, 0.115680, 0.436115, 0.082353, 0.283229, 0.120777, 0.440584, 0.086275, 0.283187,
0.125848, 0.444960, 0.090196, 0.283072, 0.130895, 0.449241, 0.094118, 0.282884, 0.135920,
0.453427, 0.098039, 0.282623, 0.140926, 0.457517, 0.101961, 0.282290, 0.145912, 0.461510,
0.105882, 0.281887, 0.150881, 0.465405, 0.109804, 0.281412, 0.155834, 0.469201, 0.113725,
0.280868, 0.160771, 0.472899, 0.117647, 0.280255, 0.165693, 0.476498, 0.121569, 0.279574,
0.170599, 0.479997, 0.125490, 0.278826, 0.175490, 0.483397, 0.129412, 0.278012, 0.180367,
0.486697, 0.133333, 0.277134, 0.185228, 0.489898, 0.137255, 0.276194, 0.190074, 0.493001,
0.141176, 0.275191, 0.194905, 0.496005, 0.145098, 0.274128, 0.199721, 0.498911, 0.149020,
0.273006, 0.204520, 0.501721, 0.152941, 0.271828, 0.209303, 0.504434, 0.156863, 0.270595,
0.214069, 0.507052, 0.160784, 0.269308, 0.218818, 0.509577, 0.164706, 0.267968, 0.223549,
0.512008, 0.168627, 0.266580, 0.228262, 0.514349, 0.172549, 0.265145, 0.232956, 0.516599,
0.176471, 0.263663, 0.237631, 0.518762, 0.180392, 0.262138, 0.242286, 0.520837, 0.184314,
0.260571, 0.246922, 0.522828, 0.188235, 0.258965, 0.251537, 0.524736, 0.192157, 0.257322,
0.256130, 0.526563, 0.196078, 0.255645, 0.260703, 0.528312, 0.200000, 0.253935, 0.265254,
0.529983, 0.203922, 0.252194, 0.269783, 0.531579, 0.207843, 0.250425, 0.274290, 0.533103,
0.211765, 0.248629, 0.278775, 0.534556, 0.215686, 0.246811, 0.283237, 0.535941, 0.219608,
0.244972, 0.287675, 0.537260, 0.223529, 0.243113, 0.292092, 0.538516, 0.227451, 0.241237,
0.296485, 0.539709, 0.231373, 0.239346, 0.300855, 0.540844, 0.235294, 0.237441, 0.305202,
0.541921, 0.239216, 0.235526, 0.309527, 0.542944, 0.243137, 0.233603, 0.313828, 0.543914,
0.247059, 0.231674, 0.318106, 0.544834, 0.250980, 0.229739, 0.322361, 0.545706, 0.254902,
0.227802, 0.326594, 0.546532, 0.258824, 0.225863, 0.330805, 0.547314, 0.262745, 0.223925,
0.334994, 0.548053, 0.266667, 0.221989, 0.339161, 0.548752, 0.270588, 0.220057, 0.343307,
0.549413, 0.274510, 0.218130, 0.347432, 0.550038, 0.278431, 0.216210, 0.351535, 0.550627,
0.282353, 0.214298, 0.355619, 0.551184, 0.286275, 0.212395, 0.359683, 0.551710, 0.290196,
0.210503, 0.363727, 0.552206, 0.294118, 0.208623, 0.367752, 0.552675, 0.298039, 0.206756,
0.371758, 0.553117, 0.301961, 0.204903, 0.375746, 0.553533, 0.305882, 0.203063, 0.379716,
0.553925, 0.309804, 0.201239, 0.383670, 0.554294, 0.313725, 0.199430, 0.387607, 0.554642,
0.317647, 0.197636, 0.391528, 0.554969, 0.321569, 0.195860, 0.395433, 0.555276, 0.325490,
0.194100, 0.399323, 0.555565, 0.329412, 0.192357, 0.403199, 0.555836, 0.333333, 0.190631,
0.407061, 0.556089, 0.337255, 0.188923, 0.410910, 0.556326, 0.341176, 0.187231, 0.414746,
0.556547, 0.345098, 0.185556, 0.418570, 0.556753, 0.349020, 0.183898, 0.422383, 0.556944,
0.352941, 0.182256, 0.426184, 0.557120, 0.356863, 0.180629, 0.429975, 0.557282, 0.360784,
0.179019, 0.433756, 0.557430, 0.364706, 0.177423, 0.437527, 0.557565, 0.368627, 0.175841,
0.441290, 0.557685, 0.372549, 0.174274, 0.445044, 0.557792, 0.376471, 0.172719, 0.448791,
0.557885, 0.380392, 0.171176, 0.452530, 0.557965, 0.384314, 0.169646, 0.456262, 0.558030,
0.388235, 0.168126, 0.459988, 0.558082, 0.392157, 0.166617, 0.463708, 0.558119, 0.396078,
0.165117, 0.467423, 0.558141, 0.400000, 0.163625, 0.471133, 0.558148, 0.403922, 0.162142,
0.474838, 0.558140, 0.407843, 0.160665, 0.478540, 0.558115, 0.411765, 0.159194, 0.482237,
0.558073, 0.415686, 0.157729, 0.485932, 0.558013, 0.419608, 0.156270, 0.489624, 0.557936,
0.423529, 0.154815, 0.493313, 0.557840, 0.427451, 0.153364, 0.497000, 0.557724, 0.431373,
0.151918, 0.500685, 0.557587, 0.435294, 0.150476, 0.504369, 0.557430, 0.439216, 0.149039,
0.508051, 0.557250, 0.443137, 0.147607, 0.511733, 0.557049, 0.447059, 0.146180, 0.515413,
0.556823, 0.450980, 0.144759, 0.519093, 0.556572, 0.454902, 0.143343, 0.522773, 0.556295,
0.458824, 0.141935, 0.526453, 0.555991, 0.462745, 0.140536, 0.530132, 0.555659, 0.466667,
0.139147, 0.533812, 0.555298, 0.470588, 0.137770, 0.537492, 0.554906, 0.474510, 0.136408,
0.541173, 0.554483, 0.478431, 0.135066, 0.544853, 0.554029, 0.482353, 0.133743, 0.548535,
0.553541, 0.486275, 0.132444, 0.552216, 0.553018, 0.490196, 0.131172, 0.555899, 0.552459,
0.494118, 0.129933, 0.559582, 0.551864, 0.498039, 0.128729, 0.563265, 0.551229, 0.501961,
0.127568, 0.566949, 0.550556, 0.505882, 0.126453, 0.570633, 0.549841, 0.509804, 0.125394,
0.574318, 0.549086, 0.513725, 0.124395, 0.578002, 0.548287, 0.517647, 0.123463, 0.581687,
0.547445, 0.521569, 0.122606, 0.585371, 0.546557, 0.525490, 0.121831, 0.589055, 0.545623,
0.529412, 0.121148, 0.592739, 0.544641, 0.533333, 0.120565, 0.596422, 0.543611, 0.537255,
0.120092, 0.600104, 0.542530, 0.541176, 0.119738, 0.603785, 0.541400, 0.545098, 0.119512,
0.607464, 0.540218, 0.549020, 0.119423, 0.611141, 0.538982, 0.552941, 0.119483, 0.614817,
0.537692, 0.556863, 0.119699, 0.618490, 0.536347, 0.560784, 0.120081, 0.622161, 0.534946,
0.564706, 0.120638, 0.625828, 0.533488, 0.568627, 0.121380, 0.629492, 0.531973, 0.572549,
0.122312, 0.633153, 0.530398, 0.576471, 0.123444, 0.636809, 0.528763, 0.580392, 0.124780,
0.640461, 0.527068, 0.584314, 0.126326, 0.644107, 0.525311, 0.588235, 0.128087, 0.647749,
0.523491, 0.592157, 0.130067, 0.651384, 0.521608, 0.596078, 0.132268, 0.655014, 0.519661,
0.600000, 0.134692, 0.658636, 0.517649, 0.603922, 0.137339, 0.662252, 0.515571, 0.607843,
0.140210, 0.665859, 0.513427, 0.611765, 0.143303, 0.669459, 0.511215, 0.615686, 0.146616,
0.673050, 0.508936, 0.619608, 0.150148, 0.676631, 0.506589, 0.623529, 0.153894, 0.680203,
0.504172, 0.627451, 0.157851, 0.683765, 0.501686, 0.631373, 0.162016, 0.687316, 0.499129,
0.635294, 0.166383, 0.690856, 0.496502, 0.639216, 0.170948, 0.694384, 0.493803, 0.643137,
0.175707, 0.697900, 0.491033, 0.647059, 0.180653, 0.701402, 0.488189, 0.650980, 0.185783,
0.704891, 0.485273, 0.654902, 0.191090, 0.708366, 0.482284, 0.658824, 0.196571, 0.711827,
0.479221, 0.662745, 0.202219, 0.715272, 0.476084, 0.666667, 0.208030, 0.718701, 0.472873,
0.670588, 0.214000, 0.722114, 0.469588, 0.674510, 0.220124, 0.725509, 0.466226, 0.678431,
0.226397, 0.728888, 0.462789, 0.682353, 0.232815, 0.732247, 0.459277, 0.686275, 0.239374,
0.735588, 0.455688, 0.690196, 0.246070, 0.738910, 0.452024, 0.694118, 0.252899, 0.742211,
0.448284, 0.698039, 0.259857, 0.745492, 0.444467, 0.701961, 0.266941, 0.748751, 0.440573,
0.705882, 0.274149, 0.751988, 0.436601, 0.709804, 0.281477, 0.755203, 0.432552, 0.713725,
0.288921, 0.758394, 0.428426, 0.717647, 0.296479, 0.761561, 0.424223, 0.721569, 0.304148,
0.764704, 0.419943, 0.725490, 0.311925, 0.767822, 0.415586, 0.729412, 0.319809, 0.770914,
0.411152, 0.733333, 0.327796, 0.773980, 0.406640, 0.737255, 0.335885, 0.777018, 0.402049,
0.741176, 0.344074, 0.780029, 0.397381, 0.745098, 0.352360, 0.783011, 0.392636, 0.749020,
0.360741, 0.785964, 0.387814, 0.752941, 0.369214, 0.788888, 0.382914, 0.756863, 0.377779,
0.791781, 0.377939, 0.760784, 0.386433, 0.794644, 0.372886, 0.764706, 0.395174, 0.797475,
0.367757, 0.768627, 0.404001, 0.800275, 0.362552, 0.772549, 0.412913, 0.803041, 0.357269,
0.776471, 0.421908, 0.805774, 0.351910, 0.780392, 0.430983, 0.808473, 0.346476, 0.784314,
0.440137, 0.811138, 0.340967, 0.788235, 0.449368, 0.813768, 0.335384, 0.792157, 0.458674,
0.816363, 0.329727, 0.796078, 0.468053, 0.818921, 0.323998, 0.800000, 0.477504, 0.821444,
0.318195, 0.803922, 0.487026, 0.823929, 0.312321, 0.807843, 0.496615, 0.826376, 0.306377,
0.811765, 0.506271, 0.828786, 0.300362, 0.815686, 0.515992, 0.831158, 0.294279, 0.819608,
0.525776, 0.833491, 0.288127, 0.823529, 0.535621, 0.835785, 0.281908, 0.827451, 0.545524,
0.838039, 0.275626, 0.831373, 0.555484, 0.840254, 0.269281, 0.835294, 0.565498, 0.842430,
0.262877, 0.839216, 0.575563, 0.844566, 0.256415, 0.843137, 0.585678, 0.846661, 0.249897,
0.847059, 0.595839, 0.848717, 0.243329, 0.850980, 0.606045, 0.850733, 0.236712, 0.854902,
0.616293, 0.852709, 0.230052, 0.858824, 0.626579, 0.854645, 0.223353, 0.862745, 0.636902,
0.856542, 0.216620, 0.866667, 0.647257, 0.858400, 0.209861, 0.870588, 0.657642, 0.860219,
0.203082, 0.874510, 0.668054, 0.861999, 0.196293, 0.878431, 0.678489, 0.863742, 0.189503,
0.882353, 0.688944, 0.865448, 0.182725, 0.886275, 0.699415, 0.867117, 0.175971, 0.890196,
0.709898, 0.868751, 0.169257, 0.894118, 0.720391, 0.870350, 0.162603, 0.898039, 0.730889,
0.871916, 0.156029, 0.901961, 0.741388, 0.873449, 0.149561, 0.905882, 0.751884, 0.874951,
0.143228, 0.909804, 0.762373, 0.876424, 0.137064, 0.913725, 0.772852, 0.877868, 0.131109,
0.917647, 0.783315, 0.879285, 0.125405, 0.921569, 0.793760, 0.880678, 0.120005, 0.925490,
0.804182, 0.882046, 0.114965, 0.929412, 0.814576, 0.883393, 0.110347, 0.933333, 0.824940,
0.884720, 0.106217, 0.937255, 0.835270, 0.886029, 0.102646, 0.941176, 0.845561, 0.887322,
0.099702, 0.945098, 0.855810, 0.888601, 0.097452, 0.949020, 0.866013, 0.889868, 0.095953,
0.952941, 0.876168, 0.891125, 0.095250, 0.956863, 0.886271, 0.892374, 0.095374, 0.960784,
0.896320, 0.893616, 0.096335, 0.964706, 0.906311, 0.894855, 0.098125, 0.968627, 0.916242,
0.896091, 0.100717, 0.972549, 0.926106, 0.897330, 0.104071, 0.976471, 0.935904, 0.898570,
0.108131, 0.980392, 0.945636, 0.899815, 0.112838, 0.984314, 0.955300, 0.901065, 0.118128,
0.988235, 0.964894, 0.902323, 0.123941, 0.992157, 0.974417, 0.903590, 0.130215, 0.996078,
0.983868, 0.904867, 0.136897, 1.000000, 0.993248, 0.906157, 0.143936
}
};
static constexpr ColorTable<7> Jet = {
vtkm::cont::ColorSpace::RGB,
{ -1, 0, 0, 0.5625,
-0.777778, 0,0,1,
-0.269841, 0, 1, 1,
-0.015873, 0.5, 1, 0.5,
0.238095, 1, 1, 0,
0.746032, 1, 0, 0,
1, 0.5, 0, 0
}
};
static constexpr ColorTable<5> Rainbow = {
vtkm::cont::ColorSpace::RGB,
{ -1, 0, 0, 1,
-0.5, 0, 1, 1,
0, 0, 1, 0,
0.5, 1, 1, 0,
1, 1, 0, 0
}
};
// clang-format on
void loadCoolToWarm(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(CoolToWarm.size, CoolToWarm.values);
table.SetColorSpace(CoolToWarm.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 1.0f, 1.0f, 0.0f });
}
void loadBlackBody(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(BlackBody.size, BlackBody.values);
table.SetColorSpace(BlackBody.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 0.0f, 0.49803921f, 1.0f });
}
void loadSamselFire(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(SamselFire.size, SamselFire.values);
table.SetColorSpace(SamselFire.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 1.0f, 1.0f, 0.0f });
}
void loadInferno(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(Inferno.size, Inferno.values);
table.SetColorSpace(Inferno.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 0.0f, 1.0f, 0.0f });
}
void loadLinearYGB(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(LinearYGB.size, LinearYGB.values);
table.SetColorSpace(LinearYGB.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 0.25f, 0.0f, 0.0f });
}
void loadColdAndHot(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(ColdAndHot.size, ColdAndHot.values);
table.SetColorSpace(ColdAndHot.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 1.0f, 1.0f, 0.0f });
}
void loadRainbowDesaturated(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(RainbowDesaturated.size, RainbowDesaturated.values);
table.SetColorSpace(RainbowDesaturated.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 1.0f, 1.0f, 0.0f });
}
void loadCoolToWarmExtended(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(CoolToWarmExtended.size, CoolToWarmExtended.values);
table.SetColorSpace(CoolToWarmExtended.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 0.25f, 0.0f, 0.0f });
}
void loadXRay(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(XRay.size, XRay.values);
table.SetColorSpace(XRay.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 1.0f, 0.0f, 0.0f });
}
void loadBlackBlueWhite(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(BlackBlueWhite.size, BlackBlueWhite.values);
table.SetColorSpace(BlackBlueWhite.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 1.0f, 1.0f, 0.0f });
}
void loadVirdis(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(Virdis.size, Virdis.values);
table.SetColorSpace(Virdis.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 1.0f, 0.0f, 0.0f });
}
void loadLinearGreen(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(LinearGreen.size, LinearGreen.values);
table.SetColorSpace(LinearGreen.space);
table.SetNaNColor(vtkm::Vec<float, 3>{ 0.25f, 0.0f, 0.0f });
}
void loadJet(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(Jet.size, Jet.values);
table.SetColorSpace(Jet.space);
}
void loadRainbow(vtkm::cont::ColorTable& table)
{
table.FillColorTableFromDataPointer(Rainbow.size, Rainbow.values);
table.SetColorSpace(Rainbow.space);
}
struct LoadColorTablePresetCommand
{
using FunctionType = void (*)(vtkm::cont::ColorTable& table);
std::string name;
FunctionType function;
};
constexpr int numberOfPresets = 14;
struct LoadColorTablePresetCommand presets[numberOfPresets] = {
{ "cool to warm", loadCoolToWarm },
{ "black-body radiation", loadBlackBody },
{ "samsel fire", loadSamselFire },
{ "inferno", loadInferno },
{ "linear ygb", loadLinearYGB },
{ "cold and hot", loadColdAndHot },
{ "rainbow desaturated", loadRainbowDesaturated },
{ "cool to warm (extended)", loadCoolToWarmExtended },
{ "x ray", loadXRay },
{ "black, blue and white", loadBlackBlueWhite },
{ "virdis", loadVirdis },
{ "linear green", loadLinearGreen },
{ "jet", loadJet },
{ "rainbow", loadRainbow },
};
}
namespace vtkm
{
namespace cont
{
namespace detail
{
VTKM_CONT_EXPORT std::set<std::string> GetPresetNames()
{
std::set<std::string> names;
for (int i = 0; i < numberOfPresets; ++i)
{
names.insert(presets[i].name);
}
return names;
}
VTKM_CONT_EXPORT bool loadColorTablePreset(std::string name, vtkm::cont::ColorTable& table)
{
//convert to lower case
std::transform(name.begin(), name.end(), name.begin(), [](char c) {
return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
});
for (int i = 0; i < numberOfPresets; ++i)
{
if (name == presets[i].name)
{
presets[i].function(table);
return true;
}
}
return false;
}
}
}
}

@ -23,6 +23,7 @@ set(unit_tests
UnitTestCudaArrayHandleVirtualCoordinates.cu
UnitTestCudaCellLocatorTwoLevelUniformGrid.cu
UnitTestCudaComputeRange.cu
UnitTestCudaColorTable.cu
UnitTestCudaDataSetExplicit.cu
UnitTestCudaDataSetSingleType.cu
UnitTestCudaDeviceAdapter.cu

@ -0,0 +1,33 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
// Make sure that the tested code is using the device adapter specified. This
// is important in the long run so we don't, for example, use the CUDA device
// for a part of an operation where the TBB device was specified.
#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_ERROR
#include <vtkm/cont/cuda/DeviceAdapterCuda.h>
#include <vtkm/cont/testing/TestingColorTable.h>
int UnitTestCudaColorTable(int, char* [])
{
return vtkm::cont::testing::TestingColorTable<vtkm::cont::DeviceAdapterTagCuda>::Run();
}

@ -24,6 +24,7 @@ set(unit_tests
UnitTestSerialArrayHandleVirtualCoordinates.cxx
UnitTestSerialCellLocatorTwoLevelUniformGrid.cxx
UnitTestSerialComputeRange.cxx
UnitTestSerialColorTable.cxx
UnitTestSerialDataSetExplicit.cxx
UnitTestSerialDataSetSingleType.cxx
UnitTestSerialDeviceAdapter.cxx

@ -0,0 +1,33 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
// Make sure that the tested code is using the device adapter specified. This
// is important in the long run so we don't, for example, use the CUDA device
// for a part of an operation where the TBB device was specified.
#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_ERROR
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/cont/testing/TestingColorTable.h>
int UnitTestSerialColorTable(int, char* [])
{
return vtkm::cont::testing::TestingColorTable<vtkm::cont::DeviceAdapterTagSerial>::Run();
}

@ -23,6 +23,7 @@ set(unit_tests
UnitTestTBBArrayHandleFancy.cxx
UnitTestTBBArrayHandleVirtualCoordinates.cxx
UnitTestTBBCellLocatorTwoLevelUniformGrid.cxx
UnitTestTBBColorTable.cxx
UnitTestTBBComputeRange.cxx
UnitTestTBBDataSetExplicit.cxx
UnitTestTBBDataSetSingleType.cxx

@ -0,0 +1,33 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
// Make sure that the tested code is using the device adapter specified. This
// is important in the long run so we don't, for example, use the CUDA device
// for a part of an operation where the TBB device was specified.
#define VTKM_DEVICE_ADAPTER VTKM_DEVICE_ADAPTER_ERROR
#include <vtkm/cont/tbb/DeviceAdapterTBB.h>
#include <vtkm/cont/testing/TestingColorTable.h>
int UnitTestTBBColorTable(int, char* [])
{
return vtkm::cont::testing::TestingColorTable<vtkm::cont::DeviceAdapterTagTBB>::Run();
}

@ -25,6 +25,7 @@ set(headers
TestingArrayHandles.h
TestingArrayHandleVirtualCoordinates.h
TestingCellLocatorTwoLevelUniformGrid.h
TestingColorTable.h
TestingComputeRange.h
TestingDeviceAdapter.h
TestingDataSetExplicit.h

@ -0,0 +1,522 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_cont_testing_TestingColorTable_h
#define vtk_m_cont_testing_TestingColorTable_h
#include <vtkm/Types.h>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/ColorTableSamples.h>
#include <vtkm/cont/testing/Testing.h>
// Required for implementation of ArrayRangeCompute for "odd" arrays
#include <vtkm/cont/ArrayRangeCompute.hxx>
// Required for implementation of ColorTable
#include <vtkm/cont/ColorTable.hxx>
#include <algorithm>
#include <iostream>
namespace vtkm
{
namespace cont
{
namespace testing
{
template <typename DeviceAdapterTag>
class TestingColorTable
{
public:
static void TestConstructors()
{
vtkm::Range inValidRange{ 1.0, 0.0 };
vtkm::Range range{ 0.0, 1.0 };
vtkm::Vec<float, 3> rgb1{ 0.0f, 0.0f, 0.0f };
vtkm::Vec<float, 3> rgb2{ 1.0f, 1.0f, 1.0f };
auto rgbspace = vtkm::cont::ColorSpace::RGB;
auto hsvspace = vtkm::cont::ColorSpace::HSV;
auto diverging = vtkm::cont::ColorSpace::DIVERGING;
vtkm::cont::ColorTable table(rgbspace);
VTKM_TEST_ASSERT(table.GetColorSpace() == rgbspace, "color space not saved");
VTKM_TEST_ASSERT(table.GetRange() == inValidRange, "default range incorrect");
vtkm::cont::ColorTable tableRGB(range, rgb1, rgb2, hsvspace);
VTKM_TEST_ASSERT(tableRGB.GetColorSpace() == hsvspace, "color space not saved");
VTKM_TEST_ASSERT(tableRGB.GetRange() == range, "color range not saved");
vtkm::Vec<float, 4> rgba1{ 0.0f, 0.0f, 0.0f, 1.0f };
vtkm::Vec<float, 4> rgba2{ 1.0f, 1.0f, 1.0f, 0.0f };
vtkm::cont::ColorTable tableRGBA(range, rgba1, rgba2, diverging);
VTKM_TEST_ASSERT(tableRGBA.GetColorSpace() == diverging, "color space not saved");
VTKM_TEST_ASSERT(tableRGBA.GetRange() == range, "color range not saved");
}
static void TestLoadPresets()
{
vtkm::Range range{ 0.0, 1.0 };
auto rgbspace = vtkm::cont::ColorSpace::RGB;
auto hsvspace = vtkm::cont::ColorSpace::HSV;
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");
//verify that we can get the presets
std::set<std::string> names = table.GetPresets();
VTKM_TEST_ASSERT(names.size() == 14, "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,
"names should contain black-body radiation");
VTKM_TEST_ASSERT(names.count("virdis") == 1, "names should contain virdis");
VTKM_TEST_ASSERT(names.count("black, blue and 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");
}
static void TestClamping()
{
vtkm::Range range{ 0.0, 1.0 };
vtkm::Vec<float, 3> rgb1{ 0.0f, 1.0f, 0.0f };
vtkm::Vec<float, 3> rgb2{ 1.0f, 0.0f, 1.0f };
auto rgbspace = vtkm::cont::ColorSpace::RGB;
vtkm::cont::ColorTable table(range, rgb1, rgb2, rgbspace);
VTKM_TEST_ASSERT(table.GetClamping() == true, "clamping not setup properly");
constexpr vtkm::Id nvals = 4;
constexpr int data[nvals] = { -1, 0, 1, 2 };
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
const bool ran = table.Map(field, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
//verify that we clamp the values to the expected range
const vtkm::Vec<vtkm::UInt8, 3> correct[nvals] = {
{ 0, 255, 0 }, { 0, 255, 0 }, { 255, 0, 255 }, { 255, 0, 255 }
};
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct[i], "incorrect value in color from clamp test");
}
}
static void TestRangeColors()
{
vtkm::Range range{ -1.0, 2.0 };
vtkm::Vec<float, 3> rgb1{ 0.0f, 1.0f, 0.0f };
vtkm::Vec<float, 3> rgb2{ 1.0f, 0.0f, 1.0f };
auto rgbspace = vtkm::cont::ColorSpace::RGB;
vtkm::cont::ColorTable table(range, rgb1, rgb2, rgbspace);
table.SetClampingOff();
VTKM_TEST_ASSERT(table.GetClamping() == false, "clamping not setup properly");
constexpr vtkm::Id nvals = 4;
constexpr int data[nvals] = { -2, -1, 2, 3 };
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
const bool ran = table.Map(field, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
//verify that both the above and below range colors are used,
//and that the default value of both is 0,0,0
const vtkm::Vec<vtkm::UInt8, 3> correct_range_defaults[nvals] = {
{ 0, 0, 0 }, { 0, 255, 0 }, { 255, 0, 255 }, { 0, 0, 0 }
};
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_range_defaults[i],
"incorrect value in color from default range color test");
}
//verify that we can specify custom above and below range colors
table.SetAboveRangeColor(vtkm::Vec<float, 3>{ 1.0f, 0.0f, 0.0f }); //red
table.SetBelowRangeColor(vtkm::Vec<float, 3>{ 0.0f, 0.0f, 1.0f }); //green
const bool ran2 = table.Map(field, colors);
VTKM_TEST_ASSERT(ran2, "color table failed to execute");
const vtkm::Vec<vtkm::UInt8, 3> correct_custom_range_colors[nvals] = {
{ 0, 0, 255 }, { 0, 255, 0 }, { 255, 0, 255 }, { 255, 0, 0 }
};
portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_custom_range_colors[i],
"incorrect value in custom above/below range color test");
}
}
static void TestRescaleRange()
{
vtkm::Range range{ -100.0, 100.0 };
//implement a blue2yellow color table
vtkm::Vec<float, 3> rgb1{ 0.0f, 0.0f, 1.0f };
vtkm::Vec<float, 3> rgb2{ 1.0f, 1.0f, 0.0f };
auto lab = vtkm::cont::ColorSpace::LAB;
vtkm::cont::ColorTable table(range, rgb1, rgb2, lab);
table.AddPoint(0.0, vtkm::Vec<float, 3>{ 0.5f, 0.5f, 0.5f });
VTKM_TEST_ASSERT(table.GetRange() == range, "custom range not saved");
vtkm::cont::ColorTable newTable = table.MakeDeepCopy();
VTKM_TEST_ASSERT(newTable.GetRange() == range, "custom range not saved");
vtkm::Range normalizedRange{ 0.0, 50.0 };
newTable.RescaleToRange(normalizedRange);
VTKM_TEST_ASSERT(table.GetRange() == range, "deep copy not working properly");
VTKM_TEST_ASSERT(newTable.GetRange() == normalizedRange, "rescale of range failed");
VTKM_TEST_ASSERT(newTable.GetNumberOfPoints() == 3,
"rescaled has incorrect number of control points");
//Verify that the rescaled color table generates correct colors
constexpr vtkm::Id nvals = 6;
constexpr int data[nvals] = { 0, 10, 20, 30, 40, 50 };
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
const bool ran = newTable.Map(field, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
//values confirmed with ParaView 5.4
const vtkm::Vec<vtkm::UInt8, 3> correct_lab_values[nvals] = {
{ 0, 0, 255 }, { 105, 69, 204 }, { 126, 109, 153 },
{ 156, 151, 117 }, { 207, 202, 87 }, { 255, 255, 0 }
};
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_lab_values[i],
"incorrect value in color after rescaling the color table");
}
}
static void TestAddPoints()
{
vtkm::Range initalRange{ 0, 1.0 };
vtkm::Range range{ -20, 20.0 };
auto rgbspace = vtkm::cont::ColorSpace::RGB;
vtkm::cont::ColorTable table(rgbspace);
table.AddPoint(-10.0, vtkm::Vec<float, 3>{ 0.0f, 1.0f, 1.0f });
table.AddPoint(-20.0, vtkm::Vec<float, 3>{ 1.0f, 1.0f, 1.0f });
table.AddPoint(20.0, vtkm::Vec<float, 3>{ 0.0f, 0.0f, 0.0f });
table.AddPoint(0.0, vtkm::Vec<float, 3>{ 0.0f, 0.0f, 1.0f });
VTKM_TEST_ASSERT(table.GetRange() == range, "adding points to make range expand properly");
VTKM_TEST_ASSERT(table.GetNumberOfPoints() == 4,
"adding points caused number of control points to be wrong");
constexpr vtkm::Id nvals = 3;
constexpr float data[nvals] = { 10.0f, -5.0f, -15.0f };
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
const bool ran = table.Map(field, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
const vtkm::Vec<vtkm::UInt8, 3> correct_rgb_values[nvals] = { { 0, 0, 128 },
{ 0, 128, 255 },
{ 128, 255, 255 } };
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_rgb_values[i],
"incorrect value when interpolating between values");
}
}
static void TestAddSegments()
{
vtkm::Range range{ 0.0, 50.0 };
auto diverging = vtkm::cont::ColorSpace::DIVERGING;
vtkm::cont::ColorTable table;
table.LoadPreset("Cool to Warm");
VTKM_TEST_ASSERT(table.GetColorSpace() == diverging,
"color space not switched when loading preset");
//Opacity Ramp from 0 to 1
table.AddSegmentAlpha(0.0, 0.0f, 1.0, 1.0f);
VTKM_TEST_ASSERT(table.GetNumberOfPointsAlpha() == 2, "incorrect number of alpha points");
table.RescaleToRange(range);
//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(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");
constexpr vtkm::Id nvals = 6;
constexpr int data[nvals] = { 0, 10, 20, 30, 40, 50 };
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> colors;
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
const bool ran = table.Map(field, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
//values confirmed with ParaView 5.4
const vtkm::Vec<vtkm::UInt8, 4> correct_diverging_values[nvals] = {
{ 59, 76, 192, 0 }, { 124, 159, 249, 51 }, { 192, 212, 245, 102 },
{ 242, 203, 183, 153 }, { 238, 133, 104, 204 }, { 180, 4, 38, 255 }
};
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_diverging_values[i],
"incorrect value when interpolating between values");
}
}
static void TestRemovePoints()
{
auto hsv = vtkm::cont::ColorSpace::HSV;
vtkm::cont::ColorTable table(hsv);
//implement Blue to Red Rainbow color table
table.AddSegment(0,
vtkm::Vec<float, 3>{ 0.0f, 0.0f, 1.0f },
1., //second points color should be replaced by following segment
vtkm::Vec<float, 3>{ 1.0f, 0.0f, 0.0f });
table.AddPoint(-10.0, vtkm::Vec<float, 3>{ 0.0f, 1.0f, 1.0f });
table.AddPoint(-20.0, vtkm::Vec<float, 3>{ 1.0f, 1.0f, 1.0f });
table.AddPoint(20.0, vtkm::Vec<float, 3>{ 1.0f, 0.0f, 0.0f });
VTKM_TEST_ASSERT(table.RemovePoint(-10.) == true, "failed to remove a existing point");
VTKM_TEST_ASSERT(table.RemovePoint(-20.) == true, "failed to remove a existing point");
VTKM_TEST_ASSERT(table.RemovePoint(20.) == true, "failed to remove a existing point");
VTKM_TEST_ASSERT(table.RemovePoint(20.) == false, "can't remove a point that doesn't exist");
VTKM_TEST_ASSERT((table.GetRange() == vtkm::Range{ 0.0, 1.0 }),
"removing points didn't update range");
table.RescaleToRange(vtkm::Range{ 0.0, 50.0 });
constexpr vtkm::Id nvals = 6;
constexpr float data[nvals] = { 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f };
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
const bool ran = table.Map(field, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
//values confirmed with ParaView 5.4
const vtkm::Vec<vtkm::UInt8, 3> correct_hsv_values[nvals] = { { 0, 0, 255 }, { 0, 204, 255 },
{ 0, 255, 102 }, { 102, 255, 0 },
{ 255, 204, 0 }, { 255, 0, 0 } };
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_hsv_values[i],
"incorrect value when interpolating between values");
}
}
static void TestOpacityOnlyPoints()
{
auto hsv = vtkm::cont::ColorSpace::HSV;
vtkm::cont::ColorTable table(hsv);
//implement only a color table
table.AddPointAlpha(0.0, 0.0f, 0.75f, 0.25f);
table.AddPointAlpha(1.0, 1.0f);
table.AddPointAlpha(10.0, 0.5f, 0.5f, 0.0f);
table.AddPointAlpha(-10.0, 0.0f);
table.AddPointAlpha(-20.0, 1.0f);
table.AddPointAlpha(20.0, 0.5f);
VTKM_TEST_ASSERT(table.RemovePointAlpha(10.) == true, "failed to remove a existing point");
VTKM_TEST_ASSERT(table.RemovePointAlpha(-10.) == true, "failed to remove a existing point");
VTKM_TEST_ASSERT(table.RemovePointAlpha(-20.) == true, "failed to remove a existing point");
VTKM_TEST_ASSERT(table.RemovePointAlpha(20.) == true, "failed to remove a existing point");
VTKM_TEST_ASSERT(table.RemovePointAlpha(20.) == false,
"can't remove a point that doesn't exist");
VTKM_TEST_ASSERT((table.GetRange() == vtkm::Range{ 0.0, 1.0 }),
"removing points didn't update range");
table.RescaleToRange(vtkm::Range{ 0.0, 50.0 });
constexpr vtkm::Id nvals = 6;
constexpr float data[nvals] = { 0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f };
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> colors;
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
const bool ran = table.Map(field, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
//values confirmed with ParaView 5.4
const vtkm::Vec<vtkm::UInt8, 4> correct_opacity_values[nvals] = {
{ 0, 0, 0, 0 }, { 0, 0, 0, 1 }, { 0, 0, 0, 11 },
{ 0, 0, 0, 52 }, { 0, 0, 0, 203 }, { 0, 0, 0, 255 }
};
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_opacity_values[i],
"incorrect value when interpolating between opacity values");
}
}
static void TestSampling()
{
vtkm::cont::ColorTable table;
table.LoadPreset("Linear 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");
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> colors;
constexpr vtkm::Id nvals = 3;
table.Sample(3, colors);
const vtkm::Vec<vtkm::UInt8, 4> correct_sampling_points[nvals] = { { 14, 28, 31, 255 },
{ 21, 150, 21, 255 },
{ 255, 251, 230, 255 } };
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_sampling_points[i],
"incorrect value when interpolating in linear green preset");
}
}
static void TestLookupTable()
{
//build a color table with clamping off and verify that sampling works
vtkm::Range range{ 0.0, 50.0 };
vtkm::cont::ColorTable table;
table.LoadPreset("Cool to Warm");
table.RescaleToRange(range);
table.SetClampingOff();
table.SetAboveRangeColor(vtkm::Vec<float, 3>{ 1.0f, 0.0f, 0.0f }); //red
table.SetBelowRangeColor(vtkm::Vec<float, 3>{ 0.0f, 0.0f, 1.0f }); //green
vtkm::cont::ColorTableSamplesRGB samples;
table.Sample(256, samples);
VTKM_TEST_ASSERT((samples.Samples.GetNumberOfValues() == 260), "invalid sample length");
constexpr vtkm::Id nvals = 8;
constexpr int data[nvals] = { -1, 0, 10, 20, 30, 40, 50, 60 };
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
auto field = vtkm::cont::make_ArrayHandle(data, nvals);
const bool ran = table.Map(field, samples, colors);
VTKM_TEST_ASSERT(ran, "color table failed to execute");
//values confirmed with ParaView 5.4
const vtkm::Vec<vtkm::UInt8, 3> correct_diverging_values[nvals] = {
{ 0, 0, 255 }, { 59, 76, 192 }, { 122, 157, 248 }, { 191, 211, 246 },
{ 241, 204, 184 }, { 238, 134, 105 }, { 180, 4, 38 }, { 255, 0, 0 }
};
auto portal = colors.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portal.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_diverging_values[i],
"incorrect value when interpolating between values");
}
}
struct TestAll
{
VTKM_CONT void operator()() const
{
TestConstructors();
TestLoadPresets();
TestClamping(); //this needs to also verify default opacity
TestRangeColors();
TestRescaleRange(); //uses Lab
TestAddPoints(); //uses RGB
TestAddSegments(); //uses Diverging && opacity
TestRemovePoints(); //use HSV
TestOpacityOnlyPoints();
TestSampling();
TestLookupTable();
}
};
static int Run()
{
//We need to verify the color table runs on this specific device
//so we need to force our single device
vtkm::cont::GetGlobalRuntimeDeviceTracker().ForceDevice(DeviceAdapterTag());
return vtkm::cont::testing::Testing::Run(TestAll());
}
};
}
}
}
#endif

@ -25,6 +25,7 @@ set(headers
CellFace.h
CellInside.h
CellInterpolate.h
ColorTable.h
ConnectivityExplicit.h
ConnectivityPermuted.h
ConnectivityStructured.h
@ -36,11 +37,16 @@ set(headers
TaskBase.h
)
set(header_impls
ColorTable.hxx
)
#-----------------------------------------------------------------------------
add_subdirectory(internal)
add_subdirectory(arg)
vtkm_declare_headers(${impl_headers} ${headers})
vtkm_declare_headers(${headers})
vtkm_declare_headers(${header_impls} TESTABLE OFF)
#-----------------------------------------------------------------------------

110
vtkm/exec/ColorTable.h Normal file

@ -0,0 +1,110 @@
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
#ifndef vtk_m_exec_ColorTable_h
#define vtk_m_exec_ColorTable_h
#include <vtkm/VirtualObjectBase.h>
namespace vtkm
{
namespace exec
{
class VTKM_ALWAYS_EXPORT ColorTableBase : public vtkm::VirtualObjectBase
{
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(double) const;
VTKM_EXEC virtual vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const = 0;
inline VTKM_EXEC float MapThroughOpacitySpace(double value) const;
double const* ColorNodes = nullptr;
vtkm::Vec<float, 3> const* RGB = nullptr;
double const* ONodes = nullptr;
float const* Alpha = nullptr;
vtkm::Vec<float, 2> const* MidSharp = nullptr;
vtkm::Int32 ColorSize = 0;
vtkm::Int32 OpacitySize = 0;
vtkm::Vec<float, 3> NaNColor = { 0.5f, 0.0f, 0.0f };
vtkm::Vec<float, 3> BelowRangeColor = { 0.0f, 0.0f, 0.0f };
vtkm::Vec<float, 3> AboveRangeColor = { 0.0f, 0.0f, 0.0f };
bool UseClamping = true;
private:
inline VTKM_EXEC void FindColors(double value,
vtkm::Vec<float, 3>& first,
vtkm::Vec<float, 3>& second,
float& weight) const;
};
class VTKM_ALWAYS_EXPORT ColorTableRGB : public ColorTableBase
{
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
};
class VTKM_ALWAYS_EXPORT ColorTableHSV : public ColorTableBase
{
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
};
class VTKM_ALWAYS_EXPORT ColorTableHSVWrap : public ColorTableBase
{
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
};
class VTKM_ALWAYS_EXPORT ColorTableLab : public ColorTableBase
{
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
};
class VTKM_ALWAYS_EXPORT ColorTableDiverging : public ColorTableBase
{
public:
inline VTKM_EXEC vtkm::Vec<float, 3> MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const final;
};
}
}
#include <vtkm/exec/ColorTable.hxx>
#endif

669
vtkm/exec/ColorTable.hxx Normal file

@ -0,0 +1,669 @@
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
#ifndef vtk_m_exec_ColorTable_hxx
#define vtk_m_exec_ColorTable_hxx
#include <vtkm/Math.h>
#include <vtkm/VectorAnalysis.h>
namespace vtkm
{
namespace exec
{
namespace detail
{
VTKM_EXEC
inline void RGBToHSV(const vtkm::Vec<float, 3>& rgb, vtkm::Vec<float, 3>& hsv)
{
constexpr float onethird = 1.0f / 3.0f;
constexpr float onesixth = 1.0f / 6.0f;
constexpr float twothird = 2.0f / 3.0f;
const float cmax = vtkm::Max(rgb[0], vtkm::Max(rgb[1], rgb[2]));
const float cmin = vtkm::Min(rgb[0], vtkm::Min(rgb[1], rgb[2]));
hsv[0] = 0.0f;
hsv[1] = 0.0f;
hsv[2] = cmax;
if (cmax > 0.0f && cmax != cmin)
{
hsv[1] = (cmax - cmin) / cmax;
if (rgb[0] == cmax)
{
hsv[0] = onesixth * (rgb[1] - rgb[2]) / (cmax - cmin);
}
else if (rgb[1] == cmax)
{
hsv[0] = onethird + onesixth * (rgb[2] - rgb[0]) / (cmax - cmin);
}
else
{
hsv[0] = twothird + onesixth * (rgb[0] - rgb[1]) / (cmax - cmin);
}
if (hsv[0] < 0.0f)
{
hsv[0] += 1.0f;
}
}
}
VTKM_EXEC
inline vtkm::Vec<float, 3> HSVToRGB(const vtkm::Vec<float, 3>& hsv)
{
vtkm::Vec<float, 3> rgb;
constexpr float onethird = 1.0f / 3.0f;
constexpr float onesixth = 1.0f / 6.0f;
constexpr float twothird = 2.0f / 3.0f;
constexpr float fivesixth = 5.0f / 6.0f;
// compute RGB from HSV
if (hsv[0] > onesixth && hsv[0] <= onethird) // green/red
{
rgb[1] = 1.0f;
rgb[0] = (onethird - hsv[0]) * 6.0f;
rgb[2] = 0.0f;
}
else if (hsv[0] > onethird && hsv[0] <= 0.5) // green/blue
{
rgb[1] = 1.0f;
rgb[2] = (hsv[0] - onethird) * 6.0f;
rgb[0] = 0.0f;
}
else if (hsv[0] > 0.5 && hsv[0] <= twothird) // blue/green
{
rgb[2] = 1.0f;
rgb[1] = (twothird - hsv[0]) * 6.0f;
rgb[0] = 0.0f;
}
else if (hsv[0] > twothird && hsv[0] <= fivesixth) // blue/red
{
rgb[2] = 1.0f;
rgb[0] = (hsv[0] - twothird) * 6.0f;
rgb[1] = 0.0f;
}
else if (hsv[0] > fivesixth && hsv[0] <= 1.0f) // red/blue
{
rgb[0] = 1.0f;
rgb[2] = (1.0f - hsv[0]) * 6.0f;
rgb[1] = 0.0f;
}
else // red/green
{
rgb[0] = 1.0f;
rgb[1] = hsv[0] * 6.0f;
rgb[2] = 0.0f;
}
// add Saturation to the equation.
rgb[0] = (hsv[1] * rgb[0] + (1.0f - hsv[1]));
rgb[1] = (hsv[1] * rgb[1] + (1.0f - hsv[1]));
rgb[2] = (hsv[1] * rgb[2] + (1.0f - hsv[1]));
rgb[0] *= hsv[2];
rgb[1] *= hsv[2];
rgb[2] *= hsv[2];
return rgb;
}
VTKM_EXEC
inline void RGBToLab(const vtkm::Vec<float, 3>& rgb, vtkm::Vec<float, 3>& lab)
{
// clang-format off
// The following performs a "gamma correction" specified by the sRGB color
// space. sRGB is defined by a canonical definition of a display monitor and
// has been standardized by the International Electrotechnical Commission (IEC
// 61966-2-1). The nonlinearity of the correction is designed to make the
// colors more perceptually uniform. This color space has been adopted by
// several applications including Adobe Photoshop and Microsoft Windows color
// management. OpenGL is agnostic on its RGB color space, but it is reasonable
// to assume it is close to this one.
{ //rgb to xyz start ( lab == xyz )
float r = rgb[0];
float g = rgb[1];
float b = rgb[2];
if ( r > 0.04045f ) r = vtkm::Pow(( r + 0.055f ) / 1.055f, 2.4f);
else r = r / 12.92f;
if ( g > 0.04045f ) g = vtkm::Pow(( g + 0.055f ) / 1.055f, 2.4f);
else g = g / 12.92f;
if ( b > 0.04045f ) b = vtkm::Pow(( b + 0.055f ) / 1.055f, 2.4f);
else b = b / 12.92f;
//Observer. = 2 deg, Illuminant = D65
lab[0] = r * 0.4124f + g * 0.3576f + b * 0.1805f;
lab[1] = r * 0.2126f + g * 0.7152f + b * 0.0722f;
lab[2] = r * 0.0193f + g * 0.1192f + b * 0.9505f;
} //rgb to xyz end ( lab == xyz )
//xyz to lab start
constexpr float onethird = 1.0f / 3.0f;
constexpr float sixteen_onesixteen = 16.0f / 116.0f;
constexpr float ref_X = 0.9505f;
constexpr float ref_Y = 1.000f;
constexpr float ref_Z = 1.089f;
float var_X = lab[0] / ref_X;
float var_Y = lab[1] / ref_Y;
float var_Z = lab[2] / ref_Z;
if ( var_X > 0.008856f ) var_X = vtkm::Pow(var_X, onethird);
else var_X = ( 7.787f * var_X ) + sixteen_onesixteen;
if ( var_Y > 0.008856f ) var_Y = vtkm::Pow(var_Y, onethird);
else var_Y = ( 7.787f * var_Y ) + sixteen_onesixteen;
if ( var_Z > 0.008856f ) var_Z = vtkm::Pow(var_Z, onethird);
else var_Z = ( 7.787f * var_Z ) + sixteen_onesixteen;
//notice that we are mapping g => L, r => a, and b => b
lab[0] = ( 116.0f * var_Y ) - 16.0f;
lab[1] = 500.0f * ( var_X - var_Y );
lab[2] = 200.0f * ( var_Y - var_Z );
// clang-format on
}
VTKM_EXEC
inline vtkm::Vec<float, 3> LabToRGB(const vtkm::Vec<float, 3>& lab)
{
// clang-format off
vtkm::Vec<float, 3> rgb;
{ //lab to xyz start ( rgb == xyz )
constexpr float sixteen_onesixteen = 16.0f / 116.0f;
//notice that we are mapping L => g, a => r, and b => b
rgb[1] = ( lab[0] + 16.0f ) / 116.0f;
rgb[0] = lab[1] / 500.0f + rgb[1];
rgb[2] = rgb[1] - lab[2] / 200.0f;
if ( vtkm::Pow(rgb[0],3) > 0.008856f ) rgb[0] = vtkm::Pow(rgb[0],3);
else rgb[0] = ( rgb[0] - sixteen_onesixteen ) / 7.787f;
if ( vtkm::Pow(rgb[1],3) > 0.008856f ) rgb[1] = vtkm::Pow(rgb[1],3);
else rgb[1] = ( rgb[1] - sixteen_onesixteen ) / 7.787f;
if ( vtkm::Pow(rgb[2],3) > 0.008856f ) rgb[2] = vtkm::Pow(rgb[2],3);
else rgb[2] = ( rgb[2] - sixteen_onesixteen ) / 7.787f;
constexpr float ref_X = 0.9505f;
constexpr float ref_Y = 1.000f;
constexpr float ref_Z = 1.089f;
rgb[0] *= ref_X; //Observer= 2 deg Illuminant= D65
rgb[1] *= ref_Y;
rgb[2] *= ref_Z;
} // lab to xyz end
//xyz to rgb start
rgb = vtkm::Vec<float,3>(
rgb[0] * 3.2406f + rgb[1] * -1.5372f + rgb[2] * -0.4986f,
rgb[0] * -0.9689f + rgb[1] * 1.8758f + rgb[2] * 0.0415f,
rgb[0] * 0.0557f + rgb[1] * -0.2040f + rgb[2] * 1.0570f);
float& r = rgb[0];
float& g = rgb[1];
float& b = rgb[2];
// The following performs a "gamma correction" specified by the sRGB color
// space. sRGB is defined by a canonical definition of a display monitor and
// has been standardized by the International Electrotechnical Commission (IEC
// 61966-2-1). The nonlinearity of the correction is designed to make the
// colors more perceptually uniform. This color space has been adopted by
// several applications including Adobe Photoshop and Microsoft Windows color
// management. OpenGL is agnostic on its RGB color space, but it is reasonable
// to assume it is close to this one.
constexpr float one_twopointfour = ( 1.0f / 2.4f );
if (r > 0.0031308f) r = 1.055f * (vtkm::Pow(r, one_twopointfour)) - 0.055f;
else r = 12.92f * r;
if (g > 0.0031308f) g = 1.055f * (vtkm::Pow(g ,one_twopointfour)) - 0.055f;
else g = 12.92f * (g);
if (b > 0.0031308f) b = 1.055f * (vtkm::Pow(b, one_twopointfour)) - 0.055f;
else b = 12.92f * (b);
// Clip colors. ideally we would do something that is perceptually closest
// (since we can see colors outside of the display gamut), but this seems to
// work well enough.
const float maxVal = vtkm::Max(r, vtkm::Max(g,b));
if (maxVal > 1.0f)
{
r /= maxVal;
g /= maxVal;
b /= maxVal;
}
r = vtkm::Max(r,0.0f);
g = vtkm::Max(g,0.0f);
b = vtkm::Max(b,0.0f);
// clang-format on
return rgb;
}
// Convert to a special polar version of CIELAB (useful for creating
// continuous diverging color maps).
VTKM_EXEC
inline void LabToMsh(const vtkm::Vec<float, 3>& lab, vtkm::Vec<float, 3>& msh)
{
const float& L = lab[0];
const float& a = lab[1];
const float& b = lab[2];
float& M = msh[0];
float& s = msh[1];
float& h = msh[2];
M = vtkm::Sqrt(L * L + a * a + b * b);
s = (M > 0.001f) ? vtkm::ACos(L / M) : 0.0f;
h = (s > 0.001f) ? vtkm::ATan2(b, a) : 0.0f;
}
// Convert from a special polar version of CIELAB (useful for creating
// continuous diverging color maps).
VTKM_EXEC
inline vtkm::Vec<float, 3> MshToLab(const vtkm::Vec<float, 3>& msh)
{
const float& M = msh[0];
const float& s = msh[1];
const float& h = msh[2];
vtkm::Vec<float, 3> r(
M * vtkm::Cos(s), M * vtkm::Sin(s) * vtkm::Cos(h), M * vtkm::Sin(s) * vtkm::Sin(h));
return r;
}
// Given two angular orientations, returns the smallest angle between the two.
VTKM_EXEC
inline float DivergingAngleDiff(float a1, float a2)
{
constexpr float f_pi = 3.141592653589793f;
constexpr float f_two_pi = 6.28318530717958647692528676655900576f;
float adiff = a1 - a2;
if (adiff < 0.0f)
adiff = -adiff;
while (adiff >= f_two_pi)
adiff -= (f_two_pi);
if (adiff > f_pi)
adiff = (f_two_pi)-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.
VTKM_EXEC
inline float DivergingAdjustHue(const vtkm::Vec<float, 3>& msh, float unsatM)
{
if (msh[0] >= unsatM - 0.1f)
{
// The best we can do is hold hue constant.
return msh[2];
}
else
{
// This equation is designed to make the perceptual change of the
// interpolation to be close to constant.
float hueSpin =
(msh[1] * vtkm::Sqrt(unsatM * unsatM - msh[0] * msh[0]) / (msh[0] * vtkm::Sin(msh[1])));
constexpr float one_third_pi = 0.33f * 3.141592653589793f;
// Spin hue away from 0 except in purple hues.
if (msh[2] > -one_third_pi)
{
return msh[2] + hueSpin;
}
else
{
return msh[2] - hueSpin;
}
}
}
} //namespace detail
//---------------------------------------------------------------------------
VTKM_EXEC
vtkm::Vec<float, 3> ColorTableBase::MapThroughColorSpace(double value) const
{
vtkm::Vec<float, 3> rgb1, rgb2;
float weight = 0;
this->FindColors(value, rgb1, rgb2, weight);
if (weight == 0)
{
return rgb1;
}
else if (weight == 1)
{
return rgb2;
}
else
{
return this->MapThroughColorSpace(rgb1, rgb2, weight);
}
}
//---------------------------------------------------------------------------
VTKM_EXEC
void ColorTableBase::FindColors(double value,
vtkm::Vec<float, 3>& rgb1,
vtkm::Vec<float, 3>& rgb2,
float& weight) const
{
// All the special cases have equivalent rgb1 and rgb2 values so we
// set the weight to 0.0f as a default
weight = 0.0f;
if (vtkm::IsNan(value))
{ //If we are trying to color NaN use the special NaN color value
rgb1 = this->NaNColor;
rgb2 = this->NaNColor;
}
else if (this->ColorSize == 0.0f)
{ //If we have no entires use the below range value
rgb1 = this->BelowRangeColor;
rgb2 = this->BelowRangeColor;
}
else if (value < this->ColorNodes[0])
{ //If we are below the color range
rgb1 = (this->UseClamping) ? this->RGB[0] : this->BelowRangeColor;
rgb2 = rgb1;
}
else if (value == this->ColorNodes[0])
{ //If we are exactly on the first color value
rgb1 = this->RGB[0];
rgb2 = rgb1;
}
else if (value > this->ColorNodes[this->ColorSize - 1])
{ //If we are above the color range
rgb1 = (this->UseClamping) ? this->RGB[this->ColorSize - 1] : this->AboveRangeColor;
rgb2 = rgb1;
}
else if (value == this->ColorNodes[this->ColorSize - 1])
{ //If we are exactly at the last color value
rgb1 = this->RGB[this->ColorSize - 1];
rgb2 = rgb1;
}
else
{
//The value is inside the range.
//Note: this for loop can be optimized to a lower_bound call as it
//accessing a sorted array
vtkm::Int32 first = 0;
vtkm::Int32 second = 1;
for (; second < this->ColorSize; ++second, ++first)
{
if (this->ColorNodes[second] >= value)
{
//this is our spot
break;
}
}
rgb1 = this->RGB[first];
rgb2 = this->RGB[second];
const auto w =
(value - this->ColorNodes[first]) / (this->ColorNodes[second] - this->ColorNodes[first]);
weight = static_cast<float>(w);
}
}
//---------------------------------------------------------------------------
VTKM_EXEC
float ColorTableBase::MapThroughOpacitySpace(double value) const
{
if (vtkm::IsNan(value))
{ //If we are trying to find the opacity of NaN use a constant of 1.0
return 1.0f;
}
else if (this->OpacitySize == 0.0f)
{ //no opacity control functions so use a constant of 1.0
return 1.0f;
}
else if (value <= this->ONodes[0])
{ //If we are below the color range
return this->Alpha[0];
}
else if (value >= this->ONodes[this->OpacitySize - 1])
{ //If we are above the color range
return this->Alpha[this->OpacitySize - 1];
}
else
{
//The value is inside the range.
//Note: this for loop can be optimized to a lower_bound call as it
//accessing a sorted array
vtkm::Int32 first = 0;
vtkm::Int32 second = 1;
for (; second < this->OpacitySize; ++second, ++first)
{
if (this->ONodes[second] >= value)
{
//this is our spot
break;
}
}
const auto w = (value - this->ONodes[first]) / (this->ONodes[second] - this->ONodes[first]);
float weight = static_cast<float>(w);
//we only need the previous midpoint and sharpness as they control this region
const auto& alpha1 = this->Alpha[first];
const auto& alpha2 = this->Alpha[second];
const auto& midsharp = this->MidSharp[first];
if (weight < midsharp[0])
{
weight = 0.5f * weight / midsharp[0];
}
else
{
weight = 0.5f + 0.5f * (weight - midsharp[0]) / (1.0f - midsharp[0]);
}
if (midsharp[1] == 1.0f)
{
// override for sharpness == 1.0f
// In this case we just want piecewise constant
// Use the first value since when we are below the midpoint
// otherwise use the second value
return (weight < 0.5f) ? alpha1 : alpha2;
}
else if (midsharp[1] == 0.0f)
{
// Override for sharpness == 0.0f
// In this case we simple linear interpolation
return vtkm::Lerp(alpha1, alpha2, weight);
}
else
{
// We have a sharpness between [0.0, 1.0] (exclusive) - we will
// used a modified hermite curve interpolation where we
// derive the slope based on the sharpness, and we compress
// the curve non-linearly based on the sharpness
// First, we will adjust our position based on sharpness in
// order to make the curve sharper (closer to piecewise constant)
if (weight < 0.5f)
{
weight = 0.5f * vtkm::Pow(weight * 2.0f, 1.0f + 10.0f * midsharp[1]);
}
else if (weight > .5)
{
weight = 1.0f - 0.5f * vtkm::Pow((1.0f - weight) * 2.0f, 1.0f + 10.0f * midsharp[1]);
}
// Compute some coefficients we will need for the hermite curve
const float ww = weight * weight;
const float www = weight * weight * weight;
const float h1 = 2.0f * www - 3.0f * ww + 1.0f;
const float h2 = -2.0f * www + 3.0f * ww;
const float h3 = www - 2.0f * ww + weight;
const float h4 = www - ww;
// Use one slope for both end points
const float slope = alpha2 - alpha1;
const float t = (1.0f - midsharp[1]) * slope;
// Compute the value
float result = h1 * alpha1 + h2 * alpha2 + h3 * t + h4 * t;
// Final error check to make sure we don't go outside
// the Y range
result = vtkm::Max(result, vtkm::Min(alpha1, alpha2));
result = vtkm::Min(result, vtkm::Max(alpha1, alpha2));
return result;
}
}
}
//---------------------------------------------------------------------------
VTKM_EXEC
vtkm::Vec<float, 3> ColorTableRGB::MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const
{
return vtkm::Lerp(rgb1, rgb2, weight);
}
//---------------------------------------------------------------------------
VTKM_EXEC
vtkm::Vec<float, 3> ColorTableHSV::MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const
{
vtkm::Vec<float, 3> hsv1, hsv2;
detail::RGBToHSV(rgb1, hsv1);
detail::RGBToHSV(rgb2, hsv2);
auto tmp = vtkm::Lerp(hsv1, hsv2, weight);
if (tmp[0] < 0.0f)
{
tmp[0] += 1.0f;
}
return detail::HSVToRGB(tmp);
}
//---------------------------------------------------------------------------
VTKM_EXEC
vtkm::Vec<float, 3> ColorTableHSVWrap::MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const
{
vtkm::Vec<float, 3> hsv1, hsv2;
detail::RGBToHSV(rgb1, hsv1);
detail::RGBToHSV(rgb2, hsv2);
const float diff = hsv1[0] - hsv2[0];
if (diff > 0.5f)
{
hsv1[0] -= 1.0f;
}
else if (diff < 0.5f)
{
hsv2[0] -= 1.0f;
}
auto tmp = vtkm::Lerp(hsv1, hsv2, weight);
if (tmp[0] < 0.0f)
{
tmp[0] += 1.0f;
}
return detail::HSVToRGB(tmp);
}
//---------------------------------------------------------------------------
VTKM_EXEC
vtkm::Vec<float, 3> ColorTableLab::MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const
{
vtkm::Vec<float, 3> lab1, lab2;
detail::RGBToLab(rgb1, lab1);
detail::RGBToLab(rgb2, lab2);
auto tmp = vtkm::Lerp(lab1, lab2, weight);
return detail::LabToRGB(tmp);
}
//---------------------------------------------------------------------------
VTKM_EXEC
vtkm::Vec<float, 3> ColorTableDiverging::MapThroughColorSpace(const vtkm::Vec<float, 3>& rgb1,
const vtkm::Vec<float, 3>& rgb2,
float weight) const
{
vtkm::Vec<float, 3> lab1, lab2;
detail::RGBToLab(rgb1, lab1);
detail::RGBToLab(rgb2, lab2);
vtkm::Vec<float, 3> msh1, msh2;
detail::LabToMsh(lab1, msh1);
detail::LabToMsh(lab2, msh2);
// If the endpoints are distinct saturated colors, then place white in between
// them.
constexpr float one_third_pi = 0.33f * 3.141592653589793f;
if ((msh1[1] > 0.05f) && (msh2[1] > 0.05f) &&
(detail::DivergingAngleDiff(msh1[2], msh2[2]) > one_third_pi))
{
// Insert the white midpoint by setting one end to white and adjusting the
// scalar value.
float Mmid = vtkm::Max(msh1[0], msh2[0]);
Mmid = vtkm::Max(88.0f, Mmid);
if (weight < 0.5f)
{
msh2[0] = Mmid;
msh2[1] = 0.0f;
msh2[2] = 0.0f;
weight = 2.0f * weight;
}
else
{
msh1[0] = Mmid;
msh1[1] = 0.0f;
msh1[2] = 0.0f;
weight = 2.0f * weight - 1.0f;
}
}
// If one color has no saturation, then its hue value is invalid. In this
// case, we want to set it to something logical so that the interpolation of
// hue makes sense.
if ((msh1[1] < 0.05f) && (msh2[1] > 0.05f))
{
msh1[2] = detail::DivergingAdjustHue(msh2, msh1[0]);
}
else if ((msh2[1] < 0.05f) && (msh1[1] > 0.05f))
{
msh2[2] = detail::DivergingAdjustHue(msh1, msh2[0]);
}
auto tmp = vtkm::Lerp(msh1, msh2, weight);
tmp = detail::MshToLab(tmp);
return detail::LabToRGB(tmp);
}
}
}
// Cuda seems to have a bug where it expects the template class VirtualObjectTransfer
// to be instantiated in a consitent order among all the translation units of an
// executable. Failing to do so results in random crashes and incorrect results.
// We workaroud this issue by explicitly instantiating VirtualObjectTransfer for
// all the portal types here.
#ifdef VTKM_CUDA
#include <vtkm/cont/cuda/internal/VirtualObjectTransferCuda.h>
VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::exec::ColorTableRGB);
VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::exec::ColorTableHSV);
VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::exec::ColorTableHSVWrap);
VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::exec::ColorTableLab);
VTKM_EXPLICITLY_INSTANTIATE_TRANSFER(vtkm::exec::ColorTableDiverging);
#endif
#endif

@ -33,16 +33,39 @@ struct Actor::InternalsType
vtkm::cont::DynamicCellSet Cells;
vtkm::cont::CoordinateSystem Coordinates;
vtkm::cont::Field ScalarField;
vtkm::rendering::ColorTable ColorTable;
vtkm::cont::ColorTable ColorTable;
vtkm::Range ScalarRange;
vtkm::Bounds SpatialBounds;
VTKM_CONT
InternalsType(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField)
: Cells(cells)
, Coordinates(coordinates)
, ScalarField(scalarField)
{
this->ColorTable.LoadPreset("Cool to Warm");
}
VTKM_CONT
InternalsType(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable)
const vtkm::rendering::Color& color)
: Cells(cells)
, Coordinates(coordinates)
, ScalarField(scalarField)
, ColorTable(vtkm::Range{ 0, 1 }, color.Components, color.Components)
{
}
VTKM_CONT
InternalsType(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::cont::ColorTable& colorTable)
: Cells(cells)
, Coordinates(coordinates)
, ScalarField(scalarField)
@ -53,10 +76,8 @@ struct Actor::InternalsType
Actor::Actor(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::Color& color)
: Internals(
new InternalsType(cells, coordinates, scalarField, vtkm::rendering::ColorTable(color)))
const vtkm::cont::Field& scalarField)
: Internals(new InternalsType(cells, coordinates, scalarField))
{
this->Init(coordinates, scalarField);
}
@ -64,7 +85,16 @@ Actor::Actor(const vtkm::cont::DynamicCellSet& cells,
Actor::Actor(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable)
const vtkm::rendering::Color& color)
: Internals(new InternalsType(cells, coordinates, scalarField, color))
{
this->Init(coordinates, scalarField);
}
Actor::Actor(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::cont::ColorTable& colorTable)
: Internals(new InternalsType(cells, coordinates, scalarField, colorTable))
{
this->Init(coordinates, scalarField);
@ -108,7 +138,7 @@ const vtkm::cont::Field& Actor::GetScalarField() const
return this->Internals->ScalarField;
}
const vtkm::rendering::ColorTable& Actor::GetColorTable() const
const vtkm::cont::ColorTable& Actor::GetColorTable() const
{
return this->Internals->ColorTable;
}

@ -36,10 +36,14 @@ namespace rendering
class VTKM_RENDERING_EXPORT Actor
{
public:
Actor(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField);
Actor(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable = vtkm::rendering::ColorTable("default"));
const vtkm::cont::ColorTable& colorTable);
Actor(const vtkm::cont::DynamicCellSet& cells,
const vtkm::cont::CoordinateSystem& coordinates,
@ -56,7 +60,7 @@ public:
const vtkm::cont::Field& GetScalarField() const;
const vtkm::rendering::ColorTable& GetColorTable() const;
const vtkm::cont::ColorTable& GetColorTable() const;
const vtkm::Range& GetScalarRange() const;

@ -32,7 +32,6 @@ set(headers
Color.h
ColorBarAnnotation.h
ColorLegendAnnotation.h
ColorTable.h
ConnectivityProxy.h
DecodePNG.h
LineRenderer.h
@ -68,7 +67,6 @@ set(sources
Color.cxx
ColorBarAnnotation.cxx
ColorLegendAnnotation.cxx
ColorTable.cxx
DecodePNG.cxx
LineRenderer.cxx
MapperConnectivity.cxx

@ -209,7 +209,9 @@ struct DrawColorBar : public vtkm::worklet::WorkletMapField
vtkm::Id x = index % BarWidth;
vtkm::Id y = index / BarWidth;
vtkm::Id sample = Horizontal ? x : y;
vtkm::Vec<vtkm::Float32, 4> color = colorMap.Get(sample);
const vtkm::Vec<vtkm::UInt8, 4> color = colorMap.Get(sample);
vtkm::Float32 normalizedHeight =
Horizontal ? vtkm::Float32(y) / BarHeight : vtkm::Float32(x) / BarWidth;
@ -220,24 +222,29 @@ struct DrawColorBar : public vtkm::worklet::WorkletMapField
vtkm::Id offset = y * ImageWidth + x;
// If the colortable has alpha values, we blend each color sample with translucent white.
// The height of the resultant translucent bar indicates the opacity.
if (color[3] < 1.0f && normalizedHeight <= color[3])
constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);
vtkm::Float32 alpha = color[3] * conversionToFloatSpace;
if (alpha < 1 && normalizedHeight <= alpha)
{
vtkm::Float32 intensity = 0.4f;
vtkm::Vec<vtkm::Float32, 4> blendedColor;
vtkm::Vec<vtkm::Float32, 4> srcColor = color;
vtkm::Float32 inverseIntensity = (1.0f - intensity);
vtkm::Float32 alpha = srcColor[3] * inverseIntensity;
blendedColor[0] = 1.0f * intensity + srcColor[0] * alpha;
blendedColor[1] = 1.0f * intensity + srcColor[1] * alpha;
blendedColor[2] = 1.0f * intensity + srcColor[2] * alpha;
blendedColor[3] = 1.0f;
constexpr vtkm::Float32 intensity = 0.4f;
constexpr vtkm::Float32 inverseIntensity = (1.0f - intensity);
alpha *= inverseIntensity;
vtkm::Vec<vtkm::Float32, 4> blendedColor(
1.0f * intensity + (color[0] * conversionToFloatSpace) * alpha,
1.0f * intensity + (color[1] * conversionToFloatSpace) * alpha,
1.0f * intensity + (color[2] * conversionToFloatSpace) * alpha,
1.0f);
frameBuffer.Set(offset, blendedColor);
}
else
{
// make sure this is opaque
color[3] = 1.f;
frameBuffer.Set(offset, color);
vtkm::Vec<vtkm::Float32, 4> fColor((color[0] * conversionToFloatSpace),
(color[1] * conversionToFloatSpace),
(color[2] * conversionToFloatSpace),
1.0f);
frameBuffer.Set(offset, fColor);
}
}
@ -292,7 +299,7 @@ struct ColorBarExecutor
vtkm::Id2 xBounds,
vtkm::Id2 yBounds,
bool horizontal,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorMap,
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& colorMap,
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colorBuffer)
: Dims(dims)
, XBounds(xBounds)
@ -320,7 +327,7 @@ struct ColorBarExecutor
vtkm::Id2 XBounds;
vtkm::Id2 YBounds;
bool Horizontal;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& ColorMap;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>>& ColorMap;
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& ColorBuffer;
}; // struct ColorSwatchExecutor
@ -525,7 +532,7 @@ void Canvas::AddLine(vtkm::Float64 x0,
}
void Canvas::AddColorBar(const vtkm::Bounds& bounds,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
bool horizontal) const
{
vtkm::Float64 width = static_cast<vtkm::Float64>(this->GetWidth());
@ -539,8 +546,8 @@ void Canvas::AddColorBar(const vtkm::Bounds& bounds,
vtkm::Id barWidth = x[1] - x[0];
vtkm::Id barHeight = y[1] - y[0];
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>> colorMap;
vtkm::Id numSamples = horizontal ? barWidth : barHeight;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> colorMap;
colorTable.Sample(static_cast<vtkm::Int32>(numSamples), colorMap);
vtkm::Id2 dims(this->GetWidth(), this->GetHeight());
@ -552,7 +559,7 @@ void Canvas::AddColorBar(vtkm::Float32 x,
vtkm::Float32 y,
vtkm::Float32 width,
vtkm::Float32 height,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
bool horizontal) const
{
this->AddColorBar(

@ -25,10 +25,10 @@
#include <vtkm/Matrix.h>
#include <vtkm/Types.h>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/rendering/BitmapFont.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/Color.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Texture2D.h>
#define VTKM_DEFAULT_CANVAS_DEPTH 1.001f
@ -155,7 +155,7 @@ public:
VTKM_CONT
virtual void AddColorBar(const vtkm::Bounds& bounds,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
bool horizontal) const;
VTKM_CONT
@ -163,7 +163,7 @@ public:
vtkm::Float32 y,
vtkm::Float32 width,
vtkm::Float32 height,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
bool horizontal) const;
virtual void AddText(const vtkm::Vec<vtkm::Float32, 2>& position,

@ -210,10 +210,14 @@ void CanvasGL::AddLine(const vtkm::Vec<vtkm::Float64, 2>& point0,
}
void CanvasGL::AddColorBar(const vtkm::Bounds& bounds,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
bool horizontal) const
{
const int n = 256;
//map through the color table for our 256 points as the first step
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> colors;
colorTable.Sample(n, colors);
vtkm::Float32 startX = static_cast<vtkm::Float32>(bounds.X.Min);
vtkm::Float32 startY = static_cast<vtkm::Float32>(bounds.Y.Min);
vtkm::Float32 width = static_cast<vtkm::Float32>(bounds.X.Length());
@ -221,22 +225,25 @@ void CanvasGL::AddColorBar(const vtkm::Bounds& bounds,
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
auto colorPortal = colors.GetPortalConstControl();
for (int i = 0; i < n; i++)
{
vtkm::Float32 v0 = static_cast<vtkm::Float32>(i) / static_cast<vtkm::Float32>(n);
vtkm::Float32 v1 = static_cast<vtkm::Float32>(i + 1) / static_cast<vtkm::Float32>(n);
vtkm::rendering::Color c0 = colorTable.MapRGB(v0);
vtkm::rendering::Color c1 = colorTable.MapRGB(v1);
auto c0 = colorPortal.Get(i);
auto c1 = colorPortal.Get(i + 1);
if (horizontal)
{
vtkm::Float32 x0 = startX + width * v0;
vtkm::Float32 x1 = startX + width * v1;
vtkm::Float32 y0 = startY;
vtkm::Float32 y1 = startY + height;
glColor3f(c0.Components[0], c0.Components[1], c0.Components[2]);
glColor3ub(c0[0], c0[1], c0[2]);
glVertex2f(x0, y0);
glVertex2f(x0, y1);
glColor3f(c1.Components[0], c1.Components[1], c1.Components[2]);
glColor3ub(c1[0], c1[1], c1[2]);
glVertex2f(x1, y1);
glVertex2f(x1, y0);
}
@ -246,10 +253,10 @@ void CanvasGL::AddColorBar(const vtkm::Bounds& bounds,
vtkm::Float32 x1 = startX + width;
vtkm::Float32 y0 = startY + height * v0;
vtkm::Float32 y1 = startY + height * v1;
glColor3f(c0.Components[0], c0.Components[1], c0.Components[2]);
glColor3ub(c0[0], c0[1], c0[2]);
glVertex2f(x0, y1);
glVertex2f(x1, y1);
glColor3f(c1.Components[0], c1.Components[1], c1.Components[2]);
glColor3ub(c1[0], c1[1], c1[2]);
glVertex2f(x1, y0);
glVertex2f(x0, y0);
}

@ -67,7 +67,7 @@ protected:
const vtkm::rendering::Color& color) const override;
void AddColorBar(const vtkm::Bounds& bounds,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
bool horizontal) const override;
void AddColorSwatch(const vtkm::Vec<vtkm::Float64, 2>& point0,

@ -22,11 +22,11 @@
#include <vtkm/rendering/vtkm_rendering_export.h>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/AxisAnnotation2D.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/Canvas.h>
#include <vtkm/rendering/ColorTable.h>
namespace vtkm
{
@ -36,7 +36,7 @@ namespace rendering
class VTKM_RENDERING_EXPORT ColorBarAnnotation
{
protected:
vtkm::rendering::ColorTable ColorTable;
vtkm::cont::ColorTable ColorTable;
vtkm::rendering::AxisAnnotation2D Axis;
vtkm::Bounds Position;
bool Horizontal;
@ -48,10 +48,7 @@ public:
virtual ~ColorBarAnnotation();
VTKM_CONT
void SetColorTable(const vtkm::rendering::ColorTable& colorTable)
{
this->ColorTable = colorTable;
}
void SetColorTable(const vtkm::cont::ColorTable& colorTable) { this->ColorTable = colorTable; }
VTKM_CONT
void SetRange(const vtkm::Range& range, vtkm::IdComponent numTicks);

File diff suppressed because it is too large Load Diff

@ -1,89 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_rendering_ColorTable_h
#define vtk_m_rendering_ColorTable_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/rendering/Color.h>
#include <vtkm/rendering/vtkm_rendering_export.h>
#include <memory>
namespace vtkm
{
namespace rendering
{
namespace detail
{
struct ColorTableInternals;
}
/// \brief It's a color table!
///
/// This class provides the basic representation of a color table. This class was
/// Ported from EAVL. Originally created by Jeremy Meredith, Dave Pugmire,
/// and Sean Ahern. This class uses separate RGB and alpha control points and can
/// be used as a transfer function.
///
class VTKM_RENDERING_EXPORT ColorTable
{
private:
std::shared_ptr<detail::ColorTableInternals> Internals;
public:
ColorTable();
/// Constructs a \c ColorTable using the name of a pre-defined color set.
ColorTable(const std::string& name);
// Make a single color ColorTable.
ColorTable(const vtkm::rendering::Color& color);
const std::string& GetName() const;
bool GetSmooth() const;
void SetSmooth(bool smooth);
void Sample(int numSamples, vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>& colors) const;
vtkm::rendering::Color MapRGB(vtkm::Float32 scalar) const;
vtkm::Float32 MapAlpha(vtkm::Float32 scalar) const;
void Clear();
void Reverse();
ColorTable CorrectOpacity(const vtkm::Float32& factor) const;
void AddControlPoint(vtkm::Float32 position, const vtkm::rendering::Color& color);
void AddControlPoint(vtkm::Float32 position,
const vtkm::rendering::Color& color,
vtkm::Float32 alpha);
void AddAlphaControlPoint(vtkm::Float32 position, vtkm::Float32 alpha);
};
}
} //namespace vtkm::rendering
#endif //vtk_m_rendering_ColorTable_h

@ -20,7 +20,6 @@
#include <cstdlib>
#include <typeinfo>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/ConnectivityProxy.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/raytracing/ConnectivityTracerFactory.h>

@ -25,7 +25,6 @@
#include <typeinfo>
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/View.h>
#include <vtkm/rendering/raytracing/Camera.h>

@ -29,9 +29,25 @@ Mapper::~Mapper()
{
}
void Mapper::SetActiveColorTable(const vtkm::rendering::ColorTable& colorTable)
void Mapper::SetActiveColorTable(const vtkm::cont::ColorTable& colorTable)
{
colorTable.Sample(1024, this->ColorMap);
constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> temp;
colorTable.Sample(1024, temp);
this->ColorMap.Allocate(1024);
auto portal = this->ColorMap.GetPortalControl();
auto colorPortal = temp.GetPortalConstControl();
for (vtkm::Id i = 0; i < 1024; ++i)
{
auto color = colorPortal.Get(i);
vtkm::Vec<vtkm::Float32, 4> t(color[0] * conversionToFloatSpace,
color[1] * conversionToFloatSpace,
color[2] * conversionToFloatSpace,
color[3] * conversionToFloatSpace);
portal.Set(i, t);
}
}
void Mapper::SetLogarithmX(bool l)

@ -20,12 +20,12 @@
#ifndef vtk_m_rendering_Mapper_h
#define vtk_m_rendering_Mapper_h
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/Canvas.h>
#include <vtkm/rendering/ColorTable.h>
namespace vtkm
{
namespace rendering
@ -42,11 +42,11 @@ public:
virtual void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange) = 0;
virtual void SetActiveColorTable(const ColorTable& ct);
virtual void SetActiveColorTable(const vtkm::cont::ColorTable& ct);
virtual void StartScene() = 0;
virtual void EndScene() = 0;

@ -18,7 +18,7 @@
// this software.
//============================================================================
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/ConnectivityProxy.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/MapperConnectivity.h>
@ -76,7 +76,7 @@ VTKM_CONT
void MapperConnectivity::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& vtkmNotUsed(colorTable),
const vtkm::cont::ColorTable& vtkmNotUsed(colorTable),
const vtkm::rendering::Camera& camera,
const vtkm::Range& vtkmNotUsed(scalarRange))
{

@ -20,8 +20,8 @@
#ifndef vtk_m_rendering_MapperConnectivity_h
#define vtk_m_rendering_MapperConnectivity_h
#include <vtkm/cont/ColorTable.h>
#include <vtkm/rendering/CanvasRayTracer.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/View.h>
@ -43,7 +43,7 @@ public:
virtual void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable&, //colorTable
const vtkm::cont::ColorTable&, //colorTable
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange) override;

@ -27,6 +27,8 @@
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/exec/ColorTable.h>
#include <vector>
namespace vtkm
@ -45,14 +47,14 @@ typedef TypeListTagId4 Id4Type;
class MapColorAndVertices : public vtkm::worklet::WorkletMapField
{
public:
const vtkm::rendering::ColorTable ColorTable;
const vtkm::exec::ColorTableBase* ColorTable;
const vtkm::Float32 SMin, SDiff;
VTKM_CONT
MapColorAndVertices(const vtkm::rendering::ColorTable& colorTable,
MapColorAndVertices(const vtkm::exec::ColorTableBase* table,
vtkm::Float32 sMin,
vtkm::Float32 sDiff)
: ColorTable(colorTable)
: ColorTable(table)
, SMin(sMin)
, SDiff(sDiff)
{
@ -86,30 +88,30 @@ public:
vtkm::Vec<vtkm::Float32, 3> p3 = verts.Get(idx[3]);
vtkm::Float32 s;
vtkm::rendering::Color color1;
vtkm::rendering::Color color2;
vtkm::rendering::Color color3;
vtkm::Vec<float, 3> color1;
vtkm::Vec<float, 3> color2;
vtkm::Vec<float, 3> color3;
if (SDiff == 0)
{
s = 0;
color1 = ColorTable.MapRGB(s);
color2 = ColorTable.MapRGB(s);
color3 = ColorTable.MapRGB(s);
color1 = ColorTable->MapThroughColorSpace(s);
color2 = ColorTable->MapThroughColorSpace(s);
color3 = ColorTable->MapThroughColorSpace(s);
}
else
{
s = scalar.Get(i1);
s = (s - SMin) / SDiff;
color1 = ColorTable.MapRGB(s);
color1 = ColorTable->MapThroughColorSpace(s);
s = scalar.Get(i2);
s = (s - SMin) / SDiff;
color2 = ColorTable.MapRGB(s);
color2 = ColorTable->MapThroughColorSpace(s);
s = scalar.Get(i3);
s = (s - SMin) / SDiff;
color3 = ColorTable.MapRGB(s);
color3 = ColorTable->MapThroughColorSpace(s);
}
const vtkm::Id offset = 9;
@ -117,23 +119,23 @@ public:
v_array.Set(i * offset, p1[0]);
v_array.Set(i * offset + 1, p1[1]);
v_array.Set(i * offset + 2, p1[2]);
c_array.Set(i * offset, color1.Components[0]);
c_array.Set(i * offset + 1, color1.Components[1]);
c_array.Set(i * offset + 2, color1.Components[2]);
c_array.Set(i * offset, color1[0]);
c_array.Set(i * offset + 1, color1[1]);
c_array.Set(i * offset + 2, color1[2]);
v_array.Set(i * offset + 3, p2[0]);
v_array.Set(i * offset + 4, p2[1]);
v_array.Set(i * offset + 5, p2[2]);
c_array.Set(i * offset + 3, color2.Components[0]);
c_array.Set(i * offset + 4, color2.Components[1]);
c_array.Set(i * offset + 5, color2.Components[2]);
c_array.Set(i * offset + 3, color2[0]);
c_array.Set(i * offset + 4, color2[1]);
c_array.Set(i * offset + 5, color2[2]);
v_array.Set(i * offset + 6, p3[0]);
v_array.Set(i * offset + 7, p3[1]);
v_array.Set(i * offset + 8, p3[2]);
c_array.Set(i * offset + 6, color3.Components[0]);
c_array.Set(i * offset + 7, color3.Components[1]);
c_array.Set(i * offset + 8, color3.Components[2]);
c_array.Set(i * offset + 6, color3[0]);
c_array.Set(i * offset + 7, color3[1]);
c_array.Set(i * offset + 8, color3[2]);
}
};
@ -141,17 +143,18 @@ template <typename PtType>
struct MapColorAndVerticesInvokeFunctor
{
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>> TriangleIndices;
vtkm::rendering::ColorTable ColorTable;
vtkm::cont::ColorTable ColorTable;
const vtkm::cont::ArrayHandle<vtkm::Float32> Scalar;
const vtkm::Range ScalarRange;
const PtType Vertices;
MapColorAndVertices Worklet;
vtkm::Float32 SMin;
vtkm::Float32 SDiff;
vtkm::cont::ArrayHandle<vtkm::Float32> OutColor;
vtkm::cont::ArrayHandle<vtkm::Float32> OutVertices;
VTKM_CONT
MapColorAndVerticesInvokeFunctor(const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& indices,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const vtkm::cont::ArrayHandle<Float32>& scalar,
const vtkm::Range& scalarRange,
const PtType& vertices,
@ -164,20 +167,21 @@ struct MapColorAndVerticesInvokeFunctor
, Scalar(scalar)
, ScalarRange(scalarRange)
, Vertices(vertices)
, Worklet(colorTable, s_min, s_max - s_min)
,
OutColor(out_color)
, SMin(s_min)
, SDiff(s_max - s_min)
, OutColor(out_color)
, OutVertices(out_vertices)
{
}
template <typename Device>
VTKM_CONT bool operator()(Device) const
VTKM_CONT bool operator()(Device device) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::worklet::DispatcherMapField<MapColorAndVertices, Device> dispatcher(this->Worklet);
auto colorHandle = this->ColorTable.GetHandleForExecution();
MapColorAndVertices worklet(colorHandle->PrepareForExecution(device), this->SMin, this->SDiff);
vtkm::worklet::DispatcherMapField<MapColorAndVertices, Device> dispatcher(worklet);
vtkm::cont::ArrayHandleIndex indexArray(this->TriangleIndices.GetNumberOfValues());
dispatcher.Invoke(indexArray,
@ -194,14 +198,24 @@ template <typename PtType>
VTKM_CONT void RenderStructuredLineSegments(vtkm::Id numVerts,
const PtType& verts,
const vtkm::cont::ArrayHandle<vtkm::Float32>& scalar,
vtkm::rendering::ColorTable ct,
vtkm::cont::ColorTable ct,
bool logY)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glLineWidth(1);
vtkm::UInt8 r, g, b, a;
ct.MapRGB(0).GetRGBA(r, g, b, a);
//This is horrible as the color table API isn't designed for users to query
//on a single value basis. We use the GetPoint and GetPointAlpha escape hatches
//and manually convert from float to uchar
vtkm::Vec<double, 4> data;
ct.GetPoint(0, data);
r = static_cast<vtkm::UInt8>(data[1] * 255.0 + 0.5);
g = static_cast<vtkm::UInt8>(data[2] * 255.0 + 0.5);
b = static_cast<vtkm::UInt8>(data[3] * 255.0 + 0.5);
ct.GetPointAlpha(0, data);
a = static_cast<vtkm::UInt8>(data[1] * 255.0 + 0.5);
glColor4ub(r, g, b, a);
glBegin(GL_LINE_STRIP);
@ -220,14 +234,23 @@ template <typename PtType>
VTKM_CONT void RenderExplicitLineSegments(vtkm::Id numVerts,
const PtType& verts,
const vtkm::cont::ArrayHandle<vtkm::Float32>& scalar,
vtkm::rendering::ColorTable ct,
vtkm::cont::ColorTable ct,
bool logY)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glLineWidth(1);
vtkm::UInt8 r, g, b, a;
ct.MapRGB(0).GetRGBA(r, g, b, a);
//This is horrible as the color table API isn't designed for users to query
//on a single value basis. We use the GetPoint and GetPointAlpha escape hatches
//and manually convert from float to uchar
vtkm::Vec<double, 4> data;
ct.GetPoint(0, data);
r = static_cast<vtkm::UInt8>(data[1] * 255.0 + 0.5);
g = static_cast<vtkm::UInt8>(data[2] * 255.0 + 0.5);
b = static_cast<vtkm::UInt8>(data[3] * 255.0 + 0.5);
ct.GetPointAlpha(0, data);
a = static_cast<vtkm::UInt8>(data[1] * 255.0 + 0.5);
glColor4ub(r, g, b, a);
glBegin(GL_LINE_STRIP);
@ -248,7 +271,7 @@ VTKM_CONT void RenderTriangles(MapperGL& mapper,
const PtType& verts,
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Id, 4>>& indices,
const vtkm::cont::ArrayHandle<vtkm::Float32>& scalar,
const vtkm::rendering::ColorTable& ct,
const vtkm::cont::ColorTable& ct,
const vtkm::Range& scalarRange,
const vtkm::rendering::Camera& camera)
{
@ -426,7 +449,7 @@ MapperGL::~MapperGL()
void MapperGL::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
{

@ -20,10 +20,10 @@
#ifndef vtk_m_rendering_MapperGL_h
#define vtk_m_rendering_MapperGL_h
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/CanvasGL.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
#include <vtkm/rendering/internal/OpenGLHeaders.h>
@ -43,7 +43,7 @@ public:
void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const vtkm::rendering::Camera&,
const vtkm::Range& scalarRange) override;

@ -83,7 +83,7 @@ vtkm::rendering::Canvas* MapperRayTracer::GetCanvas() const
void MapperRayTracer::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& vtkmNotUsed(colorTable),
const vtkm::cont::ColorTable& vtkmNotUsed(colorTable),
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
{

@ -20,8 +20,8 @@
#ifndef vtk_m_rendering_MapperRayTracer_h
#define vtk_m_rendering_MapperRayTracer_h
#include <vtkm/cont/ColorTable.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
#include <memory>
@ -44,7 +44,7 @@ public:
void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange) override;

@ -89,7 +89,7 @@ vtkm::rendering::Canvas* MapperVolume::GetCanvas() const
void MapperVolume::RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& vtkmNotUsed(colorTable),
const vtkm::cont::ColorTable& vtkmNotUsed(colorTable),
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
{

@ -42,7 +42,7 @@ public:
virtual void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable&, //colorTable
const vtkm::cont::ColorTable&, //colorTable
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange) override;

@ -320,7 +320,7 @@ void MapperWireframer::EndScene()
void MapperWireframer::RenderCells(const vtkm::cont::DynamicCellSet& inCellSet,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& inScalarField,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange)
{

@ -22,12 +22,12 @@
#include <memory>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/rendering/Camera.h>
#include <vtkm/rendering/Canvas.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/Mapper.h>
namespace vtkm
@ -58,7 +58,7 @@ public:
virtual void RenderCells(const vtkm::cont::DynamicCellSet& cellset,
const vtkm::cont::CoordinateSystem& coords,
const vtkm::cont::Field& scalarField,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const vtkm::rendering::Camera& camera,
const vtkm::Range& scalarRange) override;

@ -24,7 +24,7 @@
#include <vtkm/rendering/vtkm_rendering_export.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/Types.h>
#include <memory>
#include <vector>

@ -116,7 +116,15 @@ void View1D::RenderColorLegendAnnotations()
for (int i = 0; i < this->GetScene().GetNumberOfActors(); ++i)
{
vtkm::rendering::Actor act = this->GetScene().GetActor(i);
this->Legend.AddItem(act.GetScalarField().GetName(), act.GetColorTable().MapRGB(0));
vtkm::Vec<double, 4> colorData;
act.GetColorTable().GetPoint(0, colorData);
//colorData[0] is the transfer function x position
vtkm::rendering::Color color{ static_cast<vtkm::Float32>(colorData[1]),
static_cast<vtkm::Float32>(colorData[2]),
static_cast<vtkm::Float32>(colorData[3]) };
this->Legend.AddItem(act.GetScalarField().GetName(), color);
}
this->Legend.SetLabelColor(this->GetCanvas().GetForegroundColor());
this->Legend.Render(this->GetCamera(), this->GetWorldAnnotator(), this->GetCanvas());

@ -32,7 +32,6 @@
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/CellTables.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/MortonCodes.h>

@ -23,9 +23,10 @@
#include <math.h>
#include <stdio.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>

@ -22,8 +22,6 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/BoundingVolumeHierarchy.h>
#include <vtkm/rendering/raytracing/Camera.h>

@ -28,10 +28,10 @@
#include <vtkm/cont/ArrayHandleCounting.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/ColorTable.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/Camera.h>
#include <vtkm/rendering/raytracing/Logger.h>
#include <vtkm/rendering/raytracing/Ray.h>

@ -24,8 +24,6 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/rendering/ColorTable.h>
#include <vtkm/rendering/raytracing/Ray.h>
namespace vtkm

@ -98,7 +98,7 @@ void Render(ViewType& view, const std::string& outputFile)
template <typename MapperType, typename CanvasType, typename ViewType>
void Render(const vtkm::cont::DataSet& ds,
const std::string& fieldNm,
const vtkm::rendering::ColorTable& colorTable,
const vtkm::cont::ColorTable& colorTable,
const std::string& outputFile)
{
MapperType mapper;
@ -193,8 +193,8 @@ template <typename MapperType1, typename MapperType2, typename CanvasType, typen
void MultiMapperRender(const vtkm::cont::DataSet& ds1,
const vtkm::cont::DataSet& ds2,
const std::string& fieldNm,
const vtkm::rendering::ColorTable& colorTable1,
const vtkm::rendering::ColorTable& colorTable2,
const vtkm::cont::ColorTable& colorTable1,
const vtkm::cont::ColorTable& colorTable2,
const std::string& outputFile)
{
MapperType1 mapper1;

@ -39,7 +39,7 @@ void RenderTests()
canvas.AddLine(-0.8, -0.8, 0.8, 0.8, 1.0f, vtkm::rendering::Color::black);
canvas.AddLine(-0.8, 0.8, 0.8, -0.8, 1.0f, vtkm::rendering::Color::black);
vtkm::Bounds colorBarBounds(-0.8, -0.6, -0.8, 0.8, 0, 0);
canvas.AddColorBar(colorBarBounds, vtkm::rendering::ColorTable("thermal"), false);
canvas.AddColorBar(colorBarBounds, vtkm::cont::ColorTable("inferno"), false);
canvas.BlendBackground();
canvas.SaveAs("canvas.pnm");
}

@ -39,7 +39,7 @@ void RenderTests()
typedef vtkm::rendering::View3D V3;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "reg3D.pnm");

@ -39,17 +39,17 @@ void RenderTests()
typedef vtkm::rendering::View2D V2;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "reg3D.pnm");
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "rt_reg3D.pnm");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRectilinearDataSet0(), "pointvar", colorTable, "rect3D.pnm");
maker.Make3DRectilinearDataSet0(), "pointvar", colorTable, "rt_rect3D.pnm");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DExplicitDataSet4(), "pointvar", colorTable, "expl3D.pnm");
maker.Make3DExplicitDataSet4(), "pointvar", colorTable, "rt_expl3D.pnm");
vtkm::rendering::testing::Render<M, C, V2>(
maker.Make2DUniformDataSet1(), "pointvar", colorTable, "uni2D.pnm");
maker.Make2DUniformDataSet1(), "pointvar", colorTable, "rt_uni2D.pnm");
}
} //namespace

@ -39,9 +39,9 @@ void RenderTests()
typedef vtkm::rendering::View3D V3;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
colorTable.AddAlphaControlPoint(0.0, .01f);
colorTable.AddAlphaControlPoint(1.0, .01f);
vtkm::cont::ColorTable colorTable("inferno");
colorTable.AddPointAlpha(0.0, .01f);
colorTable.AddPointAlpha(1.0, .01f);
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "reg3D.pnm");

@ -108,18 +108,18 @@ void RenderTests()
typedef vtkm::rendering::View1D V1;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("OrRd");
vtkm::cont::ColorTable colorTable("samsel fire");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "reg3D.pnm");
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "wf_reg3D.pnm");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRectilinearDataSet0(), "pointvar", colorTable, "rect3D.pnm");
maker.Make3DRectilinearDataSet0(), "pointvar", colorTable, "wf_rect3D.pnm");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DExplicitDataSet4(), "pointvar", colorTable, "expl3D.pnm");
maker.Make3DExplicitDataSet4(), "pointvar", colorTable, "wf_expl3D.pnm");
vtkm::rendering::testing::Render<M, C, V3>(
Make3DUniformDataSet(), "pointvar", colorTable, "uniform3D.pnm");
Make3DUniformDataSet(), "pointvar", colorTable, "wf_uniform3D.pnm");
vtkm::rendering::testing::Render<M, C, V2>(
Make2DExplicitDataSet(), "cellVar", colorTable, "lines2D.pnm");
Make2DExplicitDataSet(), "cellVar", colorTable, "wf_lines2D.pnm");
//
// Test the 1D cell set line plot with multiple lines
//
@ -130,11 +130,11 @@ void RenderTests()
colors.push_back(vtkm::rendering::Color(1.f, 0.f, 0.f));
colors.push_back(vtkm::rendering::Color(0.f, 1.f, 0.f));
vtkm::rendering::testing::Render<M, C, V1>(
maker.Make1DUniformDataSet0(), fields, colors, "lines1D.pnm");
maker.Make1DUniformDataSet0(), fields, colors, "wf_lines1D.pnm");
//test log y
vtkm::rendering::Color red = vtkm::rendering::Color::red;
vtkm::rendering::testing::Render<M, C, V1>(
maker.Make1DUniformDataSet1(), "pointvar", red, "linesLogY1D.pnm", true);
maker.Make1DUniformDataSet1(), "pointvar", red, "wf_linesLogY1D.pnm", true);
}
} //namespace

@ -46,12 +46,12 @@ void RenderTests()
typedef vtkm::rendering::View3D V3;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
vtkm::rendering::ColorTable colorTable2("cool2warm");
colorTable2.AddAlphaControlPoint(0.0, .02f);
colorTable2.AddAlphaControlPoint(1.0, .02f);
vtkm::cont::ColorTable colorTable2("cool to warm");
colorTable2.AddPointAlpha(0.0, .02f);
colorTable2.AddPointAlpha(1.0, .02f);
vtkm::rendering::testing::MultiMapperRender<R, M2, C, V3>(maker.Make3DExplicitDataSetPolygonal(),
maker.Make3DRectilinearDataSet0(),

@ -45,7 +45,7 @@ void RenderTests()
vtkm::cont::DataSetFieldAdd dsf;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "reg3D.pnm");

@ -70,7 +70,7 @@ void RenderTests()
vtkm::cont::DataSetFieldAdd dsf;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
glfwInit();
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "GLFW Test", nullptr, nullptr);

@ -56,7 +56,7 @@ static void keyboardCall(unsigned char key, int vtkmNotUsed(x), int vtkmNotUsed(
static void displayCall()
{
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
typedef vtkm::rendering::MapperGL<VTKM_DEFAULT_DEVICE_ADAPTER_TAG> M;
typedef vtkm::rendering::CanvasGL C;

@ -42,7 +42,7 @@ void RenderTests()
typedef vtkm::rendering::View1D V1;
vtkm::cont::testing::MakeTestDataSet maker;
vtkm::rendering::ColorTable colorTable("thermal");
vtkm::cont::ColorTable colorTable("inferno");
vtkm::rendering::testing::Render<M, C, V3>(
maker.Make3DRegularDataSet0(), "pointvar", colorTable, "reg3D.pnm");

@ -22,9 +22,11 @@ set(headers
Conversions.h
ConvertToRGB.h
ConvertToRGBA.h
LookupTable.h
Portals.h
ShiftScaleToRGB.h
ShiftScaleToRGBA.h
TransferFunction.h
)
#-----------------------------------------------------------------------------

@ -0,0 +1,124 @@
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
#ifndef vtk_m_worklet_colorconversion_LookupTable_h
#define vtk_m_worklet_colorconversion_LookupTable_h
#include <vtkm/cont/ColorTableSamples.h>
#include <vtkm/exec/ColorTable.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/colorconversion/Conversions.h>
#include <float.h>
namespace vtkm
{
namespace worklet
{
namespace colorconversion
{
struct LookupTableTypes : vtkm::ListTagBase<vtkm::Vec<vtkm::UInt8, 3>,
vtkm::Vec<vtkm::UInt8, 4>,
vtkm::Vec<vtkm::Float32, 3>,
vtkm::Vec<vtkm::Float64, 4>>
{
};
struct LookupTable : public vtkm::worklet::WorkletMapField
{
vtkm::Float32 Shift;
vtkm::Float32 Scale;
vtkm::Range TableRange;
vtkm::Int32 NumberOfSamples;
//needs to support Nan, Above, Below Range colors
VTKM_CONT
template <typename T>
LookupTable(const T& colorTableSamples)
{
this->Shift = static_cast<vtkm::Float32>(-colorTableSamples.SampleRange.Min);
double rangeDelta = colorTableSamples.SampleRange.Length();
if (rangeDelta < DBL_MIN * colorTableSamples.NumberOfSamples)
{
// if the range is tiny, anything within the range will map to the bottom
// of the color scale.
this->Scale = 0.0;
}
else
{
this->Scale = static_cast<vtkm::Float32>(colorTableSamples.NumberOfSamples / rangeDelta);
}
this->TableRange = colorTableSamples.SampleRange;
this->NumberOfSamples = colorTableSamples.NumberOfSamples;
}
typedef void ControlSignature(FieldIn<> in,
WholeArrayIn<LookupTableTypes> lookup,
FieldOut<> color);
typedef void ExecutionSignature(_1, _2, _3);
template <typename T, typename WholeFieldIn, typename U, int N>
VTKM_EXEC void operator()(const T& in,
const WholeFieldIn lookupTable,
vtkm::Vec<U, N>& output) const
{
vtkm::Float64 v = (static_cast<vtkm::Float64>(in));
vtkm::Int32 idx = 1;
//This logic uses how ColorTableSamples is constructed. See
//vtkm/cont/ColorTableSamples to see why we use these magic offset values
if (vtkm::IsNan(v))
{
idx = this->NumberOfSamples + 3;
}
else if (v < this->TableRange.Min)
{ //If we are below the color range
idx = 0;
}
else if (v == this->TableRange.Min)
{ //If we are at the ranges min value
idx = 1;
}
else if (v > this->TableRange.Max)
{ //If we are above the ranges max value
idx = this->NumberOfSamples + 2;
}
else if (v == this->TableRange.Max)
{ //If we are at the ranges min value
idx = this->NumberOfSamples;
}
else
{
v = (v + this->Shift) * this->Scale;
// When v is very close to p.Range[1], the floating point calculation giving
// idx may map above the highest value in the lookup table. That is why it
// is padded
idx = static_cast<vtkm::Int32>(v);
}
output = lookupTable.Get(idx);
}
};
}
}
}
#endif

@ -0,0 +1,88 @@
//=============================================================================
//
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
//
// This software is distributed WITHOUT ANY WARRANTY; without even
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//
// Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2015 UT-Battelle, LLC.
// Copyright 2015 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//
//=============================================================================
#ifndef vtk_m_worklet_colorconversion_TransferFunction_h
#define vtk_m_worklet_colorconversion_TransferFunction_h
#include <vtkm/exec/ColorTable.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/colorconversion/Conversions.h>
namespace vtkm
{
namespace worklet
{
namespace colorconversion
{
struct TransferFunction : public vtkm::worklet::WorkletMapField
{
TransferFunction(const vtkm::exec::ColorTableBase* table)
: ColorTable(table)
{
}
typedef void ControlSignature(FieldIn<> in, FieldOut<> color);
typedef void ExecutionSignature(_1, _2);
template <typename T>
VTKM_EXEC void operator()(const T& in, vtkm::Vec<vtkm::UInt8, 3>& output) const
{
vtkm::Vec<float, 3> rgb = this->ColorTable->MapThroughColorSpace(static_cast<double>(in));
output[0] = colorconversion::ColorToUChar(rgb[0]);
output[1] = colorconversion::ColorToUChar(rgb[1]);
output[2] = colorconversion::ColorToUChar(rgb[2]);
}
template <typename T>
VTKM_EXEC void operator()(const T& in, vtkm::Vec<vtkm::UInt8, 4>& output) const
{
vtkm::Vec<float, 3> rgb = this->ColorTable->MapThroughColorSpace(static_cast<double>(in));
float alpha = this->ColorTable->MapThroughOpacitySpace(static_cast<double>(in));
output[0] = colorconversion::ColorToUChar(rgb[0]);
output[1] = colorconversion::ColorToUChar(rgb[1]);
output[2] = colorconversion::ColorToUChar(rgb[2]);
output[3] = colorconversion::ColorToUChar(alpha);
}
template <typename T>
VTKM_EXEC void operator()(const T& in, vtkm::Vec<float, 3>& output) const
{
output = this->ColorTable->MapThroughColorSpace(static_cast<double>(in));
}
template <typename T>
VTKM_EXEC void operator()(const T& in, vtkm::Vec<float, 4>& output) const
{
vtkm::Vec<float, 3> rgb = this->ColorTable->MapThroughColorSpace(static_cast<double>(in));
float alpha = this->ColorTable->MapThroughOpacitySpace(static_cast<double>(in));
output[0] = rgb[0];
output[1] = rgb[1];
output[2] = rgb[2];
output[3] = alpha;
}
const vtkm::exec::ColorTableBase* ColorTable;
};
}
}
}
#endif