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(
00358     const QwtDoubleInterval &interval, double value) const
00359 {
00360     const double width = interval.width();
00361 
00362     double ratio = 0.0;
00363     if ( width > 0.0 )
00364         ratio = (value - interval.minValue()) / width;
00365 
00366     return d_data->colorStops.rgb(d_data->mode, ratio);
00367 }
00368 
00375 unsigned char QwtLinearColorMap::colorIndex(
00376     const QwtDoubleInterval &interval, double value) const
00377 {
00378     const double width = interval.width();
00379 
00380     if ( width <= 0.0 || value <= interval.minValue() )
00381         return 0;
00382 
00383     if ( value >= interval.maxValue() )
00384         return (unsigned char)255;
00385 
00386     const double ratio = (value - interval.minValue()) / width;
00387     
00388     unsigned char index;
00389     if ( d_data->mode == FixedColors )
00390         index = (unsigned char)(ratio * 255); // always floor
00391     else
00392         index = (unsigned char)qRound(ratio * 255);
00393 
00394     return index;
00395 }
00396 
00397 class QwtAlphaColorMap::PrivateData
00398 {
00399 public:
00400     QColor color;
00401     QRgb rgb;
00402 };
00403 
00404 
00409 QwtAlphaColorMap::QwtAlphaColorMap(const QColor &color):
00410     QwtColorMap(QwtColorMap::RGB)
00411 {
00412     d_data = new PrivateData;
00413     d_data->color = color;
00414     d_data->rgb = color.rgb() & qRgba(255, 255, 255, 0);
00415 }
00416 
00421 QwtAlphaColorMap::QwtAlphaColorMap(const QwtAlphaColorMap &other):
00422     QwtColorMap(other)
00423 {
00424     d_data = new PrivateData;
00425     *this = other;
00426 }
00427 
00429 QwtAlphaColorMap::~QwtAlphaColorMap()
00430 {
00431     delete d_data;
00432 }
00433 
00439 QwtAlphaColorMap &QwtAlphaColorMap::operator=(
00440     const QwtAlphaColorMap &other)
00441 {
00442     QwtColorMap::operator=(other);
00443     *d_data = *other.d_data;
00444     return *this;
00445 }
00446 
00448 QwtColorMap *QwtAlphaColorMap::copy() const
00449 {
00450     QwtAlphaColorMap* map = new QwtAlphaColorMap();
00451     *map = *this;
00452 
00453     return map;
00454 }
00455 
00462 void QwtAlphaColorMap::setColor(const QColor &color)
00463 {
00464     d_data->color = color;
00465     d_data->rgb = color.rgb();
00466 }
00467 
00472 QColor QwtAlphaColorMap::color() const
00473 {
00474     return d_data->color;
00475 }
00476 
00486 QRgb QwtAlphaColorMap::rgb(const QwtDoubleInterval &interval,
00487     double value) const
00488 {
00489     const double width = interval.width();
00490     if ( width >= 0.0 )
00491     {
00492         const double ratio = (value - interval.minValue()) / width;
00493         int alpha = qRound(255 * ratio);
00494         if ( alpha < 0 )
00495             alpha = 0;
00496         if ( alpha > 255 )
00497             alpha = 255;
00498 
00499         return d_data->rgb | (alpha << 24);
00500     }
00501     return d_data->rgb;
00502 }
00503 
00511 unsigned char QwtAlphaColorMap::colorIndex(
00512     const QwtDoubleInterval &, double) const
00513 {
00514     return 0;
00515 }

Generated on Sun Mar 22 16:54:06 2009 for Qwt User's Guide by  doxygen 1.5.0