vtkLookupTable.cxx 42.3 KB
Newer Older
Will Schroeder's avatar
Will Schroeder committed
1
2
/*=========================================================================

Ken Martin's avatar
Ken Martin committed
3
  Program:   Visualization Toolkit
Ken Martin's avatar
Ken Martin committed
4
  Module:    vtkLookupTable.cxx
Will Schroeder's avatar
Will Schroeder committed
5

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7
8
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
Will Schroeder's avatar
Will Schroeder committed
9

10
11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12
     PURPOSE.  See the above copyright notice for more information.
Will Schroeder's avatar
Will Schroeder committed
13
14

=========================================================================*/
Ken Martin's avatar
Ken Martin committed
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
24
#include "vtkVariantArray.h"

25
#include <cassert>
26

27
28
29
30
31
const vtkIdType vtkLookupTable::BELOW_RANGE_COLOR_INDEX  = 0;
const vtkIdType vtkLookupTable::ABOVE_RANGE_COLOR_INDEX  = 1;
const vtkIdType vtkLookupTable::NAN_COLOR_INDEX          = 2;
const vtkIdType vtkLookupTable::NUMBER_OF_SPECIAL_COLORS = NAN_COLOR_INDEX+1;

Brad King's avatar
Brad King committed
32
vtkStandardNewMacro(vtkLookupTable);
33

34
// Construct with range=(0,1); and hsv ranges set up for rainbow color table
Will Schroeder's avatar
Will Schroeder committed
35
// (from red to blue).
Ken Martin's avatar
Ken Martin committed
36
vtkLookupTable::vtkLookupTable(int sze, int ext)
Ken Martin's avatar
Ken Martin committed
37
{
Will Schroeder's avatar
Will Schroeder committed
38
  this->NumberOfColors = sze;
39
  this->Table = vtkUnsignedCharArray::New();
40
41
  this->Table->Register(this);
  this->Table->Delete();
42
  this->Table->SetNumberOfComponents(4);
43
  this->Table->Allocate(4*(sze + NUMBER_OF_SPECIAL_COLORS), 4*ext);
Will Schroeder's avatar
Will Schroeder committed
44

Will Schroeder's avatar
Will Schroeder committed
45
46
  this->HueRange[0] = 0.0;
  this->HueRange[1] = 0.66667;
Ken Martin's avatar
Ken Martin committed
47

Will Schroeder's avatar
Will Schroeder committed
48
49
  this->SaturationRange[0] = 1.0;
  this->SaturationRange[1] = 1.0;
Ken Martin's avatar
Ken Martin committed
50

Will Schroeder's avatar
Will Schroeder committed
51
52
  this->ValueRange[0] = 1.0;
  this->ValueRange[1] = 1.0;
53

Will Schroeder's avatar
Will Schroeder committed
54
55
  this->AlphaRange[0] = 1.0;
  this->AlphaRange[1] = 1.0;
56
  this->Alpha = 1.0;
57

58
59
60
61
62
  this->NanColor[0] = 0.5;
  this->NanColor[1] = 0.0;
  this->NanColor[2] = 0.0;
  this->NanColor[3] = 1.0;

63
64
65
66
67
68
69
70
71
72
73
74
75
76
  this->BelowRangeColor[0] = 0.0;
  this->BelowRangeColor[1] = 0.0;
  this->BelowRangeColor[2] = 0.0;
  this->BelowRangeColor[3] = 1.0;

  this->UseBelowRangeColor = 0;

  this->AboveRangeColor[0] = 1.0;
  this->AboveRangeColor[1] = 1.0;
  this->AboveRangeColor[2] = 1.0;
  this->AboveRangeColor[3] = 1.0;

  this->UseAboveRangeColor = 0;

77
78
79
80
81
  this->TableRange[0] = 0.0;
  this->TableRange[1] = 1.0;

  this->Ramp = VTK_RAMP_SCURVE;
  this->Scale = VTK_SCALE_LINEAR;
82

83
  this->OpaqueFlag=1;
84
85
}

86
//----------------------------------------------------------------------------
87
88
vtkLookupTable::~vtkLookupTable()
{
89
  this->Table->UnRegister( this );
90
91
  this->Table = NULL;
}
Will Schroeder's avatar
Will Schroeder committed
92

