source: ntrip/trunk/BNC/qwt/qwt_color_map.cpp @ 4271

Last change on this file since 4271 was 4271, checked in by mervart, 7 years ago
File size: 9.9 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * Qwt Widget Library
3 * Copyright (C) 1997   Josef Wilgen
4 * Copyright (C) 2002   Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10#include "qwt_color_map.h"
11#include "qwt_math.h"
12#include "qwt_interval.h"
13#include <qnumeric.h>
14
15class QwtLinearColorMap::ColorStops
16{
17public:
18    ColorStops()
19    {
20        _stops.reserve( 256 );
21    }
22
23    void insert( double pos, const QColor &color );
24    QRgb rgb( QwtLinearColorMap::Mode, double pos ) const;
25
26    QVector<double> stops() const;
27
28private:
29
30    class ColorStop
31    {
32    public:
33        ColorStop():
34            pos( 0.0 ),
35            rgb( 0 )
36        {
37        };
38
39        ColorStop( double p, const QColor &c ):
40            pos( p ),
41            rgb( c.rgb() )
42        {
43            r = qRed( rgb );
44            g = qGreen( rgb );
45            b = qBlue( rgb );
46        }
47
48        double pos;
49        QRgb rgb;
50        int r, g, b;
51    };
52
53    inline int findUpper( double pos ) const;
54    QVector<ColorStop> _stops;
55};
56
57void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color )
58{
59    // Lookups need to be very fast, insertions are not so important.
60    // Anyway, a balanced tree is what we need here. TODO ...
61
62    if ( pos < 0.0 || pos > 1.0 )
63        return;
64
65    int index;
66    if ( _stops.size() == 0 )
67    {
68        index = 0;
69        _stops.resize( 1 );
70    }
71    else
72    {
73        index = findUpper( pos );
74        if ( index == _stops.size() ||
75                qAbs( _stops[index].pos - pos ) >= 0.001 )
76        {
77            _stops.resize( _stops.size() + 1 );
78            for ( int i = _stops.size() - 1; i > index; i-- )
79                _stops[i] = _stops[i-1];
80        }
81    }
82
83    _stops[index] = ColorStop( pos, color );
84}
85
86inline QVector<double> QwtLinearColorMap::ColorStops::stops() const
87{
88    QVector<double> positions( _stops.size() );
89    for ( int i = 0; i < _stops.size(); i++ )
90        positions[i] = _stops[i].pos;
91    return positions;
92}
93
94inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const
95{
96    int index = 0;
97    int n = _stops.size();
98
99    const ColorStop *stops = _stops.data();
100
101    while ( n > 0 )
102    {
103        const int half = n >> 1;
104        const int middle = index + half;
105
106        if ( stops[middle].pos <= pos )
107        {
108            index = middle + 1;
109            n -= half + 1;
110        }
111        else
112            n = half;
113    }
114
115    return index;
116}
117
118inline QRgb QwtLinearColorMap::ColorStops::rgb(
119    QwtLinearColorMap::Mode mode, double pos ) const
120{
121    if ( pos <= 0.0 )
122        return _stops[0].rgb;
123    if ( pos >= 1.0 )
124        return _stops[ _stops.size() - 1 ].rgb;
125
126    const int index = findUpper( pos );
127    if ( mode == FixedColors )
128    {
129        return _stops[index-1].rgb;
130    }
131    else
132    {
133        const ColorStop &s1 = _stops[index-1];
134        const ColorStop &s2 = _stops[index];
135
136        const double ratio = ( pos - s1.pos ) / ( s2.pos - s1.pos );
137
138        const int r = s1.r + qRound( ratio * ( s2.r - s1.r ) );
139        const int g = s1.g + qRound( ratio * ( s2.g - s1.g ) );
140        const int b = s1.b + qRound( ratio * ( s2.b - s1.b ) );
141
142        return qRgb( r, g, b );
143    }
144}
145
146//! Constructor
147QwtColorMap::QwtColorMap( Format format ):
148    d_format( format )
149{
150}
151
152//! Destructor
153QwtColorMap::~QwtColorMap()
154{
155}
156
157/*!
158   Build and return a color map of 256 colors
159
160   The color table is needed for rendering indexed images in combination
161   with using colorIndex().
162
163   \param interval Range for the values
164   \return A color table, that can be used for a QImage
165*/
166QVector<QRgb> QwtColorMap::colorTable( const QwtInterval &interval ) const
167{
168    QVector<QRgb> table( 256 );
169
170    if ( interval.isValid() )
171    {
172        const double step = interval.width() / ( table.size() - 1 );
173        for ( int i = 0; i < table.size(); i++ )
174            table[i] = rgb( interval, interval.minValue() + step * i );
175    }
176
177    return table;
178}
179
180class QwtLinearColorMap::PrivateData
181{
182public:
183    ColorStops colorStops;
184    QwtLinearColorMap::Mode mode;
185};
186
187/*!
188   Build a color map with two stops at 0.0 and 1.0. The color
189   at 0.0 is Qt::blue, at 1.0 it is Qt::yellow.
190
191   \param format Preferred format of the color map
192*/
193QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ):
194    QwtColorMap( format )
195{
196    d_data = new PrivateData;
197    d_data->mode = ScaledColors;
198
199    setColorInterval( Qt::blue, Qt::yellow );
200}
201
202/*!
203   Build a color map with two stops at 0.0 and 1.0.
204
205   \param color1 Color used for the minimum value of the value interval
206   \param color2 Color used for the maximum value of the value interval
207   \param format Preferred format of the coor map
208*/
209QwtLinearColorMap::QwtLinearColorMap( const QColor &color1,
210        const QColor &color2, QwtColorMap::Format format ):
211    QwtColorMap( format )
212{
213    d_data = new PrivateData;
214    d_data->mode = ScaledColors;
215    setColorInterval( color1, color2 );
216}
217
218//! Destructor
219QwtLinearColorMap::~QwtLinearColorMap()
220{
221    delete d_data;
222}
223
224/*!
225   \brief Set the mode of the color map
226
227   FixedColors means the color is calculated from the next lower
228   color stop. ScaledColors means the color is calculated
229   by interpolating the colors of the adjacent stops.
230
231   \sa mode()
232*/
233void QwtLinearColorMap::setMode( Mode mode )
234{
235    d_data->mode = mode;
236}
237
238/*!
239   \return Mode of the color map
240   \sa setMode()
241*/
242QwtLinearColorMap::Mode QwtLinearColorMap::mode() const
243{
244    return d_data->mode;
245}
246
247/*!
248   Set the color range
249
250   Add stops at 0.0 and 1.0.
251
252   \param color1 Color used for the minimum value of the value interval
253   \param color2 Color used for the maximum value of the value interval
254
255   \sa color1(), color2()
256*/
257void QwtLinearColorMap::setColorInterval(
258    const QColor &color1, const QColor &color2 )
259{
260    d_data->colorStops = ColorStops();
261    d_data->colorStops.insert( 0.0, color1 );
262    d_data->colorStops.insert( 1.0, color2 );
263}
264
265/*!
266   Add a color stop
267
268   The value has to be in the range [0.0, 1.0].
269   F.e. a stop at position 17.0 for a range [10.0,20.0] must be
270   passed as: (17.0 - 10.0) / (20.0 - 10.0)
271
272   \param value Value between [0.0, 1.0]
273   \param color Color stop
274*/
275void QwtLinearColorMap::addColorStop( double value, const QColor& color )
276{
277    if ( value >= 0.0 && value <= 1.0 )
278        d_data->colorStops.insert( value, color );
279}
280
281/*!
282   Return all positions of color stops in increasing order
283*/
284QVector<double> QwtLinearColorMap::colorStops() const
285{
286    return d_data->colorStops.stops();
287}
288
289/*!
290  \return the first color of the color range
291  \sa setColorInterval()
292*/
293QColor QwtLinearColorMap::color1() const
294{
295    return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) );
296}
297
298/*!
299  \return the second color of the color range
300  \sa setColorInterval()
301*/
302QColor QwtLinearColorMap::color2() const
303{
304    return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) );
305}
306
307/*!
308  Map a value of a given interval into a rgb value
309
310  \param interval Range for all values
311  \param value Value to map into a rgb value
312*/
313QRgb QwtLinearColorMap::rgb(
314    const QwtInterval &interval, double value ) const
315{
316    if ( qIsNaN(value) )
317        return qRgba(0, 0, 0, 0);
318
319    const double width = interval.width();
320
321    double ratio = 0.0;
322    if ( width > 0.0 )
323        ratio = ( value - interval.minValue() ) / width;
324
325    return d_data->colorStops.rgb( d_data->mode, ratio );
326}
327
328/*!
329  Map a value of a given interval into a color index, between 0 and 255
330
331  \param interval Range for all values
332  \param value Value to map into a color index
333*/
334unsigned char QwtLinearColorMap::colorIndex(
335    const QwtInterval &interval, double value ) const
336{
337    const double width = interval.width();
338
339    if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() )
340        return 0;
341
342    if ( value >= interval.maxValue() )
343        return ( unsigned char )255;
344
345    const double ratio = ( value - interval.minValue() ) / width;
346
347    unsigned char index;
348    if ( d_data->mode == FixedColors )
349        index = ( unsigned char )( ratio * 255 ); // always floor
350    else
351        index = ( unsigned char )qRound( ratio * 255 );
352
353    return index;
354}
355
356class QwtAlphaColorMap::PrivateData
357{
358public:
359    QColor color;
360    QRgb rgb;
361};
362
363
364/*!
365   Constructor
366   \param color Color of the map
367*/
368QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ):
369    QwtColorMap( QwtColorMap::RGB )
370{
371    d_data = new PrivateData;
372    d_data->color = color;
373    d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 );
374}
375
376//! Destructor
377QwtAlphaColorMap::~QwtAlphaColorMap()
378{
379    delete d_data;
380}
381
382/*!
383   Set the color
384
385   \param color Color
386   \sa color()
387*/
388void QwtAlphaColorMap::setColor( const QColor &color )
389{
390    d_data->color = color;
391    d_data->rgb = color.rgb();
392}
393
394/*!
395  \return the color
396  \sa setColor()
397*/
398QColor QwtAlphaColorMap::color() const
399{
400    return d_data->color;
401}
402
403/*!
404  \brief Map a value of a given interval into a alpha value
405
406  alpha := (value - interval.minValue()) / interval.width();
407
408  \param interval Range for all values
409  \param value Value to map into a rgb value
410  \return rgb value, with an alpha value
411*/
412QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const
413{
414    const double width = interval.width();
415    if ( !qIsNaN(value) && width >= 0.0 )
416    {
417        const double ratio = ( value - interval.minValue() ) / width;
418        int alpha = qRound( 255 * ratio );
419        if ( alpha < 0 )
420            alpha = 0;
421        if ( alpha > 255 )
422            alpha = 255;
423
424        return d_data->rgb | ( alpha << 24 );
425    }
426    return d_data->rgb;
427}
428
429/*!
430  Dummy function, needed to be implemented as it is pure virtual
431  in QwtColorMap. Color indices make no sense in combination with
432  an alpha channel.
433
434  \return Always 0
435*/
436unsigned char QwtAlphaColorMap::colorIndex(
437    const QwtInterval &, double ) const
438{
439    return 0;
440}
Note: See TracBrowser for help on using the repository browser.