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 }

Generated on Mon Feb 26 21:22:36 2007 for Qwt User's Guide by  doxygen 1.4.6