93
94
95
96
97
98
99
100
101
//----------------------------------------------------------------------------
// Description:
// Return true if all of the values defining the mapping have an opacity
// equal to 1. Default implementation return true.
int vtkLookupTable::IsOpaque()
{
  if(this->OpaqueFlagBuildTime<this->GetMTime())
    {
    int opaque=1;
102
    if (this->NanColor[3] < 1.0) { opaque = 0; }
103
104
    if (this->UseBelowRangeColor && this->BelowRangeColor[3] < 1.0) { opaque = 0; }
    if (this->UseAboveRangeColor && this->AboveRangeColor[3] < 1.0) { opaque = 0; }
Sean McBride's avatar
Sean McBride committed
105
106
    vtkIdType size=this->Table->GetNumberOfTuples();
    vtkIdType i=0;
107
108
109
110
111
112
113
114
115
116
    unsigned char *ptr=this->Table->GetPointer(0);
    while(opaque && i<size)
      {
      opaque=ptr[3]==255;
      ptr+=4;
      ++i;
      }
    this->OpaqueFlag=opaque;
    this->OpaqueFlagBuildTime.Modified();
    }
117

118
119
120
  return this->OpaqueFlag;
}

121
//----------------------------------------------------------------------------
Will Schroeder's avatar
Will Schroeder committed
122
123
// Scalar values greater than maximum range value are clamped to maximum
// range value.
Ken Martin's avatar
Ken Martin committed
124
void vtkLookupTable::SetTableRange(double r[2])
Will Schroeder's avatar
Will Schroeder committed
125
{
Will Schroeder's avatar
Will Schroeder committed
126
  this->SetTableRange(r[0],r[1]);
Will Schroeder's avatar
Will Schroeder committed
127
}
Will Schroeder's avatar
Will Schroeder committed
128

129
//----------------------------------------------------------------------------
Will Schroeder's avatar
Will Schroeder committed
130
131
132
133
// Set the minimum/maximum scalar values for scalar mapping. Scalar values
// less than minimum range value are clamped to minimum range value.
// Scalar values greater than maximum range value are clamped to maximum
// range value.
Ken Martin's avatar
Ken Martin committed
134
void vtkLookupTable::SetTableRange(double rmin, double rmax)
Ken Martin's avatar
Ken Martin committed
135
{
136
  if (this->Scale == VTK_SCALE_LOG10 &&
137
      ((rmin > 0 && rmax < 0) || (rmin < 0 && rmax > 0)))
Will Schroeder's avatar
Will Schroeder committed
138
    {
139
140
141
    vtkErrorMacro("Bad table range for log scale: ["<<rmin<<", "<<rmax<<"]");
    return;
    }
142
  if (rmax < rmin)
143
144
    {
    vtkErrorMacro("Bad table range: ["<<rmin<<", "<<rmax<<"]");
Will Schroeder's avatar
Will Schroeder committed
145
146
147
    return;
    }

148
  if (this->TableRange[0] == rmin && this->TableRange[1] == rmax)
Ken Martin's avatar
Ken Martin committed
149
    {
150
    return;
Ken Martin's avatar
Ken Martin committed
151
    }
152
153
154
155
156
157
158

  this->TableRange[0] = rmin;
  this->TableRange[1] = rmax;

  this->Modified();
}

159
//----------------------------------------------------------------------------
160
161
162
163
164
165
166
167
// Have to be careful about the range if scale is logarithmic
void vtkLookupTable::SetScale(int scale)
{
  if (this->Scale == scale)
    {
    return;
    }
  this->Scale = scale;
168
  this->Modified();
169

Ken Martin's avatar
Ken Martin committed
170
171
  double rmin = this->TableRange[0];
  double rmax = this->TableRange[1];
172

173
  if (this->Scale == VTK_SCALE_LOG10 &&
174
175
      ((rmin > 0 && rmax < 0) || (rmin < 0 && rmax > 0)))
    {
Ken Martin's avatar
Ken Martin committed
176
177
    this->TableRange[0] = 1.0;
    this->TableRange[1] = 10.0;
178
    vtkErrorMacro("Bad table range for log scale: ["<<rmin<<", "<<rmax<<"], "
179
                  "adjusting to [1, 10]");
180
181
    return;
    }
Ken Martin's avatar
Ken Martin committed
182
183
}

184
//----------------------------------------------------------------------------
Ken Martin's avatar
Ken Martin committed
185
// Allocate a color table of specified size.
186
int vtkLookupTable::Allocate(int sz, int ext)
Ken Martin's avatar
Ken Martin committed
187
188
{
  this->NumberOfColors = sz;
189
  int a = this->Table->Allocate(4*(this->NumberOfColors + NUMBER_OF_SPECIAL_COLORS), 4*ext);
190
191
  this->Modified();
  return a;
Ken Martin's avatar
Ken Martin committed
192
193
}

