1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkColorTransferFunction.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 "vtkColorTransferFunction.h"
16 
17 #include "vtkMath.h"
18 #include "vtkObjectFactory.h"
19 
20 #include <algorithm>
21 #include <iterator>
22 #include <math.h>
23 #include <set>
24 #include <vector>
25 
26 vtkStandardNewMacro(vtkColorTransferFunction);
27 
28 #define MY_MAX(x, y) ((x) > (y) ? (x) : (y))
29 
30 //=============================================================================
31 class vtkCTFNode
32 {
33 public:
34   double X;
35   double R;
36   double G;
37   double B;
38   double Sharpness;
39   double Midpoint;
40 };
41 
42 class vtkCTFCompareNodes
43 {
44 public:
operator ()(const vtkCTFNode * node1,const vtkCTFNode * node2)45   bool operator () ( const vtkCTFNode *node1,
46                      const vtkCTFNode *node2 )
47     {
48       return node1->X < node2->X;
49     }
50 };
51 
52 class vtkCTFFindNodeEqual
53 {
54 public:
55   double X;
operator ()(const vtkCTFNode * node)56   bool operator () ( const vtkCTFNode *node )
57     {
58       return node->X == this->X;
59     }
60 };
61 
62 class vtkCTFFindNodeInRange
63 {
64 public:
65   double X1;
66   double X2;
operator ()(const vtkCTFNode * node)67   bool operator () (const vtkCTFNode *node )
68     {
69       return ( node->X >= this->X1 &&
70                node->X <= this->X2 );
71     }
72 };
73 
74 class vtkCTFFindNodeOutOfRange
75 {
76 public:
77   double X1;
78   double X2;
operator ()(const vtkCTFNode * node)79   bool operator () (const vtkCTFNode *node )
80     {
81       return ( node->X < this->X1 ||
82                node->X > this->X2 );
83     }
84 };
85 
86 class vtkColorTransferFunctionInternals
87 {
88 public:
89   std::vector<vtkCTFNode*> Nodes;
90   vtkCTFCompareNodes          CompareNodes;
91   vtkCTFFindNodeEqual         FindNodeEqual;
92   vtkCTFFindNodeInRange       FindNodeInRange;
93   vtkCTFFindNodeOutOfRange    FindNodeOutOfRange;
94 };
95 
96 //=============================================================================
97 // Convert to and from a special polar version of CIELAB (useful for creating
98 // continuous diverging color maps).
vtkColorTransferFunctionLabToMsh(const double lab[3],double msh[3])99 inline void vtkColorTransferFunctionLabToMsh(const double lab[3], double msh[3])
100 {
101   const double &L = lab[0];
102   const double &a = lab[1];
103   const double &b = lab[2];
104   double &M = msh[0];
105   double &s = msh[1];
106   double &h = msh[2];
107 
108   M = sqrt(L*L + a*a + b*b);
109   s = (M > 0.001) ? acos(L/M) : 0.0;
110   h = (s > 0.001) ? atan2(b,a) : 0.0;
111 }
112 
vtkColorTransferFunctionMshToLab(const double msh[3],double lab[3])113 inline void vtkColorTransferFunctionMshToLab(const double msh[3], double lab[3])
114 {
115   const double &M = msh[0];
116   const double &s = msh[1];
117   const double &h = msh[2];
118   double &L = lab[0];
119   double &a = lab[1];
120   double &b = lab[2];
121 
122   L = M*cos(s);
123   a = M*sin(s)*cos(h);
124   b = M*sin(s)*sin(h);
125 }
126 
127 // Given two angular orientations, returns the smallest angle between the two.
vtkColorTransferFunctionAngleDiff(double a1,double a2)128 inline double vtkColorTransferFunctionAngleDiff(double a1, double a2)
129 {
130   double adiff = a1 - a2;
131   if (adiff < 0.0) adiff = -adiff;
132   while (adiff >= 2.0 * vtkMath::Pi()) adiff -= (2.0 * vtkMath::Pi());
133   if (adiff > vtkMath::Pi()) adiff = (2.0 * vtkMath::Pi()) - adiff;
134   return adiff;
135 }
136 
137 // For the case when interpolating from a saturated color to an unsaturated
138 // color, find a hue for the unsaturated color that makes sense.
vtkColorTransferFunctionAdjustHue(const double msh[3],double unsatM)139 inline double vtkColorTransferFunctionAdjustHue(const double msh[3],
140                                                 double unsatM)
141 {
142   if (msh[0] >= unsatM - 0.1)
143     {
144     // The best we can do is hold hue constant.
145     return msh[2];
146     }
147   else
148     {
149     // This equation is designed to make the perceptual change of the
150     // interpolation to be close to constant.
151     double hueSpin = (  msh[1]*sqrt(unsatM*unsatM - msh[0]*msh[0])
152                       / (msh[0]*sin(msh[1])) );
153     // Spin hue away from 0 except in purple hues.
154     if (msh[2] > -0.3*vtkMath::Pi())
155       {
156       return msh[2] + hueSpin;
157       }
158     else
159       {
160       return msh[2] - hueSpin;
161       }
162     }
163 }
164 
165 // Interpolate a diverging color map.
vtkColorTransferFunctionInterpolateDiverging(double s,const double rgb1[3],const double rgb2[3],double result[3])166 inline void vtkColorTransferFunctionInterpolateDiverging(double s,
167                                                          const double rgb1[3],
168                                                          const double rgb2[3],
169                                                          double result[3])
170 {
171   double lab1[3], lab2[3];
172   vtkMath::RGBToLab(rgb1, lab1);
173   vtkMath::RGBToLab(rgb2, lab2);
174 
175   double msh1[3], msh2[3];
176   vtkColorTransferFunctionLabToMsh(lab1, msh1);
177   vtkColorTransferFunctionLabToMsh(lab2, msh2);
178 
179   // If the endpoints are distinct saturated colors, then place white in between
180   // them.
181   if (   (msh1[1] > 0.05) && (msh2[1] > 0.05)
182       && (vtkColorTransferFunctionAngleDiff(msh1[2], msh2[2]) > 0.33*vtkMath::Pi()) )
183     {
184     // Insert the white midpoint by setting one end to white and adjusting the
185     // scalar value.
186     double Mmid = MY_MAX(msh1[0], msh2[0]);
187     Mmid = MY_MAX(88.0, Mmid);
188     if (s < 0.5)
189       {
190       msh2[0] = Mmid;  msh2[1] = 0.0;  msh2[2] = 0.0;
191       s = 2.0*s;
192       }
193     else
194       {
195       msh1[0] = Mmid;  msh1[1] = 0.0;  msh1[2] = 0.0;
196       s = 2.0*s - 1.0;
197       }
198     }
199 
200   // If one color has no saturation, then its hue value is invalid.  In this
201   // case, we want to set it to something logical so that the interpolation of
202   // hue makes sense.
203   if ((msh1[1] < 0.05) && (msh2[1] > 0.05))
204     {
205     msh1[2] = vtkColorTransferFunctionAdjustHue(msh2, msh1[0]);
206     }
207   else if ((msh2[1] < 0.05) && (msh1[1] > 0.05))
208     {
209     msh2[2] = vtkColorTransferFunctionAdjustHue(msh1, msh2[0]);
210     }
211 
212   double mshTmp[3];
213   mshTmp[0] = (1-s)*msh1[0] + s*msh2[0];
214   mshTmp[1] = (1-s)*msh1[1] + s*msh2[1];
215   mshTmp[2] = (1-s)*msh1[2] + s*msh2[2];
216 
217   // Now convert back to RGB
218   double labTmp[3];
219   vtkColorTransferFunctionMshToLab(mshTmp, labTmp);
220   vtkMath::LabToRGB(labTmp, result);
221 }
222 
223 //----------------------------------------------------------------------------
224 // Construct a new vtkColorTransferFunction with default values
vtkColorTransferFunction()225 vtkColorTransferFunction::vtkColorTransferFunction()
226 {
227   this->UnsignedCharRGBAValue[0] = 0;
228   this->UnsignedCharRGBAValue[1] = 0;
229   this->UnsignedCharRGBAValue[2] = 0;
230   this->UnsignedCharRGBAValue[3] = 0;
231 
232   this->Range[0] = 0;
233   this->Range[1] = 0;
234 
235   this->Clamping = 1;
236   this->ColorSpace = VTK_CTF_RGB;
237   this->HSVWrap = 1; //By default HSV will be wrap
238 
239   this->Scale = VTK_CTF_LINEAR;
240 
241   this->NanColor[0] = 0.5;
242   this->NanColor[1] = 0.0;
243   this->NanColor[2] = 0.0;
244 
245   this->BelowRangeColor[0] = 0.0;
246   this->BelowRangeColor[1] = 0.0;
247   this->BelowRangeColor[2] = 0.0;
248 
249   this->UseBelowRangeColor = 0;
250 
251   this->AboveRangeColor[0] = 1.0;
252   this->AboveRangeColor[1] = 1.0;
253   this->AboveRangeColor[2] = 1.0;
254 
255   this->UseAboveRangeColor = 0;
256 
257   this->Function = NULL;
258 
259   this->Table = NULL;
260   this->TableSize = 0;
261 
262   this->AllowDuplicateScalars = 0;
263 
264   this->Internal = new vtkColorTransferFunctionInternals;
265 }
266 
267 //----------------------------------------------------------------------------
268 // Destruct a vtkColorTransferFunction
~vtkColorTransferFunction()269 vtkColorTransferFunction::~vtkColorTransferFunction()
270 {
271   delete [] this->Table;
272 
273   delete [] this->Function;
274   this->Function = NULL;
275 
276   for(unsigned int i=0;i<this->Internal->Nodes.size();i++)
277     {
278     delete this->Internal->Nodes[i];
279     }
280   this->Internal->Nodes.clear();
281   delete this->Internal;
282 }
283 
284 // Return the number of points which specify this function
GetSize()285 int vtkColorTransferFunction::GetSize()
286 {
287   return static_cast<int>(this->Internal->Nodes.size());
288 }
289 
290 // Since we no longer store the data in an array, we must
291 // copy out of the vector into an array. No modified check -
292 // could be added if performance is a problem
GetDataPointer()293 double *vtkColorTransferFunction::GetDataPointer()
294 {
295   int size = static_cast<int>(this->Internal->Nodes.size());
296 
297   delete [] this->Function;
298   this->Function = NULL;
299 
300   if ( size > 0 )
301     {
302     this->Function = new double[size*4];
303     for ( int i = 0; i < size; i++ )
304       {
305       this->Function[4*i  ] = this->Internal->Nodes[i]->X;
306       this->Function[4*i+1] = this->Internal->Nodes[i]->R;
307       this->Function[4*i+2] = this->Internal->Nodes[i]->G;
308       this->Function[4*i+3] = this->Internal->Nodes[i]->B;
309       }
310     }
311 
312   return this->Function;
313 }
314 
315 //----------------------------------------------------------------------------
316 // Add a point defined in RGB
AddRGBPoint(double x,double r,double g,double b)317 int vtkColorTransferFunction::AddRGBPoint( double x, double r,
318                                            double g, double b )
319 {
320   return this->AddRGBPoint( x, r, g, b, 0.5, 0.0 );
321 }
322 
323 //----------------------------------------------------------------------------
324 // Add a point defined in RGB
AddRGBPoint(double x,double r,double g,double b,double midpoint,double sharpness)325 int vtkColorTransferFunction::AddRGBPoint( double x, double r,
326                                            double g, double b,
327                                            double midpoint,
328                                            double sharpness )
329 {
330   // Error check
331   if ( midpoint < 0.0 || midpoint > 1.0 )
332     {
333     vtkErrorMacro("Midpoint outside range [0.0, 1.0]");
334     return -1;
335     }
336 
337   if ( sharpness < 0.0 || sharpness > 1.0 )
338     {
339     vtkErrorMacro("Sharpness outside range [0.0, 1.0]");
340     return -1;
341     }
342 
343   // remove any node already at this X location
344   if (!this->AllowDuplicateScalars)
345     {
346     this->RemovePoint( x );
347     }
348 
349   // Create the new node
350   vtkCTFNode *node = new vtkCTFNode;
351   node->X         = x;
352   node->R         = r;
353   node->G         = g;
354   node->B         = b;
355   node->Midpoint  = midpoint;
356   node->Sharpness = sharpness;
357 
358   // Add it, then sort to get everything in order
359   this->Internal->Nodes.push_back(node);
360   this->SortAndUpdateRange();
361 
362   // We need to find the index of the node we just added in order
363   // to return this value
364   unsigned int i;
365   for ( i = 0; i < this->Internal->Nodes.size(); i++ )
366     {
367     if ( this->Internal->Nodes[i]->X == x )
368       {
369       break;
370       }
371     }
372 
373   int retVal;
374 
375   // If we didn't find it, something went horribly wrong so
376   // return -1
377   if ( i < this->Internal->Nodes.size() )
378     {
379     retVal = i;
380     }
381   else
382     {
383     retVal = -1;
384     }
385 
386   return retVal;
387 }
388 
389 //----------------------------------------------------------------------------
390 // Add a point defined in HSV
AddHSVPoint(double x,double h,double s,double v)391 int vtkColorTransferFunction::AddHSVPoint( double x, double h,
392                                             double s, double v )
393 {
394   double r, b, g;
395 
396   vtkMath::HSVToRGB(h, s, v, &r, &g, &b);
397   return this->AddRGBPoint( x, r, g, b );
398 }
399 
400 //----------------------------------------------------------------------------
401 // Add a point defined in HSV
AddHSVPoint(double x,double h,double s,double v,double midpoint,double sharpness)402 int vtkColorTransferFunction::AddHSVPoint( double x, double h,
403                                            double s, double v,
404                                            double midpoint,
405                                            double sharpness )
406 {
407   double r, b, g;
408 
409   vtkMath::HSVToRGB(h, s, v, &r, &g, &b);
410   return this->AddRGBPoint( x, r, g, b, midpoint, sharpness );
411 }
412 
413 //----------------------------------------------------------------------------
414 // Sort the vector in increasing order, then fill in
415 // the Range
SortAndUpdateRange()416 void vtkColorTransferFunction::SortAndUpdateRange()
417 {
418   std::sort( this->Internal->Nodes.begin(),
419                 this->Internal->Nodes.end(),
420                 this->Internal->CompareNodes );
421   bool modifiedInvoked = this->UpdateRange();
422   // If range is updated, Modified() has been called, don't call it again.
423   if (!modifiedInvoked)
424     {
425     this->Modified();
426     }
427 }
428 
429 //----------------------------------------------------------------------------
UpdateRange()430 bool vtkColorTransferFunction::UpdateRange()
431 {
432   double oldRange[2];
433   oldRange[0] = this->Range[0];
434   oldRange[1] = this->Range[1];
435 
436   int size = static_cast<int>(this->Internal->Nodes.size());
437   if ( size )
438     {
439     this->Range[0] = this->Internal->Nodes[0]->X;
440     this->Range[1] = this->Internal->Nodes[size-1]->X;
441     }
442   else
443     {
444     this->Range[0] = 0;
445     this->Range[1] = 0;
446     }
447 
448   // If the range is the same, then no need to call Modified()
449   if (oldRange[0] == this->Range[0] && oldRange[1] == this->Range[1])
450     {
451     return false;
452     }
453 
454   this->Modified();
455   return true;
456 }
457 
458 //----------------------------------------------------------------------------
459 // Remove a point
RemovePoint(double x)460 int vtkColorTransferFunction::RemovePoint( double x )
461 {
462   // First find the node since we need to know its
463   // index as our return value
464   unsigned int i;
465   for ( i = 0; i < this->Internal->Nodes.size(); i++ )
466     {
467     if ( this->Internal->Nodes[i]->X == x )
468       {
469       break;
470       }
471     }
472 
473   int retVal;
474 
475   // If the node doesn't exist, we return -1
476   if ( i < this->Internal->Nodes.size() )
477     {
478     retVal = i;
479     }
480   else
481     {
482     return -1;
483     }
484 
485   // Now use STL to find it, so that we can remove it
486   this->Internal->FindNodeEqual.X = x;
487 
488   std::vector<vtkCTFNode*>::iterator iter =
489     std::find_if(this->Internal->Nodes.begin(),
490                     this->Internal->Nodes.end(),
491                     this->Internal->FindNodeEqual );
492 
493   // Actually delete it
494   if ( iter != this->Internal->Nodes.end() )
495     {
496     delete *iter;
497     this->Internal->Nodes.erase(iter);
498     // If the first or last point has been removed, then we update the range
499     // No need to sort here as the order of points hasn't changed.
500     bool modifiedInvoked = false;
501     if (i == 0 || i == this->Internal->Nodes.size())
502       {
503       modifiedInvoked = this->UpdateRange();
504       }
505     if (!modifiedInvoked)
506       {
507       this->Modified();
508       }
509     }
510   else
511      {
512      // This should never happen - we already returned if the node
513      // didn't exist...
514      return -1;
515      }
516 
517 
518   return retVal;
519 }
520 
521 
522 //----------------------------------------------------------------------------
MovePoint(double oldX,double newX)523 void vtkColorTransferFunction::MovePoint(double oldX, double newX)
524 {
525   if (oldX == newX)
526     {
527     // Nothing to do.
528     return;
529     }
530 
531   this->RemovePoint(newX);
532   for (unsigned int i = 0; i < this->Internal->Nodes.size(); i++ )
533     {
534     if ( this->Internal->Nodes[i]->X == oldX )
535       {
536       this->Internal->Nodes[i]->X = newX;
537       this->SortAndUpdateRange();
538       break;
539       }
540     }
541 }
542 
543 //----------------------------------------------------------------------------
544 // Remove all points
RemoveAllPoints()545 void vtkColorTransferFunction::RemoveAllPoints()
546 {
547   for(unsigned int i=0;i<this->Internal->Nodes.size();i++)
548     {
549     delete this->Internal->Nodes[i];
550     }
551   this->Internal->Nodes.clear();
552 
553   this->SortAndUpdateRange();
554 }
555 
556 //----------------------------------------------------------------------------
557 // Add a line defined in RGB
AddRGBSegment(double x1,double r1,double g1,double b1,double x2,double r2,double g2,double b2)558 void vtkColorTransferFunction::AddRGBSegment( double x1, double r1,
559                                               double g1, double b1,
560                                               double x2, double r2,
561                                               double g2, double b2 )
562 {
563   int done;
564 
565   // First, find all points in this range and remove them
566   done = 0;
567   while ( !done )
568     {
569     done = 1;
570 
571     this->Internal->FindNodeInRange.X1 = x1;
572     this->Internal->FindNodeInRange.X2 = x2;
573 
574     std::vector<vtkCTFNode*>::iterator iter =
575       std::find_if(this->Internal->Nodes.begin(),
576                       this->Internal->Nodes.end(),
577                       this->Internal->FindNodeInRange );
578 
579     if ( iter != this->Internal->Nodes.end() )
580       {
581       delete *iter;
582       this->Internal->Nodes.erase(iter);
583       this->Modified();
584       done = 0;
585       }
586     }
587 
588   // Now add the points
589   this->AddRGBPoint( x1, r1, g1, b1, 0.5, 0.0 );
590   this->AddRGBPoint( x2, r2, g2, b2, 0.5, 0.0 );
591 }
592 
593 //----------------------------------------------------------------------------
594 // Add a line defined in HSV
AddHSVSegment(double x1,double h1,double s1,double v1,double x2,double h2,double s2,double v2)595 void vtkColorTransferFunction::AddHSVSegment( double x1, double h1,
596                                               double s1, double v1,
597                                               double x2, double h2,
598                                               double s2, double v2 )
599 {
600   double r1, r2, b1, b2, g1, g2;
601 
602   vtkMath::HSVToRGB(h1, s1, v1, &r1, &g1, &b1);
603   vtkMath::HSVToRGB(h2, s2, v2, &r2, &g2, &b2);
604   this->AddRGBSegment( x1, r1, g1, b1, x2, r2, g2, b2 );
605 }
606 
607 //----------------------------------------------------------------------------
608 // Returns the RGBA color evaluated at the specified location
MapValue(double x)609 unsigned char *vtkColorTransferFunction::MapValue( double x )
610 {
611   double rgb[3];
612   this->GetColor( x, rgb );
613 
614   this->UnsignedCharRGBAValue[0] =
615     static_cast<unsigned char>(255.0*rgb[0] + 0.5);
616   this->UnsignedCharRGBAValue[1] =
617     static_cast<unsigned char>(255.0*rgb[1] + 0.5);
618   this->UnsignedCharRGBAValue[2] =
619     static_cast<unsigned char>(255.0*rgb[2] + 0.5);
620   this->UnsignedCharRGBAValue[3] = 255;
621   return this->UnsignedCharRGBAValue;
622 }
623 
624 //----------------------------------------------------------------------------
625 // Returns the RGB color evaluated at the specified location
GetColor(double x,double rgb[3])626 void vtkColorTransferFunction::GetColor(double x, double rgb[3])
627 {
628   if ( this->IndexedLookup )
629     {
630     int numNodes = this->GetSize();
631     vtkVariant xv( x );
632     vtkIdType idx = this->GetAnnotatedValueIndexInternal( xv );
633     if ( idx < 0 || numNodes == 0 )
634       {
635       this->GetNanColor( rgb );
636       }
637     else
638       {
639       double nodeVal[6];
640       this->GetNodeValue( idx % numNodes, nodeVal );
641       for ( int i = 0; i < 3; ++ i )
642         rgb[i] = nodeVal[i + 1];
643       }
644     return;
645     }
646   this->GetTable( x, x, 1, rgb );
647 }
648 
649 //----------------------------------------------------------------------------
650 // Returns the red color evaluated at the specified location
GetRedValue(double x)651 double vtkColorTransferFunction::GetRedValue( double x )
652 {
653   double rgb[3];
654   this->GetColor( x, rgb );
655 
656   return rgb[0];
657 }
658 
659 //----------------------------------------------------------------------------
660 // Returns the green color evaluated at the specified location
GetGreenValue(double x)661 double vtkColorTransferFunction::GetGreenValue( double x )
662 {
663   double rgb[3];
664   this->GetColor( x, rgb );
665 
666   return rgb[1];
667 }
668 
669 //----------------------------------------------------------------------------
670 // Returns the blue color evaluated at the specified location
GetBlueValue(double x)671 double vtkColorTransferFunction::GetBlueValue( double x )
672 {
673   double rgb[3];
674   this->GetColor( x, rgb );
675 
676   return rgb[2];
677 }
678 
679 //----------------------------------------------------------------------------
680 // Returns a table of RGB colors at regular intervals along the function
GetTable(double xStart,double xEnd,int size,double * table)681 void vtkColorTransferFunction::GetTable( double xStart, double xEnd,
682                                          int size, double* table )
683 {
684   int i, j;
685 
686   // Special case: If either the start or end is a NaN, then all any
687   // interpolation done on them is also a NaN.  Therefore, fill the table with
688   // the NaN color.
689   if (vtkMath::IsNan(xStart) || vtkMath::IsNan(xEnd))
690     {
691     double *tableEntry = table;
692     for (i = 0; i < size; i++)
693       {
694       tableEntry[0] = this->NanColor[0];
695       tableEntry[1] = this->NanColor[1];
696       tableEntry[2] = this->NanColor[2];
697       tableEntry += 3;
698       }
699     return;
700     }
701 
702   int idx = 0;
703   int numNodes = static_cast<int>(this->Internal->Nodes.size());
704 
705   // Need to keep track of the last value so that
706   // we can fill in table locations past this with
707   // this value if Clamping is On.
708   double lastR = 0.0;
709   double lastG = 0.0;
710   double lastB = 0.0;
711   if ( numNodes != 0 )
712     {
713     lastR = this->Internal->Nodes[numNodes-1]->R;
714     lastG = this->Internal->Nodes[numNodes-1]->G;
715     lastB = this->Internal->Nodes[numNodes-1]->B;
716     }
717 
718   double *tptr     = NULL;
719   double x         = 0.0;
720   double x1        = 0.0;
721   double x2        = 0.0;
722   double rgb1[3]   = {0.0, 0.0, 0.0};
723   double rgb2[3]   = {0.0, 0.0, 0.0};
724   double midpoint  = 0.0;
725   double sharpness = 0.0;
726 
727   // If the scale is logarithmic, make sure the range is valid.
728   bool usingLogScale = this->Scale == VTK_CTF_LOG10;
729   if(usingLogScale)
730     {
731     // Note: This requires range[0] <= range[1].
732     usingLogScale = this->Range[0] > 0.0;
733     }
734 
735   double logStart = 0.0;
736   double logEnd   = 0.0;
737   double logX     = 0.0;
738   if(usingLogScale)
739     {
740     logStart = log10(xStart);
741     logEnd = log10(xEnd);
742     }
743 
744   // For each table entry
745   for ( i = 0; i < size; i++ )
746     {
747 
748     // Find our location in the table
749     tptr = table + 3*i;
750 
751     // Find our X location. If we are taking only 1 sample, make
752     // it halfway between start and end (usually start and end will
753     // be the same in this case)
754     if ( size > 1 )
755       {
756       if(usingLogScale)
757         {
758         logX = logStart +
759           (static_cast<double>(i)/static_cast<double>(size-1))
760           *(logEnd-logStart);
761         x = pow(static_cast<double>(10.0), logX);
762         }
763       else
764         {
765         x = xStart + (static_cast<double>(i)/static_cast<double>(size-1))
766           *(xEnd-xStart);
767         }
768       }
769     else
770       {
771       if(usingLogScale)
772         {
773         logX = 0.5*(logStart+logEnd);
774         x = pow(static_cast<double>(10.0), logX);
775         }
776       else
777         {
778         x = 0.5*(xStart+xEnd);
779         }
780       }
781 
782     // Do we need to move to the next node?
783     while ( idx < numNodes &&
784             x > this->Internal->Nodes[idx]->X )
785       {
786       idx++;
787       // If we are at a valid point index, fill in
788       // the value at this node, and the one before (the
789       // two that surround our current sample location)
790       // idx cannot be 0 since we just incremented it.
791       if ( idx < numNodes )
792         {
793         x1 = this->Internal->Nodes[idx-1]->X;
794         x2 = this->Internal->Nodes[idx  ]->X;
795         if(usingLogScale)
796           {
797           x1 = log10(x1);
798           x2 = log10(x2);
799           }
800 
801         rgb1[0] = this->Internal->Nodes[idx-1]->R;
802         rgb2[0] = this->Internal->Nodes[idx  ]->R;
803 
804         rgb1[1] = this->Internal->Nodes[idx-1]->G;
805         rgb2[1] = this->Internal->Nodes[idx  ]->G;
806 
807         rgb1[2] = this->Internal->Nodes[idx-1]->B;
808         rgb2[2] = this->Internal->Nodes[idx  ]->B;
809 
810         // We only need the previous midpoint and sharpness
811         // since these control this region
812         midpoint  = this->Internal->Nodes[idx-1]->Midpoint;
813         sharpness = this->Internal->Nodes[idx-1]->Sharpness;
814 
815         // Move midpoint away from extreme ends of range to avoid
816         // degenerate math
817         if ( midpoint < 0.00001 )
818           {
819           midpoint = 0.00001;
820           }
821 
822         if ( midpoint > 0.99999 )
823           {
824           midpoint = 0.99999;
825           }
826         }
827       }
828 
829     // Are we at or past the end? If so, just use the last value
830     if ( x > this->Range[1])
831       {
832       if (this->Clamping)
833         {
834         if (this->GetUseAboveRangeColor())
835           {
836           this->GetAboveRangeColor(tptr);
837           }
838         else
839           {
840           tptr[0] = lastR;
841           tptr[1] = lastG;
842           tptr[2] = lastB;
843           }
844         }
845       else
846         {
847         tptr[0] = 0.0;
848         tptr[1] = 0.0;
849         tptr[2] = 0.0;
850         }
851       }
852     // Are we before the first node? If so, duplicate this node's values.
853     // We have to deal with -inf here
854     else if (x < this->Range[0] || (vtkMath::IsInf(x) && x < 0))
855       {
856       if (this->Clamping)
857         {
858         if (this->GetUseBelowRangeColor())
859           {
860           this->GetBelowRangeColor(tptr);
861           }
862         else
863           {
864           tptr[0] = this->Internal->Nodes[0]->R;
865           tptr[1] = this->Internal->Nodes[0]->G;
866           tptr[2] = this->Internal->Nodes[0]->B;
867           }
868         }
869       else
870         {
871         tptr[0] = 0.0;
872         tptr[1] = 0.0;
873         tptr[2] = 0.0;
874         }
875       }
876     else if (idx == 0 && std::fabs(x - xStart) < 1e-6)
877       {
878       tptr[0] = this->Internal->Nodes[0]->R;
879       tptr[1] = this->Internal->Nodes[0]->G;
880       tptr[2] = this->Internal->Nodes[0]->B;
881       }
882     // Otherwise, we are between two nodes - interpolate
883     else
884       {
885       // Our first attempt at a normalized location [0,1] -
886       // we will be modifying this based on midpoint and
887       // sharpness to get the curve shape we want and to have
888       // it pass through (y1+y2)/2 at the midpoint.
889       double s = 0.0;
890       if(usingLogScale)
891         {
892         s = (logX - x1) / (x2 - x1);
893         }
894       else
895         {
896         s = (x - x1) / (x2 - x1);
897         }
898 
899       // Readjust based on the midpoint - linear adjustment
900       if ( s < midpoint )
901         {
902         s = 0.5 * s / midpoint;
903         }
904       else
905         {
906         s = 0.5 + 0.5*(s-midpoint)/(1.0-midpoint);
907         }
908 
909       // override for sharpness > 0.99
910       // In this case we just want piecewise constant
911       if ( sharpness > 0.99 )
912         {
913         // Use the first value since we are below the midpoint
914         if ( s < 0.5 )
915           {
916           tptr[0] = rgb1[0];
917           tptr[1] = rgb1[1];
918           tptr[2] = rgb1[2];
919           continue;
920           }
921         // Use the second value at or above the midpoint
922         else
923           {
924           tptr[0] = rgb2[0];
925           tptr[1] = rgb2[1];
926           tptr[2] = rgb2[2];
927           continue;
928           }
929         }
930 
931       // Override for sharpness < 0.01
932       // In this case we want piecewise linear
933       if ( sharpness < 0.01 )
934         {
935         // Simple linear interpolation
936         if ( this->ColorSpace == VTK_CTF_RGB )
937           {
938           tptr[0] = (1-s)*rgb1[0] + s*rgb2[0];
939           tptr[1] = (1-s)*rgb1[1] + s*rgb2[1];
940           tptr[2] = (1-s)*rgb1[2] + s*rgb2[2];
941           }
942         else if ( this->ColorSpace == VTK_CTF_HSV )
943           {
944           double hsv1[3], hsv2[3];
945           vtkMath::RGBToHSV(rgb1, hsv1);
946           vtkMath::RGBToHSV(rgb2, hsv2);
947 
948           if ( this->HSVWrap &&
949                (hsv1[0] - hsv2[0] > 0.5 ||
950                 hsv2[0] - hsv1[0] > 0.5) )
951             {
952             if ( hsv1[0] > hsv2[0] )
953               {
954               hsv1[0] -= 1.0;
955               }
956             else
957               {
958               hsv2[0] -= 1.0;
959               }
960             }
961 
962           double hsvTmp[3];
963           hsvTmp[0] = (1-s)*hsv1[0] + s*hsv2[0];
964           if ( hsvTmp[0] < 0.0 )
965             {
966             hsvTmp[0] += 1.0;
967             }
968           hsvTmp[1] = (1-s)*hsv1[1] + s*hsv2[1];
969           hsvTmp[2] = (1-s)*hsv1[2] + s*hsv2[2];
970 
971           // Now convert this back to RGB
972           vtkMath::HSVToRGB( hsvTmp, tptr );
973           }
974         else if (this->ColorSpace == VTK_CTF_LAB)
975           {
976           double lab1[3], lab2[3];
977           vtkMath::RGBToLab(rgb1, lab1);
978           vtkMath::RGBToLab(rgb2, lab2);
979 
980           double labTmp[3];
981           labTmp[0] = (1-s)*lab1[0] + s*lab2[0];
982           labTmp[1] = (1-s)*lab1[1] + s*lab2[1];
983           labTmp[2] = (1-s)*lab1[2] + s*lab2[2];
984 
985           // Now convert back to RGB
986           vtkMath::LabToRGB(labTmp, tptr);
987           }
988         else if (this->ColorSpace == VTK_CTF_DIVERGING)
989           {
990           vtkColorTransferFunctionInterpolateDiverging(s, rgb1, rgb2, tptr);
991           }
992         else
993           {
994           vtkErrorMacro("ColorSpace set to invalid value.");
995           }
996         continue;
997         }
998 
999       // We have a sharpness between [0.01, 0.99] - we will
1000       // used a modified hermite curve interpolation where we
1001       // derive the slope based on the sharpness, and we compress
1002       // the curve non-linearly based on the sharpness
1003 
1004       // First, we will adjust our position based on sharpness in
1005       // order to make the curve sharper (closer to piecewise constant)
1006       if ( s < .5 )
1007         {
1008         s = 0.5 * pow(s*2,1.0 + 10*sharpness);
1009         }
1010       else if ( s > .5 )
1011         {
1012         s = 1.0 - 0.5 * pow((1.0-s)*2,1+10*sharpness);
1013         }
1014 
1015       // Compute some coefficients we will need for the hermite curve
1016       double ss = s*s;
1017       double sss = ss*s;
1018 
1019       double h1 =  2*sss - 3*ss + 1;
1020       double h2 = -2*sss + 3*ss;
1021       double h3 =    sss - 2*ss + s;
1022       double h4 =    sss -   ss;
1023 
1024       double slope;
1025       double t;
1026 
1027       if ( this->ColorSpace == VTK_CTF_RGB )
1028         {
1029         for ( j = 0; j < 3; j++ )
1030           {
1031           // Use one slope for both end points
1032           slope = rgb2[j] - rgb1[j];
1033           t = (1.0 - sharpness)*slope;
1034 
1035           // Compute the value
1036           tptr[j] = h1*rgb1[j] + h2*rgb2[j] + h3*t + h4*t;
1037           }
1038         }
1039       else if (this->ColorSpace == VTK_CTF_HSV)
1040         {
1041         double hsv1[3], hsv2[3];
1042         vtkMath::RGBToHSV(rgb1, hsv1);
1043         vtkMath::RGBToHSV(rgb2, hsv2);
1044 
1045         if ( this->HSVWrap &&
1046              (hsv1[0] - hsv2[0] > 0.5 ||
1047               hsv2[0] - hsv1[0] > 0.5) )
1048           {
1049           if ( hsv1[0] > hsv2[0] )
1050             {
1051             hsv1[0] -= 1.0;
1052             }
1053           else
1054             {
1055             hsv2[0] -= 1.0;
1056             }
1057           }
1058 
1059         double hsvTmp[3];
1060 
1061         for ( j = 0; j < 3; j++ )
1062           {
1063           // Use one slope for both end points
1064           slope = hsv2[j] - hsv1[j];
1065           t = (1.0 - sharpness)*slope;
1066 
1067           // Compute the value
1068           hsvTmp[j] = h1*hsv1[j] + h2*hsv2[j] + h3*t + h4*t;
1069           if ( j == 0 && hsvTmp[j] < 0.0 )
1070             {
1071             hsvTmp[j] += 1.0;
1072             }
1073           }
1074         // Now convert this back to RGB
1075         vtkMath::HSVToRGB( hsvTmp, tptr );
1076         }
1077       else if (this->ColorSpace == VTK_CTF_LAB)
1078         {
1079         double lab1[3], lab2[3];
1080         vtkMath::RGBToLab(rgb1, lab1);
1081         vtkMath::RGBToLab(rgb2, lab2);
1082 
1083         double labTmp[3];
1084         for (j = 0; j < 3; j++)
1085           {
1086           // Use one slope for both end points
1087           slope = lab2[j] - lab1[j];
1088           t = (1.0 - sharpness)*slope;
1089 
1090           // Compute the value
1091           labTmp[j] = h1*lab1[j] + h2*lab2[j] + h3*t + h4*t;
1092           }
1093         // Now convert this back to RGB
1094         vtkMath::LabToRGB(labTmp, tptr);
1095         }
1096       else if (this->ColorSpace == VTK_CTF_DIVERGING)
1097         {
1098         // I have not implemented proper interpolation by a hermite curve for
1099         // the diverging color map, but I cannot think of a good use case for
1100         // that anyway.
1101         vtkColorTransferFunctionInterpolateDiverging(s, rgb1, rgb2, tptr);
1102         }
1103       else
1104         {
1105         vtkErrorMacro("ColorSpace set to invalid value.");
1106         }
1107 
1108       // Final error check to make sure we don't go outside [0,1]
1109       for ( j = 0; j < 3; j++ )
1110         {
1111         tptr[j] = (tptr[j] < 0.0)?(0.0):(tptr[j]);
1112         tptr[j] = (tptr[j] > 1.0)?(1.0):(tptr[j]);
1113         }
1114       }
1115     }
1116 }
1117 
1118 //----------------------------------------------------------------------------
GetTable(double xStart,double xEnd,int size,float * table)1119 void vtkColorTransferFunction::GetTable( double xStart, double xEnd,
1120                                          int size, float* table )
1121 {
1122   double *tmpTable = new double [size*3];
1123 
1124   this->GetTable( xStart, xEnd, size, tmpTable );
1125 
1126   double *tmpPtr = tmpTable;
1127   float *tPtr = table;
1128 
1129   for ( int i = 0; i < size*3; i++ )
1130     {
1131     *tPtr = static_cast<float>(*tmpPtr);
1132     tPtr   ++;
1133     tmpPtr ++;
1134     }
1135 
1136   delete[] tmpTable;
1137 }
1138 
1139 //----------------------------------------------------------------------------
GetTable(double xStart,double xEnd,int size)1140 const unsigned char *vtkColorTransferFunction::GetTable( double xStart,
1141                                                          double xEnd,
1142                                                          int size)
1143 {
1144   if (this->GetMTime() <= this->BuildTime &&
1145       this->TableSize == size)
1146     {
1147     return this->Table;
1148     }
1149 
1150   if ( this->Internal->Nodes.size() == 0 )
1151     {
1152     vtkErrorMacro(
1153       "Attempting to lookup a value with no points in the function");
1154     return this->Table;
1155     }
1156 
1157   if (this->TableSize != size)
1158     {
1159     delete [] this->Table;
1160     this->Table = new unsigned char [size*3];
1161     this->TableSize = size;
1162     }
1163 
1164   double *tmpTable = new double [size*3];
1165 
1166   this->GetTable( xStart, xEnd, size, tmpTable );
1167 
1168   double *tmpPtr = tmpTable;
1169   unsigned char *tPtr = this->Table;
1170 
1171   for ( int i = 0; i < size*3; i++ )
1172     {
1173     *tPtr = static_cast<unsigned char>(*tmpPtr*255.0 + 0.5);
1174     tPtr   ++;
1175     tmpPtr ++;
1176     }
1177 
1178   delete[] tmpTable;
1179 
1180   this->BuildTime.Modified();
1181 
1182   return this->Table;
1183 }
1184 
1185 //----------------------------------------------------------------------------
BuildFunctionFromTable(double xStart,double xEnd,int size,double * table)1186 void vtkColorTransferFunction::BuildFunctionFromTable(double xStart,
1187                                                       double xEnd,
1188                                                       int size,
1189                                                       double *table)
1190 {
1191   double inc = 0.0;
1192   double *tptr = table;
1193 
1194   this->RemoveAllPoints();
1195 
1196   if( size > 1 )
1197     {
1198     inc = (xEnd-xStart)/static_cast<double>(size-1);
1199     }
1200 
1201   int i;
1202   for (i=0; i < size; i++)
1203     {
1204     vtkCTFNode *node = new vtkCTFNode;
1205     node->X   = xStart + inc*i;
1206     node->R   = tptr[0];
1207     node->G   = tptr[1];
1208     node->B   = tptr[2];
1209     node->Sharpness = 0.0;
1210     node->Midpoint  = 0.5;
1211 
1212     this->Internal->Nodes.push_back(node);
1213     tptr += 3;
1214     }
1215 
1216   this->SortAndUpdateRange();
1217 }
1218 
1219 //----------------------------------------------------------------------------
1220 // For a specified index value, get the node parameters
GetNodeValue(int index,double val[6])1221 int vtkColorTransferFunction::GetNodeValue( int index, double val[6] )
1222 {
1223   int size = static_cast<int>(this->Internal->Nodes.size());
1224 
1225   if ( index < 0 || index >= size )
1226     {
1227     vtkErrorMacro("Index out of range!");
1228     return -1;
1229     }
1230 
1231   val[0] = this->Internal->Nodes[index]->X;
1232   val[1] = this->Internal->Nodes[index]->R;
1233   val[2] = this->Internal->Nodes[index]->G;
1234   val[3] = this->Internal->Nodes[index]->B;
1235   val[4] = this->Internal->Nodes[index]->Midpoint;
1236   val[5] = this->Internal->Nodes[index]->Sharpness;
1237 
1238   return 1;
1239 }
1240 
1241 //----------------------------------------------------------------------------
1242 // For a specified index value, get the node parameters
SetNodeValue(int index,double val[6])1243 int vtkColorTransferFunction::SetNodeValue( int index, double val[6] )
1244 {
1245   int size = static_cast<int>(this->Internal->Nodes.size());
1246 
1247   if ( index < 0 || index >= size )
1248     {
1249     vtkErrorMacro("Index out of range!");
1250     return -1;
1251     }
1252 
1253   double oldX = this->Internal->Nodes[index]->X;
1254   this->Internal->Nodes[index]->X = val[0];
1255   this->Internal->Nodes[index]->R = val[1];
1256   this->Internal->Nodes[index]->G = val[2];
1257   this->Internal->Nodes[index]->B = val[3];
1258   this->Internal->Nodes[index]->Midpoint = val[4];
1259   this->Internal->Nodes[index]->Sharpness = val[5];
1260 
1261   if (oldX != val[0])
1262     {
1263     // The point has been moved, the order of points or the range might have
1264     // been modified.
1265     this->SortAndUpdateRange();
1266     // No need to call Modified() here because SortAndUpdateRange() has done it
1267     // already.
1268     }
1269   else
1270     {
1271     this->Modified();
1272     }
1273 
1274   return 1;
1275 }
1276 
1277 //----------------------------------------------------------------------------
DeepCopy(vtkScalarsToColors * o)1278 void vtkColorTransferFunction::DeepCopy( vtkScalarsToColors *o )
1279 {
1280   vtkColorTransferFunction *f = NULL;
1281   if (o)
1282     {
1283     this->Superclass::DeepCopy(o);
1284     f = vtkColorTransferFunction::SafeDownCast(o);
1285     }
1286 
1287   if (f != NULL)
1288     {
1289     this->Clamping     = f->Clamping;
1290     this->ColorSpace   = f->ColorSpace;
1291     this->HSVWrap      = f->HSVWrap;
1292     this->Scale        = f->Scale;
1293 
1294     int i;
1295     this->RemoveAllPoints();
1296     for ( i = 0; i < f->GetSize(); i++ )
1297       {
1298       double val[6];
1299       f->GetNodeValue(i, val);
1300       this->AddRGBPoint(val[0], val[1], val[2], val[3], val[4], val[5]);
1301       }
1302     this->Modified();
1303     }
1304 }
1305 
1306 //----------------------------------------------------------------------------
ShallowCopy(vtkColorTransferFunction * f)1307 void vtkColorTransferFunction::ShallowCopy( vtkColorTransferFunction *f )
1308 {
1309   if (f != NULL)
1310     {
1311     this->Superclass::DeepCopy(f);
1312 
1313     this->Clamping     = f->Clamping;
1314     this->ColorSpace   = f->ColorSpace;
1315     this->HSVWrap      = f->HSVWrap;
1316     this->Scale        = f->Scale;
1317 
1318     int i;
1319     this->RemoveAllPoints();
1320     for ( i = 0; i < f->GetSize(); i++ )
1321       {
1322       double val[6];
1323       f->GetNodeValue(i, val);
1324       this->AddRGBPoint(val[0], val[1], val[2], val[3], val[4], val[5]);
1325       }
1326     this->Modified();
1327     }
1328 }
1329 
1330 //----------------------------------------------------------------------------
1331 // Accelerate the mapping by copying the data in 32-bit chunks instead
1332 // of 8-bit chunks.  The extra "long" argument is to help broken
1333 // compilers select the non-templates below for unsigned char
1334 // and unsigned short.
1335 template <class T>
vtkColorTransferFunctionMapData(vtkColorTransferFunction * self,T * input,unsigned char * output,int length,int inIncr,int outFormat,long)1336 void vtkColorTransferFunctionMapData(vtkColorTransferFunction* self,
1337                                      T* input,
1338                                      unsigned char* output,
1339                                      int length, int inIncr,
1340                                      int outFormat, long)
1341 {
1342   double         x;
1343   int            i = length;
1344   double         rgb[3];
1345   unsigned char *optr = output;
1346   T             *iptr = input;
1347   unsigned char  alpha = static_cast<unsigned char>(self->GetAlpha()*255.0);
1348 
1349   if(self->GetSize() == 0)
1350     {
1351     vtkGenericWarningMacro("Transfer Function Has No Points!");
1352     return;
1353     }
1354 
1355   while (--i >= 0)
1356     {
1357     x = static_cast<double>(*iptr);
1358     self->GetColor(x, rgb);
1359 
1360     if (outFormat == VTK_RGB || outFormat == VTK_RGBA)
1361       {
1362       *(optr++) = static_cast<unsigned char>(rgb[0]*255.0 + 0.5);
1363       *(optr++) = static_cast<unsigned char>(rgb[1]*255.0 + 0.5);
1364       *(optr++) = static_cast<unsigned char>(rgb[2]*255.0 + 0.5);
1365       }
1366     else // LUMINANCE  use coeffs of (0.30  0.59  0.11)*255.0
1367       {
1368       *(optr++) = static_cast<unsigned char>(rgb[0]*76.5 + rgb[1]*150.45 +
1369                                              rgb[2]*28.05 + 0.5);
1370       }
1371 
1372     if (outFormat == VTK_RGBA || outFormat == VTK_LUMINANCE_ALPHA)
1373       {
1374       *(optr++) = alpha;
1375       }
1376     iptr += inIncr;
1377     }
1378 }
1379 
1380 
1381 
1382 //----------------------------------------------------------------------------
1383 // Special implementation for unsigned char input.
vtkColorTransferFunctionMapData(vtkColorTransferFunction * self,unsigned char * input,unsigned char * output,int length,int inIncr,int outFormat,int)1384 static void vtkColorTransferFunctionMapData(vtkColorTransferFunction* self,
1385                                      unsigned char* input,
1386                                      unsigned char* output,
1387                                      int length, int inIncr,
1388                                      int outFormat, int)
1389 {
1390   int            x;
1391   int            i = length;
1392   unsigned char  *optr = output;
1393   unsigned char  *iptr = input;
1394 
1395   if(self->GetSize() == 0)
1396     {
1397     vtkGenericWarningMacro("Transfer Function Has No Points!");
1398     return;
1399     }
1400 
1401   const unsigned char *table = self->GetTable(0,255,256);
1402   switch (outFormat)
1403     {
1404     case VTK_RGB:
1405       while (--i >= 0)
1406         {
1407         x = *iptr*3;
1408         *(optr++) = table[x];
1409         *(optr++) = table[x+1];
1410         *(optr++) = table[x+2];
1411         iptr += inIncr;
1412         }
1413       break;
1414     case VTK_RGBA:
1415       while (--i >= 0)
1416         {
1417         x = *iptr*3;
1418         *(optr++) = table[x];
1419         *(optr++) = table[x+1];
1420         *(optr++) = table[x+2];
1421         *(optr++) = 255;
1422         iptr += inIncr;
1423         }
1424       break;
1425     case VTK_LUMINANCE_ALPHA:
1426       while (--i >= 0)
1427         {
1428         x = *iptr*3;
1429         *(optr++) = table[x];
1430         *(optr++) = 255;
1431         iptr += inIncr;
1432         }
1433       break;
1434     case VTK_LUMINANCE:
1435       while (--i >= 0)
1436         {
1437         x = *iptr*3;
1438         *(optr++) = table[x];
1439         iptr += inIncr;
1440         }
1441       break;
1442     }
1443 }
1444 
1445 //----------------------------------------------------------------------------
1446 // Special implementation for unsigned short input.
vtkColorTransferFunctionMapData(vtkColorTransferFunction * self,unsigned short * input,unsigned char * output,int length,int inIncr,int outFormat,int)1447 static void vtkColorTransferFunctionMapData(vtkColorTransferFunction* self,
1448                                             unsigned short* input,
1449                                             unsigned char* output,
1450                                             int length, int inIncr,
1451                                             int outFormat, int)
1452 {
1453   int            x;
1454   int            i = length;
1455   unsigned char  *optr = output;
1456   unsigned short *iptr = input;
1457 
1458   if(self->GetSize() == 0)
1459     {
1460     vtkGenericWarningMacro("Transfer Function Has No Points!");
1461     return;
1462     }
1463 
1464 
1465   const unsigned char *table = self->GetTable(0,65535,65536);
1466   switch (outFormat)
1467     {
1468     case VTK_RGB:
1469       while (--i >= 0)
1470         {
1471         x = *iptr*3;
1472         *(optr++) = table[x];
1473         *(optr++) = table[x+1];
1474         *(optr++) = table[x+2];
1475         iptr += inIncr;
1476         }
1477       break;
1478     case VTK_RGBA:
1479       while (--i >= 0)
1480         {
1481         x = *iptr*3;
1482         *(optr++) = table[x];
1483         *(optr++) = table[x+1];
1484         *(optr++) = table[x+2];
1485         *(optr++) = 255;
1486         iptr += inIncr;
1487         }
1488       break;
1489     case VTK_LUMINANCE_ALPHA:
1490       while (--i >= 0)
1491         {
1492         x = *iptr*3;
1493         *(optr++) = table[x];
1494         *(optr++) = 255;
1495         iptr += inIncr;
1496         }
1497       break;
1498     case VTK_LUMINANCE:
1499       while (--i >= 0)
1500         {
1501         x = *iptr*3;
1502         *(optr++) = table[x];
1503         iptr += inIncr;
1504         }
1505       break;
1506     }
1507 }
1508 
1509 //----------------------------------------------------------------------------
1510 template<class T>
vtkColorTransferFunctionIndexedMapData(vtkColorTransferFunction * self,T * input,unsigned char * output,int length,int inIncr,int outFormat,long)1511 void vtkColorTransferFunctionIndexedMapData(
1512   vtkColorTransferFunction* self, T* input, unsigned char* output, int length,
1513   int inIncr, int outFormat, long )
1514 {
1515   int i = length;
1516   double nodeVal[6];
1517   double alpha;
1518   int numNodes = self->GetSize();
1519 
1520   vtkVariant vin;
1521   if ( (alpha=self->GetAlpha()) >= 1.0 ) //no blending required
1522     {
1523     if (outFormat == VTK_RGBA)
1524       {
1525       while (--i >= 0)
1526         {
1527         vin = *input;
1528         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1529         if ( idx < 0 || numNodes == 0 )
1530           self->GetNanColor( &nodeVal[1] );
1531         else
1532           self->GetNodeValue( idx % numNodes, nodeVal );
1533 
1534         output[0] = static_cast<unsigned char>(255. * nodeVal[1]);
1535         output[1] = static_cast<unsigned char>(255. * nodeVal[2]);
1536         output[2] = static_cast<unsigned char>(255. * nodeVal[3]);
1537         output[3] = static_cast<unsigned char>(255.); // * nodeVal[3];
1538         input += inIncr;
1539         output += 4;
1540         }
1541       }
1542     else if (outFormat == VTK_RGB)
1543       {
1544       while (--i >= 0)
1545         {
1546         vin = *input;
1547         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1548         if ( idx < 0 || numNodes == 0 )
1549           self->GetNanColor( &nodeVal[1] );
1550         else
1551           self->GetNodeValue( idx % numNodes, nodeVal );
1552 
1553         output[0] = static_cast<unsigned char>(255. * nodeVal[1]);
1554         output[1] = static_cast<unsigned char>(255. * nodeVal[2]);
1555         output[2] = static_cast<unsigned char>(255. * nodeVal[3]);
1556         input += inIncr;
1557         output += 3;
1558         }
1559       }
1560     else if (outFormat == VTK_LUMINANCE_ALPHA)
1561       {
1562       while (--i >= 0)
1563         {
1564         vin = *input;
1565         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1566         if ( idx < 0 || numNodes == 0 )
1567           self->GetNanColor( &nodeVal[1] );
1568         else
1569           self->GetNodeValue( idx % numNodes, nodeVal );
1570         output[0] = static_cast<unsigned char>(255. * nodeVal[1]*0.30 + 255. * nodeVal[2]*0.59 +
1571                                                255. * nodeVal[3]*0.11 + 0.5);
1572         output[1] = static_cast<unsigned char>(255. * nodeVal[3]);
1573         input += inIncr;
1574         output += 2;
1575         }
1576       }
1577     else // outFormat == VTK_LUMINANCE
1578       {
1579       while (--i >= 0)
1580         {
1581         vin = *input;
1582         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1583         if ( idx < 0 || numNodes == 0 )
1584           self->GetNanColor( &nodeVal[1] );
1585         else
1586           self->GetNodeValue( idx % numNodes, nodeVal );
1587         *output++ = static_cast<unsigned char>(255. * nodeVal[1]*0.30 + 255. * nodeVal[2]*0.59 +
1588                                                255. * nodeVal[3]*0.11 + 0.5);
1589         input += inIncr;
1590         }
1591       }
1592     } // if blending not needed
1593 
1594   else // blend with the specified alpha
1595     {
1596     if (outFormat == VTK_RGBA)
1597       {
1598       while (--i >= 0)
1599         {
1600         vin = *input;
1601         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1602         if ( idx < 0 || numNodes == 0 )
1603           self->GetNanColor( &nodeVal[1] );
1604         else
1605           self->GetNodeValue( idx % numNodes, nodeVal );
1606         output[0] = static_cast<unsigned char>(255. * nodeVal[1]);
1607         output[1] = static_cast<unsigned char>(255. * nodeVal[2]);
1608         output[2] = static_cast<unsigned char>(255. * nodeVal[3]);
1609         output[3] = static_cast<unsigned char>(255. * /*nodeVal[3]*/alpha + 0.5);
1610         input += inIncr;
1611         output += 4;
1612         }
1613       }
1614     else if (outFormat == VTK_RGB)
1615       {
1616       while (--i >= 0)
1617         {
1618         vin = *input;
1619         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1620         if ( idx < 0 || numNodes == 0 )
1621           self->GetNanColor( &nodeVal[1] );
1622         else
1623           self->GetNodeValue( idx % numNodes, nodeVal );
1624         output[0] = static_cast<unsigned char>(255. * nodeVal[1]);
1625         output[1] = static_cast<unsigned char>(255. * nodeVal[2]);
1626         output[2] = static_cast<unsigned char>(255. * nodeVal[3]);
1627         input += inIncr;
1628         output += 3;
1629         }
1630       }
1631     else if (outFormat == VTK_LUMINANCE_ALPHA)
1632       {
1633       while (--i >= 0)
1634         {
1635         vin = *input;
1636         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1637         if ( idx < 0 || numNodes == 0 )
1638           self->GetNanColor( &nodeVal[1] );
1639         else
1640           self->GetNodeValue( idx % numNodes, nodeVal );
1641         output[0] = static_cast<unsigned char>(255. * nodeVal[1]*0.30 + 255. * nodeVal[2]*0.59 +
1642                                                255. * nodeVal[3]*0.11 + 0.5);
1643         output[1] = static_cast<unsigned char>(255. * /*nodeVal[3]*/alpha + 0.5);
1644         input += inIncr;
1645         output += 2;
1646         }
1647       }
1648     else // outFormat == VTK_LUMINANCE
1649       {
1650       while (--i >= 0)
1651         {
1652         vin = *input;
1653         vtkIdType idx = self->GetAnnotatedValueIndexInternal( vin );
1654         if ( idx < 0 || numNodes == 0 )
1655           self->GetNanColor( &nodeVal[1] );
1656         else
1657           self->GetNodeValue( idx % numNodes, nodeVal );
1658         *output++ = static_cast<unsigned char>(255. * nodeVal[1]*0.30 + 255. * nodeVal[2]*0.59 +
1659                                                255. * nodeVal[3]*0.11 + 0.5);
1660         input += inIncr;
1661         }
1662       }
1663     } // alpha blending
1664 }
1665 
1666 //----------------------------------------------------------------------------
MapScalarsThroughTable2(void * input,unsigned char * output,int inputDataType,int numberOfValues,int inputIncrement,int outputFormat)1667 void vtkColorTransferFunction::MapScalarsThroughTable2(void *input,
1668                                                        unsigned char *output,
1669                                                        int inputDataType,
1670                                                        int numberOfValues,
1671                                                        int inputIncrement,
1672                                                        int outputFormat)
1673 {
1674   if(this->GetSize() == 0)
1675     {
1676     vtkDebugMacro("Transfer Function Has No Points!");
1677     return;
1678     }
1679   if ( this->IndexedLookup )
1680     {
1681     switch (inputDataType)
1682       {
1683       // Use vtkExtendedTemplateMacro to cover case of VTK_STRING input
1684       vtkExtendedTemplateMacro(
1685         vtkColorTransferFunctionIndexedMapData(
1686           this, static_cast<VTK_TT*>(input),
1687           output, numberOfValues, inputIncrement,
1688           outputFormat, 1)
1689         );
1690 
1691       default:
1692         vtkErrorMacro(<< "MapImageThroughTable: Unknown input ScalarType");
1693         return;
1694       }
1695     }
1696   else
1697     {
1698     switch (inputDataType)
1699       {
1700       vtkTemplateMacro(
1701         vtkColorTransferFunctionMapData(this, static_cast<VTK_TT*>(input),
1702                                         output, numberOfValues, inputIncrement,
1703                                         outputFormat, 1)
1704         );
1705       default:
1706         vtkErrorMacro(<< "MapImageThroughTable: Unknown input ScalarType");
1707         return;
1708       }
1709     }
1710 }
1711 
1712 //----------------------------------------------------------------------------
GetNumberOfAvailableColors()1713 vtkIdType vtkColorTransferFunction::GetNumberOfAvailableColors()
1714 {
1715   if ( this->IndexedLookup && this->GetSize() )
1716     {
1717     return this->GetSize();
1718     }
1719   if(this->Table)
1720     {
1721     // Not sure if this is correct since it is only set if
1722     // "const unsigned char *::GetTable( double xStart, double xEnd,int size)"
1723     // has been called.
1724     return static_cast<vtkIdType>(this->TableSize);
1725     }
1726   return 16777216;  //2^24
1727 }
1728 
1729 //----------------------------------------------------------------------------
GetIndexedColor(vtkIdType idx,double rgba[4])1730 void vtkColorTransferFunction::GetIndexedColor(vtkIdType idx, double rgba[4])
1731 {
1732   vtkIdType n = this->GetSize();
1733   if (n > 0 && idx >= 0)
1734     {
1735     double nodeValue[6];
1736     this->GetNodeValue(idx % n, nodeValue);
1737     for (int j = 0; j < 3; ++j)
1738       {
1739       rgba[j] = nodeValue[j+1];
1740       }
1741     rgba[3] = 1.0; // NodeColor is RGB-only.
1742     return;
1743     }
1744   this->GetNanColor(rgba);
1745   rgba[3] = 1.0; // NanColor is RGB-only.
1746 }
1747 
1748 //----------------------------------------------------------------------------
FillFromDataPointer(int nb,double * ptr)1749 void vtkColorTransferFunction::FillFromDataPointer(int nb, double *ptr)
1750 {
1751   if (nb <= 0 || !ptr)
1752     {
1753     return;
1754     }
1755 
1756   this->RemoveAllPoints();
1757 
1758   while (nb)
1759     {
1760     this->AddRGBPoint(ptr[0], ptr[1], ptr[2], ptr[3]);
1761     ptr += 4;
1762     nb--;
1763     }
1764 }
1765 
1766 //----------------------------------------------------------------------------
AdjustRange(double range[2])1767 int vtkColorTransferFunction::AdjustRange(double range[2])
1768 {
1769   if (!range)
1770     {
1771     return 0;
1772     }
1773 
1774   double *function_range = this->GetRange();
1775 
1776   // Make sure we have points at each end of the range
1777 
1778   double rgb[3];
1779   if (function_range[0] < range[0])
1780     {
1781     this->GetColor(range[0], rgb);
1782     this->AddRGBPoint(range[0], rgb[0], rgb[1], rgb[2]);
1783     }
1784   else
1785     {
1786     this->GetColor(function_range[0], rgb);
1787     this->AddRGBPoint(range[0], rgb[0], rgb[1], rgb[2]);
1788     }
1789 
1790   if (function_range[1] > range[1])
1791     {
1792     this->GetColor(range[1], rgb);
1793     this->AddRGBPoint(range[1], rgb[0], rgb[1], rgb[2]);
1794     }
1795   else
1796     {
1797     this->GetColor(function_range[1], rgb);
1798     this->AddRGBPoint(range[1], rgb[0], rgb[1], rgb[2]);
1799     }
1800 
1801   // Remove all points out-of-range
1802   int done;
1803 
1804   done = 0;
1805   while ( !done )
1806     {
1807     done = 1;
1808 
1809     this->Internal->FindNodeOutOfRange.X1 = range[0];
1810     this->Internal->FindNodeOutOfRange.X2 = range[1];
1811 
1812     std::vector<vtkCTFNode*>::iterator iter =
1813       std::find_if(this->Internal->Nodes.begin(),
1814                       this->Internal->Nodes.end(),
1815                       this->Internal->FindNodeOutOfRange );
1816 
1817     if ( iter != this->Internal->Nodes.end() )
1818       {
1819       delete *iter;
1820       this->Internal->Nodes.erase(iter);
1821       this->Modified();
1822       done = 0;
1823       }
1824     }
1825 
1826   this->SortAndUpdateRange();
1827 
1828 
1829   return 1;
1830 }
1831 
1832 //----------------------------------------------------------------------------
1833 // Print method for vtkColorTransferFunction
PrintSelf(ostream & os,vtkIndent indent)1834 void vtkColorTransferFunction::PrintSelf(ostream& os, vtkIndent indent)
1835 {
1836   this->Superclass::PrintSelf(os, indent);
1837 
1838   os << indent << "Size: " << this->Internal->Nodes.size() << endl;
1839   if ( this->Clamping )
1840     {
1841     os << indent << "Clamping: On\n";
1842     }
1843   else
1844     {
1845     os << indent << "Clamping: Off\n";
1846     }
1847 
1848   if ( this->ColorSpace == VTK_CTF_RGB )
1849     {
1850     os << indent << "Color Space: RGB\n";
1851     }
1852   else if ( this->ColorSpace == VTK_CTF_HSV && this->HSVWrap )
1853     {
1854     os << indent << "Color Space: HSV\n";
1855     }
1856   else if ( this->ColorSpace == VTK_CTF_HSV )
1857     {
1858     os << indent << "Color Space: HSV (No Wrap)\n";
1859     }
1860   else
1861     {
1862     os << indent << "Color Space: CIE-L*ab\n";
1863     }
1864 
1865   if ( this->Scale == VTK_CTF_LOG10 )
1866     {
1867     os << indent << "Scale: Log10\n";
1868     }
1869   else
1870     {
1871     os << indent << "Scale: Linear\n";
1872     }
1873 
1874   os << indent << "Range: " << this->Range[0] << " to "
1875      << this->Range[1] << endl;
1876 
1877   os << indent << "AllowDuplicateScalars: " << this->AllowDuplicateScalars << endl;
1878 
1879   os << indent << "NanColor: "
1880      << this->NanColor[0] << ", " << this->NanColor[1] << ", "
1881      << this->NanColor[2] << endl;
1882 
1883   os << indent << "BelowRangeColor: (" << this->BelowRangeColor[0] << ", "
1884      << this->BelowRangeColor[1] << ", " << this->BelowRangeColor[2] << ")\n";
1885   os << indent << "UseBelowRangeColor: "
1886      << (this->UseBelowRangeColor != 0 ? "ON" : "OFF") << "\n";
1887 
1888   os << indent << "ABoveRangeColor: (" << this->AboveRangeColor[0] << ", "
1889      << this->AboveRangeColor[1] << ", " << this->AboveRangeColor[2] << ")\n";
1890   os << indent << "UseAboveRangeColor: "
1891      << (this->UseAboveRangeColor != 0 ? "ON" : "OFF") << "\n";
1892 
1893 
1894   unsigned int i;
1895   for( i = 0; i < this->Internal->Nodes.size(); i++ )
1896     {
1897     os << indent << "  " << i
1898        << " X: " << this->Internal->Nodes[i]->X
1899        << " R: " << this->Internal->Nodes[i]->R
1900        << " G: " << this->Internal->Nodes[i]->G
1901        << " B: " << this->Internal->Nodes[i]->B
1902        << " Sharpness: " << this->Internal->Nodes[i]->Sharpness
1903        << " Midpoint: " << this->Internal->Nodes[i]->Midpoint << endl;
1904     }
1905 }
1906 
1907 
1908 
1909