/*========================================================================= Program: Visualization Toolkit Module: vtkLookupTableWithEnabling.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm 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 "vtkLookupTableWithEnabling.h" #include "vtkBitArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkVariant.h" #include vtkStandardNewMacro(vtkLookupTableWithEnabling); vtkCxxSetObjectMacro(vtkLookupTableWithEnabling, EnabledArray, vtkDataArray); // Construct with range=(0,1); and hsv ranges set up for rainbow color table // (from red to blue). vtkLookupTableWithEnabling::vtkLookupTableWithEnabling(int sze, int ext) : vtkLookupTable(sze, ext) { this->EnabledArray = nullptr; } //------------------------------------------------------------------------------ vtkLookupTableWithEnabling::~vtkLookupTableWithEnabling() { if (this->EnabledArray) { this->EnabledArray->Delete(); this->EnabledArray = nullptr; } } void vtkLookupTableWithEnabling::DisableColor(unsigned char r, unsigned char g, unsigned char b, unsigned char* rd, unsigned char* gd, unsigned char* bd) { double rgb[3], hsv[3]; rgb[0] = static_cast(r); rgb[1] = static_cast(g); rgb[2] = static_cast(b); vtkMath::RGBToHSV(rgb, hsv); hsv[1] = 0; hsv[2] = 0; vtkMath::HSVToRGB(hsv, rgb); *rd = static_cast(rgb[0]); *gd = static_cast(rgb[1]); *bd = static_cast(rgb[2]); } //------------------------------------------------------------------------------ // There is a little more to this than simply taking the log10 of the // two range values: we do conversion of negative ranges to positive // ranges, and conversion of zero to a 'very small number' static void vtkLookupTableWithEnablingLogRange(double range[2], double logRange[2]) { double rmin = range[0]; double rmax = range[1]; if (rmin == 0) { rmin = 1.0e-6 * (rmax - rmin); if (rmax < 0) { rmin = -rmin; } } if (rmax == 0) { rmax = 1.0e-6 * (rmin - rmax); if (rmin < 0) { rmax = -rmax; } } if (rmin < 0 && rmax < 0) { logRange[0] = log10(-static_cast(rmin)); logRange[1] = log10(-static_cast(rmax)); } else if (rmin > 0 && rmax > 0) { logRange[0] = log10(static_cast(rmin)); logRange[1] = log10(static_cast(rmax)); } else { logRange[0] = 0.; logRange[1] = 0.; } } //------------------------------------------------------------------------------ // Apply log to value, with appropriate constraints. inline double vtkApplyLogScale(double v, double range[2], double logRange[2]) { // is the range set for negative numbers? if (range[0] < 0) { if (v < 0) { v = log10(-static_cast(v)); } else if (range[0] > range[1]) { v = logRange[0]; } else { v = logRange[1]; } } else { if (v > 0) { v = log10(static_cast(v)); } else if (range[0] < range[1]) { v = logRange[0]; } else { v = logRange[1]; } } return v; } //------------------------------------------------------------------------------ // Apply shift/scale to the scalar value v and do table lookup. inline unsigned char* vtkLinearLookup( double v, unsigned char* table, double maxIndex, double shift, double scale) { double findx = (v + shift) * scale; if (findx < 0) { findx = 0; } if (findx > maxIndex) { findx = maxIndex; } return &table[4 * static_cast(findx)]; /* round return &table[4*(int)(findx + 0.5f)]; */ } //------------------------------------------------------------------------------ // accelerate the mapping by copying the data in 32-bit chunks instead // of 8-bit chunks template void vtkLookupTableWithEnablingMapData(vtkLookupTableWithEnabling* self, T* input, unsigned char* output, int length, int inIncr, int outFormat) { int i = length; double* range = self->GetTableRange(); double maxIndex = self->GetNumberOfColors() - 1; double shift, scale; unsigned char* table = self->GetPointer(0); unsigned char* cptr; double alpha; unsigned char r, g, b; bool hasEnabledArray = false; if (self->GetEnabledArray() && self->GetEnabledArray()->GetNumberOfTuples() == length) { hasEnabledArray = true; } if ((alpha = self->GetAlpha()) >= 1.0) // no blending required { if (self->GetScale() == VTK_SCALE_LOG10) { double val; double logRange[2]; vtkLookupTableWithEnablingLogRange(range, logRange); shift = -logRange[0]; if (logRange[1] <= logRange[0]) { scale = VTK_DOUBLE_MAX; } else { /* while this looks like the wrong scale, it is the correct scale * taking into account the truncation to int that happens below. */ scale = (maxIndex + 1) / (logRange[1] - logRange[0]); } if (outFormat == VTK_RGBA) { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; cptr += 3; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; } *output++ = *cptr++; input += inIncr; } } else if (outFormat == VTK_RGB) { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; } input += inIncr; } } else if (outFormat == VTK_LUMINANCE_ALPHA) { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); *output++ = cptr[3]; input += inIncr; } } else // outFormat == VTK_LUMINANCE { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); input += inIncr; } } } // if log scale else // not log scale { shift = -range[0]; if (range[1] <= range[0]) { scale = VTK_DOUBLE_MAX; } else { /* while this looks like the wrong scale, it is the correct scale * taking into account the truncation to int that happens below. */ scale = (maxIndex + 1) / (range[1] - range[0]); } if (outFormat == VTK_RGBA) { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; cptr += 3; *output++ = static_cast((*cptr) * 0.2); cptr++; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; } input += inIncr; } } else if (outFormat == VTK_RGB) { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; } input += inIncr; } } else if (outFormat == VTK_LUMINANCE_ALPHA) { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); *output++ = cptr[3]; input += inIncr; } } else // outFormat == VTK_LUMINANCE { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); input += inIncr; } } } // if not log lookup } // if blending not needed else // blend with the specified alpha { if (self->GetScale() == VTK_SCALE_LOG10) { double val; double logRange[2]; vtkLookupTableWithEnablingLogRange(range, logRange); shift = -logRange[0]; if (logRange[1] <= logRange[0]) { scale = VTK_DOUBLE_MAX; } else { /* while this looks like the wrong scale, it is the correct scale * taking into account the truncation to int that happens below. */ scale = (maxIndex + 1) / (logRange[1] - logRange[0]); } if (outFormat == VTK_RGBA) { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; cptr += 3; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; } *output++ = static_cast((*cptr) * alpha); cptr++; input += inIncr; } } else if (outFormat == VTK_RGB) { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; } input += inIncr; } } else if (outFormat == VTK_LUMINANCE_ALPHA) { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); *output++ = static_cast(alpha * cptr[3]); input += inIncr; } } else // outFormat == VTK_LUMINANCE { while (--i >= 0) { val = vtkApplyLogScale(*input, range, logRange); cptr = vtkLinearLookup(val, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); input += inIncr; } } } // log scale with blending else // no log scale with blending { shift = -range[0]; if (range[1] <= range[0]) { scale = VTK_DOUBLE_MAX; } else { /* while this looks like the wrong scale, it is the correct scale * taking into account the truncation to int that happens below. */ scale = (maxIndex + 1) / (range[1] - range[0]); } if (outFormat == VTK_RGBA) { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; cptr += 3; *output++ = static_cast((*cptr) * alpha * 0.2); cptr++; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; if (hasEnabledArray) { *output++ = *cptr++; } else { *output++ = static_cast((*cptr) * alpha); cptr++; } } input += inIncr; } } else if (outFormat == VTK_RGB) { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); if (hasEnabledArray && !self->GetEnabledArray()->GetTuple1(length - i - 1)) { self->DisableColor(cptr[0], cptr[1], cptr[2], &r, &g, &b); *output++ = r; *output++ = g; *output++ = b; } else { *output++ = *cptr++; *output++ = *cptr++; *output++ = *cptr++; } input += inIncr; } } else if (outFormat == VTK_LUMINANCE_ALPHA) { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); *output++ = static_cast(cptr[3] * alpha); input += inIncr; } } else // outFormat == VTK_LUMINANCE { while (--i >= 0) { cptr = vtkLinearLookup(*input, table, maxIndex, shift, scale); *output++ = static_cast(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5); input += inIncr; } } } // no log scale } // alpha blending } //------------------------------------------------------------------------------ void vtkLookupTableWithEnabling::MapScalarsThroughTable2(void* input, unsigned char* output, int inputDataType, int numberOfValues, int inputIncrement, int outputFormat) { switch (inputDataType) { case VTK_BIT: { vtkIdType i, id; vtkBitArray* bitArray = vtkBitArray::New(); bitArray->SetVoidArray(input, numberOfValues, 1); vtkUnsignedCharArray* newInput = vtkUnsignedCharArray::New(); newInput->SetNumberOfValues(numberOfValues); for (id = i = 0; i < numberOfValues; i++, id += inputIncrement) { newInput->SetValue(i, bitArray->GetValue(id)); } vtkLookupTableWithEnablingMapData(this, static_cast(newInput->GetPointer(0)), output, numberOfValues, inputIncrement, outputFormat); newInput->Delete(); bitArray->Delete(); } break; vtkTemplateMacro(vtkLookupTableWithEnablingMapData( this, static_cast(input), output, numberOfValues, inputIncrement, outputFormat)); default: vtkErrorMacro(<< "MapImageThroughTable: Unknown input ScalarType"); return; } } //------------------------------------------------------------------------------ void vtkLookupTableWithEnabling::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "EnabledArray: "; if (this->EnabledArray) { this->EnabledArray->PrintSelf(os << "\n", indent.GetNextIndent()); } else { // Should not happen os << "(none)\n"; } }