194
//----------------------------------------------------------------------------
195
196
// Force the lookup table to rebuild
void vtkLookupTable::ForceBuild()
Ken Martin's avatar
Ken Martin committed
197
{
Ken Martin's avatar
Ken Martin committed
198
199
  double hue, sat, val, hinc, sinc, vinc, ainc;
  double rgba[4], alpha;
200
  unsigned char *c_rgba;
Ken Martin's avatar
Ken Martin committed
201

Sean McBride's avatar
Sean McBride committed
202
  vtkIdType maxIndex = this->NumberOfColors - 1;
203

204
205
206
207
208
209
210
211
212
  if( maxIndex )
    {
    hinc = (this->HueRange[1] - this->HueRange[0])/maxIndex;
    sinc = (this->SaturationRange[1] - this->SaturationRange[0])/maxIndex;
    vinc = (this->ValueRange[1] - this->ValueRange[0])/maxIndex;
    ainc = (this->AlphaRange[1] - this->AlphaRange[0])/maxIndex;
    }
  else
    {
213
    hinc = sinc = vinc = ainc = 0.0;
214
    }
Will Schroeder's avatar
Will Schroeder committed
215

Sean McBride's avatar
Sean McBride committed
216
  for (vtkIdType i = 0; i <= maxIndex; i++)
217
218
219
220
221
222
    {
    hue = this->HueRange[0] + i*hinc;
    sat = this->SaturationRange[0] + i*sinc;
    val = this->ValueRange[0] + i*vinc;
    alpha = this->AlphaRange[0] + i*ainc;

223
    vtkMath::HSVToRGB(hue, sat, val, &rgba[0], &rgba[1], &rgba[2]);
224
225
226
227
    rgba[3] = alpha;

    c_rgba = this->Table->WritePointer(4*i,4);

Bill Hoffman's avatar
Bill Hoffman committed
228
    switch(this->Ramp)
229
      {
Bill Hoffman's avatar
Bill Hoffman committed
230
231
      case VTK_RAMP_SCURVE:
        {
232
        c_rgba[0] = static_cast<unsigned char>
233
          (127.5*(1.0+cos((1.0-static_cast<double>(rgba[0]))*vtkMath::Pi())));
234
        c_rgba[1] = static_cast<unsigned char>
235
           (127.5*(1.0+cos((1.0-static_cast<double>(rgba[1]))*vtkMath::Pi())));
236
        c_rgba[2] = static_cast<unsigned char>
237
          (127.5*(1.0+cos((1.0-static_cast<double>(rgba[2]))*vtkMath::Pi())));
Bill Hoffman's avatar
Bill Hoffman committed
238
        c_rgba[3] = static_cast<unsigned char> (alpha*255.0);
239
240
        /* same code, but with rounding for correctness
        c_rgba[0] = static_cast<unsigned char>
241
          (127.5*(1.0 + cos((1.0 - rgba[0])*vtkMath::Pi())) + 0.5);
242
        c_rgba[1] = static_cast<unsigned char>
243
          (127.5*(1.0 + cos((1.0 - rgba[1])*vtkMath::Pi())) + 0.5);
244
        c_rgba[2] = static_cast<unsigned char>
245
          (127.5*(1.0 + cos((1.0 - rgba[2])*vtkMath::Pi())) + 0.5);
246
        c_rgba[3] = static_cast<unsigned char>(alpha*255.0 + 0.5);
Bill Hoffman's avatar
Bill Hoffman committed
247
248
        */
        }
249
        break;
Bill Hoffman's avatar
Bill Hoffman committed
250
251
      case VTK_RAMP_LINEAR:
        {
252
253
254
255
        c_rgba[0] = static_cast<unsigned char>(rgba[0]*255.0 + 0.5);
        c_rgba[1] = static_cast<unsigned char>(rgba[1]*255.0 + 0.5);
        c_rgba[2] = static_cast<unsigned char>(rgba[2]*255.0 + 0.5);
        c_rgba[3] = static_cast<unsigned char>(rgba[3]*255.0 + 0.5);
Bill Hoffman's avatar
Bill Hoffman committed
256
        }
257
        break;
Bill Hoffman's avatar
Bill Hoffman committed
258
259
      case VTK_RAMP_SQRT:
        {
260
261
262
263
        c_rgba[0] = static_cast<unsigned char>(sqrt(rgba[0])*255.0 + 0.5);
        c_rgba[1] = static_cast<unsigned char>(sqrt(rgba[1])*255.0 + 0.5);
        c_rgba[2] = static_cast<unsigned char>(sqrt(rgba[2])*255.0 + 0.5);
        c_rgba[3] = static_cast<unsigned char>(sqrt(rgba[3])*255.0 + 0.5);
Bill Hoffman's avatar
Bill Hoffman committed
264
        }
265
        break;
266
      default:
267
        assert("check: impossible case." && 0); // reaching this line is a bug.
268
        break;
269
270
      }
    }
271

272
273
  this->BuildSpecialColors();

274
275
276
  this->BuildTime.Modified();
}

