a2ab460f5d
We have been doing a better job at hiding device code (and moving code into libraries). Smoke out source that no longer needs to be compiled by device compilers.
1287 lines
42 KiB
C++
1287 lines
42 KiB
C++
//============================================================================
|
|
// 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.
|
|
//============================================================================
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <memory>
|
|
|
|
#include <vtkm/cont/ColorTable.h>
|
|
#include <vtkm/cont/ColorTableMap.h>
|
|
#include <vtkm/cont/ErrorBadType.h>
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
template <typename T>
|
|
struct MinDelta
|
|
{
|
|
};
|
|
// This value seems to work well for vtkm::Float32 ranges we have tested
|
|
template <>
|
|
struct MinDelta<vtkm::Float32>
|
|
{
|
|
static constexpr int value = 2048;
|
|
};
|
|
template <>
|
|
struct MinDelta<vtkm::Float64>
|
|
{
|
|
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<vtkm::Float32>
|
|
{
|
|
static constexpr int value = 8388608;
|
|
};
|
|
template <>
|
|
struct MinRepresentable<vtkm::Float64>
|
|
{
|
|
static constexpr vtkm::Int64 value = 4503599627370496L;
|
|
};
|
|
|
|
inline 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 + 1, &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>
|
|
inline vtkm::Float64 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<vtkm::Float64>(result);
|
|
}
|
|
return static_cast<vtkm::Float64>(r[1]);
|
|
}
|
|
|
|
inline 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<vtkm::Float64>(std::numeric_limits<vtkm::Float32>::lowest()) &&
|
|
r.Max < static_cast<vtkm::Float64>(std::numeric_limits<vtkm::Float32>::max()))
|
|
{ //We've found it best to offset it in vtkm::Float32 space if the numbers
|
|
//lay inside that representable range
|
|
vtkm::Float32 frange[2] = { static_cast<vtkm::Float32>(r.Min),
|
|
static_cast<vtkm::Float32>(r.Max) };
|
|
result.Max = expandRange(frange);
|
|
}
|
|
else
|
|
{
|
|
vtkm::Float64 drange[2] = { r.Min, r.Max };
|
|
result.Max = expandRange(drange);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
inline vtkm::Vec3f_32 hsvTorgb(const vtkm::Vec3f_32& hsv)
|
|
{
|
|
vtkm::Vec3f_32 rgb;
|
|
constexpr vtkm::Float32 onethird = 1.0f / 3.0f;
|
|
constexpr vtkm::Float32 onesixth = 1.0f / 6.0f;
|
|
constexpr vtkm::Float32 twothird = 2.0f / 3.0f;
|
|
constexpr vtkm::Float32 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.5f) // 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.0) // 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;
|
|
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;
|
|
}
|
|
|
|
inline bool outside_vrange(vtkm::Float64 x)
|
|
{
|
|
return x < 0.0 || x > 1.0;
|
|
}
|
|
inline bool outside_vrange(vtkm::Float32 x)
|
|
{
|
|
return x < 0.0f || x > 1.0f;
|
|
}
|
|
template <typename T>
|
|
inline bool outside_vrange(const vtkm::Vec<T, 2>& x)
|
|
{
|
|
return outside_vrange(x[0]) || outside_vrange(x[1]);
|
|
}
|
|
template <typename T>
|
|
inline bool outside_vrange(const vtkm::Vec<T, 3>& x)
|
|
{
|
|
return outside_vrange(x[0]) || outside_vrange(x[1]) || outside_vrange(x[2]);
|
|
}
|
|
|
|
inline bool outside_range()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool outside_range(T&& t)
|
|
{
|
|
return outside_vrange(t);
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
inline bool outside_range(T&& t, U&& u)
|
|
{
|
|
return outside_vrange(t) || outside_vrange(u);
|
|
}
|
|
|
|
template <typename T, typename U, typename V, typename... Args>
|
|
inline 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)...);
|
|
}
|
|
|
|
template <typename T>
|
|
inline vtkm::cont::ArrayHandle<T> buildSampleHandle(vtkm::Int32 numSamples,
|
|
T start,
|
|
T end,
|
|
T inc,
|
|
bool appendNanAndRangeColors)
|
|
{
|
|
|
|
//number of samples + end + appendNanAndRangeColors
|
|
vtkm::Int32 allocationSize = (appendNanAndRangeColors) ? numSamples + 5 : numSamples + 1;
|
|
|
|
vtkm::cont::ArrayHandle<T> handle;
|
|
handle.Allocate(allocationSize);
|
|
|
|
auto portal = handle.WritePortal();
|
|
vtkm::Id index = 0;
|
|
|
|
//Insert the below range first
|
|
if (appendNanAndRangeColors)
|
|
{
|
|
portal.Set(index++, std::numeric_limits<T>::lowest()); //below
|
|
}
|
|
|
|
//add number of samples which doesn't account for the end
|
|
T value = start;
|
|
for (vtkm::Int32 i = 0; i < numSamples; ++i, ++index, value += inc)
|
|
{
|
|
portal.Set(index, value);
|
|
}
|
|
portal.Set(index++, end);
|
|
|
|
if (appendNanAndRangeColors)
|
|
{
|
|
//push back the last value again so that when lookups near the max value
|
|
//occur we don't need to clamp as if they are out-of-bounds they will
|
|
//land in the extra 'end' color
|
|
portal.Set(index++, end);
|
|
portal.Set(index++, std::numeric_limits<T>::max()); //above
|
|
portal.Set(index++, vtkm::Nan<T>()); //nan
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
template <typename OutputColors>
|
|
inline bool sampleColorTable(const vtkm::cont::ColorTable* self,
|
|
vtkm::Int32 numSamples,
|
|
OutputColors& colors,
|
|
vtkm::Float64 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 vtkm::Float64 d_samples = static_cast<vtkm::Float64>(numSamples - 1);
|
|
const vtkm::Float64 d_delta = r.Length() / d_samples;
|
|
|
|
if (r.Min > static_cast<vtkm::Float64>(std::numeric_limits<vtkm::Float32>::lowest()) &&
|
|
r.Max < static_cast<vtkm::Float64>(std::numeric_limits<vtkm::Float32>::max()))
|
|
{
|
|
//we can try and see if Float32 space has enough resolution
|
|
const vtkm::Float32 f_samples = static_cast<vtkm::Float32>(numSamples - 1);
|
|
const vtkm::Float32 f_start = static_cast<vtkm::Float32>(r.Min);
|
|
const vtkm::Float32 f_delta = static_cast<vtkm::Float32>(r.Length()) / f_samples;
|
|
const vtkm::Float32 f_end = f_start + (f_delta * f_samples);
|
|
|
|
if (vtkm::Abs(static_cast<vtkm::Float64>(f_end) - r.Max) <= tolerance &&
|
|
vtkm::Abs(static_cast<vtkm::Float64>(f_delta) - d_delta) <= tolerance)
|
|
{
|
|
auto handle =
|
|
buildSampleHandle((numSamples - 1), f_start, f_end, f_delta, appendNanAndRangeColors);
|
|
return vtkm::cont::ColorTableMap(handle, *self, colors);
|
|
}
|
|
}
|
|
|
|
//otherwise we need to use Float64 space
|
|
auto handle = buildSampleHandle((numSamples - 1), r.Min, r.Max, d_delta, appendNanAndRangeColors);
|
|
return vtkm::cont::ColorTableMap(handle, *self, colors);
|
|
}
|
|
} // anonymous namespace
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace cont
|
|
{
|
|
|
|
namespace detail
|
|
{
|
|
|
|
struct ColorTableInternals
|
|
{
|
|
std::string Name;
|
|
|
|
vtkm::ColorSpace Space = vtkm::ColorSpace::Lab;
|
|
vtkm::Range TableRange = { 1.0, 0.0 };
|
|
|
|
vtkm::Vec3f_32 NaNColor = { 0.5f, 0.0f, 0.0f };
|
|
vtkm::Vec3f_32 BelowRangeColor = { 0.0f, 0.0f, 0.0f };
|
|
vtkm::Vec3f_32 AboveRangeColor = { 0.0f, 0.0f, 0.0f };
|
|
|
|
bool UseClamping = true;
|
|
|
|
std::vector<vtkm::Float64> ColorNodePos;
|
|
std::vector<vtkm::Vec3f_32> ColorRGB;
|
|
|
|
std::vector<vtkm::Float64> OpacityNodePos;
|
|
std::vector<vtkm::Float32> OpacityAlpha;
|
|
std::vector<vtkm::Vec2f_32> OpacityMidSharp;
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Float64> ColorPosHandle;
|
|
vtkm::cont::ArrayHandle<vtkm::Vec3f_32> ColorRGBHandle;
|
|
vtkm::cont::ArrayHandle<vtkm::Float64> OpacityPosHandle;
|
|
vtkm::cont::ArrayHandle<vtkm::Float32> OpacityAlphaHandle;
|
|
vtkm::cont::ArrayHandle<vtkm::Vec2f_32> OpacityMidSharpHandle;
|
|
bool ColorArraysChanged = true;
|
|
bool OpacityArraysChanged = true;
|
|
|
|
vtkm::Id ModifiedCount = 1;
|
|
void Modified() { ++this->ModifiedCount; }
|
|
|
|
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 internal
|
|
{
|
|
std::set<std::string> GetPresetNames();
|
|
bool LoadColorTablePreset(vtkm::cont::ColorTable::Preset preset, vtkm::cont::ColorTable& table);
|
|
bool LoadColorTablePreset(std::string name, vtkm::cont::ColorTable& table);
|
|
} // namespace internal
|
|
|
|
//----------------------------------------------------------------------------
|
|
ColorTable::ColorTable(vtkm::cont::ColorTable::Preset preset)
|
|
: Internals(std::make_shared<detail::ColorTableInternals>())
|
|
{
|
|
const bool loaded = this->LoadPreset(preset);
|
|
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 LAB as it is the default
|
|
//when the no parameter constructor is called
|
|
this->SetColorSpace(vtkm::ColorSpace::Lab);
|
|
}
|
|
this->AddSegmentAlpha(
|
|
this->Internals->TableRange.Min, 1.0f, this->Internals->TableRange.Max, 1.0f);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ColorTable::ColorTable(const std::string& name)
|
|
: Internals(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 LAB as it is the default
|
|
//when the no parameter constructor is called
|
|
this->SetColorSpace(vtkm::ColorSpace::Lab);
|
|
}
|
|
this->AddSegmentAlpha(
|
|
this->Internals->TableRange.Min, 1.0f, this->Internals->TableRange.Max, 1.0f);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ColorTable::ColorTable(vtkm::ColorSpace space)
|
|
: Internals(std::make_shared<detail::ColorTableInternals>())
|
|
{
|
|
this->SetColorSpace(space);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ColorTable::ColorTable(const vtkm::Range& range,
|
|
const vtkm::Vec3f_32& rgb1,
|
|
const vtkm::Vec3f_32& rgb2,
|
|
vtkm::ColorSpace space)
|
|
: Internals(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::Vec4f_32& rgba1,
|
|
const vtkm::Vec4f_32& rgba2,
|
|
vtkm::ColorSpace space)
|
|
: Internals(std::make_shared<detail::ColorTableInternals>())
|
|
{
|
|
vtkm::Vec3f_32 rgb1(rgba1[0], rgba1[1], rgba1[2]);
|
|
vtkm::Vec3f_32 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(const std::string& name,
|
|
vtkm::ColorSpace colorSpace,
|
|
const vtkm::Vec3f_64& nanColor,
|
|
const std::vector<vtkm::Float64>& rgbPoints,
|
|
const std::vector<vtkm::Float64>& alphaPoints)
|
|
: Internals(std::make_shared<detail::ColorTableInternals>())
|
|
{
|
|
this->SetName(name);
|
|
this->SetColorSpace(colorSpace);
|
|
this->SetNaNColor(nanColor);
|
|
this->FillColorTableFromDataPointer(static_cast<vtkm::Int32>(rgbPoints.size()), rgbPoints.data());
|
|
this->FillOpacityTableFromDataPointer(static_cast<vtkm::Int32>(alphaPoints.size()),
|
|
alphaPoints.data());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ColorTable::~ColorTable() {}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const std::string& ColorTable::GetName() const
|
|
{
|
|
return this->Internals->Name;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::SetName(const std::string& name)
|
|
{
|
|
this->Internals->Name = name;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool ColorTable::LoadPreset(vtkm::cont::ColorTable::Preset preset)
|
|
{
|
|
return internal::LoadColorTablePreset(preset, *this);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
std::set<std::string> ColorTable::GetPresets()
|
|
{
|
|
return internal::GetPresetNames();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool ColorTable::LoadPreset(const std::string& name)
|
|
{
|
|
return internal::LoadColorTablePreset(name, *this);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
ColorTable ColorTable::MakeDeepCopy()
|
|
{
|
|
ColorTable dcopy(this->Internals->Space);
|
|
|
|
dcopy.Internals->TableRange = this->Internals->TableRange;
|
|
|
|
dcopy.Internals->NaNColor = this->Internals->NaNColor;
|
|
dcopy.Internals->BelowRangeColor = this->Internals->BelowRangeColor;
|
|
dcopy.Internals->AboveRangeColor = this->Internals->AboveRangeColor;
|
|
|
|
dcopy.Internals->UseClamping = this->Internals->UseClamping;
|
|
|
|
dcopy.Internals->ColorNodePos = this->Internals->ColorNodePos;
|
|
dcopy.Internals->ColorRGB = this->Internals->ColorRGB;
|
|
|
|
dcopy.Internals->OpacityNodePos = this->Internals->OpacityNodePos;
|
|
dcopy.Internals->OpacityAlpha = this->Internals->OpacityAlpha;
|
|
dcopy.Internals->OpacityMidSharp = this->Internals->OpacityMidSharp;
|
|
return dcopy;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkm::ColorSpace ColorTable::GetColorSpace() const
|
|
{
|
|
return this->Internals->Space;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::SetColorSpace(vtkm::ColorSpace space)
|
|
{
|
|
this->Internals->Space = space;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::SetClamping(bool state)
|
|
{
|
|
this->Internals->UseClamping = state;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool ColorTable::GetClamping() const
|
|
{
|
|
return this->Internals->UseClamping;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::SetBelowRangeColor(const vtkm::Vec3f_32& c)
|
|
{
|
|
this->Internals->BelowRangeColor = c;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const vtkm::Vec3f_32& ColorTable::GetBelowRangeColor() const
|
|
{
|
|
return this->Internals->BelowRangeColor;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::SetAboveRangeColor(const vtkm::Vec3f_32& c)
|
|
{
|
|
this->Internals->AboveRangeColor = c;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const vtkm::Vec3f_32& ColorTable::GetAboveRangeColor() const
|
|
{
|
|
return this->Internals->AboveRangeColor;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::SetNaNColor(const vtkm::Vec3f_32& c)
|
|
{
|
|
this->Internals->NaNColor = c;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const vtkm::Vec3f_32& ColorTable::GetNaNColor() const
|
|
{
|
|
return this->Internals->NaNColor;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::Clear()
|
|
{
|
|
this->ClearColors();
|
|
this->ClearAlpha();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void ColorTable::ClearColors()
|
|
{
|
|
this->Internals->ColorNodePos.clear();
|
|
this->Internals->ColorRGB.clear();
|
|
this->Internals->ColorArraysChanged = true;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void ColorTable::ClearAlpha()
|
|
{
|
|
this->Internals->OpacityNodePos.clear();
|
|
this->Internals->OpacityAlpha.clear();
|
|
this->Internals->OpacityMidSharp.clear();
|
|
this->Internals->OpacityArraysChanged = true;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void ColorTable::ReverseColors()
|
|
{
|
|
std::reverse(this->Internals->ColorRGB.begin(), this->Internals->ColorRGB.end());
|
|
this->Internals->ColorArraysChanged = true;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void ColorTable::ReverseAlpha()
|
|
{
|
|
std::reverse(this->Internals->OpacityAlpha.begin(), this->Internals->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->Internals->OpacityMidSharp.begin(),
|
|
this->Internals->OpacityMidSharp.end() - 1);
|
|
this->Internals->OpacityArraysChanged = true;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
const vtkm::Range& ColorTable::GetRange() const
|
|
{
|
|
return this->Internals->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 vtkm::Float64 minv = this->GetRange().Min;
|
|
const vtkm::Float64 oldScale = this->GetRange().Length();
|
|
const vtkm::Float64 newScale = newRange.Length();
|
|
VTKM_ASSERT(oldScale > 0);
|
|
VTKM_ASSERT(newScale > 0);
|
|
for (auto i = this->Internals->ColorNodePos.begin(); i != this->Internals->ColorNodePos.end();
|
|
++i)
|
|
{
|
|
const auto t = (*i - minv) / oldScale;
|
|
*i = (t * newScale) + newRange.Min;
|
|
}
|
|
for (auto i = this->Internals->OpacityNodePos.begin(); i != this->Internals->OpacityNodePos.end();
|
|
++i)
|
|
{
|
|
const auto t = (*i - minv) / oldScale;
|
|
*i = (t * newScale) + newRange.Min;
|
|
}
|
|
|
|
this->Internals->ColorArraysChanged = true;
|
|
this->Internals->OpacityArraysChanged = true;
|
|
this->Internals->TableRange = newRange;
|
|
this->Internals->Modified();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::AddPoint(vtkm::Float64 x, const vtkm::Vec3f_32& rgb)
|
|
{
|
|
if (outside_range(rgb))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
std::size_t index = 0;
|
|
if (this->Internals->ColorNodePos.size() == 0 || this->Internals->ColorNodePos.back() < x)
|
|
{
|
|
this->Internals->ColorNodePos.emplace_back(x);
|
|
this->Internals->ColorRGB.emplace_back(rgb);
|
|
index = this->Internals->ColorNodePos.size();
|
|
}
|
|
else
|
|
{
|
|
auto begin = this->Internals->ColorNodePos.begin();
|
|
auto pos = std::lower_bound(begin, this->Internals->ColorNodePos.end(), x);
|
|
index = static_cast<std::size_t>(std::distance(begin, pos));
|
|
|
|
if (*pos == x)
|
|
{
|
|
this->Internals->ColorRGB[index] = rgb;
|
|
}
|
|
else
|
|
{
|
|
this->Internals->ColorRGB.emplace(
|
|
this->Internals->ColorRGB.begin() + std::distance(begin, pos), rgb);
|
|
this->Internals->ColorNodePos.emplace(pos, x);
|
|
}
|
|
}
|
|
this->Internals->TableRange.Include(x); //update range to include x
|
|
this->Internals->ColorArraysChanged = true;
|
|
this->Internals->Modified();
|
|
return static_cast<vtkm::Int32>(index);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::AddPointHSV(vtkm::Float64 x, const vtkm::Vec3f_32& hsv)
|
|
{
|
|
return this->AddPoint(x, hsvTorgb(hsv));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::AddSegment(vtkm::Float64 x1,
|
|
const vtkm::Vec3f_32& rgb1,
|
|
vtkm::Float64 x2,
|
|
const vtkm::Vec3f_32& rgb2)
|
|
{
|
|
if (outside_range(rgb1, rgb2))
|
|
{
|
|
return -1;
|
|
}
|
|
if (this->Internals->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->Internals->ColorNodePos.begin();
|
|
auto nodeEnd = this->Internals->ColorNodePos.end();
|
|
|
|
auto rgbBegin = this->Internals->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->Internals->ColorNodePos.erase(nodeStart, nodeStop);
|
|
this->Internals->ColorRGB.erase(rgbStart, rgbStop);
|
|
}
|
|
vtkm::Int32 pos = this->AddPoint(x1, rgb1);
|
|
this->AddPoint(x2, rgb2);
|
|
return pos;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::AddSegmentHSV(vtkm::Float64 x1,
|
|
const vtkm::Vec3f_32& hsv1,
|
|
vtkm::Float64 x2,
|
|
const vtkm::Vec3f_32& hsv2)
|
|
{
|
|
return this->AddSegment(x1, hsvTorgb(hsv1), x2, hsvTorgb(hsv2));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::GetPoint(vtkm::Int32 index, vtkm::Vec4f_64& data) const
|
|
{
|
|
std::size_t i = static_cast<std::size_t>(index);
|
|
const std::size_t size = this->Internals->ColorNodePos.size();
|
|
if (index < 0 || i >= size)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const auto& pos = this->Internals->ColorNodePos[i];
|
|
const auto& rgb = this->Internals->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::Vec4f_64& 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->Internals->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->Internals->ColorNodePos.begin() + index;
|
|
auto newPos = std::lower_bound(
|
|
this->Internals->ColorNodePos.begin(), this->Internals->ColorNodePos.end(), data[0]);
|
|
if (oldPos == newPos)
|
|
{ //node's relative location hasn't changed
|
|
this->Internals->ColorArraysChanged = true;
|
|
auto& rgb = this->Internals->ColorRGB[i];
|
|
*newPos = data[0];
|
|
rgb[0] = static_cast<vtkm::Float32>(data[1]);
|
|
rgb[1] = static_cast<vtkm::Float32>(data[2]);
|
|
rgb[2] = static_cast<vtkm::Float32>(data[3]);
|
|
this->Internals->Modified();
|
|
return index;
|
|
}
|
|
else
|
|
{ //remove the point, and add the new values as the relative location is different
|
|
this->RemovePoint(index);
|
|
vtkm::Vec3f_32 newrgb(static_cast<vtkm::Float32>(data[1]),
|
|
static_cast<vtkm::Float32>(data[2]),
|
|
static_cast<vtkm::Float32>(data[3]));
|
|
return this->AddPoint(data[0], newrgb);
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::RemovePoint(vtkm::Float64 x)
|
|
{
|
|
auto begin = this->Internals->ColorNodePos.begin();
|
|
auto pos = std::lower_bound(begin, this->Internals->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->Internals->ColorNodePos.size();
|
|
if (index < 0 || i >= size)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this->Internals->ColorNodePos.erase(this->Internals->ColorNodePos.begin() + index);
|
|
this->Internals->ColorRGB.erase(this->Internals->ColorRGB.begin() + index);
|
|
this->Internals->ColorArraysChanged = true;
|
|
this->Internals->RecalculateRange();
|
|
this->Internals->Modified();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::GetNumberOfPoints() const
|
|
{
|
|
return static_cast<vtkm::Int32>(this->Internals->ColorNodePos.size());
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::AddPointAlpha(vtkm::Float64 x,
|
|
vtkm::Float32 alpha,
|
|
vtkm::Float32 midpoint,
|
|
vtkm::Float32 sharpness)
|
|
{
|
|
if (outside_range(alpha, midpoint, sharpness))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
const vtkm::Vec2f_32 midsharp(midpoint, sharpness);
|
|
std::size_t index = 0;
|
|
if (this->Internals->OpacityNodePos.size() == 0 || this->Internals->OpacityNodePos.back() < x)
|
|
{
|
|
this->Internals->OpacityNodePos.emplace_back(x);
|
|
this->Internals->OpacityAlpha.emplace_back(alpha);
|
|
this->Internals->OpacityMidSharp.emplace_back(midsharp);
|
|
index = this->Internals->OpacityNodePos.size();
|
|
}
|
|
else
|
|
{
|
|
auto begin = this->Internals->OpacityNodePos.begin();
|
|
auto pos = std::lower_bound(begin, this->Internals->OpacityNodePos.end(), x);
|
|
index = static_cast<std::size_t>(std::distance(begin, pos));
|
|
if (*pos == x)
|
|
{
|
|
this->Internals->OpacityAlpha[index] = alpha;
|
|
this->Internals->OpacityMidSharp[index] = midsharp;
|
|
}
|
|
else
|
|
{
|
|
this->Internals->OpacityAlpha.emplace(
|
|
this->Internals->OpacityAlpha.begin() + std::distance(begin, pos), alpha);
|
|
this->Internals->OpacityMidSharp.emplace(
|
|
this->Internals->OpacityMidSharp.begin() + std::distance(begin, pos), midsharp);
|
|
this->Internals->OpacityNodePos.emplace(pos, x);
|
|
}
|
|
}
|
|
this->Internals->OpacityArraysChanged = true;
|
|
this->Internals->TableRange.Include(x); //update range to include x
|
|
this->Internals->Modified();
|
|
return static_cast<vtkm::Int32>(index);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::AddSegmentAlpha(vtkm::Float64 x1,
|
|
vtkm::Float32 alpha1,
|
|
vtkm::Float64 x2,
|
|
vtkm::Float32 alpha2,
|
|
const vtkm::Vec2f_32& mid_sharp1,
|
|
const vtkm::Vec2f_32& mid_sharp2)
|
|
{
|
|
if (outside_range(alpha1, alpha2, mid_sharp1, mid_sharp2))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (this->Internals->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->Internals->OpacityNodePos.begin();
|
|
auto nodeEnd = this->Internals->OpacityNodePos.end();
|
|
|
|
auto alphaBegin = this->Internals->OpacityAlpha.begin();
|
|
auto midBegin = this->Internals->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->Internals->OpacityNodePos.erase(nodeStart, nodeStop);
|
|
this->Internals->OpacityAlpha.erase(alphaStart, alphaStop);
|
|
this->Internals->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::Vec4f_64& data) const
|
|
{
|
|
std::size_t i = static_cast<std::size_t>(index);
|
|
const std::size_t size = this->Internals->OpacityNodePos.size();
|
|
if (index < 0 || i >= size)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const auto& pos = this->Internals->OpacityNodePos[i];
|
|
const auto& alpha = this->Internals->OpacityAlpha[i];
|
|
const auto& midsharp = this->Internals->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::Vec4f_64& 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->Internals->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->Internals->OpacityNodePos.begin() + index;
|
|
auto newPos = std::lower_bound(
|
|
this->Internals->OpacityNodePos.begin(), this->Internals->OpacityNodePos.end(), data[0]);
|
|
if (oldPos == newPos)
|
|
{ //node's relative location hasn't changed
|
|
this->Internals->OpacityArraysChanged = true;
|
|
auto& alpha = this->Internals->OpacityAlpha[i];
|
|
auto& midsharp = this->Internals->OpacityMidSharp[i];
|
|
*newPos = data[0];
|
|
alpha = static_cast<vtkm::Float32>(data[1]);
|
|
midsharp[0] = static_cast<vtkm::Float32>(data[2]);
|
|
midsharp[1] = static_cast<vtkm::Float32>(data[3]);
|
|
this->Internals->Modified();
|
|
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<vtkm::Float32>(data[1]),
|
|
static_cast<vtkm::Float32>(data[2]),
|
|
static_cast<vtkm::Float32>(data[3]));
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::RemovePointAlpha(vtkm::Float64 x)
|
|
{
|
|
auto begin = this->Internals->OpacityNodePos.begin();
|
|
auto pos = std::lower_bound(begin, this->Internals->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->Internals->OpacityNodePos.size();
|
|
if (index < 0 || i >= size)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this->Internals->OpacityNodePos.erase(this->Internals->OpacityNodePos.begin() + index);
|
|
this->Internals->OpacityAlpha.erase(this->Internals->OpacityAlpha.begin() + index);
|
|
this->Internals->OpacityMidSharp.erase(this->Internals->OpacityMidSharp.begin() + index);
|
|
this->Internals->OpacityArraysChanged = true;
|
|
this->Internals->RecalculateRange();
|
|
this->Internals->Modified();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Int32 ColorTable::GetNumberOfPointsAlpha() const
|
|
{
|
|
return static_cast<vtkm::Int32>(this->Internals->OpacityNodePos.size());
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::FillColorTableFromDataPointer(vtkm::Int32 n, const vtkm::Float64* ptr)
|
|
{
|
|
if (n <= 0 || ptr == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
this->ClearColors();
|
|
|
|
std::size_t size = static_cast<std::size_t>(n / 4);
|
|
this->Internals->ColorNodePos.reserve(size);
|
|
this->Internals->ColorRGB.reserve(size);
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
{ //allows us to support unsorted arrays
|
|
vtkm::Vec3f_32 rgb(static_cast<vtkm::Float32>(ptr[1]),
|
|
static_cast<vtkm::Float32>(ptr[2]),
|
|
static_cast<vtkm::Float32>(ptr[3]));
|
|
this->AddPoint(ptr[0], rgb);
|
|
ptr += 4;
|
|
}
|
|
this->Internals->ColorArraysChanged = true;
|
|
this->Internals->Modified();
|
|
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::FillColorTableFromDataPointer(vtkm::Int32 n, const vtkm::Float32* ptr)
|
|
{
|
|
if (n <= 0 || ptr == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
this->ClearColors();
|
|
|
|
std::size_t size = static_cast<std::size_t>(n / 4);
|
|
this->Internals->ColorNodePos.reserve(size);
|
|
this->Internals->ColorRGB.reserve(size);
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
{ //allows us to support unsorted arrays
|
|
vtkm::Vec3f_32 rgb(ptr[1], ptr[2], ptr[3]);
|
|
this->AddPoint(ptr[0], rgb);
|
|
ptr += 4;
|
|
}
|
|
this->Internals->ColorArraysChanged = true;
|
|
this->Internals->Modified();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::FillOpacityTableFromDataPointer(vtkm::Int32 n, const vtkm::Float64* ptr)
|
|
{
|
|
if (n <= 0 || ptr == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
this->ClearAlpha();
|
|
|
|
std::size_t size = static_cast<std::size_t>(n / 4);
|
|
this->Internals->OpacityNodePos.reserve(size);
|
|
this->Internals->OpacityAlpha.reserve(size);
|
|
this->Internals->OpacityMidSharp.reserve(size);
|
|
for (std::size_t i = 0; i < size; ++i)
|
|
{ //allows us to support unsorted arrays
|
|
this->AddPointAlpha(ptr[0],
|
|
static_cast<vtkm::Float32>(ptr[1]),
|
|
static_cast<vtkm::Float32>(ptr[2]),
|
|
static_cast<vtkm::Float32>(ptr[3]));
|
|
ptr += 4;
|
|
}
|
|
|
|
this->Internals->OpacityArraysChanged = true;
|
|
this->Internals->Modified();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::FillOpacityTableFromDataPointer(vtkm::Int32 n, const vtkm::Float32* ptr)
|
|
{
|
|
if (n <= 0 || ptr == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
this->ClearAlpha();
|
|
|
|
|
|
std::size_t size = static_cast<std::size_t>(n / 4);
|
|
this->Internals->OpacityNodePos.reserve(size);
|
|
this->Internals->OpacityAlpha.reserve(size);
|
|
this->Internals->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->Internals->OpacityArraysChanged = true;
|
|
this->Internals->Modified();
|
|
return true;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::Sample(vtkm::Int32 numSamples,
|
|
vtkm::cont::ColorTableSamplesRGBA& samples,
|
|
vtkm::Float64 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,
|
|
vtkm::Float64 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::Vec4ui_8>& colors,
|
|
vtkm::Float64 tolerance) const
|
|
{
|
|
if (numSamples <= 1)
|
|
{
|
|
return false;
|
|
}
|
|
return sampleColorTable(this, numSamples, colors, tolerance, false);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
bool ColorTable::Sample(vtkm::Int32 numSamples,
|
|
vtkm::cont::ArrayHandle<vtkm::Vec3ui_8>& colors,
|
|
vtkm::Float64 tolerance) const
|
|
{
|
|
if (numSamples <= 1)
|
|
{
|
|
return false;
|
|
}
|
|
return sampleColorTable(this, numSamples, colors, tolerance, false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void ColorTable::UpdateArrayHandles() const
|
|
{
|
|
//Only rebuild the array handles that have changed since the last time
|
|
//we have modified or color / opacity information
|
|
|
|
if (this->Internals->ColorArraysChanged)
|
|
{
|
|
this->Internals->ColorPosHandle =
|
|
vtkm::cont::make_ArrayHandle(this->Internals->ColorNodePos, vtkm::CopyFlag::Off);
|
|
this->Internals->ColorRGBHandle =
|
|
vtkm::cont::make_ArrayHandle(this->Internals->ColorRGB, vtkm::CopyFlag::Off);
|
|
this->Internals->ColorArraysChanged = false;
|
|
}
|
|
|
|
if (this->Internals->OpacityArraysChanged)
|
|
{
|
|
this->Internals->OpacityPosHandle =
|
|
vtkm::cont::make_ArrayHandle(this->Internals->OpacityNodePos, vtkm::CopyFlag::Off);
|
|
this->Internals->OpacityAlphaHandle =
|
|
vtkm::cont::make_ArrayHandle(this->Internals->OpacityAlpha, vtkm::CopyFlag::Off);
|
|
this->Internals->OpacityMidSharpHandle =
|
|
vtkm::cont::make_ArrayHandle(this->Internals->OpacityMidSharp, vtkm::CopyFlag::Off);
|
|
this->Internals->OpacityArraysChanged = false;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::exec::ColorTable ColorTable::PrepareForExecution(vtkm::cont::DeviceAdapterId device,
|
|
vtkm::cont::Token& token) const
|
|
{
|
|
this->UpdateArrayHandles();
|
|
|
|
vtkm::exec::ColorTable execTable;
|
|
|
|
execTable.Space = this->Internals->Space;
|
|
execTable.NaNColor = this->Internals->NaNColor;
|
|
execTable.BelowRangeColor = this->Internals->BelowRangeColor;
|
|
execTable.AboveRangeColor = this->Internals->AboveRangeColor;
|
|
execTable.UseClamping = this->Internals->UseClamping;
|
|
|
|
VTKM_ASSERT(static_cast<vtkm::Id>(this->Internals->ColorNodePos.size()) ==
|
|
this->Internals->ColorPosHandle.GetNumberOfValues());
|
|
execTable.ColorSize =
|
|
static_cast<vtkm::Int32>(this->Internals->ColorPosHandle.GetNumberOfValues());
|
|
VTKM_ASSERT(static_cast<vtkm::Id>(execTable.ColorSize) ==
|
|
this->Internals->ColorRGBHandle.GetNumberOfValues());
|
|
execTable.ColorNodes = this->Internals->ColorPosHandle.PrepareForInput(device, token).GetArray();
|
|
execTable.RGB = this->Internals->ColorRGBHandle.PrepareForInput(device, token).GetArray();
|
|
|
|
VTKM_ASSERT(static_cast<vtkm::Id>(this->Internals->OpacityNodePos.size()) ==
|
|
this->Internals->OpacityPosHandle.GetNumberOfValues());
|
|
execTable.OpacitySize =
|
|
static_cast<vtkm::Int32>(this->Internals->OpacityPosHandle.GetNumberOfValues());
|
|
VTKM_ASSERT(static_cast<vtkm::Id>(execTable.OpacitySize) ==
|
|
this->Internals->OpacityAlphaHandle.GetNumberOfValues());
|
|
VTKM_ASSERT(static_cast<vtkm::Id>(execTable.OpacitySize) ==
|
|
this->Internals->OpacityMidSharpHandle.GetNumberOfValues());
|
|
execTable.ONodes = this->Internals->OpacityPosHandle.PrepareForInput(device, token).GetArray();
|
|
execTable.Alpha = this->Internals->OpacityAlphaHandle.PrepareForInput(device, token).GetArray();
|
|
execTable.MidSharp =
|
|
this->Internals->OpacityMidSharpHandle.PrepareForInput(device, token).GetArray();
|
|
|
|
return execTable;
|
|
}
|
|
|
|
vtkm::exec::ColorTable ColorTable::PrepareForExecution(vtkm::cont::DeviceAdapterId device) const
|
|
{
|
|
vtkm::cont::Token token;
|
|
return this->PrepareForExecution(device, token);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
vtkm::Id ColorTable::GetModifiedCount() const
|
|
{
|
|
return this->Internals->ModifiedCount;
|
|
}
|
|
}
|
|
} //namespace vtkm::cont
|