# qwt_color_map.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 #include "qwt_array.h"
    00011 #include "qwt_math.h"
    00012 #include "qwt_double_interval.h"
    00013 #include "qwt_color_map.h"
    00014
    00015 #if QT_VERSION < 0x040000
    00016 #include <qvaluelist.h>
    00017 typedef QValueVector<QRgb> QwtColorTable;
    00018 #else
    00019 typedef QVector<QRgb> QwtColorTable;
    00020 #endif
    00021
    00022 class QwtLinearColorMap::ColorStops
    00023 {
    00024 public:
    00025     ColorStops()
    00026     {
    00027 #if QT_VERSION >= 0x040000
    00028         _stops.reserve(256);
    00029 #endif
    00030     }
    00031
    00032     void insert(double pos, const QColor &color);
    00033     QRgb rgb(QwtLinearColorMap::Mode, double pos) const;
    00034
    00035     QwtArray<double> stops() const;
    00036
    00037 private:
    00038
    00039     class ColorStop
    00040     {
    00041     public:
    00042         ColorStop():
    00043             pos(0.0),
    00044             rgb(0)
    00045         {
    00046         };
    00047
    00048         ColorStop(double p, const QColor &c):
    00049             pos(p),
    00050             rgb(c.rgb())
    00051         {
    00052             r = qRed(rgb);
    00053             g = qGreen(rgb);
    00054             b = qBlue(rgb);
    00055         }
    00056
    00057         double pos;
    00058         QRgb rgb;
    00059         int r, g, b;
    00060     };
    00061
    00062     inline int findUpper(double pos) const;
    00063     QwtArray<ColorStop> _stops;
    00064 };
    00065
    00066 void QwtLinearColorMap::ColorStops::insert(double pos, const QColor &color)
    00067 {
    00068     // Lookups need to be very fast, insertions are not so important.
    00069     // Anyway, a balanced tree is what we need here. TODO ...
    00070
    00071     if ( pos < 0.0 || pos > 1.0 )
    00072         return;
    00073
    00074     int index;
    00075     if ( _stops.size() == 0 )
    00076     {
    00077         index = 0;
    00078 #if QT_VERSION < 0x040000
    00079         _stops.resize(1, QGArray::SpeedOptim);
    00080 #else
    00081         _stops.resize(1);
    00082 #endif
    00083     }
    00084     else
    00085     {
    00086         index = findUpper(pos);
    00087         if ( index == (int)_stops.size() ||
    00088             qwtAbs(_stops[index].pos - pos) >= 0.001 )
    00089         {
    00090 #if QT_VERSION < 0x040000
    00091             _stops.resize(_stops.size() + 1, QGArray::SpeedOptim);
    00092 #else
    00093             _stops.resize(_stops.size() + 1);
    00094 #endif
    00095             for ( int i = _stops.size() - 1; i > index; i-- )
    00096                 _stops[i] = _stops[i-1];
    00097         }
    00098     }
    00099
    00100     _stops[index] = ColorStop(pos, color);
    00101 }
    00102
    00103 inline QwtArray<double> QwtLinearColorMap::ColorStops::stops() const
    00104 {
    00105     QwtArray<double> positions(_stops.size());
    00106     for ( int i = 0; i < (int)_stops.size(); i++ )
    00107         positions[i] = _stops[i].pos;
    00108     return positions;
    00109 }
    00110
    00111 inline int QwtLinearColorMap::ColorStops::findUpper(double pos) const
    00112 {
    00113     int index = 0;
    00114     int n = _stops.size();
    00115
    00116     const ColorStop *stops = _stops.data();
    00117
    00118     while (n > 0)
    00119     {
    00120         const int half = n >> 1;
    00121         const int middle = index + half;
    00122
    00123         if ( stops[middle].pos <= pos )
    00124         {
    00125             index = middle + 1;
    00126             n -= half + 1;
    00127         }
    00128         else
    00129             n = half;
    00130     }
    00131
    00132     return index;
    00133 }
    00134
    00135 inline QRgb QwtLinearColorMap::ColorStops::rgb(
    00136     QwtLinearColorMap::Mode mode, double pos) const
    00137 {
    00138     if ( pos <= 0.0 )
    00139         return _stops[0].rgb;
    00140     if ( pos >= 1.0 )
    00141         return _stops[(int)(_stops.size() - 1)].rgb;
    00142
    00143     const int index = findUpper(pos);
    00144     if ( mode == FixedColors )
    00145     {
    00146         return _stops[index-1].rgb;
    00147     }
    00148     else
    00149     {
    00150         const ColorStop &s1 = _stops[index-1];
    00151         const ColorStop &s2 = _stops[index];
    00152
    00153         const double ratio = (pos - s1.pos) / (s2.pos - s1.pos);
    00154
    00155         const int r = s1.r + qRound(ratio * (s2.r - s1.r));
    00156         const int g = s1.g + qRound(ratio * (s2.g - s1.g));
    00157         const int b = s1.b + qRound(ratio * (s2.b - s1.b));
    00158
    00159         return qRgb(r, g, b);
    00160     }
    00161 }
    00162
    00164 QwtColorMap::QwtColorMap(Format format):
    00165     d_format(format)
    00166 {
    00167 }
    00168
    00170 QwtColorMap::~QwtColorMap()
    00171 {
    00172 }
    00173
    00183 QwtColorTable QwtColorMap::colorTable(
    00184     const QwtDoubleInterval &interval) const
    00185 {
    00186     QwtColorTable table(256);
    00187
    00188     if ( interval.isValid() )
    00189     {
    00190         const double step = interval.width() / (table.size() - 1);
    00191         for ( int i = 0; i < (int) table.size(); i++ )
    00192             table[i] = rgb(interval, interval.minValue() + step * i);
    00193     }
    00194
    00195     return table;
    00196 }
    00197
    00198 class QwtLinearColorMap::PrivateData
    00199 {
    00200 public:
    00201     ColorStops colorStops;
    00202     QwtLinearColorMap::Mode mode;
    00203 };
    00204
    00211 QwtLinearColorMap::QwtLinearColorMap(QwtColorMap::Format format):
    00212     QwtColorMap(format)
    00213 {
    00214     d_data = new PrivateData;
    00215     d_data->mode = ScaledColors;
    00216
    00217     setColorInterval( Qt::blue, Qt::yellow);
    00218 }
    00219
    00221 QwtLinearColorMap::QwtLinearColorMap(const QwtLinearColorMap &other):
    00222     QwtColorMap(other)
    00223 {
    00224     d_data = new PrivateData;
    00225     *this = other;
    00226 }
    00227
    00235 QwtLinearColorMap::QwtLinearColorMap(const QColor &color1,
    00236         const QColor &color2, QwtColorMap::Format format):
    00237     QwtColorMap(format)
    00238 {
    00239     d_data = new PrivateData;
    00240     d_data->mode = ScaledColors;
    00241     setColorInterval(color1, color2);
    00242 }
    00243
    00245 QwtLinearColorMap::~QwtLinearColorMap()
    00246 {
    00247     delete d_data;
    00248 }
    00249
    00251 QwtLinearColorMap &QwtLinearColorMap::operator=(
    00252     const QwtLinearColorMap &other)
    00253 {
    00254     QwtColorMap::operator=(other);
    00255     *d_data = *other.d_data;
    00256     return *this;
    00257 }
    00258
    00260 QwtColorMap *QwtLinearColorMap::copy() const
    00261 {
    00262     QwtLinearColorMap* map = new QwtLinearColorMap();
    00263     *map = *this;
    00264
    00265     return map;
    00266 }
    00267
    00277 void QwtLinearColorMap::setMode(Mode mode)
    00278 {
    00279     d_data->mode = mode;
    00280 }
    00281
    00286 QwtLinearColorMap::Mode QwtLinearColorMap::mode() const
    00287 {
    00288     return d_data->mode;
    00289 }
    00290
    00301 void QwtLinearColorMap::setColorInterval(
    00302     const QColor &color1, const QColor &color2)
    00303 {
    00304     d_data->colorStops = ColorStops();
    00305     d_data->colorStops.insert(0.0, color1);
    00306     d_data->colorStops.insert(1.0, color2);
    00307 }
    00308
    00319 void QwtLinearColorMap::addColorStop(double value, const QColor& color)
    00320 {
    00321     if ( value >= 0.0 && value <= 1.0 )
    00322         d_data->colorStops.insert(value, color);
    00323 }
    00324
    00328 QwtArray<double> QwtLinearColorMap::colorStops() const
    00329 {
    00330     return d_data->colorStops.stops();
    00331 }
    00332
    00337 QColor QwtLinearColorMap::color1() const
    00338 {
    00339     return QColor(d_data->colorStops.rgb(d_data->mode, 0.0));
    00340 }
    00341
    00346 QColor QwtLinearColorMap::color2() const
    00347 {
    00348     return QColor(d_data->colorStops.rgb(d_data->mode, 1.0));
    00349 }
    00350
    00357 QRgb QwtLinearColorMap::rgb(const QwtDoubleInterval &interval,
    00358     double value) const
    00359 {
    00360     const double ratio = (value - interval.minValue()) / interval.width();
    00361     return d_data->colorStops.rgb(d_data->mode, ratio);
    00362 }
    00363
    00370 unsigned char QwtLinearColorMap::colorIndex(
    00371     const QwtDoubleInterval &interval, double value) const
    00372 {
    00373     if ( !interval.isValid() || value <= interval.minValue() )
    00374         return 0;
    00375
    00376     if ( value >= interval.maxValue() )
    00377         return (unsigned char)255;
    00378
    00379     const double ratio = (value - interval.minValue()) / interval.width();
    00380
    00381     unsigned char index;
    00382     if ( d_data->mode == FixedColors )
    00383         index = (unsigned char)(ratio * 255); // always floor
    00384     else
    00385         index = (unsigned char)qRound(ratio * 255);
    00386
    00387     return index;
    00388 }
    00389
    00390 class QwtAlphaColorMap::PrivateData
    00391 {
    00392 public:
    00393     QColor color;
    00394     QRgb rgb;
    00395 };
    00396
    00397
    00402 QwtAlphaColorMap::QwtAlphaColorMap(const QColor &color):
    00403     QwtColorMap(QwtColorMap::RGB)
    00404 {
    00405     d_data = new PrivateData;
    00406     d_data->color = color;
    00407     d_data->rgb = color.rgb() & qRgba(255, 255, 255, 0);
    00408 }
    00409
    00414 QwtAlphaColorMap::QwtAlphaColorMap(const QwtAlphaColorMap &other):
    00415     QwtColorMap(other)
    00416 {
    00417     d_data = new PrivateData;
    00418     *this = other;
    00419 }
    00420
    00422 QwtAlphaColorMap::~QwtAlphaColorMap()
    00423 {
    00424     delete d_data;
    00425 }
    00426
    00432 QwtAlphaColorMap &QwtAlphaColorMap::operator=(
    00433     const QwtAlphaColorMap &other)
    00434 {
    00435     QwtColorMap::operator=(other);
    00436     *d_data = *other.d_data;
    00437     return *this;
    00438 }
    00439
    00441 QwtColorMap *QwtAlphaColorMap::copy() const
    00442 {
    00443     QwtAlphaColorMap* map = new QwtAlphaColorMap();
    00444     *map = *this;
    00445
    00446     return map;
    00447 }
    00448
    00455 void QwtAlphaColorMap::setColor(const QColor &color)
    00456 {
    00457     d_data->color = color;
    00458     d_data->rgb = color.rgb();
    00459 }
    00460
    00465 QColor QwtAlphaColorMap::color() const
    00466 {
    00467     return d_data->color;
    00468 }
    00469
    00479 QRgb QwtAlphaColorMap::rgb(const QwtDoubleInterval &interval,
    00480     double value) const
    00481 {
    00482     if ( interval.isValid() )
    00483     {
    00484         const double ratio = (value - interval.minValue()) / interval.width();
    00485         int alpha = qRound(255 * ratio);
    00486         if ( alpha < 0 )
    00487             alpha = 0;
    00488         if ( alpha > 255 )
    00489             alpha = 255;
    00490
    00491         return d_data->rgb | (alpha << 24);
    00492     }
    00493     return d_data->rgb;
    00494 }
    00495
    00503 unsigned char QwtAlphaColorMap::colorIndex(
    00504     const QwtDoubleInterval &, double) const
    00505 {
    00506     return 0;
    00507 }