277
//----------------------------------------------------------------------------
278
// Generate lookup table from hue, saturation, value, alpha min/max values.
279
280
281
282
// Table is built from linear ramp of each value.
void vtkLookupTable::Build()
{
  if (this->Table->GetNumberOfTuples() < 1 ||
283
      (this->GetMTime() > this->BuildTime &&
284
       this->InsertTime <= this->BuildTime))
285
286
    {
    this->ForceBuild();
Ken Martin's avatar
Ken Martin committed
287
288
289
    }
}

290
291
292
293
294
295
296
297

//----------------------------------------------------------------------------
void vtkLookupTable::BuildSpecialColors()
{
  // Add "special" colors (NaN, below range, above range) to table here.
  vtkIdType numberOfColors = this->GetTable()->GetNumberOfTuples();

  this->ResizeTableForSpecialColors();
298
299
300
  unsigned char *table = this->GetTable()->GetPointer(0);
  unsigned char *tptr = table + 4*(numberOfColors + vtkLookupTable::BELOW_RANGE_COLOR_INDEX);
  unsigned char color[4];
301
302

  // Below range color
303
  if (this->GetUseBelowRangeColor() || numberOfColors == 0)
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
    {
    vtkLookupTable::GetColorAsUnsignedChars(this->GetBelowRangeColor(), color);
    tptr[0] = color[0];
    tptr[1] = color[1];
    tptr[2] = color[2];
    tptr[3] = color[3];
    }
  else
    {
    // Duplicate the first color in the table.
    tptr[0] = table[0];
    tptr[1] = table[1];
    tptr[2] = table[2];
    tptr[3] = table[3];
    }

  // Above range color
  tptr = table + 4*(numberOfColors + vtkLookupTable::ABOVE_RANGE_COLOR_INDEX);
322
  if (this->GetUseAboveRangeColor() || numberOfColors == 0)
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
    {
    vtkLookupTable::GetColorAsUnsignedChars(this->GetAboveRangeColor(), color);
    tptr[0] = color[0];
    tptr[1] = color[1];
    tptr[2] = color[2];
    tptr[3] = color[3];
    }
  else
    {
    // Duplicate the last color in the table.
    tptr[0] = table[4*(numberOfColors-1) + 0];
    tptr[1] = table[4*(numberOfColors-1) + 1];
    tptr[2] = table[4*(numberOfColors-1) + 2];
    tptr[3] = table[4*(numberOfColors-1) + 3];
    }

  // Always use NanColor
  vtkLookupTable::GetColorAsUnsignedChars(this->GetNanColor(), color);
  tptr = table + 4*(numberOfColors + vtkLookupTable::NAN_COLOR_INDEX);
  tptr[0] = color[0];
  tptr[1] = color[1];
  tptr[2] = color[2];
  tptr[3] = color[3];
}

348
//----------------------------------------------------------------------------
349
// get the color for a scalar value
Ken Martin's avatar
Ken Martin committed
350
void vtkLookupTable::GetColor(double v, double rgb[3])
351
352
353
354
355
356
357
358
{
  unsigned char *rgb8 = this->MapValue(v);

  rgb[0] = rgb8[0]/255.0;
  rgb[1] = rgb8[1]/255.0;
  rgb[2] = rgb8[2]/255.0;
}

359
//----------------------------------------------------------------------------
360
// get the opacity (alpha) for a scalar value
Ken Martin's avatar
Ken Martin committed
361
double vtkLookupTable::GetOpacity(double v)
362
363
364
365
366
{
  unsigned char *rgb8 = this->MapValue(v);

  return rgb8[3]/255.0;
}
367

