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

Last change on this file since 8127 was 8127, checked in by stoecker, 2 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 11.3 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        d_doAlpha( false )
20    {
21        d_stops.reserve( 256 );
22    }
23
24    void insert( double pos, const QColor &color );
25    QRgb rgb( QwtLinearColorMap::Mode, double pos ) const;
26
27    QVector<double> stops() const;
28
29private:
30
31    class ColorStop
32    {
33    public:
34        ColorStop():
35            pos( 0.0 ),
36            rgb( 0 )
37        {
38        };
39
40        ColorStop( double p, const QColor &c ):
41            pos( p ),
42            rgb( c.rgba() )
43        {
44            r = qRed( rgb );
45            g = qGreen( rgb );
46            b = qBlue( rgb );
47            a = qAlpha( rgb );
48
49            /*
50                when mapping a value to rgb we will have to calcualate:
51                   - const int v = int( ( s1.v0 + ratio * s1.vStep ) + 0.5 );
52
53                Thus adding 0.5 ( for rounding ) can be done in advance
54             */
55            r0 = r + 0.5;
56            g0 = g + 0.5;
57            b0 = b + 0.5;
58            a0 = a + 0.5;
59
60            rStep = gStep = bStep = aStep = 0.0;
61            posStep = 0.0;
62        }
63
64        void updateSteps( const ColorStop &nextStop )
65        {
66            rStep = nextStop.r - r;
67            gStep = nextStop.g - g;
68            bStep = nextStop.b - b;
69            aStep = nextStop.a - a;
70            posStep = nextStop.pos - pos;
71        }
72
73        double pos;
74        QRgb rgb;
75        int r, g, b, a;
76
77        // precalculated values
78        double rStep, gStep, bStep, aStep;
79        double r0, g0, b0, a0;
80        double posStep;
81    };
82
83    inline int findUpper( double pos ) const;
84    QVector<ColorStop> d_stops;
85    bool d_doAlpha;
86};
87
88void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color )
89{
90    // Lookups need to be very fast, insertions are not so important.
91    // Anyway, a balanced tree is what we need here. TODO ...
92
93    if ( pos < 0.0 || pos > 1.0 )
94        return;
95
96    int index;
97    if ( d_stops.size() == 0 )
98    {
99        index = 0;
100        d_stops.resize( 1 );
101    }
102    else
103    {
104        index = findUpper( pos );
105        if ( index == d_stops.size() ||
106                qAbs( d_stops[index].pos - pos ) >= 0.001 )
107        {
108            d_stops.resize( d_stops.size() + 1 );
109            for ( int i = d_stops.size() - 1; i > index; i-- )
110                d_stops[i] = d_stops[i-1];
111        }
112    }
113
114    d_stops[index] = ColorStop( pos, color );
115    if ( color.alpha() != 255 )
116        d_doAlpha = true;
117
118    if ( index > 0 )
119        d_stops[index-1].updateSteps( d_stops[index] );
120
121    if ( index < d_stops.size() - 1 )
122        d_stops[index].updateSteps( d_stops[index+1] );
123}
124
125inline QVector<double> QwtLinearColorMap::ColorStops::stops() const
126{
127    QVector<double> positions( d_stops.size() );
128    for ( int i = 0; i < d_stops.size(); i++ )
129        positions[i] = d_stops[i].pos;
130    return positions;
131}
132
133inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const
134{
135    int index = 0;
136    int n = d_stops.size();
137
138    const ColorStop *stops = d_stops.data();
139
140    while ( n > 0 )
141    {
142        const int half = n >> 1;
143        const int middle = index + half;
144
145        if ( stops[middle].pos <= pos )
146        {
147            index = middle + 1;
148            n -= half + 1;
149        }
150        else
151            n = half;
152    }
153
154    return index;
155}
156
157inline QRgb QwtLinearColorMap::ColorStops::rgb(
158    QwtLinearColorMap::Mode mode, double pos ) const
159{
160    if ( pos <= 0.0 )
161        return d_stops[0].rgb;
162    if ( pos >= 1.0 )
163        return d_stops[ d_stops.size() - 1 ].rgb;
164
165    const int index = findUpper( pos );
166    if ( mode == FixedColors )
167    {
168        return d_stops[index-1].rgb;
169    }
170    else
171    {
172        const ColorStop &s1 = d_stops[index-1];
173
174        const double ratio = ( pos - s1.pos ) / ( s1.posStep );
175
176        const int r = int( s1.r0 + ratio * s1.rStep );
177        const int g = int( s1.g0 + ratio * s1.gStep );
178        const int b = int( s1.b0 + ratio * s1.bStep );
179
180        if ( d_doAlpha )
181        {
182            if ( s1.aStep )
183            {
184                const int a = int( s1.a0 + ratio * s1.aStep );
185                return qRgba( r, g, b, a );
186            }
187            else
188            {
189                return qRgba( r, g, b, s1.a );
190            }
191        }
192        else
193        {
194            return qRgb( r, g, b );
195        }
196    }
197}
198
199//! Constructor
200QwtColorMap::QwtColorMap( Format format ):
201    d_format( format )
202{
203}
204
205//! Destructor
206QwtColorMap::~QwtColorMap()
207{
208}
209
210/*!
211   Build and return a color map of 256 colors
212
213   The color table is needed for rendering indexed images in combination
214   with using colorIndex().
215
216   \param interval Range for the values
217   \return A color table, that can be used for a QImage
218*/
219QVector<QRgb> QwtColorMap::colorTable( const QwtInterval &interval ) const
220{
221    QVector<QRgb> table( 256 );
222
223    if ( interval.isValid() )
224    {
225        const double step = interval.width() / ( table.size() - 1 );
226        for ( int i = 0; i < table.size(); i++ )
227            table[i] = rgb( interval, interval.minValue() + step * i );
228    }
229
230    return table;
231}
232
233class QwtLinearColorMap::PrivateData
234{
235public:
236    ColorStops colorStops;
237    QwtLinearColorMap::Mode mode;
238};
239
240/*!
241   Build a color map with two stops at 0.0 and 1.0. The color
242   at 0.0 is Qt::blue, at 1.0 it is Qt::yellow.
243
244   \param format Preferred format of the color map
245*/
246QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ):
247    QwtColorMap( format )
248{
249    d_data = new PrivateData;
250    d_data->mode = ScaledColors;
251
252    setColorInterval( Qt::blue, Qt::yellow );
253}
254
255/*!
256   Build a color map with two stops at 0.0 and 1.0.
257
258   \param color1 Color used for the minimum value of the value interval
259   \param color2 Color used for the maximum value of the value interval
260   \param format Preferred format for the color map
261*/
262QwtLinearColorMap::QwtLinearColorMap( const QColor &color1,
263        const QColor &color2, QwtColorMap::Format format ):
264    QwtColorMap( format )
265{
266    d_data = new PrivateData;
267    d_data->mode = ScaledColors;
268    setColorInterval( color1, color2 );
269}
270
271//! Destructor
272QwtLinearColorMap::~QwtLinearColorMap()
273{
274    delete d_data;
275}
276
277/*!
278   \brief Set the mode of the color map
279
280   FixedColors means the color is calculated from the next lower
281   color stop. ScaledColors means the color is calculated
282   by interpolating the colors of the adjacent stops.
283
284   \sa mode()
285*/
286void QwtLinearColorMap::setMode( Mode mode )
287{
288    d_data->mode = mode;
289}
290
291/*!
292   \return Mode of the color map
293   \sa setMode()
294*/
295QwtLinearColorMap::Mode QwtLinearColorMap::mode() const
296{
297    return d_data->mode;
298}
299
300/*!
301   Set the color range
302
303   Add stops at 0.0 and 1.0.
304
305   \param color1 Color used for the minimum value of the value interval
306   \param color2 Color used for the maximum value of the value interval
307
308   \sa color1(), color2()
309*/
310void QwtLinearColorMap::setColorInterval(
311    const QColor &color1, const QColor &color2 )
312{
313    d_data->colorStops = ColorStops();
314    d_data->colorStops.insert( 0.0, color1 );
315    d_data->colorStops.insert( 1.0, color2 );
316}
317
318/*!
319   Add a color stop
320
321   The value has to be in the range [0.0, 1.0].
322   F.e. a stop at position 17.0 for a range [10.0,20.0] must be
323   passed as: (17.0 - 10.0) / (20.0 - 10.0)
324
325   \param value Value between [0.0, 1.0]
326   \param color Color stop
327*/
328void QwtLinearColorMap::addColorStop( double value, const QColor& color )
329{
330    if ( value >= 0.0 && value <= 1.0 )
331        d_data->colorStops.insert( value, color );
332}
333
334/*!
335   \return Positions of color stops in increasing order
336*/
337QVector<double> QwtLinearColorMap::colorStops() const
338{
339    return d_data->colorStops.stops();
340}
341
342/*!
343  \return the first color of the color range
344  \sa setColorInterval()
345*/
346QColor QwtLinearColorMap::color1() const
347{
348    return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) );
349}
350
351/*!
352  \return the second color of the color range
353  \sa setColorInterval()
354*/
355QColor QwtLinearColorMap::color2() const
356{
357    return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) );
358}
359
360/*!
361  Map a value of a given interval into a RGB value
362
363  \param interval Range for all values
364  \param value Value to map into a RGB value
365
366  \return RGB value for value
367*/
368QRgb QwtLinearColorMap::rgb(
369    const QwtInterval &interval, double value ) const
370{
371    if ( qIsNaN(value) )
372        return 0u;
373
374    const double width = interval.width();
375    if ( width <= 0.0 )
376        return 0u;
377
378    const double ratio = ( value - interval.minValue() ) / width;
379    return d_data->colorStops.rgb( d_data->mode, ratio );
380}
381
382/*!
383  \brief Map a value of a given interval into a color index
384
385  \param interval Range for all values
386  \param value Value to map into a color index
387
388  \return Index, between 0 and 255
389*/
390unsigned char QwtLinearColorMap::colorIndex(
391    const QwtInterval &interval, double value ) const
392{
393    const double width = interval.width();
394
395    if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() )
396        return 0;
397
398    if ( value >= interval.maxValue() )
399        return 255;
400
401    const double ratio = ( value - interval.minValue() ) / width;
402
403    unsigned char index;
404    if ( d_data->mode == FixedColors )
405        index = static_cast<unsigned char>( ratio * 255 ); // always floor
406    else
407        index = static_cast<unsigned char>( ratio * 255 + 0.5 );
408
409    return index;
410}
411
412class QwtAlphaColorMap::PrivateData
413{
414public:
415    QColor color;
416    QRgb rgb;
417    QRgb rgbMax;
418};
419
420
421/*!
422   Constructor
423   \param color Color of the map
424*/
425QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ):
426    QwtColorMap( QwtColorMap::RGB )
427{
428    d_data = new PrivateData;
429    setColor( color );
430}
431
432//! Destructor
433QwtAlphaColorMap::~QwtAlphaColorMap()
434{
435    delete d_data;
436}
437
438/*!
439   Set the color
440
441   \param color Color
442   \sa color()
443*/
444void QwtAlphaColorMap::setColor( const QColor &color )
445{
446    d_data->color = color;
447    d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 );
448    d_data->rgbMax = d_data->rgb | ( 255 << 24 );
449}
450
451/*!
452  \return the color
453  \sa setColor()
454*/
455QColor QwtAlphaColorMap::color() const
456{
457    return d_data->color;
458}
459
460/*!
461  \brief Map a value of a given interval into a alpha value
462
463  alpha := (value - interval.minValue()) / interval.width();
464
465  \param interval Range for all values
466  \param value Value to map into a RGB value
467  \return RGB value, with an alpha value
468*/
469QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const
470{
471    if ( qIsNaN(value) )
472        return 0u;
473
474    const double width = interval.width();
475    if ( width <= 0.0 )
476        return 0u;
477
478    if ( value <= interval.minValue() )
479        return d_data->rgb;
480
481    if ( value >= interval.maxValue() )
482        return d_data->rgbMax;
483
484    const double ratio = ( value - interval.minValue() ) / width;
485    return d_data->rgb | ( qRound( 255 * ratio ) << 24 );
486}
487
488/*!
489  Dummy function, needed to be implemented as it is pure virtual
490  in QwtColorMap. Color indices make no sense in combination with
491  an alpha channel.
492
493  \return Always 0
494*/
495unsigned char QwtAlphaColorMap::colorIndex(
496    const QwtInterval &, double ) const
497{
498    return 0;
499}
Note: See TracBrowser for help on using the repository browser.