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

Last change on this file since 2290 was 2261, checked in by ldelgass, 13 years ago

Add GPU volume rendering support to vtkvis render server

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