368
369
namespace {

370
//----------------------------------------------------------------------------
371
372
373
// There is a little more to this than simply taking the log10 of the
// two range values: we do conversion of negative ranges to positive
// ranges, and conversion of zero to a 'very small number'
374
inline void vtkLookupTableLogRange(const double range[2], double logRange[2])
Ken Martin's avatar
Ken Martin committed
375
{
Ken Martin's avatar
Ken Martin committed
376
377
  double rmin = range[0];
  double rmax = range[1];
Ken Martin's avatar
Ken Martin committed
378

379
380
381
  // does the range include zero?
  if ((rmin <= 0 && rmax >= 0) ||
      (rmin >= 0 && rmax <= 0))
382
    {
383
384
    // clamp the smaller value to 1e-6 times the larger
    if (fabs(rmax) >= fabs(rmin))
385
      {
386
      rmin = rmax*1e-6;
387
      }
388
389
390
391
392
393
394
    else
      {
      rmax = rmin*1e-6;
      }

    // ensure values are not zero
    if (rmax == 0)
395
      {
396
397
398
399
400
      rmax = (rmin < 0 ? -VTK_DBL_MIN : VTK_DBL_MIN);
      }
    if (rmin == 0)
      {
      rmin = (rmax < 0 ? -VTK_DBL_MIN : VTK_DBL_MIN);
401
402
      }
    }
403
404

  if (rmax < 0) // rmin and rmax have same sign now
405
    {
406
407
    logRange[0] = -log10(-rmin);
    logRange[1] = -log10(-rmax);
408
    }
409
  else
410
    {
411
412
    logRange[0] = log10(rmin);
    logRange[1] = log10(rmax);
413
414
415
    }
}

416
//----------------------------------------------------------------------------
417
// Apply log to value, with appropriate constraints.
418
inline double vtkApplyLogScale(double v, const double range[2],
419
                               const double logRange[2])
420
421
422
423
424
425
{
  // is the range set for negative numbers?
  if (range[0] < 0)
    {
    if (v < 0)
      {
426
      v = -log10(-v);
427
428
429
430
431
432
433
434
435
436
437
438
439
440
      }
    else if (range[0] > range[1])
      {
      v = logRange[0];
      }
    else
      {
      v = logRange[1];
      }
    }
  else
    {
    if (v > 0)
      {
441
      v = log10(v);
442
      }
443
    else if (range[0] <= range[1])
444
445
446
447
448
449
450
451
452
      {
      v = logRange[0];
      }
    else
      {
      v = logRange[1];
      }
    }
  return v;
453
}
454

455
//----------------------------------------------------------------------------
456
457
458
// Data structure for passing data around various internal functions
struct TableParameters {
  double         MaxIndex;
459
  double         Range[2];
460
461
462
463
464
465
  double         Shift;
  double         Scale;
};

//----------------------------------------------------------------------------
// Apply shift/scale to the scalar value v and return the index.
466
inline vtkIdType vtkLinearIndexLookupMain(double v, const TableParameters & p)
467
{
468
  double dIndex;
469

470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
  if (v < p.Range[0])
    {
    dIndex = p.MaxIndex + vtkLookupTable::BELOW_RANGE_COLOR_INDEX + 1.5;
    }
  else if (v > p.Range[1])
    {
    dIndex = p.MaxIndex + vtkLookupTable::ABOVE_RANGE_COLOR_INDEX + 1.5;
    }
  else
    {
    dIndex = (v + p.Shift)*p.Scale;

    // This conditional is needed because when v is very close to
    // p.Range[1], it may map above p.MaxIndex in the linear mapping
    // above.
    dIndex = (dIndex < p.MaxIndex ? dIndex : p.MaxIndex);
    }
487

488
  return static_cast<vtkIdType>(dIndex);
489
490
491
492
}

//----------------------------------------------------------------------------
// Get index and do the table lookup.
493
494
495
inline const unsigned char *vtkLinearLookupMain(double v,
                                                unsigned char *table,
                                                const TableParameters & p)
496
{
497
498
  vtkIdType index = vtkLinearIndexLookupMain(v, p);
  return &table[4*index];
499
500
}

501
//----------------------------------------------------------------------------
502
template<class T>
503
const unsigned char *vtkLinearLookup(T v, unsigned char *table, const TableParameters & p)
504
{
505
  return vtkLinearLookupMain(v, table, p);
506
507
508
509
}

//----------------------------------------------------------------------------
// Check for not-a-number when mapping double or float
510
inline const unsigned char *vtkLinearLookup(
511
  double v, unsigned char *table, const TableParameters & p)
512
513
514
{
  if (vtkMath::IsNan(v))
    {
515
516
    vtkIdType maxIndex = static_cast<vtkIdType>(p.MaxIndex + 0.5) + 1;
    return table + 4*(maxIndex + vtkLookupTable::NAN_COLOR_INDEX);
517
518
    }

519
  return vtkLinearLookupMain(v, table, p);
520
521
}

522
//----------------------------------------------------------------------------
523
inline const unsigned char *vtkLinearLookup(
524
525
526
527
528
529
530
531
532
  float v, unsigned char *table, const TableParameters & p)
{
  return vtkLinearLookup(static_cast<double>(v), table, p);
}

//----------------------------------------------------------------------------
inline void vtkLookupShiftAndScale(double range[2],
                                   double maxIndex,
                                   double& shift, double& scale)
533
{
534
535
536
537
538
539
540
541
542
  shift = -range[0];
  if (range[1] <= range[0])
    {
    scale = VTK_DOUBLE_MAX;
    }
  else
    {
    scale = (maxIndex + 1)/(range[1] - range[0]);
    }
543
544
}

545
546
} // end anonymous namespace

