1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkLookupTable.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkLookupTable.h"
16 
17 #include "vtkAbstractArray.h"
18 #include "vtkBitArray.h"
19 #include "vtkMath.h"
20 #include "vtkMathConfigure.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkStringArray.h"
23 #include "vtkVariantArray.h"
24 
25 #include <cassert>
26 
27 const vtkIdType vtkLookupTable::REPEATED_LAST_COLOR_INDEX = 0;
28 const vtkIdType vtkLookupTable::BELOW_RANGE_COLOR_INDEX = 1;
29 const vtkIdType vtkLookupTable::ABOVE_RANGE_COLOR_INDEX = 2;
30 const vtkIdType vtkLookupTable::NAN_COLOR_INDEX = 3;
31 const vtkIdType vtkLookupTable::NUMBER_OF_SPECIAL_COLORS = NAN_COLOR_INDEX + 1;
32 
33 vtkStandardNewMacro(vtkLookupTable);
34 
35 // Construct with range=(0,1); and hsv ranges set up for rainbow color table
36 // (from red to blue).
vtkLookupTable(int sze,int ext)37 vtkLookupTable::vtkLookupTable(int sze, int ext)
38 {
39   this->NumberOfColors = sze;
40   this->Table = vtkUnsignedCharArray::New();
41   this->Table->Register(this);
42   this->Table->Delete();
43   this->Table->SetNumberOfComponents(4);
44   this->Table->Allocate(4 * (sze + NUMBER_OF_SPECIAL_COLORS), 4 * ext);
45 
46   this->HueRange[0] = 0.0;
47   this->HueRange[1] = 0.66667;
48 
49   this->SaturationRange[0] = 1.0;
50   this->SaturationRange[1] = 1.0;
51 
52   this->ValueRange[0] = 1.0;
53   this->ValueRange[1] = 1.0;
54 
55   this->AlphaRange[0] = 1.0;
56   this->AlphaRange[1] = 1.0;
57   this->Alpha = 1.0;
58 
59   this->NanColor[0] = 0.5;
60   this->NanColor[1] = 0.0;
61   this->NanColor[2] = 0.0;
62   this->NanColor[3] = 1.0;
63 
64   this->BelowRangeColor[0] = 0.0;
65   this->BelowRangeColor[1] = 0.0;
66   this->BelowRangeColor[2] = 0.0;
67   this->BelowRangeColor[3] = 1.0;
68 
69   this->UseBelowRangeColor = 0;
70 
71   this->AboveRangeColor[0] = 1.0;
72   this->AboveRangeColor[1] = 1.0;
73   this->AboveRangeColor[2] = 1.0;
74   this->AboveRangeColor[3] = 1.0;
75 
76   this->UseAboveRangeColor = 0;
77 
78   this->TableRange[0] = 0.0;
79   this->TableRange[1] = 1.0;
80 
81   this->Ramp = VTK_RAMP_SCURVE;
82   this->Scale = VTK_SCALE_LINEAR;
83 
84   this->OpaqueFlag = 1;
85 }
86 
87 //------------------------------------------------------------------------------
~vtkLookupTable()88 vtkLookupTable::~vtkLookupTable()
89 {
90   this->Table->UnRegister(this);
91   this->Table = nullptr;
92 }
93 
94 //------------------------------------------------------------------------------
95 // Description:
96 // Return true if all of the values defining the mapping have an opacity
97 // equal to 1. Default implementation returns true.
IsOpaque()98 int vtkLookupTable::IsOpaque()
99 {
100   if (this->OpaqueFlagBuildTime < this->GetMTime())
101   {
102     int opaque = 1;
103     if (this->NanColor[3] < 1.0)
104     {
105       opaque = 0;
106     }
107     if (this->UseBelowRangeColor && this->BelowRangeColor[3] < 1.0)
108     {
109       opaque = 0;
110     }
111     if (this->UseAboveRangeColor && this->AboveRangeColor[3] < 1.0)
112     {
113       opaque = 0;
114     }
115     vtkIdType size = this->Table->GetNumberOfTuples();
116     vtkIdType i = 0;
117     const unsigned char* ptr = this->Table->GetPointer(0);
118     while (opaque && i < size)
119     {
120       opaque = ptr[3] == 255;
121       ptr += 4;
122       ++i;
123     }
124     this->OpaqueFlag = opaque;
125     this->OpaqueFlagBuildTime.Modified();
126   }
127 
128   return this->OpaqueFlag;
129 }
130 
IsOpaque(vtkAbstractArray * scalars,int colorMode,int component)131 int vtkLookupTable::IsOpaque(vtkAbstractArray* scalars, int colorMode, int component)
132 {
133   // use superclass logic?
134   vtkDataArray* dataArray = vtkArrayDownCast<vtkDataArray>(scalars);
135   if ((colorMode == VTK_COLOR_MODE_DEFAULT &&
136         vtkArrayDownCast<vtkUnsignedCharArray>(dataArray) != nullptr) ||
137     (colorMode == VTK_COLOR_MODE_DIRECT_SCALARS && dataArray))
138   {
139     return this->Superclass::IsOpaque(scalars, colorMode, component);
140   }
141   // otherwise look at our table
142   return this->IsOpaque();
143 }
144 
145 //------------------------------------------------------------------------------
SetTableRange(const double r[2])146 void vtkLookupTable::SetTableRange(const double r[2])
147 {
148   this->SetTableRange(r[0], r[1]);
149 }
150 
151 //------------------------------------------------------------------------------
152 // Set the minimum/maximum scalar values for scalar mapping. Scalar values
153 // less than minimum range value are clamped to minimum range value.
154 // Scalar values greater than maximum range value are clamped to maximum
155 // range value.
SetTableRange(double rmin,double rmax)156 void vtkLookupTable::SetTableRange(double rmin, double rmax)
157 {
158   if (this->Scale == VTK_SCALE_LOG10 && ((rmin > 0 && rmax < 0) || (rmin < 0 && rmax > 0)))
159   {
160     vtkErrorMacro("Bad table range for log scale: [" << rmin << ", " << rmax << "]");
161     return;
162   }
163   if (rmax < rmin)
164   {
165     vtkErrorMacro("Bad table range: [" << rmin << ", " << rmax << "]");
166     return;
167   }
168 
169   if (this->TableRange[0] == rmin && this->TableRange[1] == rmax)
170   {
171     return;
172   }
173 
174   this->TableRange[0] = rmin;
175   this->TableRange[1] = rmax;
176 
177   this->Modified();
178 }
179 
180 //------------------------------------------------------------------------------
181 // Have to be careful about the range if scale is logarithmic
SetScale(int scale)182 void vtkLookupTable::SetScale(int scale)
183 {
184   if (this->Scale == scale)
185   {
186     return;
187   }
188   this->Scale = scale;
189   this->Modified();
190 
191   double rmin = this->TableRange[0];
192   double rmax = this->TableRange[1];
193 
194   if (this->Scale == VTK_SCALE_LOG10 && ((rmin > 0 && rmax < 0) || (rmin < 0 && rmax > 0)))
195   {
196     this->TableRange[0] = 1.0;
197     this->TableRange[1] = 10.0;
198     vtkErrorMacro("Bad table range for log scale: [" << rmin << ", " << rmax
199                                                      << "], "
200                                                         "adjusting to [1, 10]");
201     return;
202   }
203 }
204 
205 //------------------------------------------------------------------------------
206 // Allocate a color table of specified size.
Allocate(int sz,int ext)207 int vtkLookupTable::Allocate(int sz, int ext)
208 {
209   this->NumberOfColors = sz;
210   int a = this->Table->Allocate(4 * (this->NumberOfColors + NUMBER_OF_SPECIAL_COLORS), 4 * ext);
211   this->Modified();
212   return a;
213 }
214 
215 //------------------------------------------------------------------------------
216 // Force the lookup table to rebuild
ForceBuild()217 void vtkLookupTable::ForceBuild()
218 {
219   vtkIdType maxIndex = this->NumberOfColors - 1;
220 
221   double hinc, sinc, vinc, ainc;
222   if (maxIndex > 0)
223   {
224     hinc = (this->HueRange[1] - this->HueRange[0]) / maxIndex;
225     sinc = (this->SaturationRange[1] - this->SaturationRange[0]) / maxIndex;
226     vinc = (this->ValueRange[1] - this->ValueRange[0]) / maxIndex;
227     ainc = (this->AlphaRange[1] - this->AlphaRange[0]) / maxIndex;
228   }
229   else
230   {
231     hinc = sinc = vinc = ainc = 0.0;
232   }
233 
234   double rgba[4];
235   for (vtkIdType i = 0; i <= maxIndex; i++)
236   {
237     double hue = this->HueRange[0] + i * hinc;
238     double sat = this->SaturationRange[0] + i * sinc;
239     double val = this->ValueRange[0] + i * vinc;
240     double alpha = this->AlphaRange[0] + i * ainc;
241 
242     vtkMath::HSVToRGB(hue, sat, val, &rgba[0], &rgba[1], &rgba[2]);
243     rgba[3] = alpha;
244 
245     unsigned char* c_rgba = this->Table->WritePointer(4 * i, 4);
246 
247     switch (this->Ramp)
248     {
249       case VTK_RAMP_SCURVE:
250       {
251         c_rgba[0] = static_cast<unsigned char>(
252           127.5 * (1.0 + cos((1.0 - static_cast<double>(rgba[0])) * vtkMath::Pi())));
253         c_rgba[1] = static_cast<unsigned char>(
254           127.5 * (1.0 + cos((1.0 - static_cast<double>(rgba[1])) * vtkMath::Pi())));
255         c_rgba[2] = static_cast<unsigned char>(
256           127.5 * (1.0 + cos((1.0 - static_cast<double>(rgba[2])) * vtkMath::Pi())));
257         c_rgba[3] = static_cast<unsigned char>(alpha * 255.0);
258         /* same code, but with rounding for correctness
259         c_rgba[0] = static_cast<unsigned char>
260           (127.5*(1.0 + cos((1.0 - rgba[0])*vtkMath::Pi())) + 0.5);
261         c_rgba[1] = static_cast<unsigned char>
262           (127.5*(1.0 + cos((1.0 - rgba[1])*vtkMath::Pi())) + 0.5);
263         c_rgba[2] = static_cast<unsigned char>
264           (127.5*(1.0 + cos((1.0 - rgba[2])*vtkMath::Pi())) + 0.5);
265         c_rgba[3] = static_cast<unsigned char>(alpha*255.0 + 0.5);
266         */
267       }
268       break;
269       case VTK_RAMP_LINEAR:
270       {
271         c_rgba[0] = static_cast<unsigned char>(rgba[0] * 255.0 + 0.5);
272         c_rgba[1] = static_cast<unsigned char>(rgba[1] * 255.0 + 0.5);
273         c_rgba[2] = static_cast<unsigned char>(rgba[2] * 255.0 + 0.5);
274         c_rgba[3] = static_cast<unsigned char>(rgba[3] * 255.0 + 0.5);
275       }
276       break;
277       case VTK_RAMP_SQRT:
278       {
279         c_rgba[0] = static_cast<unsigned char>(sqrt(rgba[0]) * 255.0 + 0.5);
280         c_rgba[1] = static_cast<unsigned char>(sqrt(rgba[1]) * 255.0 + 0.5);
281         c_rgba[2] = static_cast<unsigned char>(sqrt(rgba[2]) * 255.0 + 0.5);
282         c_rgba[3] = static_cast<unsigned char>(sqrt(rgba[3]) * 255.0 + 0.5);
283       }
284       break;
285       default:
286         assert("check: impossible case." && 0); // reaching this line is a bug.
287         break;
288     }
289   }
290 
291   this->BuildSpecialColors();
292 
293   this->BuildTime.Modified();
294 }
295 
296 //------------------------------------------------------------------------------
297 // Generate lookup table from hue, saturation, value, alpha min/max values.
298 // Table is built from linear ramp of each value.
Build()299 void vtkLookupTable::Build()
300 {
301   vtkMTimeType mtime = this->GetMTime();
302 
303   if ((mtime > this->BuildTime && this->InsertTime <= this->BuildTime) ||
304     this->Table->GetNumberOfTuples() < 1)
305   {
306     this->ForceBuild();
307   }
308   else if (mtime > this->SpecialColorsBuildTime)
309   {
310     this->BuildSpecialColors();
311   }
312 }
313 
314 //------------------------------------------------------------------------------
BuildSpecialColors()315 void vtkLookupTable::BuildSpecialColors()
316 {
317   // Append 4 "special" colors (repeated last, below range, above range, NaN) to table here.
318   vtkIdType numberOfColors = this->GetTable()->GetNumberOfTuples();
319   this->ResizeTableForSpecialColors();
320   unsigned char* table = this->GetTable()->GetPointer(0);
321   unsigned char color[4];
322 
323   // Repeat the last color. This is done to improve performance later on.
324   // Floating point math in vtkLinearIndexLookupMain may result in an off-by-one,
325   // and having an extra copy of the last color lets us avoid a test in that very hot function.
326   unsigned char* tptr = table + 4 * (numberOfColors + vtkLookupTable::REPEATED_LAST_COLOR_INDEX);
327   if (numberOfColors > 0)
328   {
329     // Duplicate the last color in the table.
330     tptr[0] = table[4 * (numberOfColors - 1) + 0];
331     tptr[1] = table[4 * (numberOfColors - 1) + 1];
332     tptr[2] = table[4 * (numberOfColors - 1) + 2];
333     tptr[3] = table[4 * (numberOfColors - 1) + 3];
334   }
335   else if (this->GetUseAboveRangeColor())
336   {
337     vtkLookupTable::GetColorAsUnsignedChars(this->GetAboveRangeColor(), color);
338     tptr[0] = color[0];
339     tptr[1] = color[1];
340     tptr[2] = color[2];
341     tptr[3] = color[3];
342   }
343   else
344   {
345     tptr[0] = 0;
346     tptr[1] = 0;
347     tptr[2] = 0;
348     tptr[3] = 0;
349   }
350 
351   // Below range color
352   tptr = table + 4 * (numberOfColors + vtkLookupTable::BELOW_RANGE_COLOR_INDEX);
353   if (this->GetUseBelowRangeColor() || numberOfColors == 0)
354   {
355     vtkLookupTable::GetColorAsUnsignedChars(this->GetBelowRangeColor(), color);
356     tptr[0] = color[0];
357     tptr[1] = color[1];
358     tptr[2] = color[2];
359     tptr[3] = color[3];
360   }
361   else
362   {
363     // Duplicate the first color in the table.
364     tptr[0] = table[0];
365     tptr[1] = table[1];
366     tptr[2] = table[2];
367     tptr[3] = table[3];
368   }
369 
370   // Above range color
371   tptr = table + 4 * (numberOfColors + vtkLookupTable::ABOVE_RANGE_COLOR_INDEX);
372   if (this->GetUseAboveRangeColor() || numberOfColors == 0)
373   {
374     vtkLookupTable::GetColorAsUnsignedChars(this->GetAboveRangeColor(), color);
375     tptr[0] = color[0];
376     tptr[1] = color[1];
377     tptr[2] = color[2];
378     tptr[3] = color[3];
379   }
380   else
381   {
382     // Duplicate the last color in the table.
383     tptr[0] = table[4 * (numberOfColors - 1) + 0];
384     tptr[1] = table[4 * (numberOfColors - 1) + 1];
385     tptr[2] = table[4 * (numberOfColors - 1) + 2];
386     tptr[3] = table[4 * (numberOfColors - 1) + 3];
387   }
388 
389   // Always use NanColor
390   vtkLookupTable::GetColorAsUnsignedChars(this->GetNanColor(), color);
391   tptr = table + 4 * (numberOfColors + vtkLookupTable::NAN_COLOR_INDEX);
392   tptr[0] = color[0];
393   tptr[1] = color[1];
394   tptr[2] = color[2];
395   tptr[3] = color[3];
396 
397   this->SpecialColorsBuildTime.Modified();
398 }
399 
400 //------------------------------------------------------------------------------
401 // get the color for a scalar value
GetColor(double v,double rgb[3])402 void vtkLookupTable::GetColor(double v, double rgb[3])
403 {
404   const unsigned char* rgb8 = this->MapValue(v);
405 
406   rgb[0] = rgb8[0] / 255.0;
407   rgb[1] = rgb8[1] / 255.0;
408   rgb[2] = rgb8[2] / 255.0;
409 }
410 
411 //------------------------------------------------------------------------------
412 // get the opacity (alpha) for a scalar value
GetOpacity(double v)413 double vtkLookupTable::GetOpacity(double v)
414 {
415   const unsigned char* rgb8 = this->MapValue(v);
416 
417   return rgb8[3] / 255.0;
418 }
419 
420 namespace
421 {
422 
423 //------------------------------------------------------------------------------
424 // There is a little more to this than simply taking the log10 of the
425 // two range values: we do conversion of negative ranges to positive
426 // ranges, and conversion of zero to a 'very small number'
vtkLookupTableLogRange(const double range[2],double logRange[2])427 inline void vtkLookupTableLogRange(const double range[2], double logRange[2])
428 {
429   double rmin = range[0];
430   double rmax = range[1];
431 
432   // does the range include zero?
433   if ((rmin <= 0 && rmax >= 0) || (rmin >= 0 && rmax <= 0))
434   {
435     // clamp the smaller value to 1e-6 times the larger
436     if (fabs(rmax) >= fabs(rmin))
437     {
438       rmin = rmax * 1e-6;
439     }
440     else
441     {
442       rmax = rmin * 1e-6;
443     }
444 
445     // ensure values are not zero
446     if (rmax == 0)
447     {
448       rmax = (rmin < 0 ? -VTK_DBL_MIN : VTK_DBL_MIN);
449     }
450     if (rmin == 0)
451     {
452       rmin = (rmax < 0 ? -VTK_DBL_MIN : VTK_DBL_MIN);
453     }
454   }
455 
456   if (rmax < 0) // rmin and rmax have same sign now
457   {
458     logRange[0] = -log10(-rmin);
459     logRange[1] = -log10(-rmax);
460   }
461   else
462   {
463     logRange[0] = log10(rmin);
464     logRange[1] = log10(rmax);
465   }
466 }
467 
468 //------------------------------------------------------------------------------
469 // Apply log to value, with appropriate constraints.
vtkApplyLogScaleMain(double v,const double range[2],const double logRange[2])470 double vtkApplyLogScaleMain(double v, const double range[2], const double logRange[2])
471 {
472   // is the range set for negative numbers?
473   if (range[0] < 0)
474   {
475     if (v < 0)
476     {
477       v = -log10(-v);
478     }
479     else if (range[0] > range[1])
480     {
481       v = logRange[0];
482     }
483     else
484     {
485       v = logRange[1];
486     }
487   }
488   else
489   {
490     if (v > 0)
491     {
492       v = log10(v);
493     }
494     else if (range[0] <= range[1])
495     {
496       v = logRange[0];
497     }
498     else
499     {
500       v = logRange[1];
501     }
502   }
503   return v;
504 }
505 
506 //------------------------------------------------------------------------------
507 template <class T>
vtkApplyLogScale(T v,const double range[2],const double logRange[2])508 double vtkApplyLogScale(T v, const double range[2], const double logRange[2])
509 {
510   return vtkApplyLogScaleMain(v, range, logRange);
511 }
512 
513 //------------------------------------------------------------------------------
514 // Apply log to a float value (NaN values pass through)
vtkApplyLogScale(float v,const double range[2],const double logRange[2])515 inline double vtkApplyLogScale(float v, const double range[2], const double logRange[2])
516 {
517   if (vtkMath::IsNan(v))
518   {
519     return v;
520   }
521 
522   return vtkApplyLogScaleMain(v, range, logRange);
523 }
524 
525 //------------------------------------------------------------------------------
526 // Apply log to a double value (NaN values pass through)
vtkApplyLogScale(double v,const double range[2],const double logRange[2])527 inline double vtkApplyLogScale(double v, const double range[2], const double logRange[2])
528 {
529   if (vtkMath::IsNan(v))
530   {
531     return v;
532   }
533 
534   return vtkApplyLogScaleMain(v, range, logRange);
535 }
536 
537 //------------------------------------------------------------------------------
538 // Private structure for passing data between various internal functions
539 struct TableParameters
540 {
541   vtkIdType NumColors;
542   double Range[2];
543   double Shift;
544   double Scale;
545 };
546 
547 //------------------------------------------------------------------------------
548 // Apply shift/scale to the scalar value v and return the index.
vtkLinearIndexLookupMain(double v,const TableParameters & p)549 inline vtkIdType vtkLinearIndexLookupMain(double v, const TableParameters& p)
550 {
551   vtkIdType index;
552 
553   // This is a very hot function.
554   // Be very careful changing it, as it affects performance greatly.
555 
556   if (v < p.Range[0])
557   {
558     index = p.NumColors + vtkLookupTable::BELOW_RANGE_COLOR_INDEX;
559   }
560   else if (v > p.Range[1])
561   {
562     index = p.NumColors + vtkLookupTable::ABOVE_RANGE_COLOR_INDEX;
563   }
564   else
565   {
566     double dIndex = (v + p.Shift) * p.Scale;
567 
568     // When v is very close to p.Range[1], the floating point calculation giving
569     // dIndex may map above the highest value in the lut (at index p.NumColors-1)
570     // in the linear mapping above. This is why we keep an extra copy of the last
571     // lut value, to avoid extra work in this very hot function.
572     // It should never be more than 1 off, assert to be sure.
573     index = static_cast<vtkIdType>(dIndex);
574     assert(index >= 0 && index <= p.NumColors);
575   }
576 
577   return index;
578 }
579 
580 //------------------------------------------------------------------------------
581 // integer variant
582 template <class T>
vtkLinearLookup(T v,const TableParameters & p)583 inline vtkIdType vtkLinearLookup(T v, const TableParameters& p)
584 {
585   // First convert from integer to double.
586   double dv = static_cast<double>(v);
587   return vtkLinearIndexLookupMain(dv, p);
588 }
589 
590 //------------------------------------------------------------------------------
591 // double variant
vtkLinearLookup(double v,const TableParameters & p)592 inline vtkIdType vtkLinearLookup(double v, const TableParameters& p)
593 {
594   // If Nan, use the special NaN color.
595   if (vtkMath::IsNan(v))
596   {
597     vtkIdType maxIndex = p.NumColors + vtkLookupTable::NAN_COLOR_INDEX;
598     return maxIndex;
599   }
600 
601   return vtkLinearIndexLookupMain(v, p);
602 }
603 
604 //------------------------------------------------------------------------------
605 // float variant
vtkLinearLookup(float v,const TableParameters & p)606 inline vtkIdType vtkLinearLookup(float v, const TableParameters& p)
607 {
608   // Convert from float to double, then call the double variant.
609   double dv = static_cast<double>(v);
610   return vtkLinearLookup(dv, p);
611 }
612 
613 //------------------------------------------------------------------------------
vtkLookupShiftAndScale(const double range[2],double numColors,double & shift,double & scale)614 inline void vtkLookupShiftAndScale(
615   const double range[2], double numColors, double& shift, double& scale)
616 {
617   shift = -range[0];
618   double rangeDelta = range[1] - range[0];
619   if (rangeDelta < VTK_DBL_MIN * numColors)
620   {
621     // if the range is tiny, anything within the range will map to the bottom
622     // of the color scale.
623     scale = 0.0;
624   }
625   else
626   {
627     scale = numColors / rangeDelta;
628   }
629   assert(scale >= 0.0);
630 }
631 
632 } // end anonymous namespace
633 
634 //------------------------------------------------------------------------------
GetLogRange(const double range[2],double log_range[2])635 void vtkLookupTable::GetLogRange(const double range[2], double log_range[2])
636 {
637   vtkLookupTableLogRange(range, log_range);
638 }
639 
640 //------------------------------------------------------------------------------
ApplyLogScale(double v,const double range[2],const double log_range[2])641 double vtkLookupTable::ApplyLogScale(double v, const double range[2], const double log_range[2])
642 {
643   return vtkApplyLogScale(v, range, log_range);
644 }
645 
646 //------------------------------------------------------------------------------
647 // Given a scalar value v, return an index into the lookup table
GetIndex(double v)648 vtkIdType vtkLookupTable::GetIndex(double v)
649 {
650   if (this->IndexedLookup)
651   {
652     if (this->NumberOfColors > 0)
653     {
654       return this->GetAnnotatedValueIndex(v) % this->NumberOfColors;
655     }
656     else
657     {
658       // Treat as a NaN
659       return -1;
660     }
661   }
662 
663   // Map to an index:
664   //   First, check whether we have a number...
665   if (vtkMath::IsNan(v))
666   {
667     // For backwards compatibility
668     return -1;
669   }
670 
671   TableParameters p;
672   p.NumColors = this->NumberOfColors;
673 
674   if (this->Scale == VTK_SCALE_LOG10)
675   { // handle logarithmic scale
676     double logRange[2];
677     vtkLookupTableLogRange(this->TableRange, logRange);
678     vtkLookupShiftAndScale(logRange, p.NumColors, p.Shift, p.Scale);
679     v = vtkApplyLogScale(v, this->TableRange, logRange);
680     p.Range[0] = logRange[0];
681     p.Range[1] = logRange[1];
682   }
683   else
684   { // plain old linear
685     vtkLookupShiftAndScale(this->TableRange, p.NumColors, p.Shift, p.Scale);
686     p.Range[0] = this->TableRange[0];
687     p.Range[1] = this->TableRange[1];
688   }
689 
690   vtkIdType index = vtkLinearIndexLookupMain(v, p);
691 
692   // For backwards compatibility, if the index indicates an
693   // out-of-range value, truncate to index range for in-range colors.
694   if (index == this->NumberOfColors + BELOW_RANGE_COLOR_INDEX)
695   {
696     index = 0;
697   }
698   else if ((index == this->NumberOfColors + REPEATED_LAST_COLOR_INDEX) ||
699     (index == this->NumberOfColors + ABOVE_RANGE_COLOR_INDEX))
700   {
701     index = this->NumberOfColors - 1;
702   }
703 
704   return index;
705 }
706 
707 //------------------------------------------------------------------------------
708 // Given a table, set the internal table and set the number of colors.
SetTable(vtkUnsignedCharArray * table)709 void vtkLookupTable::SetTable(vtkUnsignedCharArray* table)
710 {
711   if (table != this->Table && table != nullptr)
712   {
713     // Check for incorrect arrays.
714     if (table->GetNumberOfComponents() != this->Table->GetNumberOfComponents())
715     {
716       vtkErrorMacro(<< "Number of components in given table (" << table->GetNumberOfComponents()
717                     << ") is incorrect, it should have " << this->Table->GetNumberOfComponents()
718                     << ".");
719       return;
720     }
721     this->Table->UnRegister(this);
722     this->Table = table;
723     this->Table->Register(this);
724     this->NumberOfColors = this->Table->GetNumberOfTuples();
725     this->BuildSpecialColors();
726 
727     // If InsertTime is not modified the array will be rebuilt.  So we
728     // use the same approach that the SetTableValue function does.
729     this->InsertTime.Modified();
730     this->Modified();
731   }
732 }
733 
734 //------------------------------------------------------------------------------
GetColorAsUnsignedChars(const double colorIn[4],unsigned char colorOut[4])735 void vtkLookupTable::GetColorAsUnsignedChars(const double colorIn[4], unsigned char colorOut[4])
736 {
737   assert(colorIn && colorOut);
738   if (!colorIn || !colorOut)
739   {
740     return;
741   }
742 
743   for (int c = 0; c < 4; ++c)
744   {
745     double v = colorIn[c];
746     if (v < 0.0)
747     {
748       v = 0.0;
749     }
750     else if (v > 1.0)
751     {
752       v = 1.0;
753     }
754     colorOut[c] = static_cast<unsigned char>(v * 255.0 + 0.5);
755   }
756 }
757 
758 //------------------------------------------------------------------------------
GetNanColorAsUnsignedChars()759 unsigned char* vtkLookupTable::GetNanColorAsUnsignedChars()
760 {
761   this->GetColorAsUnsignedChars(this->GetNanColor(), this->NanColorChar);
762   return this->NanColorChar;
763 }
764 
765 //------------------------------------------------------------------------------
766 // Given a scalar value v, return an RGBA color value from lookup table.
MapValue(double v)767 const unsigned char* vtkLookupTable::MapValue(double v)
768 {
769   vtkIdType index = this->GetIndex(v);
770   if (index < 0)
771   {
772     return this->GetNanColorAsUnsignedChars();
773   }
774   else if (index == 0)
775   {
776     if (this->UseBelowRangeColor && v < this->TableRange[0])
777     {
778       this->GetColorAsUnsignedChars(this->GetBelowRangeColor(), this->RGBABytes);
779       return this->RGBABytes;
780     }
781   }
782   else if (index == this->NumberOfColors - 1)
783   {
784     if (this->UseAboveRangeColor && v > this->TableRange[1])
785     {
786       this->GetColorAsUnsignedChars(this->GetAboveRangeColor(), this->RGBABytes);
787       return this->RGBABytes;
788     }
789   }
790 
791   return this->Table->GetPointer(0) + 4 * index;
792 }
793 
794 namespace
795 {
796 
797 //------------------------------------------------------------------------------
798 template <class T>
vtkLookupTableMapData(vtkLookupTable * self,T * input,unsigned char * output,int length,int inIncr,int outFormat,TableParameters & p)799 void vtkLookupTableMapData(vtkLookupTable* self, T* input, unsigned char* output, int length,
800   int inIncr, int outFormat, TableParameters& p)
801 {
802   int i = length;
803   const double* range = self->GetTableRange();
804   const unsigned char* cptr;
805 
806   // Resize the internal table to hold the special colors at the
807   // end. When this function is called repeatedly with the same size
808   // lookup table, memory reallocation will be done only one the first
809   // call if at all.
810 
811   vtkUnsignedCharArray* lookupTable = self->GetTable();
812 
813   const unsigned char* table = lookupTable->GetPointer(0);
814 
815   double alpha = self->GetAlpha();
816   if (alpha >= 1.0) // no blending required
817   {
818     if (self->GetScale() == VTK_SCALE_LOG10)
819     {
820       double val;
821       double logRange[2];
822       vtkLookupTableLogRange(range, logRange);
823       vtkLookupShiftAndScale(logRange, p.NumColors, p.Shift, p.Scale);
824       p.Range[0] = logRange[0];
825       p.Range[1] = logRange[1];
826 
827       if (outFormat == VTK_RGBA)
828       {
829         while (--i >= 0)
830         {
831           val = vtkApplyLogScale(*input, range, logRange);
832           vtkIdType idx = vtkLinearLookup(val, p);
833           cptr = table + 4 * idx;
834           memcpy(output, cptr, 4);
835           input += inIncr;
836           output += 4;
837         }
838       }
839       else if (outFormat == VTK_RGB)
840       {
841         while (--i >= 0)
842         {
843           val = vtkApplyLogScale(*input, range, logRange);
844           vtkIdType idx = vtkLinearLookup(val, p);
845           cptr = table + 4 * idx;
846           memcpy(output, cptr, 3);
847           input += inIncr;
848           output += 3;
849         }
850       }
851       else if (outFormat == VTK_LUMINANCE_ALPHA)
852       {
853         while (--i >= 0)
854         {
855           val = vtkApplyLogScale(*input, range, logRange);
856           vtkIdType idx = vtkLinearLookup(val, p);
857           cptr = table + 4 * idx;
858           output[0] =
859             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
860           output[1] = cptr[3];
861           input += inIncr;
862           output += 2;
863         }
864       }
865       else // outFormat == VTK_LUMINANCE
866       {
867         while (--i >= 0)
868         {
869           val = vtkApplyLogScale(*input, range, logRange);
870           vtkIdType idx = vtkLinearLookup(val, p);
871           cptr = table + 4 * idx;
872           *output++ =
873             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
874           input += inIncr;
875         }
876       }
877     } // if log scale
878 
879     else // not log scale
880     {
881       vtkLookupShiftAndScale(range, p.NumColors, p.Shift, p.Scale);
882       p.Range[0] = range[0];
883       p.Range[1] = range[1];
884       if (outFormat == VTK_RGBA)
885       {
886         while (--i >= 0)
887         {
888           vtkIdType idx = vtkLinearLookup(*input, p);
889           cptr = table + 4 * idx;
890           memcpy(output, cptr, 4);
891           input += inIncr;
892           output += 4;
893         }
894       }
895       else if (outFormat == VTK_RGB)
896       {
897         while (--i >= 0)
898         {
899           vtkIdType idx = vtkLinearLookup(*input, p);
900           cptr = table + 4 * idx;
901           memcpy(output, cptr, 3);
902           input += inIncr;
903           output += 3;
904         }
905       }
906       else if (outFormat == VTK_LUMINANCE_ALPHA)
907       {
908         while (--i >= 0)
909         {
910           vtkIdType idx = vtkLinearLookup(*input, p);
911           cptr = table + 4 * idx;
912           output[0] =
913             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
914           output[1] = cptr[3];
915           input += inIncr;
916           output += 2;
917         }
918       }
919       else // outFormat == VTK_LUMINANCE
920       {
921         while (--i >= 0)
922         {
923           vtkIdType idx = vtkLinearLookup(*input, p);
924           cptr = table + 4 * idx;
925           *output++ =
926             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
927           input += inIncr;
928         }
929       }
930     } // if not log lookup
931   }   // if blending not needed
932 
933   else // blend with the specified alpha
934   {
935     if (self->GetScale() == VTK_SCALE_LOG10)
936     {
937       double val;
938       double logRange[2];
939       vtkLookupTableLogRange(range, logRange);
940       vtkLookupShiftAndScale(logRange, p.NumColors, p.Shift, p.Scale);
941       p.Range[0] = logRange[0];
942       p.Range[1] = logRange[1];
943 
944       if (outFormat == VTK_RGBA)
945       {
946         while (--i >= 0)
947         {
948           val = vtkApplyLogScale(*input, range, logRange);
949           vtkIdType idx = vtkLinearLookup(val, p);
950           cptr = table + 4 * idx;
951           output[0] = cptr[0];
952           output[1] = cptr[1];
953           output[2] = cptr[2];
954           output[3] = static_cast<unsigned char>(cptr[3] * alpha + 0.5);
955           input += inIncr;
956           output += 4;
957         }
958       }
959       else if (outFormat == VTK_RGB)
960       {
961         while (--i >= 0)
962         {
963           val = vtkApplyLogScale(*input, range, logRange);
964           vtkIdType idx = vtkLinearLookup(val, p);
965           cptr = table + 4 * idx;
966           memcpy(output, cptr, 3);
967           input += inIncr;
968           output += 3;
969         }
970       }
971       else if (outFormat == VTK_LUMINANCE_ALPHA)
972       {
973         while (--i >= 0)
974         {
975           val = vtkApplyLogScale(*input, range, logRange);
976           vtkIdType idx = vtkLinearLookup(val, p);
977           cptr = table + 4 * idx;
978           output[0] =
979             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
980           output[1] = static_cast<unsigned char>(alpha * cptr[3] + 0.5);
981           input += inIncr;
982           output += 2;
983         }
984       }
985       else // outFormat == VTK_LUMINANCE
986       {
987         while (--i >= 0)
988         {
989           val = vtkApplyLogScale(*input, range, logRange);
990           vtkIdType idx = vtkLinearLookup(val, p);
991           cptr = table + 4 * idx;
992           *output++ =
993             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
994           input += inIncr;
995         }
996       }
997     } // log scale with blending
998 
999     else // no log scale with blending
1000     {
1001       vtkLookupShiftAndScale(range, p.NumColors, p.Shift, p.Scale);
1002       p.Range[0] = range[0];
1003       p.Range[1] = range[1];
1004 
1005       if (outFormat == VTK_RGBA)
1006       {
1007         while (--i >= 0)
1008         {
1009           vtkIdType idx = vtkLinearLookup(*input, p);
1010           cptr = table + 4 * idx;
1011           output[0] = cptr[0];
1012           output[1] = cptr[1];
1013           output[2] = cptr[2];
1014           output[3] = static_cast<unsigned char>(cptr[3] * alpha + 0.5);
1015           input += inIncr;
1016           output += 4;
1017         }
1018       }
1019       else if (outFormat == VTK_RGB)
1020       {
1021         while (--i >= 0)
1022         {
1023           vtkIdType idx = vtkLinearLookup(*input, p);
1024           cptr = table + 4 * idx;
1025           memcpy(output, cptr, 3);
1026           input += inIncr;
1027           output += 3;
1028         }
1029       }
1030       else if (outFormat == VTK_LUMINANCE_ALPHA)
1031       {
1032         while (--i >= 0)
1033         {
1034           vtkIdType idx = vtkLinearLookup(*input, p);
1035           cptr = table + 4 * idx;
1036           output[0] =
1037             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
1038           output[1] = static_cast<unsigned char>(cptr[3] * alpha + 0.5);
1039           input += inIncr;
1040           output += 2;
1041         }
1042       }
1043       else // outFormat == VTK_LUMINANCE
1044       {
1045         while (--i >= 0)
1046         {
1047           vtkIdType idx = vtkLinearLookup(*input, p);
1048           cptr = table + 4 * idx;
1049           *output++ =
1050             static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
1051           input += inIncr;
1052         }
1053       }
1054     } // no log scale
1055   }   // alpha blending
1056 }
1057 
1058 //------------------------------------------------------------------------------
1059 template <class T>
vtkLookupTableIndexedMapData(vtkLookupTable * self,const T * input,unsigned char * output,int length,int inIncr,int outFormat)1060 void vtkLookupTableIndexedMapData(vtkLookupTable* self, const T* input, unsigned char* output,
1061   int length, int inIncr, int outFormat)
1062 {
1063   int i = length;
1064   unsigned char* cptr;
1065 
1066   unsigned char nanColor[4];
1067   vtkLookupTable::GetColorAsUnsignedChars(self->GetNanColor(), nanColor);
1068 
1069   vtkVariant vin;
1070   double alpha = self->GetAlpha();
1071   if (alpha >= 1.0) // no blending required
1072   {
1073     if (outFormat == VTK_RGBA)
1074     {
1075       while (--i >= 0)
1076       {
1077         vin = *input;
1078         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1079         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1080 
1081         memcpy(output, cptr, 4);
1082         input += inIncr;
1083         output += 4;
1084       }
1085     }
1086     else if (outFormat == VTK_RGB)
1087     {
1088       while (--i >= 0)
1089       {
1090         vin = *input;
1091         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1092         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1093 
1094         memcpy(output, cptr, 3);
1095         input += inIncr;
1096         output += 3;
1097       }
1098     }
1099     else if (outFormat == VTK_LUMINANCE_ALPHA)
1100     {
1101       while (--i >= 0)
1102       {
1103         vin = *input;
1104         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1105         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1106         output[0] =
1107           static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
1108         output[1] = cptr[3];
1109         input += inIncr;
1110         output += 2;
1111       }
1112     }
1113     else // outFormat == VTK_LUMINANCE
1114     {
1115       while (--i >= 0)
1116       {
1117         vin = *input;
1118         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1119         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1120         *output++ =
1121           static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
1122         input += inIncr;
1123       }
1124     }
1125   } // if blending not needed
1126 
1127   else // blend with the specified alpha
1128   {
1129     if (outFormat == VTK_RGBA)
1130     {
1131       while (--i >= 0)
1132       {
1133         vin = *input;
1134         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1135         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1136         memcpy(output, cptr, 3);
1137         output[3] = static_cast<unsigned char>(cptr[3] * alpha + 0.5);
1138         input += inIncr;
1139         output += 4;
1140       }
1141     }
1142     else if (outFormat == VTK_RGB)
1143     {
1144       while (--i >= 0)
1145       {
1146         vin = *input;
1147         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1148         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1149         memcpy(output, cptr, 3);
1150         input += inIncr;
1151         output += 3;
1152       }
1153     }
1154     else if (outFormat == VTK_LUMINANCE_ALPHA)
1155     {
1156       while (--i >= 0)
1157       {
1158         vin = *input;
1159         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1160         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1161         output[0] =
1162           static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
1163         output[1] = static_cast<unsigned char>(cptr[3] * alpha + 0.5);
1164         input += inIncr;
1165         output += 2;
1166       }
1167     }
1168     else // outFormat == VTK_LUMINANCE
1169     {
1170       while (--i >= 0)
1171       {
1172         vin = *input;
1173         vtkIdType idx = self->GetAnnotatedValueIndexInternal(vin);
1174         cptr = idx < 0 ? nanColor : self->GetPointer(idx);
1175         *output++ =
1176           static_cast<unsigned char>(cptr[0] * 0.30 + cptr[1] * 0.59 + cptr[2] * 0.11 + 0.5);
1177         input += inIncr;
1178       }
1179     }
1180   } // alpha blending
1181 }
1182 
1183 } // end anonymous namespace
1184 
1185 //------------------------------------------------------------------------------
MapScalarsThroughTable2(void * input,unsigned char * output,int inputDataType,int numberOfValues,int inputIncrement,int outputFormat)1186 void vtkLookupTable::MapScalarsThroughTable2(void* input, unsigned char* output, int inputDataType,
1187   int numberOfValues, int inputIncrement, int outputFormat)
1188 {
1189   if (this->IndexedLookup)
1190   {
1191     switch (inputDataType)
1192     {
1193       case VTK_BIT:
1194       {
1195         vtkIdType i, id;
1196         vtkBitArray* bitArray = vtkBitArray::New();
1197         bitArray->SetVoidArray(input, numberOfValues, 1);
1198         vtkUnsignedCharArray* newInput = vtkUnsignedCharArray::New();
1199         newInput->SetNumberOfValues(numberOfValues);
1200         for (id = i = 0; i < numberOfValues; i++, id += inputIncrement)
1201         {
1202           newInput->SetValue(i, bitArray->GetValue(id));
1203         }
1204         vtkLookupTableIndexedMapData(
1205           this, newInput->GetPointer(0), output, numberOfValues, inputIncrement, outputFormat);
1206         newInput->Delete();
1207         bitArray->Delete();
1208       }
1209       break;
1210 
1211         vtkTemplateMacro(vtkLookupTableIndexedMapData(
1212           this, static_cast<VTK_TT*>(input), output, numberOfValues, inputIncrement, outputFormat));
1213 
1214       case VTK_STRING:
1215         vtkLookupTableIndexedMapData(this, static_cast<vtkStdString*>(input), output,
1216           numberOfValues, inputIncrement, outputFormat);
1217         break;
1218 
1219       default:
1220         vtkErrorMacro(<< "MapScalarsThroughTable2: Unknown input ScalarType");
1221         return;
1222     }
1223   }
1224   else
1225   {
1226     TableParameters p;
1227     p.NumColors = this->GetNumberOfColors();
1228 
1229     switch (inputDataType)
1230     {
1231       case VTK_BIT:
1232       {
1233         vtkIdType i, id;
1234         vtkBitArray* bitArray = vtkBitArray::New();
1235         bitArray->SetVoidArray(input, numberOfValues, 1);
1236         vtkUnsignedCharArray* newInput = vtkUnsignedCharArray::New();
1237         newInput->SetNumberOfValues(numberOfValues);
1238         for (id = i = 0; i < numberOfValues; i++, id += inputIncrement)
1239         {
1240           newInput->SetValue(i, bitArray->GetValue(id));
1241         }
1242         vtkLookupTableMapData(
1243           this, newInput->GetPointer(0), output, numberOfValues, inputIncrement, outputFormat, p);
1244         newInput->Delete();
1245         bitArray->Delete();
1246       }
1247       break;
1248 
1249         vtkTemplateMacro(vtkLookupTableMapData(this, static_cast<VTK_TT*>(input), output,
1250           numberOfValues, inputIncrement, outputFormat, p));
1251       default:
1252         vtkErrorMacro(<< "MapScalarsThroughTable2: Unknown input ScalarType");
1253         return;
1254     }
1255   }
1256 }
1257 
1258 //------------------------------------------------------------------------------
1259 // Specify the number of values (i.e., colors) in the lookup
1260 // table. This method simply allocates memory and prepares the table
1261 // for use with SetTableValue(). It differs from Build() method in
1262 // that the allocated memory is not initialized according to HSVA ramps.
SetNumberOfTableValues(vtkIdType number)1263 void vtkLookupTable::SetNumberOfTableValues(vtkIdType number)
1264 {
1265   if (this->NumberOfColors == number)
1266   {
1267     return;
1268   }
1269   this->Modified();
1270   this->NumberOfColors = number;
1271   this->ResizeTableForSpecialColors();
1272   this->Table->SetNumberOfTuples(number);
1273 }
1274 
1275 //------------------------------------------------------------------------------
1276 // Directly load color into lookup table. Use [0,1] double values for color
1277 // component specification. Make sure that you've either used the
1278 // Build() method or used SetNumberOfTableValues() prior to using this method.
SetTableValue(vtkIdType indx,const double rgba[4])1279 void vtkLookupTable::SetTableValue(vtkIdType indx, const double rgba[4])
1280 {
1281   // Check the index to make sure it is valid
1282   if (indx < 0)
1283   {
1284     vtkErrorMacro("Can't set the table value for negative index " << indx);
1285     return;
1286   }
1287   if (indx >= this->NumberOfColors)
1288   {
1289     vtkErrorMacro(
1290       "Index " << indx << " is greater than the number of colors " << this->NumberOfColors);
1291     return;
1292   }
1293 
1294   unsigned char* _rgba = this->Table->WritePointer(4 * indx, 4);
1295 
1296   _rgba[0] = static_cast<unsigned char>(rgba[0] * 255.0 + 0.5);
1297   _rgba[1] = static_cast<unsigned char>(rgba[1] * 255.0 + 0.5);
1298   _rgba[2] = static_cast<unsigned char>(rgba[2] * 255.0 + 0.5);
1299   _rgba[3] = static_cast<unsigned char>(rgba[3] * 255.0 + 0.5);
1300 
1301   if (indx == 0 || indx == this->NumberOfColors - 1)
1302   {
1303     // This is needed due to the way the special colors are stored in
1304     // the internal table. If Above/BelowRangeColors are not used and
1305     // the min/max colors are changed in the table with this member
1306     // function, then the colors used for values outside the range may
1307     // be incorrect. Calling this here ensures the out-of-range colors
1308     // are set correctly.
1309     this->BuildSpecialColors();
1310   }
1311 
1312   this->InsertTime.Modified();
1313   this->Modified();
1314 }
1315 
1316 //------------------------------------------------------------------------------
1317 // Directly load color into lookup table. Use [0,1] double values for color
1318 // component specification.
SetTableValue(vtkIdType indx,double r,double g,double b,double a)1319 void vtkLookupTable::SetTableValue(vtkIdType indx, double r, double g, double b, double a)
1320 {
1321   const double rgba[4] = { r, g, b, a };
1322   this->SetTableValue(indx, rgba);
1323 }
1324 
1325 //------------------------------------------------------------------------------
1326 // Return an RGBA color value for the given index into the lookup Table. Color
1327 // components are expressed as [0,1] double values.
GetTableValue(vtkIdType indx,double rgba[4])1328 void vtkLookupTable::GetTableValue(vtkIdType indx, double rgba[4])
1329 {
1330   indx = (indx < 0 ? 0 : (indx >= this->NumberOfColors ? this->NumberOfColors - 1 : indx));
1331 
1332   const unsigned char* _rgba = this->Table->GetPointer(indx * 4);
1333 
1334   rgba[0] = _rgba[0] / 255.0;
1335   rgba[1] = _rgba[1] / 255.0;
1336   rgba[2] = _rgba[2] / 255.0;
1337   rgba[3] = _rgba[3] / 255.0;
1338 }
1339 
1340 // Return an RGBA color value for the given index into the lookup table. Color
1341 // components are expressed as [0,1] double values.
GetTableValue(vtkIdType indx)1342 double* vtkLookupTable::GetTableValue(vtkIdType indx)
1343 {
1344   this->GetTableValue(indx, this->RGBA);
1345   return this->RGBA;
1346 }
1347 
1348 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1349 void vtkLookupTable::PrintSelf(ostream& os, vtkIndent indent)
1350 {
1351   this->Superclass::PrintSelf(os, indent);
1352 
1353   os << indent << "TableRange: (" << this->TableRange[0] << ", " << this->TableRange[1] << ")\n";
1354   os << indent << "Scale: " << (this->Scale == VTK_SCALE_LOG10 ? "Log10\n" : "Linear\n");
1355   os << indent << "HueRange: (" << this->HueRange[0] << ", " << this->HueRange[1] << ")\n";
1356   os << indent << "SaturationRange: (" << this->SaturationRange[0] << ", "
1357      << this->SaturationRange[1] << ")\n";
1358   os << indent << "ValueRange: (" << this->ValueRange[0] << ", " << this->ValueRange[1] << ")\n";
1359   os << indent << "AlphaRange: (" << this->AlphaRange[0] << ", " << this->AlphaRange[1] << ")\n";
1360 
1361   os << indent << "NanColor: (" << this->NanColor[0] << ", " << this->NanColor[1] << ", "
1362      << this->NanColor[2] << ", " << this->NanColor[3] << ")\n";
1363 
1364   os << indent << "BelowRangeColor: (" << this->BelowRangeColor[0] << ", "
1365      << this->BelowRangeColor[1] << ", " << this->BelowRangeColor[2] << ", "
1366      << this->BelowRangeColor[3] << ")\n";
1367   os << indent << "UseBelowRangeColor: " << (this->UseBelowRangeColor != 0 ? "ON" : "OFF") << "\n";
1368 
1369   os << indent << "AboveRangeColor: (" << this->AboveRangeColor[0] << ", "
1370      << this->AboveRangeColor[1] << ", " << this->AboveRangeColor[2] << ", "
1371      << this->AboveRangeColor[3] << ")\n";
1372   os << indent << "UseAboveRangeColor: " << (this->UseAboveRangeColor != 0 ? "ON" : "OFF") << "\n";
1373 
1374   os << indent << "NumberOfTableValues: " << this->GetNumberOfTableValues() << "\n";
1375   os << indent << "NumberOfColors: " << this->NumberOfColors << "\n";
1376   os << indent << "Ramp: " << (this->Ramp == VTK_RAMP_SCURVE ? "SCurve\n" : "Linear\n");
1377   os << indent << "InsertTime: " << this->InsertTime.GetMTime() << "\n";
1378   os << indent << "BuildTime: " << this->BuildTime.GetMTime() << "\n";
1379   os << indent << "Table: ";
1380   if (this->Table)
1381   {
1382     this->Table->PrintSelf(os << "\n", indent.GetNextIndent());
1383   }
1384   else
1385   {
1386     // Should not happen
1387     os << "(none)\n";
1388   }
1389 }
1390 
1391 //------------------------------------------------------------------------------
DeepCopy(vtkScalarsToColors * obj)1392 void vtkLookupTable::DeepCopy(vtkScalarsToColors* obj)
1393 {
1394   if (!obj)
1395   {
1396     return;
1397   }
1398 
1399   vtkLookupTable* lut = vtkLookupTable::SafeDownCast(obj);
1400 
1401   if (!lut)
1402   {
1403     vtkErrorMacro("Cannot DeepCopy a " << obj->GetClassName() << " into a vtkLookupTable.");
1404     return;
1405   }
1406 
1407   this->Scale = lut->Scale;
1408   this->TableRange[0] = lut->TableRange[0];
1409   this->TableRange[1] = lut->TableRange[1];
1410   this->HueRange[0] = lut->HueRange[0];
1411   this->HueRange[1] = lut->HueRange[1];
1412   this->SaturationRange[0] = lut->SaturationRange[0];
1413   this->SaturationRange[1] = lut->SaturationRange[1];
1414   this->ValueRange[0] = lut->ValueRange[0];
1415   this->ValueRange[1] = lut->ValueRange[1];
1416   this->AlphaRange[0] = lut->AlphaRange[0];
1417   this->AlphaRange[1] = lut->AlphaRange[1];
1418   this->NumberOfColors = lut->NumberOfColors;
1419   this->Ramp = lut->Ramp;
1420   this->InsertTime = lut->InsertTime;
1421   this->BuildTime = lut->BuildTime;
1422 
1423   for (int i = 0; i < 4; ++i)
1424   {
1425     this->NanColor[i] = lut->NanColor[i];
1426   }
1427   this->Table->DeepCopy(lut->Table);
1428   this->ResizeTableForSpecialColors();
1429 
1430   this->Superclass::DeepCopy(obj);
1431 }
1432 
1433 //------------------------------------------------------------------------------
GetNumberOfAvailableColors()1434 vtkIdType vtkLookupTable::GetNumberOfAvailableColors()
1435 {
1436   return this->Table->GetNumberOfTuples();
1437 }
1438 
1439 //------------------------------------------------------------------------------
GetIndexedColor(vtkIdType idx,double rgba[4])1440 void vtkLookupTable::GetIndexedColor(vtkIdType idx, double rgba[4])
1441 {
1442   vtkIdType n = this->GetNumberOfAvailableColors();
1443   if (n > 0 && idx >= 0)
1444   {
1445     this->GetTableValue(idx % n, rgba);
1446     return;
1447   }
1448   this->GetNanColor(rgba);
1449 }
1450 
1451 //------------------------------------------------------------------------------
ResizeTableForSpecialColors()1452 void vtkLookupTable::ResizeTableForSpecialColors()
1453 {
1454   vtkIdType neededColors = this->NumberOfColors + vtkLookupTable::NUMBER_OF_SPECIAL_COLORS;
1455   if (this->Table->GetSize() < neededColors * this->Table->GetNumberOfComponents())
1456   {
1457     this->Table->Resize(neededColors);
1458   }
1459 }
1460