1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkCompositeTransferFunctionItem.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 
16 // Hide VTK_DEPRECATED_IN_9_0_0() warnings for this class.
17 #define VTK_DEPRECATION_LEVEL 0
18 
19 #include "vtkCompositeTransferFunctionItem.h"
20 #include "vtkAxis.h"
21 #include "vtkCallbackCommand.h"
22 #include "vtkColorTransferFunction.h"
23 #include "vtkCommand.h"
24 #include "vtkImageData.h"
25 #include "vtkObjectFactory.h"
26 #include "vtkPen.h"
27 #include "vtkPiecewiseFunction.h"
28 #include "vtkPointData.h"
29 #include "vtkPoints2D.h"
30 
31 // STD includes
32 #include <algorithm>
33 #include <cassert>
34 #include <vector>
35 
36 //------------------------------------------------------------------------------
37 vtkStandardNewMacro(vtkCompositeTransferFunctionItem);
38 
39 //------------------------------------------------------------------------------
vtkCompositeTransferFunctionItem()40 vtkCompositeTransferFunctionItem::vtkCompositeTransferFunctionItem()
41 {
42   this->PolyLinePen->SetLineType(vtkPen::SOLID_LINE);
43   this->OpacityFunction = nullptr;
44 }
45 
46 //------------------------------------------------------------------------------
~vtkCompositeTransferFunctionItem()47 vtkCompositeTransferFunctionItem::~vtkCompositeTransferFunctionItem()
48 {
49   if (this->OpacityFunction)
50   {
51     this->OpacityFunction->RemoveObserver(this->Callback);
52     this->OpacityFunction->Delete();
53     this->OpacityFunction = nullptr;
54   }
55 }
56 
57 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)58 void vtkCompositeTransferFunctionItem::PrintSelf(ostream& os, vtkIndent indent)
59 {
60   this->Superclass::PrintSelf(os, indent);
61   os << indent << "CompositeTransferFunction: ";
62   if (this->OpacityFunction)
63   {
64     os << endl;
65     this->OpacityFunction->PrintSelf(os, indent.GetNextIndent());
66   }
67   else
68   {
69     os << "(none)" << endl;
70   }
71 }
72 
73 //------------------------------------------------------------------------------
ComputeBounds(double * bounds)74 void vtkCompositeTransferFunctionItem::ComputeBounds(double* bounds)
75 {
76   this->Superclass::ComputeBounds(bounds);
77   if (this->OpacityFunction)
78   {
79     double unused;
80     double opacityRange[2];
81     this->OpacityFunction->GetRange(opacityRange);
82     this->TransformDataToScreen(opacityRange[0], 1, bounds[0], unused);
83     this->TransformDataToScreen(opacityRange[1], 1, bounds[1], unused);
84   }
85 }
86 
87 //------------------------------------------------------------------------------
SetOpacityFunction(vtkPiecewiseFunction * opacity)88 void vtkCompositeTransferFunctionItem::SetOpacityFunction(vtkPiecewiseFunction* opacity)
89 {
90   if (opacity == this->OpacityFunction)
91   {
92     return;
93   }
94   if (this->OpacityFunction)
95   {
96     this->OpacityFunction->RemoveObserver(this->Callback);
97   }
98   vtkSetObjectBodyMacro(OpacityFunction, vtkPiecewiseFunction, opacity);
99   if (opacity)
100   {
101     opacity->AddObserver(vtkCommand::ModifiedEvent, this->Callback);
102   }
103   this->ScalarsToColorsModified(this->OpacityFunction, vtkCommand::ModifiedEvent, nullptr);
104 }
105 
106 //------------------------------------------------------------------------------
ComputeTexture()107 void vtkCompositeTransferFunctionItem::ComputeTexture()
108 {
109   this->Superclass::ComputeTexture();
110   double screenBounds[4];
111   this->GetBounds(screenBounds);
112   if (screenBounds[0] == screenBounds[1] || !this->OpacityFunction)
113   {
114     return;
115   }
116   if (this->Texture == nullptr)
117   {
118     this->Texture = vtkImageData::New();
119   }
120 
121   double dataBounds[4];
122   this->TransformScreenToData(screenBounds[0], screenBounds[2], dataBounds[0], dataBounds[2]);
123   this->TransformScreenToData(screenBounds[1], screenBounds[3], dataBounds[1], dataBounds[3]);
124 
125   const bool logX = this->GetXAxis()->GetLogScaleActive();
126   const bool logY = this->GetYAxis()->GetLogScaleActive();
127 
128   const int dimension = this->GetTextureWidth();
129   std::vector<double> values(dimension);
130   this->OpacityFunction->GetTable(
131     dataBounds[0], dataBounds[1], dimension, values.data(), 1, logX ? 1 : 0);
132   unsigned char* ptr = reinterpret_cast<unsigned char*>(this->Texture->GetScalarPointer(0, 0, 0));
133 
134   // TBD: maybe the shape should be defined somewhere else...
135   if (this->MaskAboveCurve || this->PolyLinePen->GetLineType() != vtkPen::SOLID_LINE)
136   {
137     this->Shape->SetNumberOfPoints(dimension);
138     const double step = (dataBounds[1] - dataBounds[0]) / dimension;
139 
140     for (int i = 0; i < dimension; ++i)
141     {
142       if (values[i] < 0. || values[i] > 1.)
143       {
144         vtkWarningMacro(<< "Opacity at point " << i << " is " << values[i]
145                         << " which is outside the valid range of [0,1]");
146       }
147       ptr[3] = static_cast<unsigned char>(values[i] * this->Opacity * 255);
148 
149       double xValue = dataBounds[0] + step * i;
150       double yValue = values[i];
151       if (logY)
152       {
153         yValue = std::log10(yValue);
154       }
155       this->Shape->SetPoint(i, xValue, yValue);
156       ptr += 4;
157     }
158   }
159   else
160   {
161     for (int i = 0; i < dimension; ++i)
162     {
163       ptr[3] = static_cast<unsigned char>(values[i] * this->Opacity * 255);
164       assert(values[i] <= 1. && values[i] >= 0.);
165       ptr += 4;
166     }
167   }
168 }
169