~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.1.1/src/qwt_color_map.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2008-05-26 10:26:31 UTC
  • mfrom: (1.1.3 upstream) (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526102631-bp95mfccnrb957nx
Tags: 5.1.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

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