547
548
549
550
551
552
553
554
555
556
557
558
559
//----------------------------------------------------------------------------
void vtkLookupTable::GetLogRange(const double range[2], double log_range[2])
{
  vtkLookupTableLogRange(range, log_range);
}

//----------------------------------------------------------------------------
double vtkLookupTable::ApplyLogScale(double v, const double range[2],
  const double log_range[2])
{
  return vtkApplyLogScale(v, range, log_range);
}

560
//----------------------------------------------------------------------------
561
// Given a scalar value v, return an index into the lookup table
Ken Martin's avatar
Ken Martin committed
562
vtkIdType vtkLookupTable::GetIndex(double v)
563
{
564
565
566
567
568
  if ( this->IndexedLookup )
    {
    return this->GetAnnotatedValueIndex( v ) % this->GetNumberOfTableValues();
    }

569
570
  TableParameters p;
  p.MaxIndex = this->NumberOfColors - 1;
571
572
573

  if (this->Scale == VTK_SCALE_LOG10)
    {   // handle logarithmic scale
Ken Martin's avatar
Ken Martin committed
574
    double logRange[2];
575
    vtkLookupTableLogRange(this->TableRange, logRange);
576
    vtkLookupShiftAndScale(logRange, p.MaxIndex, p.Shift, p.Scale);
577
    v = vtkApplyLogScale(v, this->TableRange, logRange);
578
579
    p.Range[0] = logRange[0];
    p.Range[1] = logRange[1];
580
581
582
    }
  else
    {   // plain old linear
583
    vtkLookupShiftAndScale(this->TableRange, p.MaxIndex, p.Shift, p.Scale);
584
585
    p.Range[0] = this->TableRange[0];
    p.Range[1] = this->TableRange[1];
586
587
    }

588
589
590
591
  // Map to an index:
  //   First, check whether we have a number...
  if ( vtkMath::IsNan( v ) )
    {
592
    // For backwards compatibility
593
594
    return -1;
    }
595

596
597
598
599
600
601
602
603
604
605
606
607
608
609
  vtkIdType index = vtkLinearIndexLookupMain(v, p);

  // For backwards compatibility, if the index indicates an
  // out-of-range value, truncate to index range for in-range colors.
  if (index == this->NumberOfColors + BELOW_RANGE_COLOR_INDEX)
    {
    index = 0;
    }
  else if (index == this->NumberOfColors + ABOVE_RANGE_COLOR_INDEX)
    {
    index = this->NumberOfColors - 1;
    }

  return index;
610
611
}

612
613
614
615
616
617
618
619
620
//----------------------------------------------------------------------------
// Given a table, set the internal table and set the number of colors.
void vtkLookupTable::SetTable(vtkUnsignedCharArray *table)
{
  if (table != this->Table && table != NULL)
    {
    // Check for incorrect arrays.
    if (table->GetNumberOfComponents() != this->Table->GetNumberOfComponents())
      {
621
      vtkErrorMacro(<<"Number of components in given table ("
622
623
                    << table->GetNumberOfComponents()
                    << ") is incorrect, it should have "
624
                    << this->Table->GetNumberOfComponents()
625
626
627
628
629
630
631
                    << "." );
      return;
      }
    this->Table->UnRegister(this);
    this->Table = table;
    this->Table->Register(this);
    this->NumberOfColors = this->Table->GetNumberOfTuples();
632
    this->ResizeTableForSpecialColors();
633

634
635
636
637
638
639
640
    // If InsertTime is not modified the array will be rebuilt.  So we
    // use the same approach that the SetTableValue function does.
    this->InsertTime.Modified();
    this->Modified();
    }
}

