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

Last change on this file since 9573 was 9383, checked in by stoecker, 3 years ago

update to qwt verion 6.1.1 to fix build with newer Qt5

File size: 11.4 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::fromRgba( 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::fromRgba( 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.