//============================================================================ // 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 #include #include #include #include #include #include #include namespace vtkm { namespace cont { namespace internal { std::set 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) : Impl(std::make_shared()) { 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(ColorSpace::LAB); } this->AddSegmentAlpha(this->Impl->TableRange.Min, 1.0f, this->Impl->TableRange.Max, 1.0f); } //---------------------------------------------------------------------------- ColorTable::ColorTable(const std::string& name) : Impl(std::make_shared()) { 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(ColorSpace::LAB); } this->AddSegmentAlpha(this->Impl->TableRange.Min, 1.0f, this->Impl->TableRange.Max, 1.0f); } //---------------------------------------------------------------------------- ColorTable::ColorTable(ColorSpace space) : Impl(std::make_shared()) { this->SetColorSpace(space); } //---------------------------------------------------------------------------- ColorTable::ColorTable(const vtkm::Range& range, const vtkm::Vec& rgb1, const vtkm::Vec& rgb2, ColorSpace space) : Impl(std::make_shared()) { 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& rgba1, const vtkm::Vec& rgba2, ColorSpace space) : Impl(std::make_shared()) { vtkm::Vec rgb1(rgba1[0], rgba1[1], rgba1[2]); vtkm::Vec 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::cont::ColorSpace colorSpace, const vtkm::Vec& nanColor, const std::vector& rgbPoints, const std::vector& alphaPoints) : Impl(std::make_shared()) { this->SetName(name); this->SetColorSpace(colorSpace); this->SetNaNColor(nanColor); this->FillColorTableFromDataPointer(static_cast(rgbPoints.size()), rgbPoints.data()); this->FillOpacityTableFromDataPointer(static_cast(alphaPoints.size()), alphaPoints.data()); } //---------------------------------------------------------------------------- ColorTable::~ColorTable() { } //---------------------------------------------------------------------------- const std::string& ColorTable::GetName() const { return this->Impl->Name; } //---------------------------------------------------------------------------- void ColorTable::SetName(const std::string& name) { this->Impl->Name = name; } //---------------------------------------------------------------------------- bool ColorTable::LoadPreset(vtkm::cont::ColorTable::Preset preset) { return internal::LoadColorTablePreset(preset, *this); } //---------------------------------------------------------------------------- std::set ColorTable::GetPresets() { return internal::GetPresetNames(); } //---------------------------------------------------------------------------- bool ColorTable::LoadPreset(const std::string& name) { return internal::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.get() == nullptr) { this->Impl->HostSideCacheChanged = true; this->Impl->CSpace = space; //Remove any existing host information switch (space) { case vtkm::cont::ColorSpace::RGB: { auto* hostPortal = new vtkm::exec::ColorTableRGB(); this->Impl->HostSideCache.reset(hostPortal); break; } case vtkm::cont::ColorSpace::HSV: { auto* hostPortal = new vtkm::exec::ColorTableHSV(); this->Impl->HostSideCache.reset(hostPortal); break; } case vtkm::cont::ColorSpace::HSV_WRAP: { auto* hostPortal = new vtkm::exec::ColorTableHSVWrap(); this->Impl->HostSideCache.reset(hostPortal); break; } case vtkm::cont::ColorSpace::LAB: { auto* hostPortal = new vtkm::exec::ColorTableLab(); this->Impl->HostSideCache.reset(hostPortal); break; } case vtkm::cont::ColorSpace::DIVERGING: { auto* hostPortal = new vtkm::exec::ColorTableDiverging(); this->Impl->HostSideCache.reset(hostPortal); break; } default: throw vtkm::cont::ErrorBadType("unknown 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& c) { this->Impl->HostSideCache->BelowRangeColor = c; this->Impl->HostSideCache->Modified(); } //---------------------------------------------------------------------------- const vtkm::Vec& ColorTable::GetBelowRangeColor() const { return this->Impl->HostSideCache->BelowRangeColor; } //---------------------------------------------------------------------------- void ColorTable::SetAboveRangeColor(const vtkm::Vec& c) { this->Impl->HostSideCache->AboveRangeColor = c; this->Impl->HostSideCache->Modified(); } //---------------------------------------------------------------------------- const vtkm::Vec& ColorTable::GetAboveRangeColor() const { return this->Impl->HostSideCache->AboveRangeColor; } //---------------------------------------------------------------------------- void ColorTable::SetNaNColor(const vtkm::Vec& c) { this->Impl->HostSideCache->NaNColor = c; this->Impl->HostSideCache->Modified(); } //---------------------------------------------------------------------------- const vtkm::Vec& 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& 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::distance(begin, pos)); if (*pos == x) { this->Impl->ColorRGB[index] = rgb; } else { this->Impl->ColorRGB.emplace(this->Impl->ColorRGB.begin() + std::distance(begin, pos), rgb); this->Impl->ColorNodePos.emplace(pos, x); } } this->Impl->TableRange.Include(x); //update range to include x this->Impl->ColorArraysChanged = true; return static_cast(index); } //--------------------------------------------------------------------------- vtkm::Int32 ColorTable::AddPointHSV(double x, const vtkm::Vec& hsv) { return this->AddPoint(x, hsvTorgb(hsv)); } //--------------------------------------------------------------------------- vtkm::Int32 ColorTable::AddSegment(double x1, const vtkm::Vec& rgb1, double x2, const vtkm::Vec& 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& hsv1, double x2, const vtkm::Vec& hsv2) { return this->AddSegment(x1, hsvTorgb(hsv1), x2, hsvTorgb(hsv2)); } //--------------------------------------------------------------------------- bool ColorTable::GetPoint(vtkm::Int32 index, vtkm::Vec& data) const { std::size_t i = static_cast(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& 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(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(data[1]); rgb[1] = static_cast(data[2]); rgb[2] = static_cast(data[3]); return index; } else { //remove the point, and add the new values as the relative location is different this->RemovePoint(index); vtkm::Vec newrgb( static_cast(data[1]), static_cast(data[2]), static_cast(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(std::distance(begin, pos))); } //--------------------------------------------------------------------------- bool ColorTable::RemovePoint(vtkm::Int32 index) { std::size_t i = static_cast(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(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 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::distance(begin, pos)); if (*pos == x) { this->Impl->OpacityAlpha[index] = alpha; this->Impl->OpacityMidSharp[index] = midsharp; } else { this->Impl->OpacityAlpha.emplace(this->Impl->OpacityAlpha.begin() + std::distance(begin, pos), alpha); this->Impl->OpacityMidSharp.emplace( this->Impl->OpacityMidSharp.begin() + std::distance(begin, pos), midsharp); this->Impl->OpacityNodePos.emplace(pos, x); } } this->Impl->OpacityArraysChanged = true; this->Impl->TableRange.Include(x); //update range to include x return static_cast(index); } //--------------------------------------------------------------------------- vtkm::Int32 ColorTable::AddSegmentAlpha(double x1, float alpha1, double x2, float alpha2, const vtkm::Vec& mid_sharp1, const vtkm::Vec& 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& data) const { std::size_t i = static_cast(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& 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(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(data[1]); midsharp[0] = static_cast(data[2]); midsharp[1] = static_cast(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(data[1]), static_cast(data[2]), static_cast(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(std::distance(begin, pos))); } //--------------------------------------------------------------------------- bool ColorTable::RemovePointAlpha(vtkm::Int32 index) { std::size_t i = static_cast(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(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(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 rgb( static_cast(ptr[1]), static_cast(ptr[2]), static_cast(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(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 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(n / 4); 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(ptr[1]), static_cast(ptr[2]), static_cast(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(n / 4); 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; } //--------------------------------------------------------------------------- vtkm::Id ColorTable::GetModifiedCount() const { return this->Impl->HostSideCache->GetModifiedCount(); } //---------------------------------------------------------------------------- bool ColorTable::NeedToCreateExecutionColorTable() const { return this->Impl->HostSideCacheChanged; } //---------------------------------------------------------------------------- void ColorTable::UpdateExecutionColorTable( vtkm::cont::VirtualObjectHandle* handle) const { this->Impl->ExecHandle.reset(handle); } //---------------------------------------------------------------------------- ColorTable::TransferState ColorTable::GetExecutionDataForTransfer() 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); } TransferState state = { (this->Impl->ColorArraysChanged || this->Impl->OpacityArraysChanged || this->Impl->HostSideCacheChanged), this->Impl->HostSideCache.get(), this->Impl->ColorPosHandle, this->Impl->ColorRGBHandle, this->Impl->OpacityPosHandle, this->Impl->OpacityAlphaHandle, this->Impl->OpacityMidSharpHandle }; this->Impl->ColorArraysChanged = false; this->Impl->OpacityArraysChanged = false; this->Impl->HostSideCacheChanged = false; return state; } //---------------------------------------------------------------------------- vtkm::exec::ColorTableBase* ColorTable::GetControlRepresentation() const { return this->Impl->HostSideCache.get(); } //---------------------------------------------------------------------------- vtkm::cont::VirtualObjectHandle const* ColorTable::GetExecutionHandle() const { return this->Impl->ExecHandle.get(); } } } //namespace vtkm::cont