Add a filter that uses ColorTable to color any field from a dataset.

This commit is contained in:
Robert Maynard 2018-03-29 14:46:39 -04:00
parent 944bc3c0d6
commit 79d922ee49
7 changed files with 482 additions and 8 deletions

@ -852,6 +852,12 @@ vtkm::cont::VirtualObjectHandle<vtkm::exec::ColorTableBase>* ColorTable::GetHand
return this->Impl->ExecHandle;
}
//---------------------------------------------------------------------------
vtkm::Id ColorTable::GetModifiedCount() const
{
return this->Impl->HostSideCache->GetModifiedCount();
}
/*
#define ColorTableExportMapFunctions(T) \

@ -100,11 +100,8 @@ enum struct ColorSpace
/// 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.
/// To map a field from a vtkm::cont::DataSet through the color and opacity transfer
/// functions and into a RGB or RGBA array you should use vtkm::filter::FieldToColor.
///
class VTKM_CONT_EXPORT ColorTable
{
@ -635,9 +632,12 @@ public:
/// 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
/// \brief returns the modified count for the virtual object handle of the exec color table
///
/// The modified count allows consumers of a shared color table to keep track
/// if the color table has been modified since the last time they used it.
vtkm::Id GetModifiedCount() const;
};
}
} //namespace vtkm::cont

@ -33,6 +33,7 @@ set(headers
ExtractStructured.h
FieldMetadata.h
FieldSelection.h
FieldToColors.h
Filter.h
FilterCell.h
FilterDataSet.h
@ -75,6 +76,7 @@ set(header_template_sources
ExtractGeometry.hxx
ExtractPoints.hxx
ExtractStructured.hxx
FieldToColors.hxx
Filter.hxx
FilterCell.hxx
FilterDataSet.hxx

@ -0,0 +1,98 @@
//============================================================================
// 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_filter_FieldToColors_h
#define vtk_m_filter_FieldToColors_h
#include <vtkm/cont/ColorTable.h>
#include <vtkm/filter/FilterField.h>
namespace vtkm
{
namespace filter
{
/// \brief Convert an arbitrary field to an RGB or RGBA field
///
class FieldToColors : public vtkm::filter::FilterField<FieldToColors>
{
public:
VTKM_CONT
FieldToColors(const vtkm::cont::ColorTable& table);
enum FieldToColorsInputMode
{
SCALAR,
MAGNITUDE,
COMPONENT
};
enum FieldToColorsOutputMode
{
RGB,
RGBA
};
void SetMappingMode(FieldToColorsInputMode mode) { this->InputMode = mode; }
void SetMappingToScalar() { this->InputMode = FieldToColorsInputMode::SCALAR; }
void SetMappingToMagnitude() { this->InputMode = FieldToColorsInputMode::MAGNITUDE; }
void SetMappingToComponent() { this->InputMode = FieldToColorsInputMode::COMPONENT; }
FieldToColorsInputMode GetMappingMode() const { return this->InputMode; }
bool IsMappingScalar() const { return this->InputMode == FieldToColorsInputMode::SCALAR; }
bool IsMappingMagnitude() const { return this->InputMode == FieldToColorsInputMode::MAGNITUDE; }
bool IsMappingComponent() const { return this->InputMode == FieldToColorsInputMode::COMPONENT; }
void SetMappingComponent(vtkm::Int32 comp) { this->Component = comp; }
vtkm::Int32 GetMappingComponent() const { return this->Component; }
void SetOutputMode(FieldToColorsOutputMode mode) { this->OutputMode = mode; }
void SetOutputToRGB() { this->OutputMode = FieldToColorsOutputMode::RGB; }
void SetOutputToRGBA() { this->OutputMode = FieldToColorsOutputMode::RGBA; }
FieldToColorsOutputMode GetOutputMode() const { return this->OutputMode; }
bool IsMappingRGB() const { return this->OutputMode == FieldToColorsOutputMode::RGB; }
bool IsMappingRGBA() const { return this->OutputMode == FieldToColorsOutputMode::RGBA; }
void SetNumberOfSamplingPoints(vtkm::Int32 count);
vtkm::Int32 GetNumberOfSamplingPoints() const { return this->SampleCount; }
template <typename T, typename StorageType, typename DerivedPolicy, typename DeviceAdapter>
VTKM_CONT vtkm::filter::Result DoExecute(const vtkm::cont::DataSet& input,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
const vtkm::filter::FieldMetadata& fieldMeta,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy,
const DeviceAdapter& tag);
private:
vtkm::cont::ColorTable Table;
FieldToColorsInputMode InputMode;
FieldToColorsOutputMode OutputMode;
vtkm::cont::ColorTableSamplesRGB SamplesRGB;
vtkm::cont::ColorTableSamplesRGBA SamplesRGBA;
vtkm::Int32 Component;
vtkm::Int32 SampleCount;
vtkm::Id ModifiedCount;
};
}
} // namespace vtkm::filter
#include <vtkm/filter/FieldToColors.hxx>
#endif // vtk_m_filter_FieldToColors_h

@ -0,0 +1,270 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/VecTraits.h>
#include <vtkm/cont/ColorTable.hxx>
namespace vtkm
{
namespace filter
{
namespace
{
struct ScalarInputMode
{
};
struct MagnitudeInputMode
{
};
struct ComponentInputMode
{
};
}
template <typename T, typename S, typename U>
inline bool execute(const vtkm::cont::ColorTable& table,
ScalarInputMode,
int,
const T& input,
const S& samples,
U& output,
vtkm::VecTraitsTagSingleComponent)
{
return table.Map(input, samples, output);
}
template <typename T, typename S, typename U>
inline bool execute(const vtkm::cont::ColorTable& table,
MagnitudeInputMode,
int,
const T& input,
const S& samples,
U& output,
vtkm::VecTraitsTagMultipleComponents)
{
return table.MapMagnitude(input, samples, output);
}
template <typename T, typename S, typename U>
inline bool execute(const vtkm::cont::ColorTable& table,
ComponentInputMode,
int comp,
const T& input,
const S& samples,
U& output,
vtkm::VecTraitsTagMultipleComponents)
{
return table.MapComponent(input, comp, samples, output);
}
//error cases
template <typename T, typename S, typename U>
inline bool execute(const vtkm::cont::ColorTable& table,
ScalarInputMode,
int,
const T& input,
const S& samples,
U& output,
vtkm::VecTraitsTagMultipleComponents)
{ //vector input in scalar mode so do magnitude
return table.MapMagnitude(input, samples, output);
}
template <typename T, typename S, typename U>
inline bool execute(const vtkm::cont::ColorTable& table,
MagnitudeInputMode,
int,
const T& input,
const S& samples,
U& output,
vtkm::VecTraitsTagSingleComponent)
{ //is a scalar array so ignore Magnitude mode
return table.Map(input, samples, output);
}
template <typename T, typename S, typename U>
inline bool execute(const vtkm::cont::ColorTable& table,
ComponentInputMode,
int,
const T& input,
const S& samples,
U& output,
vtkm::VecTraitsTagSingleComponent)
{ //is a scalar array so ignore COMPONENT mode
return table.Map(input, samples, output);
}
//-----------------------------------------------------------------------------
inline VTKM_CONT FieldToColors::FieldToColors(const vtkm::cont::ColorTable& table)
: vtkm::filter::FilterField<FieldToColors>()
, Table(table)
, InputMode(SCALAR)
, OutputMode(RGBA)
, SamplesRGB()
, SamplesRGBA()
, Component(0)
, SampleCount(256)
, ModifiedCount(-1)
{
}
//-----------------------------------------------------------------------------
inline VTKM_CONT void FieldToColors::SetNumberOfSamplingPoints(vtkm::Int32 count)
{
if (this->SampleCount != count && count > 0)
{
this->ModifiedCount = -1;
this->SampleCount = count;
}
}
//-----------------------------------------------------------------------------
template <typename T, typename StorageType, typename DerivedPolicy, typename DeviceAdapter>
inline VTKM_CONT vtkm::filter::Result FieldToColors::DoExecute(
const vtkm::cont::DataSet& input,
const vtkm::cont::ArrayHandle<T, StorageType>& inField,
const vtkm::filter::FieldMetadata& fieldMetadata,
const vtkm::filter::PolicyBase<DerivedPolicy>&,
const DeviceAdapter&)
{
//If the table has been modified we need to rebuild our
//sample tables
if (this->Table.GetModifiedCount() > this->ModifiedCount)
{
this->Table.Sample(this->SampleCount, this->SamplesRGB);
this->Table.Sample(this->SampleCount, this->SamplesRGBA);
this->ModifiedCount = this->Table.GetModifiedCount();
}
std::string outputName = this->GetOutputFieldName();
if (outputName == "")
{
// Default name is name of input_colors.
outputName = fieldMetadata.GetName() + "_colors";
}
vtkm::cont::Field outField;
//We need to verify if the array is a vtkm::Vec
using IsVec = typename vtkm::VecTraits<T>::HasMultipleComponents;
if (this->OutputMode == RGBA)
{
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> output;
bool ran = false;
switch (this->InputMode)
{
case SCALAR:
{
ran = execute(this->Table,
ScalarInputMode{},
this->Component,
inField,
this->SamplesRGBA,
output,
IsVec{});
break;
}
case MAGNITUDE:
{
ran = execute(this->Table,
MagnitudeInputMode{},
this->Component,
inField,
this->SamplesRGBA,
output,
IsVec{});
break;
}
case COMPONENT:
{
ran = execute(this->Table,
ComponentInputMode{},
this->Component,
inField,
this->SamplesRGBA,
output,
IsVec{});
break;
}
}
if (!ran)
{
return vtkm::filter::Result();
}
outField = vtkm::cont::Field(outputName, vtkm::cont::Field::ASSOC_POINTS, output);
}
else
{
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> output;
bool ran = false;
switch (this->InputMode)
{
case SCALAR:
{
ran = execute(this->Table,
ScalarInputMode{},
this->Component,
inField,
this->SamplesRGB,
output,
IsVec{});
break;
}
case MAGNITUDE:
{
ran = execute(this->Table,
MagnitudeInputMode{},
this->Component,
inField,
this->SamplesRGB,
output,
IsVec{});
break;
}
case COMPONENT:
{
ran = execute(this->Table,
ComponentInputMode{},
this->Component,
inField,
this->SamplesRGB,
output,
IsVec{});
break;
}
}
if (!ran)
{
return vtkm::filter::Result();
}
outField = vtkm::cont::Field(outputName, vtkm::cont::Field::ASSOC_POINTS, output);
}
return vtkm::filter::Result(input, outField);
}
}
} // namespace vtkm::filter

@ -33,6 +33,7 @@ set(unit_tests
UnitTestExtractStructuredFilter.cxx
UnitTestFieldMetadata.cxx
UnitTestFieldSelection.cxx
UnitTestFieldToColors.cxx
UnitTestGradient.cxx
UnitTestHistogramFilter.cxx
UnitTestMarchingCubesFilter.cxx

@ -0,0 +1,97 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/filter/FieldToColors.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
namespace
{
void TestFieldToColors()
{
//faux input field
constexpr vtkm::Id nvals = 8;
constexpr int data[nvals] = { -1, 0, 10, 20, 30, 40, 50, 60 };
//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::DataSet ds = vtkm::cont::testing::MakeTestDataSet().Make3DExplicitDataSetPolygonal();
vtkm::cont::DataSetFieldAdd dsf;
dsf.AddPointField(ds, "faux", data, nvals);
vtkm::filter::FieldToColors ftc(table);
ftc.SetOutputToRGBA();
ftc.SetActiveField("faux");
ftc.SetOutputFieldName("colors");
auto rgbaResult = ftc.Execute(ds);
VTKM_TEST_ASSERT(rgbaResult.HasField("colors", vtkm::cont::Field::ASSOC_POINTS),
"Field missing.");
vtkm::cont::Field Result = rgbaResult.GetField("colors", vtkm::cont::Field::ASSOC_POINTS);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> resultRGBAHandle;
Result.GetData().CopyTo(resultRGBAHandle);
//values confirmed with ParaView 5.4
const vtkm::Vec<vtkm::UInt8, 4> correct_diverging_rgba_values[nvals] = {
{ 0, 0, 255, 255 }, { 59, 76, 192, 255 }, { 122, 157, 248, 255 }, { 191, 211, 246, 255 },
{ 241, 204, 184, 255 }, { 238, 134, 105, 255 }, { 180, 4, 38, 255 }, { 255, 0, 0, 255 }
};
auto portalRGBA = resultRGBAHandle.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portalRGBA.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_diverging_rgba_values[i],
"incorrect value when interpolating between values");
}
//Now verify that we can switching our output mode
ftc.SetOutputToRGB();
auto rgbResult = ftc.Execute(ds);
VTKM_TEST_ASSERT(rgbResult.HasField("colors", vtkm::cont::Field::ASSOC_POINTS), "Field missing.");
Result = rgbResult.GetField("colors", vtkm::cont::Field::ASSOC_POINTS);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 3>> resultRGBHandle;
Result.GetData().CopyTo(resultRGBHandle);
//values confirmed with ParaView 5.4
const vtkm::Vec<vtkm::UInt8, 3> correct_diverging_rgb_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 portalRGB = resultRGBHandle.GetPortalConstControl();
for (std::size_t i = 0; i < nvals; ++i)
{
auto result = portalRGB.Get(static_cast<vtkm::Id>(i));
VTKM_TEST_ASSERT(result == correct_diverging_rgb_values[i],
"incorrect value when interpolating between values");
}
}
}
int UnitTestFieldToColors(int, char* [])
{
return vtkm::cont::testing::Testing::Run(TestFieldToColors);
}