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