641
//----------------------------------------------------------------------------
642
643
void vtkLookupTable::GetColorAsUnsignedChars(const double colorIn[4],
                                             unsigned char colorOut[4])
644
{
645
  assert(colorIn && colorOut);
646
647
648
649
650
  if (!colorIn || !colorOut)
    {
    return;
    }

651
652
  for ( int c = 0; c < 4; ++ c )
    {
653
    double v = colorIn[c];
654
655
    if (v < 0.0) { v = 0.0; }
    else if (v > 1.0) { v = 1.0; }
656
    colorOut[c] = static_cast<unsigned char>( v * 255.0 + 0.5 );
657
    }
658
659
660
661
662
663
664

  return;
}

//----------------------------------------------------------------------------
unsigned char* vtkLookupTable::GetNanColorAsUnsignedChars()
{
665
  this->GetColorAsUnsignedChars(this->GetNanColor(), this->NanColorChar);
666
667
668
  return this->NanColorChar;
}

669
//----------------------------------------------------------------------------
670
// Given a scalar value v, return an rgba color value from lookup table.
671
unsigned char* vtkLookupTable::MapValue(double v)
672
{
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
  vtkIdType index = this->GetIndex(v);
  if (index < 0)
    {
    return this->GetNanColorAsUnsignedChars();
    }
  else if (index == 0)
    {
    if (this->UseBelowRangeColor && v < this->TableRange[0])
      {
      this->GetColorAsUnsignedChars(this->GetBelowRangeColor(),
                                    this->RGBABytes);
      return this->RGBABytes;
      }
    }
  else if (index == this->NumberOfColors-1)
    {
    if (this->UseAboveRangeColor && v > this->TableRange[1])
      {
      this->GetColorAsUnsignedChars(this->GetAboveRangeColor(),
                                    this->RGBABytes);
      return this->RGBABytes;
      }
    }

  return this->Table->GetPointer(0) + 4*index;
698
}
Ken Martin's avatar
Ken Martin committed
699

