source: trunk/packages/vizservers/vtkvis/ColorMap.cpp @ 2317

Last change on this file since 2317 was 2317, checked in by ldelgass, 13 years ago
  • Add Streamlines/tubes/ribbons to vtkvis: currently supports random points or a rake line as seeds
  • Add user clipping planes to vtkvis renderer and protocol
  • Add a skylight in addition to headlight in vtkvis renderer (TODO: add protocol to control lighting)
  • Set view angle based on window height
  • Dolly camera for zoom instead of changing view angle for perspective camera
  • Add wireframe option to PseudoColor? (lines are colormapped)
  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2011, Purdue Research Foundation
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <string>
9#include <list>
10#include <cstring>
11#include <cassert>
12#include <vtkLookupTable.h>
13#include <vtkColorTransferFunction.h>
14#include <vtkPiecewiseFunction.h>
15
16#include "ColorMap.h"
17#include "Trace.h"
18
19using namespace Rappture::VtkVis;
20
21ColorMap *ColorMap::_default = NULL;
22ColorMap *ColorMap::_volumeDefault = NULL;
23
24ColorMap::ColorMap(const std::string& name) :
25    _name(name),
26    _needsBuild(true),
27    _numTableEntries(256)
28{
29    _colorTF = vtkSmartPointer<vtkColorTransferFunction>::New();
30    _colorTF->ClampingOn();
31    _opacityTF = vtkSmartPointer<vtkPiecewiseFunction>::New();
32    _opacityTF->ClampingOn();
33}
34
35ColorMap::~ColorMap()
36{
37}
38
39/**
40 * \brief Return the name/ID of the ColorMap
41 */
42const std::string& ColorMap::getName()
43{
44    return _name;
45}
46
47/**
48 * \brief Build and return the vtkLookupTable from the transfer function
49 */
50vtkLookupTable *ColorMap::getLookupTable()
51{
52    build();
53    assert(_lookupTable != NULL);
54    return _lookupTable;
55}
56
57/**
58 * \brief Return a newly allocated color transfer function with values
59 * scaled to the given data range
60 */
61vtkSmartPointer<vtkColorTransferFunction>
62ColorMap::getColorTransferFunction(double range[2])
63{
64    vtkSmartPointer<vtkColorTransferFunction> tf = vtkSmartPointer<vtkColorTransferFunction>::New();
65    tf->DeepCopy(_colorTF);
66    double tmp[6];
67    for (int i = 0; i < tf->GetSize(); i++) {
68        tf->GetNodeValue(i, tmp);
69        tmp[0] = range[0] + tmp[0] * (range[1] - range[0]);
70        tf->SetNodeValue(i, tmp);
71    }
72    return tf;
73}
74
75/**
76 * \brief Return a newly allocated opacity transfer function with values
77 * scaled to the given data range
78 */
79vtkSmartPointer<vtkPiecewiseFunction>
80ColorMap::getOpacityTransferFunction(double range[2])
81{
82    vtkSmartPointer<vtkPiecewiseFunction> tf = vtkSmartPointer<vtkPiecewiseFunction>::New();
83    tf->DeepCopy(_opacityTF);
84    double tmp[4];
85    for (int i = 0; i < tf->GetSize(); i++) {
86        tf->GetNodeValue(i, tmp);
87        tmp[0] = range[0] + tmp[0] * (range[1] - range[0]);
88        tf->SetNodeValue(i, tmp);
89    }
90    return tf;
91}
92
93/**
94 * \brief Insert a new RGB control point into the transfer function
95 */
96void ColorMap::addControlPoint(ControlPoint& cp)
97{
98    _needsBuild = true;
99    // Clamp value to [0,1]
100    if (cp.value < 0.0)
101        cp.value = 0.0;
102    if (cp.value > 1.0)
103        cp.value = 1.0;
104
105    TRACE("New control point: %g  = %g %g %g",
106          cp.value, cp.color[0], cp.color[1], cp.color[2]);
107
108    for (std::list<ControlPoint>::iterator itr = _controlPoints.begin();
109         itr != _controlPoints.end(); ++itr) {
110        if (itr->value == cp.value) {
111            *itr = cp;
112            return;
113        } else if (itr->value > cp.value) {
114            _controlPoints.insert(itr, cp);
115            return;
116        }
117    }
118    // If we reach here, our control point goes at the end
119    _controlPoints.insert(_controlPoints.end(), cp);
120    _colorTF->AddRGBPoint(cp.value, cp.color[0], cp.color[1], cp.color[2]);
121}
122
123/**
124 * \brief Insert a new opacity/alpha control point into the transfer function
125 */
126void ColorMap::addOpacityControlPoint(OpacityControlPoint& cp)
127{
128    _needsBuild = true;
129    // Clamp value to [0,1]
130    if (cp.value < 0.0)
131        cp.value = 0.0;
132    if (cp.value > 1.0)
133        cp.value = 1.0;
134
135    TRACE("New opacity control point: %g  = %g",
136          cp.value, cp.alpha);
137
138    for (std::list<OpacityControlPoint>::iterator itr = _opacityControlPoints.begin();
139         itr != _opacityControlPoints.end(); ++itr) {
140        if (itr->value == cp.value) {
141            *itr = cp;
142            return;
143        } else if (itr->value > cp.value) {
144            _opacityControlPoints.insert(itr, cp);
145            return;
146        }
147    }
148    // If we reach here, our control point goes at the end
149    _opacityControlPoints.insert(_opacityControlPoints.end(), cp);
150    _opacityTF->AddPoint(cp.value, cp.alpha);
151}
152
153/**
154 * \brief Set the number of discrete color table entries
155 *
156 * The number of table entries refers to the underlying
157 * vtkLookupTable and is independent of the number of
158 * control points in the transfer function.
159 */
160void ColorMap::setNumberOfTableEntries(int numEntries)
161{
162    if (numEntries != _numTableEntries) {
163        _needsBuild = true;
164        _numTableEntries = numEntries;
165        if (_lookupTable != NULL) {
166            build();
167        }
168    }
169}
170
171/**
172 * \brief Build the lookup table from the control points in the transfer
173 * function
174 */
175void ColorMap::build()
176{
177    if (!_needsBuild)
178        return;
179
180    if (_lookupTable == NULL) {
181        _lookupTable = vtkSmartPointer<vtkLookupTable>::New();
182    }
183
184    _lookupTable->SetNumberOfTableValues(_numTableEntries);
185
186    std::list<ControlPoint>::iterator itr = _controlPoints.begin();
187    std::list<OpacityControlPoint>::iterator oitr = _opacityControlPoints.begin();
188
189    // If first value is > 0, insert a copy at 0 to create
190    // constant range up to first specified cp
191    if (itr->value > 0.0) {
192        ControlPoint cp = *itr;
193        cp.value = 0.0;
194        itr = _controlPoints.insert(itr, cp);
195    }
196    if (oitr->value > 0.0) {
197        OpacityControlPoint ocp = *oitr;
198        ocp.value = 0.0;
199        oitr = _opacityControlPoints.insert(oitr, ocp);
200    }
201
202    std::list<ControlPoint>::iterator itr2 = itr;
203    itr2++;
204    std::list<OpacityControlPoint>::iterator oitr2 = oitr;
205    oitr2++;
206
207    for (int i = 0; i < _numTableEntries; i++) {
208        double value = ((double)i)/(_numTableEntries-1);
209        double color[4];
210        if (itr2 != _controlPoints.end() && value > itr2->value) {
211            itr = itr2;
212            itr2++;
213        }
214        if (oitr2 != _opacityControlPoints.end() && value > oitr2->value) {
215            oitr = oitr2;
216            oitr2++;
217        }
218        if (itr2 == _controlPoints.end()) {
219            TRACE("val: %g Range: %g - 1 Color: %g %g %g", value, itr->value,
220                  itr->color[0], itr->color[1], itr->color[2]);
221            memcpy(color, itr->color, sizeof(double)*3);
222        } else {
223            assert(itr->value < itr2->value);
224            assert(value >= itr->value && value <= itr2->value);
225            lerp(color, *itr, *itr2, value);
226            TRACE("val: %g Range: %g - %g Color: %g %g %g", value, itr->value, itr2->value,
227                  color[0], color[1], color[2]);
228        }
229        if (oitr2 == _opacityControlPoints.end()) {
230            TRACE("val: %g Range: %g - 1 Alpha %g", value, oitr->value,
231                  oitr->alpha);
232            color[3] = oitr->alpha;
233        } else {
234            assert(oitr->value < oitr2->value);
235            assert(value >= oitr->value && value <= oitr2->value);
236            lerp(&color[3], *oitr, *oitr2, value);
237            TRACE("val: %g Range: %g - %g Alpha: %g", value, oitr->value, oitr2->value,
238                  color[3]);
239        }
240        _lookupTable->SetTableValue(i, color);
241    }
242    _needsBuild = false;
243}
244
245/**
246 * \brief Perform linear interpolation of two color control points
247 */
248void ColorMap::lerp(double *result, const ControlPoint& cp1, const ControlPoint& cp2, double value)
249{
250    double factor = (value - cp1.value) / (cp2.value - cp1.value);
251    for (int i = 0; i < 3; i++) {
252        result[i] = cp1.color[i] * (1.0 - factor) + cp2.color[i] * factor;
253    }
254}
255
256/**
257 * \brief Perform linear interpolation of two opacity control points
258 */
259void ColorMap::lerp(double *result, const OpacityControlPoint& cp1, const OpacityControlPoint& cp2, double value)
260{
261    double factor = (value - cp1.value) / (cp2.value - cp1.value);
262    *result = cp1.alpha * (1.0 - factor) + cp2.alpha * factor;
263}
264
265/**
266 * \brief Remove all control points and lookup table
267 */
268void ColorMap::clear()
269{
270    _controlPoints.clear();
271    _colorTF->RemoveAllPoints();
272    _opacityControlPoints.clear();
273    _opacityTF->RemoveAllPoints();
274    _lookupTable = NULL;
275}
276
277/**
278 * \brief Create a default ColorMap with a blue-cyan-green-yellow-red ramp
279 */
280ColorMap * ColorMap::getDefault()
281{
282    if (_default != NULL) {
283        return _default;
284    }
285
286    _default = new ColorMap("default");
287    ControlPoint cp[5];
288    cp[0].value = 0.0;
289    cp[0].color[0] = 0.0;
290    cp[0].color[1] = 0.0;
291    cp[0].color[2] = 1.0;
292    cp[1].value = 0.25;
293    cp[1].color[0] = 0.0;
294    cp[1].color[1] = 1.0;
295    cp[1].color[2] = 1.0;
296    cp[2].value = 0.5;
297    cp[2].color[0] = 0.0;
298    cp[2].color[1] = 1.0;
299    cp[2].color[2] = 0.0;
300    cp[3].value = 0.75;
301    cp[3].color[0] = 1.0;
302    cp[3].color[1] = 1.0;
303    cp[3].color[2] = 0.0;
304    cp[4].value = 1.0;
305    cp[4].color[0] = 1.0;
306    cp[4].color[1] = 0.0;
307    cp[4].color[2] = 0.0;
308    for (int i = 0; i < 5; i++) {
309        _default->addControlPoint(cp[i]);
310    }
311    OpacityControlPoint ocp[2];
312    ocp[0].value = 0.0;
313    ocp[0].alpha = 1.0;
314    ocp[1].value = 1.0;
315    ocp[1].alpha = 1.0;
316    _default->addOpacityControlPoint(ocp[0]);
317    _default->addOpacityControlPoint(ocp[1]);
318    _default->build();
319    return _default;
320}
321
322/**
323 * \brief Create a default ColorMap with a blue-cyan-green-yellow-red ramp
324 * and transparent to opaque ramp
325 */
326ColorMap * ColorMap::getVolumeDefault()
327{
328    if (_volumeDefault != NULL) {
329        return _volumeDefault;
330    }
331
332    _volumeDefault = new ColorMap("volumeDefault");
333    ControlPoint cp[5];
334    cp[0].value = 0.0;
335    cp[0].color[0] = 0.0;
336    cp[0].color[1] = 0.0;
337    cp[0].color[2] = 1.0;
338    cp[1].value = 0.25;
339    cp[1].color[0] = 0.0;
340    cp[1].color[1] = 1.0;
341    cp[1].color[2] = 1.0;
342    cp[2].value = 0.5;
343    cp[2].color[0] = 0.0;
344    cp[2].color[1] = 1.0;
345    cp[2].color[2] = 0.0;
346    cp[3].value = 0.75;
347    cp[3].color[0] = 1.0;
348    cp[3].color[1] = 1.0;
349    cp[3].color[2] = 0.0;
350    cp[4].value = 1.0;
351    cp[4].color[0] = 1.0;
352    cp[4].color[1] = 0.0;
353    cp[4].color[2] = 0.0;
354    for (int i = 0; i < 5; i++) {
355        _volumeDefault->addControlPoint(cp[i]);
356    }
357    OpacityControlPoint ocp[2];
358    ocp[0].value = 0.0;
359    ocp[0].alpha = 0.0;
360    ocp[1].value = 1.0;
361    ocp[1].alpha = 1.0;
362    _volumeDefault->addOpacityControlPoint(ocp[0]);
363    _volumeDefault->addOpacityControlPoint(ocp[1]);
364    _volumeDefault->build();
365    return _volumeDefault;
366}
Note: See TracBrowser for help on using the repository browser.