qwt_color_map.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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. #include "qwt_color_map.h"
  10. #include "qwt_math.h"
  11. #include "qwt_interval.h"
  12. #include <qnumeric.h>
  13. typedef QVector<QRgb> QwtColorTable;
  14. class QwtLinearColorMap::ColorStops
  15. {
  16. public:
  17. ColorStops()
  18. {
  19. _stops.reserve( 256 );
  20. }
  21. void insert( double pos, const QColor &color );
  22. QRgb rgb( QwtLinearColorMap::Mode, double pos ) const;
  23. QVector<double> stops() const;
  24. private:
  25. class ColorStop
  26. {
  27. public:
  28. ColorStop():
  29. pos( 0.0 ),
  30. rgb( 0 )
  31. {
  32. };
  33. ColorStop( double p, const QColor &c ):
  34. pos( p ),
  35. rgb( c.rgb() )
  36. {
  37. r = qRed( rgb );
  38. g = qGreen( rgb );
  39. b = qBlue( rgb );
  40. }
  41. double pos;
  42. QRgb rgb;
  43. int r, g, b;
  44. };
  45. inline int findUpper( double pos ) const;
  46. QVector<ColorStop> _stops;
  47. };
  48. void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color )
  49. {
  50. // Lookups need to be very fast, insertions are not so important.
  51. // Anyway, a balanced tree is what we need here. TODO ...
  52. if ( pos < 0.0 || pos > 1.0 )
  53. return;
  54. int index;
  55. if ( _stops.size() == 0 )
  56. {
  57. index = 0;
  58. _stops.resize( 1 );
  59. }
  60. else
  61. {
  62. index = findUpper( pos );
  63. if ( index == ( int )_stops.size() ||
  64. qAbs( _stops[index].pos - pos ) >= 0.001 )
  65. {
  66. _stops.resize( _stops.size() + 1 );
  67. for ( int i = _stops.size() - 1; i > index; i-- )
  68. _stops[i] = _stops[i-1];
  69. }
  70. }
  71. _stops[index] = ColorStop( pos, color );
  72. }
  73. inline QVector<double> QwtLinearColorMap::ColorStops::stops() const
  74. {
  75. QVector<double> positions( _stops.size() );
  76. for ( int i = 0; i < ( int )_stops.size(); i++ )
  77. positions[i] = _stops[i].pos;
  78. return positions;
  79. }
  80. inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const
  81. {
  82. int index = 0;
  83. int n = _stops.size();
  84. const ColorStop *stops = _stops.data();
  85. while ( n > 0 )
  86. {
  87. const int half = n >> 1;
  88. const int middle = index + half;
  89. if ( stops[middle].pos <= pos )
  90. {
  91. index = middle + 1;
  92. n -= half + 1;
  93. }
  94. else
  95. n = half;
  96. }
  97. return index;
  98. }
  99. inline QRgb QwtLinearColorMap::ColorStops::rgb(
  100. QwtLinearColorMap::Mode mode, double pos ) const
  101. {
  102. if ( pos <= 0.0 )
  103. return _stops[0].rgb;
  104. if ( pos >= 1.0 )
  105. return _stops[( int )( _stops.size() - 1 )].rgb;
  106. const int index = findUpper( pos );
  107. if ( mode == FixedColors )
  108. {
  109. return _stops[index-1].rgb;
  110. }
  111. else
  112. {
  113. const ColorStop &s1 = _stops[index-1];
  114. const ColorStop &s2 = _stops[index];
  115. const double ratio = ( pos - s1.pos ) / ( s2.pos - s1.pos );
  116. const int r = s1.r + qRound( ratio * ( s2.r - s1.r ) );
  117. const int g = s1.g + qRound( ratio * ( s2.g - s1.g ) );
  118. const int b = s1.b + qRound( ratio * ( s2.b - s1.b ) );
  119. return qRgb( r, g, b );
  120. }
  121. }
  122. //! Constructor
  123. QwtColorMap::QwtColorMap( Format format ):
  124. d_format( format )
  125. {
  126. }
  127. //! Destructor
  128. QwtColorMap::~QwtColorMap()
  129. {
  130. }
  131. /*!
  132. Build and return a color map of 256 colors
  133. The color table is needed for rendering indexed images in combination
  134. with using colorIndex().
  135. \param interval Range for the values
  136. \return A color table, that can be used for a QImage
  137. */
  138. QwtColorTable QwtColorMap::colorTable( const QwtInterval &interval ) const
  139. {
  140. QwtColorTable table( 256 );
  141. if ( interval.isValid() )
  142. {
  143. const double step = interval.width() / ( table.size() - 1 );
  144. for ( int i = 0; i < ( int ) table.size(); i++ )
  145. table[i] = rgb( interval, interval.minValue() + step * i );
  146. }
  147. return table;
  148. }
  149. class QwtLinearColorMap::PrivateData
  150. {
  151. public:
  152. ColorStops colorStops;
  153. QwtLinearColorMap::Mode mode;
  154. };
  155. /*!
  156. Build a color map with two stops at 0.0 and 1.0. The color
  157. at 0.0 is Qt::blue, at 1.0 it is Qt::yellow.
  158. \param format Preferred format of the color map
  159. */
  160. QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ):
  161. QwtColorMap( format )
  162. {
  163. d_data = new PrivateData;
  164. d_data->mode = ScaledColors;
  165. setColorInterval( Qt::blue, Qt::yellow );
  166. }
  167. /*!
  168. Build a color map with two stops at 0.0 and 1.0.
  169. \param color1 Color used for the minimum value of the value interval
  170. \param color2 Color used for the maximum value of the value interval
  171. \param format Preferred format of the coor map
  172. */
  173. QwtLinearColorMap::QwtLinearColorMap( const QColor &color1,
  174. const QColor &color2, QwtColorMap::Format format ):
  175. QwtColorMap( format )
  176. {
  177. d_data = new PrivateData;
  178. d_data->mode = ScaledColors;
  179. setColorInterval( color1, color2 );
  180. }
  181. //! Destructor
  182. QwtLinearColorMap::~QwtLinearColorMap()
  183. {
  184. delete d_data;
  185. }
  186. /*!
  187. \brief Set the mode of the color map
  188. FixedColors means the color is calculated from the next lower
  189. color stop. ScaledColors means the color is calculated
  190. by interpolating the colors of the adjacent stops.
  191. \sa mode()
  192. */
  193. void QwtLinearColorMap::setMode( Mode mode )
  194. {
  195. d_data->mode = mode;
  196. }
  197. /*!
  198. \return Mode of the color map
  199. \sa setMode()
  200. */
  201. QwtLinearColorMap::Mode QwtLinearColorMap::mode() const
  202. {
  203. return d_data->mode;
  204. }
  205. /*!
  206. Set the color range
  207. Add stops at 0.0 and 1.0.
  208. \param color1 Color used for the minimum value of the value interval
  209. \param color2 Color used for the maximum value of the value interval
  210. \sa color1(), color2()
  211. */
  212. void QwtLinearColorMap::setColorInterval(
  213. const QColor &color1, const QColor &color2 )
  214. {
  215. d_data->colorStops = ColorStops();
  216. d_data->colorStops.insert( 0.0, color1 );
  217. d_data->colorStops.insert( 1.0, color2 );
  218. }
  219. /*!
  220. Add a color stop
  221. The value has to be in the range [0.0, 1.0].
  222. F.e. a stop at position 17.0 for a range [10.0,20.0] must be
  223. passed as: (17.0 - 10.0) / (20.0 - 10.0)
  224. \param value Value between [0.0, 1.0]
  225. \param color Color stop
  226. */
  227. void QwtLinearColorMap::addColorStop( double value, const QColor& color )
  228. {
  229. if ( value >= 0.0 && value <= 1.0 )
  230. d_data->colorStops.insert( value, color );
  231. }
  232. /*!
  233. Return all positions of color stops in increasing order
  234. */
  235. QVector<double> QwtLinearColorMap::colorStops() const
  236. {
  237. return d_data->colorStops.stops();
  238. }
  239. /*!
  240. \return the first color of the color range
  241. \sa setColorInterval()
  242. */
  243. QColor QwtLinearColorMap::color1() const
  244. {
  245. return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) );
  246. }
  247. /*!
  248. \return the second color of the color range
  249. \sa setColorInterval()
  250. */
  251. QColor QwtLinearColorMap::color2() const
  252. {
  253. return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) );
  254. }
  255. /*!
  256. Map a value of a given interval into a rgb value
  257. \param interval Range for all values
  258. \param value Value to map into a rgb value
  259. */
  260. QRgb QwtLinearColorMap::rgb(
  261. const QwtInterval &interval, double value ) const
  262. {
  263. if ( qIsNaN(value) )
  264. return qRgba(0, 0, 0, 0);
  265. const double width = interval.width();
  266. double ratio = 0.0;
  267. if ( width > 0.0 )
  268. ratio = ( value - interval.minValue() ) / width;
  269. return d_data->colorStops.rgb( d_data->mode, ratio );
  270. }
  271. /*!
  272. Map a value of a given interval into a color index, between 0 and 255
  273. \param interval Range for all values
  274. \param value Value to map into a color index
  275. */
  276. unsigned char QwtLinearColorMap::colorIndex(
  277. const QwtInterval &interval, double value ) const
  278. {
  279. const double width = interval.width();
  280. if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() )
  281. return 0;
  282. if ( value >= interval.maxValue() )
  283. return ( unsigned char )255;
  284. const double ratio = ( value - interval.minValue() ) / width;
  285. unsigned char index;
  286. if ( d_data->mode == FixedColors )
  287. index = ( unsigned char )( ratio * 255 ); // always floor
  288. else
  289. index = ( unsigned char )qRound( ratio * 255 );
  290. return index;
  291. }
  292. class QwtAlphaColorMap::PrivateData
  293. {
  294. public:
  295. QColor color;
  296. QRgb rgb;
  297. };
  298. /*!
  299. Constructor
  300. \param color Color of the map
  301. */
  302. QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ):
  303. QwtColorMap( QwtColorMap::RGB )
  304. {
  305. d_data = new PrivateData;
  306. d_data->color = color;
  307. d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 );
  308. }
  309. //! Destructor
  310. QwtAlphaColorMap::~QwtAlphaColorMap()
  311. {
  312. delete d_data;
  313. }
  314. /*!
  315. Set the color
  316. \param color Color
  317. \sa color()
  318. */
  319. void QwtAlphaColorMap::setColor( const QColor &color )
  320. {
  321. d_data->color = color;
  322. d_data->rgb = color.rgb();
  323. }
  324. /*!
  325. \return the color
  326. \sa setColor()
  327. */
  328. QColor QwtAlphaColorMap::color() const
  329. {
  330. return d_data->color;
  331. }
  332. /*!
  333. \brief Map a value of a given interval into a alpha value
  334. alpha := (value - interval.minValue()) / interval.width();
  335. \param interval Range for all values
  336. \param value Value to map into a rgb value
  337. \return rgb value, with an alpha value
  338. */
  339. QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const
  340. {
  341. const double width = interval.width();
  342. if ( !qIsNaN(value) && width >= 0.0 )
  343. {
  344. const double ratio = ( value - interval.minValue() ) / width;
  345. int alpha = qRound( 255 * ratio );
  346. if ( alpha < 0 )
  347. alpha = 0;
  348. if ( alpha > 255 )
  349. alpha = 255;
  350. return d_data->rgb | ( alpha << 24 );
  351. }
  352. return d_data->rgb;
  353. }
  354. /*!
  355. Dummy function, needed to be implemented as it is pure virtual
  356. in QwtColorMap. Color indices make no sense in combination with
  357. an alpha channel.
  358. \return Always 0
  359. */
  360. unsigned char QwtAlphaColorMap::colorIndex(
  361. const QwtInterval &, double ) const
  362. {
  363. return 0;
  364. }