700
701
namespace {

702
//----------------------------------------------------------------------------
703
template<class T>
704
void vtkLookupTableMapData(vtkLookupTable *self,
705
                           T *input, unsigned char *output, int length,
706
                           int inIncr, int outFormat, TableParameters & p)
707
708
{
  int i = length;
Ken Martin's avatar
Ken Martin committed
709
  double *range = self->GetTableRange();
710
  const unsigned char *cptr;
Ken Martin's avatar
Ken Martin committed
711
  double alpha;
712

713
714
715
716
  // Resize the internal table to hold the special colors at the
  // end. When this function is called repeatedly with the same size
  // lookup table, memory reallocation will be done only one the first
  // call if at all.
717

718
  vtkUnsignedCharArray* lookupTable = self->GetTable();
719

720
721
  unsigned char* table = lookupTable->GetPointer(0);

722
  if ( (alpha=self->GetAlpha()) >= 1.0 ) //no blending required
723
    {
724
    if (self->GetScale() == VTK_SCALE_LOG10)
725
      {
Ken Martin's avatar
Ken Martin committed
726
727
      double val;
      double logRange[2];
728
      vtkLookupTableLogRange(range, logRange);
729
      vtkLookupShiftAndScale(logRange, p.MaxIndex, p.Shift, p.Scale);
730
731
      p.Range[0] = logRange[0];
      p.Range[1] = logRange[1];
732

733
      if (outFormat == VTK_RGBA)
734
        {
735
        while (--i >= 0)
736
          {
737
          val = vtkApplyLogScale(*input, range, logRange);
738
          cptr = vtkLinearLookup(val, table, p);
739
740
741
742
          output[0] = cptr[0];
          output[1] = cptr[1];
          output[2] = cptr[2];
          output[3] = cptr[3];
743
          input += inIncr;
744
          output += 4;
745
          }
746
        }
747
      else if (outFormat == VTK_RGB)
748
        {
749
        while (--i >= 0)
750
          {
751
          val = vtkApplyLogScale(*input, range, logRange);
752
          cptr = vtkLinearLookup(val, table, p);
753
754
755
          output[0] = cptr[0];
          output[1] = cptr[1];
          output[2] = cptr[2];
756
          input += inIncr;
757
          output += 3;
758
          }
759
        }
760
      else if (outFormat == VTK_LUMINANCE_ALPHA)
761
        {
762
        while (--i >= 0)
763
          {
764
          val = vtkApplyLogScale(*input, range, logRange);
765
          cptr = vtkLinearLookup(val, table, p);
766
          output[0] = static_cast<unsigned char>(cptr[0]*0.30 + cptr[1]*0.59 +
767
                                                 cptr[2]*0.11 + 0.5);
768
          output[1] = cptr[3];
769
          input += inIncr;
770
          output += 2;
771
          }
772
        }
773
      else // outFormat == VTK_LUMINANCE
774
        {
775
        while (--i >= 0)
776
          {
777
          val = vtkApplyLogScale(*input, range, logRange);
778
          cptr = vtkLinearLookup(val, table, p);
779
          *output++ = static_cast<unsigned char>(cptr[0]*0.30 + cptr[1]*0.59 +
780
                                                 cptr[2]*0.11 + 0.5);
781
782
          input += inIncr;
          }
783
        }
784
      }//if log scale
785

786
    else //not log scale
787
      {
788
      vtkLookupShiftAndScale(range, p.MaxIndex, p.Shift, p.Scale);
789
790
      p.Range[0] = range[0];
      p.Range[1] = range[1];
791
      if (outFormat == VTK_RGBA)
792
        {
793
        while (--i >= 0)
794
          {
795
          cptr = vtkLinearLookup(*input, table, p);
796
797
798
799
          output[0] = cptr[0];
          output[1] = cptr[1];
          output[2] = cptr[2];
          output[3] = cptr[3];
800
          input += inIncr;
801
          output += 4;
802
          }
803
        }
804
      else if (outFormat == VTK_RGB)
805
        {
806
        while (--i >= 0)
807
          {
808
          cptr = vtkLinearLookup(*input, table, p);
809
810
811
          output[0] = cptr[0];
          output[1] = cptr[1];
          output[2] = cptr[2];
812
          input += inIncr;
813
          output += 3;
814
          }
815
        }
816
817
      else if (outFormat == VTK_LUMINANCE_ALPHA)
        {
818
        while (--i >= 0)
819
          {
820
          cptr = vtkLinearLookup(*input, table, p);
821
          output[0] = static_cast<unsigned char>(cptr[0]*0.30 + cptr[1]*0.59 +
822
                                                 cptr[2]*0.11 + 0.5);
823
          output[1] = cptr[3];
824
          input += inIncr;
825
          output += 2;
826
827
828
829
          }
        }
      else // outFormat == VTK_LUMINANCE
        {
830
        while (--i >= 0)
831
          {
832
          cptr = vtkLinearLookup(*input, table, p);
833
          *output++ = static_cast<unsigned char>(cptr[0]*0.30 + cptr[1]*0.59 +
834
                                                 cptr[2]*0.11 + 0.5);
835
836
837
838
839
840
841
842
843
          input += inIncr;
          }
        }
      }//if not log lookup
    }//if blending not needed

  else //blend with the specified alpha
    {
    if (self->GetScale() == VTK_SCALE_LOG10)
844
      {
Ken Martin's avatar
Ken Martin committed
845
846
      double val;
      double logRange[2];
847
      vtkLookupTableLogRange(range, logRange);
848
      vtkLookupShiftAndScale(logRange, p.MaxIndex, p.Shift, p.Scale);
849
850
851
      p.Range[0] = logRange[0];
      p.Range[1] = logRange[1];

852
      if (outFormat == VTK_RGBA)
853
        {
854
        while (--i >= 0)
855
          {
856
          val = vtkApplyLogScale(*input, range, logRange);
857
          cptr = vtkLinearLookup(val, table, p);
858
859
860
          output[0] = cptr[0];
          output[1] = cptr[1];
          output[2] = cptr[2];
861
          output[3] = static_cast<unsigned char>(cptr[3]*alpha + 0.5);
862
          input += inIncr;
863
          output += 4;
864
          }
865
        }
866
867
      else if (outFormat == VTK_RGB)
        {
868
        while (--i >= 0)
869
          {
870
          val = vtkApplyLogScale(*input, range, logRange);
871
          cptr = vtkLinearLookup(val, table, p);
872
873
874
          output[0] = cptr[0];
          output[1] = cptr[1];
          output[2] = cptr[2];
875
          input += inIncr;
876
          output += 3;
877
878
879
880
          }
        }
      else if (outFormat == VTK_LUMINANCE_ALPHA)
        {
881
        while (--i >= 0)
882
          {
883
          val = vtkApplyLogScale(*input, range, logRange);
884
          cptr = vtkLinearLookup(val, table, p);
885
          output[0] = static_cast<unsigned char>(cptr[0]*0.30 + cptr[1]*0.59 +