// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause // Test some generic features of vtkLookupTable #include "vtkCommand.h" #include "vtkLookupTable.h" #include "vtkMath.h" #include "vtkMathUtilities.h" #include "vtkSmartPointer.h" #include // simple macro for performing tests #define TestAssert(t) \ do \ { \ if (!(t)) \ { \ std::cerr << "In " << __FILE__ << ":"; \ std::cerr << " Test assertion failed line " << __LINE__ << ": " << #t << "\n"; \ rval |= 1; \ } \ } while (false) #define TestVector4d(t1, t2) \ TestAssert((vtkMathUtilities::FuzzyCompare(t1[0], t2[0]) && \ vtkMathUtilities::FuzzyCompare(t1[1], t2[1]) && \ vtkMathUtilities::FuzzyCompare(t1[2], t2[2]) && \ vtkMathUtilities::FuzzyCompare(t1[3], t2[3]))) int TestColor4uc(const unsigned char* expected, const unsigned char* test) { int failed = expected[0] != test[0] || expected[1] != test[1] || expected[2] != test[2] || expected[3] != test[3] ? 1 : 0; if (failed) { std::cerr << "Expected color: " << static_cast(expected[0]) << ", " << static_cast(expected[1]) << ", " << static_cast(expected[2]) << ", " << static_cast(expected[3]) << std::endl; std::cerr << "Test color: " << static_cast(test[0]) << ", " << static_cast(test[1]) << ", " << static_cast(test[2]) << ", " << static_cast(test[3]) << std::endl; } return !failed; } // a simple error observer namespace { class errorObserver { public: errorObserver() : EventId(0) { } void Reset() { this->EventId = 0; } unsigned long GetEvent() const { return this->EventId; } void Callback(vtkObject*, unsigned long e, void*) { this->EventId = e; } private: unsigned long EventId; }; } int TestLookupTable(int, char*[]) { int rval = 0; vtkSmartPointer table = vtkSmartPointer::New(); // == check computation of table index == // basic mapping test double lo = 3.234; double hi = 6.123; double tol = 1e-6; double step = (hi - lo) / 255.0; table->SetTableRange(lo, hi); table->Build(); TestAssert(table->GetIndex(lo) == 0); TestAssert(table->GetIndex(hi) == 255); TestAssert(table->GetIndex(lo + tol) == 0); TestAssert(table->GetIndex(hi - tol) == 255); TestAssert(table->GetIndex(lo - step) == 0); TestAssert(table->GetIndex(hi + step) == 255); TestAssert(table->GetIndex(lo + step) == 1); TestAssert(table->GetIndex(hi - step) == 254); TestAssert(table->GetIndex(vtkMath::Nan()) == -1); double rgba[4]; rgba[0] = 0.0; rgba[1] = 0.0; rgba[2] = 0.0; rgba[3] = 1.0; TestVector4d(table->GetBelowRangeColor(), rgba); rgba[0] = 1.0; rgba[1] = 1.0; rgba[2] = 1.0; rgba[3] = 1.0; TestVector4d(table->GetAboveRangeColor(), rgba); TestAssert(table->GetUseBelowRangeColor() == 0); TestAssert(table->GetUseAboveRangeColor() == 0); unsigned char expected[4]; // Test handling of below-range colors vtkMath::HSVToRGB(table->GetHueRange()[0], table->GetSaturationRange()[0], table->GetValueRange()[0], &rgba[0], &rgba[1], &rgba[2]); rgba[3] = table->GetAlphaRange()[0]; vtkLookupTable::GetColorAsUnsignedChars(rgba, expected); table->UseBelowRangeColorOff(); table->Build(); const unsigned char* result = table->MapValue(lo); TestAssert(TestColor4uc(expected, result)); table->GetBelowRangeColor(rgba); vtkLookupTable::GetColorAsUnsignedChars(rgba, expected); table->UseBelowRangeColorOn(); table->Build(); result = table->MapValue(lo - tol); TestAssert(TestColor4uc(expected, result)); // Test handling of above-range colors vtkMath::HSVToRGB(table->GetHueRange()[1], table->GetSaturationRange()[1], table->GetValueRange()[1], &rgba[0], &rgba[1], &rgba[2]); rgba[3] = table->GetAlphaRange()[1]; vtkLookupTable::GetColorAsUnsignedChars(rgba, expected); table->UseAboveRangeColorOff(); table->Build(); result = table->MapValue(hi); TestAssert(TestColor4uc(expected, result)); table->GetAboveRangeColor(rgba); vtkLookupTable::GetColorAsUnsignedChars(rgba, expected); table->UseAboveRangeColorOn(); table->Build(); result = table->MapValue(hi + tol); TestAssert(TestColor4uc(expected, result)); // log range test lo = pow(10.0, lo); hi = pow(10.0, hi); step = pow(10.0, step); table->SetScaleToLog10(); table->SetTableRange(lo, hi); table->Build(); TestAssert(table->GetIndex(lo) == 0); TestAssert(table->GetIndex(hi) == 255); TestAssert(table->GetIndex(lo + tol) == 0); TestAssert(table->GetIndex(hi - tol) == 255); TestAssert(table->GetIndex(vtkMath::Nan()) == -1); // Note - both below- and above-range colors are enabled at this point TestAssert(table->GetIndex(lo / step) == 0); TestAssert(table->GetIndex(hi * step) == 255); TestAssert(table->GetIndex(lo * step) == 1); TestAssert(table->GetIndex(hi / step) == 254); // negative log range double tmp = hi; hi = -lo; lo = -tmp; step = 1.0 / step; table->SetScaleToLog10(); table->SetTableRange(lo, hi); table->Build(); TestAssert(table->GetIndex(lo) == 0); TestAssert(table->GetIndex(hi) == 255); TestAssert(table->GetIndex(lo + tol) == 0); TestAssert(table->GetIndex(hi - tol) == 255); TestAssert(table->GetIndex(lo / step) == 0); TestAssert(table->GetIndex(hi * step) == 255); TestAssert(table->GetIndex(lo * step) == 1); TestAssert(table->GetIndex(hi / step) == 254); // == check error reporting == errorObserver observer; unsigned long observerId = table->AddObserver(vtkCommand::ErrorEvent, &observer, &errorObserver::Callback); // linear table, range is null, permitted (step function) observer.Reset(); table->SetScaleToLinear(); table->SetTableRange(0, 0); TestAssert(observer.GetEvent() == 0); // linear table, range is inverted, illegal observer.Reset(); table->SetScaleToLinear(); table->SetTableRange(1, -1); TestAssert(observer.GetEvent() != 0); // log table, range is null, permitted (step function) observer.Reset(); table->SetScaleToLog10(); table->SetTableRange(0, 0); TestAssert(observer.GetEvent() == 0); // log table, zero on upper end of range, permitted observer.Reset(); table->SetScaleToLog10(); table->SetTableRange(-1.2, 0); TestAssert(observer.GetEvent() == 0); // log table, zero on lower end of range, permitted observer.Reset(); table->SetScaleToLog10(); table->SetTableRange(0, 1.3); TestAssert(observer.GetEvent() == 0); // log table, range straddles zero, illegal observer.Reset(); table->SetScaleToLog10(); table->SetTableRange(-0.5, 1.1); TestAssert(observer.GetEvent() != 0); table->RemoveObserver(observerId); return rval; }