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