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