QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgscolorrampimpl.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscolorrampimpl.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgscolorrampimpl.h"
17 #include "qgscolorbrewerpalette.h"
18 #include "qgscptcityarchive.h"
19 
20 #include "qgssymbollayerutils.h"
21 #include "qgsapplication.h"
22 #include "qgslogger.h"
23 
24 #include <algorithm>
25 #include <random>
26 
27 #include <QTime>
28 #include <QDir>
29 #include <QFileInfo>
30 
32 
33 
34 static QColor _interpolateRgb( const QColor &c1, const QColor &c2, const double value, const Qgis::AngularDirection )
35 {
36  if ( std::isnan( value ) )
37  return c2;
38 
39  const qreal red1 = c1.redF();
40  const qreal red2 = c2.redF();
41  const qreal red = ( red1 + value * ( red2 - red1 ) );
42 
43  const qreal green1 = c1.greenF();
44  const qreal green2 = c2.greenF();
45  const qreal green = ( green1 + value * ( green2 - green1 ) );
46 
47  const qreal blue1 = c1.blueF();
48  const qreal blue2 = c2.blueF();
49  const qreal blue = ( blue1 + value * ( blue2 - blue1 ) );
50 
51  const qreal alpha1 = c1.alphaF();
52  const qreal alpha2 = c2.alphaF();
53  const qreal alpha = ( alpha1 + value * ( alpha2 - alpha1 ) );
54 
55  return QColor::fromRgbF( red, green, blue, alpha );
56 }
57 
58 static QColor _interpolateHsv( const QColor &c1, const QColor &c2, const double value, const Qgis::AngularDirection direction )
59 {
60  if ( std::isnan( value ) )
61  return c2;
62 
63  qreal hue1 = c1.hsvHueF();
64  qreal hue2 = c2.hsvHueF();
65  qreal hue = 0;
66  if ( hue1 == -1 )
67  hue = hue2;
68  else if ( hue2 == -1 )
69  hue = hue1;
70  else
71  {
72  switch ( direction )
73  {
75  {
76  if ( hue1 < hue2 )
77  hue1 += 1;
78 
79  hue = hue1 - value * ( hue1 - hue2 );
80  if ( hue < 0 )
81  hue += 1;
82  if ( hue > 1 )
83  hue -= 1;
84  break;
85  }
86 
88  {
89  if ( hue2 < hue1 )
90  hue2 += 1;
91 
92  hue = hue1 + value * ( hue2 - hue1 );
93  if ( hue > 1 )
94  hue -= 1;
95  break;
96  }
97  }
98  }
99 
100  const qreal saturation1 = c1.hsvSaturationF();
101  const qreal saturation2 = c2.hsvSaturationF();
102  const qreal saturation = ( saturation1 + value * ( saturation2 - saturation1 ) );
103 
104  const qreal value1 = c1.valueF();
105  const qreal value2 = c2.valueF();
106  const qreal valueOut = ( value1 + value * ( value2 - value1 ) );
107 
108  const qreal alpha1 = c1.alphaF();
109  const qreal alpha2 = c2.alphaF();
110  const qreal alpha = ( alpha1 + value * ( alpha2 - alpha1 ) );
111 
112  return QColor::fromHsvF( hue > 1 ? hue - 1 : hue, saturation, valueOut, alpha );
113 }
114 
115 static QColor _interpolateHsl( const QColor &c1, const QColor &c2, const double value, const Qgis::AngularDirection direction )
116 {
117  if ( std::isnan( value ) )
118  return c2;
119 
120  qreal hue1 = c1.hslHueF();
121  qreal hue2 = c2.hslHueF();
122  qreal hue = 0;
123  if ( hue1 == -1 )
124  hue = hue2;
125  else if ( hue2 == -1 )
126  hue = hue1;
127  else
128  {
129  switch ( direction )
130  {
132  {
133  if ( hue1 < hue2 )
134  hue1 += 1;
135 
136  hue = hue1 - value * ( hue1 - hue2 );
137  if ( hue < 0 )
138  hue += 1;
139  if ( hue > 1 )
140  hue -= 1;
141  break;
142  }
143 
145  {
146  if ( hue2 < hue1 )
147  hue2 += 1;
148 
149  hue = hue1 + value * ( hue2 - hue1 );
150  if ( hue > 1 )
151  hue -= 1;
152  break;
153  }
154  }
155  }
156 
157  const qreal saturation1 = c1.hslSaturationF();
158  const qreal saturation2 = c2.hslSaturationF();
159  const qreal saturation = ( saturation1 + value * ( saturation2 - saturation1 ) );
160 
161  const qreal lightness1 = c1.lightnessF();
162  const qreal lightness2 = c2.lightnessF();
163  const qreal lightness = ( lightness1 + value * ( lightness2 - lightness1 ) );
164 
165  const qreal alpha1 = c1.alphaF();
166  const qreal alpha2 = c2.alphaF();
167  const qreal alpha = ( alpha1 + value * ( alpha2 - alpha1 ) );
168 
169  return QColor::fromHslF( hue > 1 ? hue - 1 : hue, saturation, lightness, alpha );
170 }
171 
173 
174 
175 QgsGradientStop::QgsGradientStop( double offset, const QColor &color )
176  : offset( offset )
177  , color( color )
178  , mFunc( _interpolateRgb )
179 {
180 
181 }
182 
183 void QgsGradientStop::setColorSpec( QColor::Spec spec )
184 {
185  mColorSpec = spec;
186 
187  switch ( mColorSpec )
188  {
189  case QColor::Rgb:
190  case QColor::Invalid:
191 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
192  case QColor::ExtendedRgb:
193 #endif
194  case QColor::Cmyk:
195  mFunc = _interpolateRgb;
196  break;
197  case QColor::Hsv:
198  mFunc = _interpolateHsv;
199  break;
200  case QColor::Hsl:
201  mFunc = _interpolateHsl;
202  break;
203  }
204 }
205 
206 QgsGradientColorRamp::QgsGradientColorRamp( const QColor &color1, const QColor &color2,
207  bool discrete, const QgsGradientStopsList &stops )
208  : mColor1( color1 )
209  , mColor2( color2 )
210  , mDiscrete( discrete )
211  , mStops( stops )
212  , mFunc( _interpolateRgb )
213 {
214 }
215 
216 QgsColorRamp *QgsGradientColorRamp::create( const QVariantMap &props )
217 {
218  // color1 and color2
221  if ( props.contains( QStringLiteral( "color1" ) ) )
222  color1 = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color1" )].toString() );
223  if ( props.contains( QStringLiteral( "color2" ) ) )
224  color2 = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color2" )].toString() );
225 
226  //stops
228  if ( props.contains( QStringLiteral( "stops" ) ) )
229  {
230  const auto constSplit = props[QStringLiteral( "stops" )].toString().split( ':' );
231  for ( const QString &stop : constSplit )
232  {
233  const QStringList parts = stop.split( ';' );
234  if ( parts.size() != 2 && parts.size() != 4 )
235  continue;
236 
237  QColor c = QgsSymbolLayerUtils::decodeColor( parts.at( 1 ) );
238  stops.append( QgsGradientStop( parts.at( 0 ).toDouble(), c ) );
239 
240  if ( parts.size() == 4 )
241  {
242  if ( parts.at( 2 ).compare( QLatin1String( "rgb" ) ) == 0 )
243  stops.last().setColorSpec( QColor::Spec::Rgb );
244  else if ( parts.at( 2 ).compare( QLatin1String( "hsv" ) ) == 0 )
245  stops.last().setColorSpec( QColor::Spec::Hsv );
246  else if ( parts.at( 2 ).compare( QLatin1String( "hsl" ) ) == 0 )
247  stops.last().setColorSpec( QColor::Spec::Hsl );
248 
249  if ( parts.at( 3 ).compare( QLatin1String( "cw" ) ) == 0 )
250  stops.last().setDirection( Qgis::AngularDirection::Clockwise );
251  else if ( parts.at( 3 ).compare( QLatin1String( "ccw" ) ) == 0 )
252  stops.last().setDirection( Qgis::AngularDirection::CounterClockwise );
253  }
254  }
255  }
256 
257  // discrete vs. continuous
258  bool discrete = false;
259  if ( props.contains( QStringLiteral( "discrete" ) ) )
260  {
261  if ( props[QStringLiteral( "discrete" )] == QLatin1String( "1" ) )
262  discrete = true;
263  }
264 
265  // search for information keys starting with "info_"
267  for ( QVariantMap::const_iterator it = props.constBegin();
268  it != props.constEnd(); ++it )
269  {
270  if ( it.key().startsWith( QLatin1String( "info_" ) ) )
271  info[ it.key().mid( 5 )] = it.value().toString();
272  }
273 
275  r->setInfo( info );
276 
277  if ( props.contains( QStringLiteral( "spec" ) ) )
278  {
279  const QString spec = props.value( QStringLiteral( "spec" ) ).toString().trimmed();
280  if ( spec.compare( QLatin1String( "rgb" ) ) == 0 )
281  r->setColorSpec( QColor::Spec::Rgb );
282  else if ( spec.compare( QLatin1String( "hsv" ) ) == 0 )
283  r->setColorSpec( QColor::Spec::Hsv );
284  else if ( spec.compare( QLatin1String( "hsl" ) ) == 0 )
285  r->setColorSpec( QColor::Spec::Hsl );
286  }
287 
288  if ( props.contains( QStringLiteral( "direction" ) ) )
289  {
290  const QString direction = props.value( QStringLiteral( "direction" ) ).toString().trimmed();
291  if ( direction.compare( QLatin1String( "ccw" ) ) == 0 )
293  else if ( direction.compare( QLatin1String( "cw" ) ) == 0 )
295  }
296 
297  return r;
298 }
299 
300 double QgsGradientColorRamp::value( int index ) const
301 {
302  if ( index <= 0 )
303  {
304  return 0;
305  }
306  else if ( index >= mStops.size() + 1 )
307  {
308  return 1;
309  }
310  else
311  {
312  return mStops[index - 1].offset;
313  }
314 }
315 
316 QColor QgsGradientColorRamp::color( double value ) const
317 {
318  if ( qgsDoubleNear( value, 0.0 ) || value < 0.0 )
319  {
320  return mColor1;
321  }
322  else if ( qgsDoubleNear( value, 1.0 ) || value > 1.0 )
323  {
324  return mColor2;
325  }
326  else if ( mStops.isEmpty() )
327  {
328  if ( mDiscrete )
329  return mColor1;
330 
331  return mFunc( mColor1, mColor2, value, mDirection );
332  }
333  else
334  {
335  double lower = 0, upper = 0;
336  QColor c1 = mColor1, c2;
337  for ( QgsGradientStopsList::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
338  {
339  if ( it->offset > value )
340  {
341  if ( mDiscrete )
342  return c1;
343 
344  upper = it->offset;
345  c2 = it->color;
346 
347  return qgsDoubleNear( upper, lower ) ? c1 : it->mFunc( c1, c2, ( value - lower ) / ( upper - lower ), it->mDirection );
348  }
349  lower = it->offset;
350  c1 = it->color;
351  }
352 
353  if ( mDiscrete )
354  return c1;
355 
356  upper = 1;
357  c2 = mColor2;
358  return qgsDoubleNear( upper, lower ) ? c1 : mFunc( c1, c2, ( value - lower ) / ( upper - lower ), mDirection );
359  }
360 }
361 
363 {
365 }
366 
368 {
369  QgsGradientStopsList newStops;
370  newStops.reserve( mStops.size() );
371 
372  if ( mDiscrete )
373  {
374  mColor2 = mColor1;
375  mColor1 = mStops.at( mStops.size() - 1 ).color;
376  for ( int k = mStops.size() - 1; k >= 1; k-- )
377  {
378  newStops << QgsGradientStop( 1 - mStops.at( k ).offset, mStops.at( k - 1 ).color );
379  }
380  newStops << QgsGradientStop( 1 - mStops.at( 0 ).offset, mColor2 );
381  }
382  else
383  {
384  QColor tmpColor = mColor2;
385  mColor2 = mColor1;
386  mColor1 = tmpColor;
387  for ( int k = mStops.size() - 1; k >= 0; k-- )
388  {
389  newStops << QgsGradientStop( 1 - mStops.at( k ).offset, mStops.at( k ).color );
390  }
391  }
392 
393  // transfer color spec, invert directions
394  if ( mStops.empty() )
395  {
396  // reverse direction
398  }
399  else
400  {
401  newStops[0].setColorSpec( mColorSpec );
403  for ( int i = 1, j = mStops.size() - 1; i < mStops.size(); ++i, --j )
404  {
405  newStops[i].setColorSpec( mStops.at( j ).colorSpec() );
407  }
408  mColorSpec = mStops.at( 0 ).colorSpec();
410  }
411 
412  mStops = newStops;
413 }
414 
416 {
418  mDiscrete, mStops );
419  r->setInfo( mInfo );
420  r->setColorSpec( mColorSpec );
421  r->setDirection( mDirection );
422  return r;
423 }
424 
426 {
427  QVariantMap map;
428  map[QStringLiteral( "color1" )] = QgsSymbolLayerUtils::encodeColor( mColor1 );
429  map[QStringLiteral( "color2" )] = QgsSymbolLayerUtils::encodeColor( mColor2 );
430  if ( !mStops.isEmpty() )
431  {
432  QStringList lst;
433  lst.reserve( mStops.size() );
434  for ( const QgsGradientStop &stop : mStops )
435  {
436  lst.append( QStringLiteral( "%1;%2;%3;%4" ).arg( stop.offset ).arg( QgsSymbolLayerUtils::encodeColor( stop.color ),
437  stop.colorSpec() == QColor::Rgb ? QStringLiteral( "rgb" )
438  : stop.colorSpec() == QColor::Hsv ? QStringLiteral( "hsv" )
439  : stop.colorSpec() == QColor::Hsl ? QStringLiteral( "hsl" ) : QString(),
440  stop.direction() == Qgis::AngularDirection::CounterClockwise ? QStringLiteral( "ccw" ) : QStringLiteral( "cw" ) ) );
441  }
442  map[QStringLiteral( "stops" )] = lst.join( QLatin1Char( ':' ) );
443  }
444 
445  map[QStringLiteral( "discrete" )] = mDiscrete ? "1" : "0";
446 
447  for ( QgsStringMap::const_iterator it = mInfo.constBegin();
448  it != mInfo.constEnd(); ++it )
449  {
450  map["info_" + it.key()] = it.value();
451  }
452 
453  switch ( mColorSpec )
454  {
455  case QColor::Rgb:
456  map[QStringLiteral( "spec" ) ] = QStringLiteral( "rgb" );
457  break;
458  case QColor::Hsv:
459  map[QStringLiteral( "spec" ) ] = QStringLiteral( "hsv" );
460  break;
461  case QColor::Hsl:
462  map[QStringLiteral( "spec" ) ] = QStringLiteral( "hsl" );
463  break;
464  case QColor::Cmyk:
465  case QColor::Invalid:
466 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
467  case QColor::ExtendedRgb:
468 #endif
469  break;
470  }
471 
472  switch ( mDirection )
473  {
475  map[QStringLiteral( "direction" ) ] = QStringLiteral( "cw" );
476  break;
478  map[QStringLiteral( "direction" ) ] = QStringLiteral( "ccw" );
479  break;
480  }
481 
482  map[QStringLiteral( "rampType" )] = type();
483  return map;
484 }
486 {
487  if ( discrete == mDiscrete )
488  return;
489 
490  // if going to/from Discrete, re-arrange stops
491  // this will only work when stops are equally-spaced
492  QgsGradientStopsList newStops;
493  if ( discrete )
494  {
495  // re-arrange stops offset
496  int numStops = mStops.count() + 2;
497  int i = 1;
498  for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
499  it != mStops.constEnd(); ++it )
500  {
501  newStops.append( QgsGradientStop( static_cast< double >( i ) / numStops, it->color ) );
502  if ( i == numStops - 1 )
503  break;
504  i++;
505  }
506  // replicate last color
507  newStops.append( QgsGradientStop( static_cast< double >( i ) / numStops, mColor2 ) );
508  }
509  else
510  {
511  // re-arrange stops offset, remove duplicate last color
512  int numStops = mStops.count() + 2;
513  int i = 1;
514  for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
515  it != mStops.constEnd(); ++it )
516  {
517  newStops.append( QgsGradientStop( static_cast< double >( i ) / ( numStops - 2 ), it->color ) );
518  if ( i == numStops - 3 )
519  break;
520  i++;
521  }
522  }
523  mStops = newStops;
524  mDiscrete = discrete;
525 }
526 
527 bool stopLessThan( const QgsGradientStop &s1, const QgsGradientStop &s2 )
528 {
529  return s1.offset < s2.offset;
530 }
531 
533 {
534  mStops = stops;
535 
536  //sort stops by offset
537  std::sort( mStops.begin(), mStops.end(), stopLessThan );
538 }
539 
540 void QgsGradientColorRamp::addStopsToGradient( QGradient *gradient, double opacity ) const
541 {
542  //copy color ramp stops to a QGradient
543  QColor color1 = mColor1;
544  QColor color2 = mColor2;
545  if ( opacity < 1 )
546  {
547  color1.setAlpha( color1.alpha() * opacity );
548  color2.setAlpha( color2.alpha() * opacity );
549  }
550  gradient->setColorAt( 0, color1 );
551  gradient->setColorAt( 1, color2 );
552 
553  double lastOffset = 0;
554  for ( const QgsGradientStop &stop : mStops )
555  {
556 
557  QColor rampColor = stop.color;
558  if ( opacity < 1 )
559  {
560  rampColor.setAlpha( rampColor.alpha() * opacity );
561  }
562  gradient->setColorAt( stop.offset, rampColor );
563 
564  if ( stop.colorSpec() != QColor::Rgb )
565  {
566  // QGradient only supports RGB interpolation. For other color specs we have
567  // to "fake" things by populating the gradient with additional stops
568  for ( double offset = lastOffset + 0.05; offset < stop.offset; offset += 0.05 )
569  {
570  QColor midColor = color( offset );
571  if ( opacity < 1 )
572  {
573  midColor.setAlpha( midColor.alpha() * opacity );
574  }
575  gradient->setColorAt( offset, midColor );
576  }
577  }
578  lastOffset = stop.offset;
579  }
580 
581  if ( mColorSpec != QColor::Rgb )
582  {
583  for ( double offset = lastOffset + 0.05; offset < 1; offset += 0.05 )
584  {
585  QColor midColor = color( offset );
586  if ( opacity < 1 )
587  {
588  midColor.setAlpha( midColor.alpha() * opacity );
589  }
590  gradient->setColorAt( offset, midColor );
591  }
592  }
593 }
594 
595 void QgsGradientColorRamp::setColorSpec( QColor::Spec spec )
596 {
597  mColorSpec = spec;
598  switch ( mColorSpec )
599  {
600  case QColor::Rgb:
601  case QColor::Invalid:
602 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
603  case QColor::ExtendedRgb:
604 #endif
605  case QColor::Cmyk:
606  mFunc = _interpolateRgb;
607  break;
608  case QColor::Hsv:
609  mFunc = _interpolateHsv;
610  break;
611  case QColor::Hsl:
612  mFunc = _interpolateHsl;
613  break;
614  }
615 }
616 
617 
619 
620 
621 QgsLimitedRandomColorRamp::QgsLimitedRandomColorRamp( int count, int hueMin, int hueMax,
622  int satMin, int satMax, int valMin, int valMax )
623  : mCount( count )
624  , mHueMin( hueMin ), mHueMax( hueMax )
625  , mSatMin( satMin ), mSatMax( satMax )
626  , mValMin( valMin ), mValMax( valMax )
627 {
628  updateColors();
629 }
630 
632 {
637 
638  if ( props.contains( QStringLiteral( "count" ) ) ) count = props[QStringLiteral( "count" )].toInt();
639  if ( props.contains( QStringLiteral( "hueMin" ) ) ) hueMin = props[QStringLiteral( "hueMin" )].toInt();
640  if ( props.contains( QStringLiteral( "hueMax" ) ) ) hueMax = props[QStringLiteral( "hueMax" )].toInt();
641  if ( props.contains( QStringLiteral( "satMin" ) ) ) satMin = props[QStringLiteral( "satMin" )].toInt();
642  if ( props.contains( QStringLiteral( "satMax" ) ) ) satMax = props[QStringLiteral( "satMax" )].toInt();
643  if ( props.contains( QStringLiteral( "valMin" ) ) ) valMin = props[QStringLiteral( "valMin" )].toInt();
644  if ( props.contains( QStringLiteral( "valMax" ) ) ) valMax = props[QStringLiteral( "valMax" )].toInt();
645 
647 }
648 
649 double QgsLimitedRandomColorRamp::value( int index ) const
650 {
651  if ( mColors.empty() )
652  return 0;
653  return static_cast< double >( index ) / ( mColors.size() - 1 );
654 }
655 
656 QColor QgsLimitedRandomColorRamp::color( double value ) const
657 {
658  if ( value < 0 || value > 1 )
659  return QColor();
660 
661  int colorCnt = mColors.count();
662  int colorIdx = std::min( static_cast< int >( value * colorCnt ), colorCnt - 1 );
663 
664  if ( colorIdx >= 0 && colorIdx < colorCnt )
665  return mColors.at( colorIdx );
666 
667  return QColor();
668 }
669 
671 {
673 }
674 
676 {
678 }
679 
681 {
682  QVariantMap map;
683  map[QStringLiteral( "count" )] = QString::number( mCount );
684  map[QStringLiteral( "hueMin" )] = QString::number( mHueMin );
685  map[QStringLiteral( "hueMax" )] = QString::number( mHueMax );
686  map[QStringLiteral( "satMin" )] = QString::number( mSatMin );
687  map[QStringLiteral( "satMax" )] = QString::number( mSatMax );
688  map[QStringLiteral( "valMin" )] = QString::number( mValMin );
689  map[QStringLiteral( "valMax" )] = QString::number( mValMax );
690  map[QStringLiteral( "rampType" )] = type();
691  return map;
692 }
693 
695  int hueMax, int hueMin, int satMax, int satMin, int valMax, int valMin )
696 {
697  int h, s, v;
698  QList<QColor> colors;
699 
700  //normalize values
701  int safeHueMax = std::max( hueMin, hueMax );
702  int safeHueMin = std::min( hueMin, hueMax );
703  int safeSatMax = std::max( satMin, satMax );
704  int safeSatMin = std::min( satMin, satMax );
705  int safeValMax = std::max( valMin, valMax );
706  int safeValMin = std::min( valMin, valMax );
707 
708  //start hue at random angle
709  double currentHueAngle = 360.0 * static_cast< double >( std::rand() ) / RAND_MAX;
710 
711  colors.reserve( count );
712  for ( int i = 0; i < count; ++i )
713  {
714  //increment hue by golden ratio (approx 137.507 degrees)
715  //as this minimizes hue nearness as count increases
716  //see http://basecase.org/env/on-rainbows for more details
717  currentHueAngle += 137.50776;
718  //scale hue to between hueMax and hueMin
719  h = std::clamp( std::round( ( std::fmod( currentHueAngle, 360.0 ) / 360.0 ) * ( safeHueMax - safeHueMin ) + safeHueMin ), 0.0, 359.0 );
720  s = std::clamp( ( static_cast<int>( std::rand() ) % ( safeSatMax - safeSatMin + 1 ) ) + safeSatMin, 0, 255 );
721  v = std::clamp( ( static_cast<int>( std::rand() ) % ( safeValMax - safeValMin + 1 ) ) + safeValMin, 0, 255 );
722  colors.append( QColor::fromHsv( h, s, v ) );
723  }
724  return colors;
725 }
726 
728 {
730 }
731 
733 
735 {
736  return -1;
737 }
738 
739 double QgsRandomColorRamp::value( int index ) const
740 {
741  Q_UNUSED( index )
742  return 0.0;
743 }
744 
745 QColor QgsRandomColorRamp::color( double value ) const
746 {
747  int minVal = 130;
748  int maxVal = 255;
749 
750  //if value is nan, then use last precalculated color
751  if ( std::isnan( value ) )
752  {
753  value = 1.0;
754  }
755  // Caller has converted an index into a value in [0.0, 1.0]
756  // by doing "index / (mTotalColorCount - 1)"; retrieve the original index.
757  int colorIndex = std::round( value * ( mTotalColorCount - 1 ) );
758  if ( mTotalColorCount >= 1 && mPrecalculatedColors.length() > colorIndex )
759  {
760  //use precalculated hue
761  return mPrecalculatedColors.at( colorIndex );
762  }
763 
764  //can't use precalculated hues, use a totally random hue
765  int h = static_cast< int >( 360.0 * std::rand() / ( RAND_MAX + 1.0 ) );
766  int s = ( std::rand() % ( DEFAULT_RANDOM_SAT_MAX - DEFAULT_RANDOM_SAT_MIN + 1 ) ) + DEFAULT_RANDOM_SAT_MIN;
767  int v = ( std::rand() % ( maxVal - minVal + 1 ) ) + minVal;
768  return QColor::fromHsv( h, s, v );
769 }
770 
771 void QgsRandomColorRamp::setTotalColorCount( const int colorCount )
772 {
773  //calculate colors in advance, so that we can ensure they are more visually distinct than pure random colors
774  mPrecalculatedColors.clear();
775  mTotalColorCount = colorCount;
776 
777  //This works OK for low color counts, but for > 10 or so colors there's still a good chance of
778  //similar colors being picked. TODO - investigate alternative "n-visually distinct color" routines
779 
780  //random offsets
781  double hueOffset = ( 360.0 * std::rand() / ( RAND_MAX + 1.0 ) );
782 
783  //try to maximise difference between hues. this is not an ideal implementation, as constant steps
784  //through the hue wheel are not visually perceived as constant changes in hue
785  //(for instance, we are much more likely to get green hues than yellow hues)
786  double hueStep = 359.0 / colorCount;
787  double currentHue = hueOffset;
788 
789  //build up a list of colors
790  for ( int idx = 0; idx < colorCount; ++ idx )
791  {
792  int h = static_cast< int >( std::round( currentHue ) ) % 360;
793  int s = ( std::rand() % ( DEFAULT_RANDOM_SAT_MAX - DEFAULT_RANDOM_SAT_MIN + 1 ) ) + DEFAULT_RANDOM_SAT_MIN;
794  int v = ( std::rand() % ( DEFAULT_RANDOM_VAL_MAX - DEFAULT_RANDOM_VAL_MIN + 1 ) ) + DEFAULT_RANDOM_VAL_MIN;
795  mPrecalculatedColors << QColor::fromHsv( h, s, v );
796  currentHue += hueStep;
797  }
798 
799  //lastly, shuffle color list
800  std::random_device rd;
801  std::mt19937 g( rd() );
802  std::shuffle( mPrecalculatedColors.begin(), mPrecalculatedColors.end(), g );
803 }
804 
806 {
808 }
809 
811 {
812  return new QgsRandomColorRamp();
813 }
814 
816 {
817  return QVariantMap();
818 }
819 
821 
822 QgsColorBrewerColorRamp::QgsColorBrewerColorRamp( const QString &schemeName, int colors, bool inverted )
823  : mSchemeName( schemeName )
824  , mColors( colors )
825  , mInverted( inverted )
826 {
827  loadPalette();
828 }
829 
830 QgsColorRamp *QgsColorBrewerColorRamp::create( const QVariantMap &props )
831 {
834  bool inverted = false;
835 
836  if ( props.contains( QStringLiteral( "schemeName" ) ) )
837  schemeName = props[QStringLiteral( "schemeName" )].toString();
838  if ( props.contains( QStringLiteral( "colors" ) ) )
839  colors = props[QStringLiteral( "colors" )].toInt();
840  if ( props.contains( QStringLiteral( "inverted" ) ) )
841  inverted = props[QStringLiteral( "inverted" )].toInt();
842 
843  return new QgsColorBrewerColorRamp( schemeName, colors, inverted );
844 }
845 
847 {
849 
850  if ( mInverted )
851  {
852  QList<QColor> tmpPalette;
853 
854  for ( int k = mPalette.size() - 1; k >= 0; k-- )
855  {
856  tmpPalette << mPalette.at( k );
857  }
858  mPalette = tmpPalette;
859  }
860 }
861 
863 {
865 }
866 
867 QList<int> QgsColorBrewerColorRamp::listSchemeVariants( const QString &schemeName )
868 {
870 }
871 
872 double QgsColorBrewerColorRamp::value( int index ) const
873 {
874  if ( mPalette.empty() )
875  return 0;
876  return static_cast< double >( index ) / ( mPalette.size() - 1 );
877 }
878 
879 QColor QgsColorBrewerColorRamp::color( double value ) const
880 {
881  if ( mPalette.isEmpty() || value < 0 || value > 1 || std::isnan( value ) )
882  return QColor();
883 
884  int paletteEntry = static_cast< int >( value * mPalette.count() );
885  if ( paletteEntry >= mPalette.count() )
886  paletteEntry = mPalette.count() - 1;
887  return mPalette.at( paletteEntry );
888 }
889 
891 {
892  mInverted = !mInverted;
893  loadPalette();
894 }
895 
897 {
899 }
900 
902 {
903  QVariantMap map;
904  map[QStringLiteral( "schemeName" )] = mSchemeName;
905  map[QStringLiteral( "colors" )] = QString::number( mColors );
906  map[QStringLiteral( "inverted" )] = QString::number( mInverted );
907  map[QStringLiteral( "rampType" )] = type();
908  return map;
909 }
910 
911 
913 
914 
915 QgsCptCityColorRamp::QgsCptCityColorRamp( const QString &schemeName, const QString &variantName,
916  bool inverted, bool doLoadFile )
918  , mSchemeName( schemeName )
919  , mVariantName( variantName )
920  , mInverted( inverted )
921 {
922  // TODO replace this with hard-coded data in the default case
923  // don't load file if variant is missing
924  if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
925  loadFile();
926 }
927 
928 QgsCptCityColorRamp::QgsCptCityColorRamp( const QString &schemeName, const QStringList &variantList,
929  const QString &variantName, bool inverted, bool doLoadFile )
931  , mSchemeName( schemeName )
932  , mVariantName( variantName )
933  , mVariantList( variantList )
934  , mInverted( inverted )
935 {
937 
938  // TODO replace this with hard-coded data in the default case
939  // don't load file if variant is missing
940  if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
941  loadFile();
942 }
943 
944 QgsColorRamp *QgsCptCityColorRamp::create( const QVariantMap &props )
945 {
948  bool inverted = false;
949 
950  if ( props.contains( QStringLiteral( "schemeName" ) ) )
951  schemeName = props[QStringLiteral( "schemeName" )].toString();
952  if ( props.contains( QStringLiteral( "variantName" ) ) )
953  variantName = props[QStringLiteral( "variantName" )].toString();
954  if ( props.contains( QStringLiteral( "inverted" ) ) )
955  inverted = props[QStringLiteral( "inverted" )].toInt();
956 
957  return new QgsCptCityColorRamp( schemeName, variantName, inverted );
958 }
959 
961 {
963 }
964 
966 {
967  mInverted = !mInverted;
969 }
970 
972 {
973  QgsCptCityColorRamp *ramp = new QgsCptCityColorRamp( QString(), QString(), mInverted, false );
974  ramp->copy( this );
975  return ramp;
976 }
977 
979 {
980  if ( ! other )
981  return;
982  mColor1 = other->color1();
983  mColor2 = other->color2();
984  mDiscrete = other->isDiscrete();
985  mStops = other->stops();
986  mSchemeName = other->mSchemeName;
987  mVariantName = other->mVariantName;
988  mVariantList = other->mVariantList;
989  mFileLoaded = other->mFileLoaded;
990  mInverted = other->mInverted;
991 }
992 
994 {
995  QgsGradientColorRamp *ramp =
997  // add author and copyright information
998  // TODO also add COPYING.xml file/link?
1000  info[QStringLiteral( "cpt-city-gradient" )] = "<cpt-city>/" + mSchemeName + mVariantName + ".svg";
1001  QString copyingFilename = copyingFileName();
1002  copyingFilename.remove( QgsCptCityArchive::defaultBaseDir() );
1003  info[QStringLiteral( "cpt-city-license" )] = "<cpt-city>" + copyingFilename;
1004  ramp->setInfo( info );
1005  return ramp;
1006 }
1007 
1008 
1010 {
1011  QVariantMap map;
1012  map[QStringLiteral( "schemeName" )] = mSchemeName;
1013  map[QStringLiteral( "variantName" )] = mVariantName;
1014  map[QStringLiteral( "inverted" )] = QString::number( mInverted );
1015  map[QStringLiteral( "rampType" )] = type();
1016  return map;
1017 }
1018 
1019 
1021 {
1022  if ( mSchemeName.isEmpty() )
1023  return QString();
1024  else
1025  {
1026  return QgsCptCityArchive::defaultBaseDir() + QDir::separator() + mSchemeName + mVariantName + ".svg";
1027  }
1028 }
1029 
1031 {
1032  return QgsCptCityArchive::findFileName( QStringLiteral( "COPYING.xml" ), QFileInfo( fileName() ).dir().path(),
1034 }
1035 
1037 {
1038  return QgsCptCityArchive::findFileName( QStringLiteral( "DESC.xml" ), QFileInfo( fileName() ).dir().path(),
1040 }
1041 
1043 {
1045 }
1046 
1048 {
1049  if ( mFileLoaded )
1050  {
1051  QgsDebugMsg( "File already loaded for " + mSchemeName + mVariantName );
1052  return true;
1053  }
1054 
1055  // get filename
1056  QString filename = fileName();
1057  if ( filename.isNull() )
1058  {
1059  QgsDebugMsg( "Couldn't get fileName() for " + mSchemeName + mVariantName );
1060  return false;
1061  }
1062 
1063  QgsDebugMsgLevel( QStringLiteral( "filename= %1 loaded=%2" ).arg( filename ).arg( mFileLoaded ), 2 );
1064 
1065  // get color ramp from svg file
1066  QMap< double, QPair<QColor, QColor> > colorMap =
1068 
1069  // add colors to palette
1070  mFileLoaded = false;
1071  mStops.clear();
1072  QMap<double, QPair<QColor, QColor> >::const_iterator it, prev;
1073  // first detect if file is gradient is continuous or discrete
1074  // discrete: stop contains 2 colors and first color is identical to previous second
1075  // multi: stop contains 2 colors and no relation with previous stop
1076  mDiscrete = false;
1077  mMultiStops = false;
1078  it = prev = colorMap.constBegin();
1079  while ( it != colorMap.constEnd() )
1080  {
1081  // look for stops that contain multiple values
1082  if ( it != colorMap.constBegin() && ( it.value().first != it.value().second ) )
1083  {
1084  if ( it.value().first == prev.value().second )
1085  {
1086  mDiscrete = true;
1087  break;
1088  }
1089  else
1090  {
1091  mMultiStops = true;
1092  break;
1093  }
1094  }
1095  prev = it;
1096  ++it;
1097  }
1098 
1099  // fill all stops
1100  it = prev = colorMap.constBegin();
1101  while ( it != colorMap.constEnd() )
1102  {
1103  if ( mDiscrete )
1104  {
1105  // mPalette << qMakePair( it.key(), it.value().second );
1106  mStops.append( QgsGradientStop( it.key(), it.value().second ) );
1107  }
1108  else
1109  {
1110  // mPalette << qMakePair( it.key(), it.value().first );
1111  mStops.append( QgsGradientStop( it.key(), it.value().first ) );
1112  if ( ( mMultiStops ) &&
1113  ( it.key() != 0.0 && it.key() != 1.0 ) )
1114  {
1115  mStops.append( QgsGradientStop( it.key(), it.value().second ) );
1116  }
1117  }
1118  prev = it;
1119  ++it;
1120  }
1121 
1122  // remove first and last items (mColor1 and mColor2)
1123  if ( ! mStops.isEmpty() && mStops.at( 0 ).offset == 0.0 )
1124  mColor1 = mStops.takeFirst().color;
1125  if ( ! mStops.isEmpty() && mStops.last().offset == 1.0 )
1126  mColor2 = mStops.takeLast().color;
1127 
1128  if ( mInverted )
1129  {
1131  }
1132 
1133  mFileLoaded = true;
1134  return true;
1135 }
1136 
1137 
1138 //
1139 // QgsPresetColorRamp
1140 //
1141 
1143 {
1144  const auto constColors = colors;
1145  for ( const QColor &color : constColors )
1146  {
1147  mColors << qMakePair( color, color.name() );
1148  }
1149  // need at least one color
1150  if ( mColors.isEmpty() )
1151  mColors << qMakePair( QColor( 250, 75, 60 ), QStringLiteral( "#fa4b3c" ) );
1152 }
1153 
1155  : mColors( colors )
1156 {
1157  // need at least one color
1158  if ( mColors.isEmpty() )
1159  mColors << qMakePair( QColor( 250, 75, 60 ), QStringLiteral( "#fa4b3c" ) );
1160 }
1161 
1162 QgsColorRamp *QgsPresetSchemeColorRamp::create( const QVariantMap &properties )
1163 {
1165 
1166  int i = 0;
1167  QString colorString = properties.value( QStringLiteral( "preset_color_%1" ).arg( i ), QString() ).toString();
1168  QString colorName = properties.value( QStringLiteral( "preset_color_name_%1" ).arg( i ), QString() ).toString();
1169  while ( !colorString.isEmpty() )
1170  {
1171  colors << qMakePair( QgsSymbolLayerUtils::decodeColor( colorString ), colorName );
1172  i++;
1173  colorString = properties.value( QStringLiteral( "preset_color_%1" ).arg( i ), QString() ).toString();
1174  colorName = properties.value( QStringLiteral( "preset_color_name_%1" ).arg( i ), QString() ).toString();
1175  }
1176 
1177  return new QgsPresetSchemeColorRamp( colors );
1178 }
1179 
1181 {
1182  QList< QColor > l;
1183  l.reserve( mColors.count() );
1184  for ( int i = 0; i < mColors.count(); ++i )
1185  {
1186  l << mColors.at( i ).first;
1187  }
1188  return l;
1189 }
1190 
1191 double QgsPresetSchemeColorRamp::value( int index ) const
1192 {
1193  if ( mColors.empty() )
1194  return 0;
1195  return static_cast< double >( index ) / ( mColors.size() - 1 );
1196 }
1197 
1198 QColor QgsPresetSchemeColorRamp::color( double value ) const
1199 {
1200  if ( value < 0 || value > 1 )
1201  return QColor();
1202 
1203  int colorCnt = mColors.count();
1204  int colorIdx = std::min( static_cast< int >( value * colorCnt ), colorCnt - 1 );
1205 
1206  if ( colorIdx >= 0 && colorIdx < colorCnt )
1207  return mColors.at( colorIdx ).first;
1208 
1209  return QColor();
1210 }
1211 
1213 {
1215 }
1216 
1218 {
1219  QgsNamedColorList tmpColors;
1220 
1221  for ( int k = mColors.size() - 1; k >= 0; k-- )
1222  {
1223  tmpColors << mColors.at( k );
1224  }
1225  mColors = tmpColors;
1226 }
1227 
1229 {
1230  return new QgsPresetSchemeColorRamp( *this );
1231 }
1232 
1234 {
1235  QVariantMap props;
1236  for ( int i = 0; i < mColors.count(); ++i )
1237  {
1238  props.insert( QStringLiteral( "preset_color_%1" ).arg( i ), QgsSymbolLayerUtils::encodeColor( mColors.at( i ).first ) );
1239  props.insert( QStringLiteral( "preset_color_name_%1" ).arg( i ), mColors.at( i ).second );
1240  }
1241  props[QStringLiteral( "rampType" )] = type();
1242  return props;
1243 }
1244 
1246 {
1247  return mColors.count();
1248 }
1249 
1251 {
1252  return mColors;
1253 }
AngularDirection
Angular directions.
Definition: qgis.h:1279
@ CounterClockwise
Counter-clockwise direction.
@ Clockwise
Clockwise direction.
Color ramp utilising "Color Brewer" preset color schemes.
void invert() override
Inverts the ordering of the color ramp.
static QList< int > listSchemeVariants(const QString &schemeName)
Returns a list of the valid variants (numbers of colors) for a specified color brewer scheme name.
QColor color(double value) const override
Returns the color corresponding to a specified value.
QgsColorBrewerColorRamp * clone() const override
Creates a clone of the color ramp.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Returns a new QgsColorBrewerColorRamp color ramp created using the properties encoded in a string map...
static QStringList listSchemeNames()
Returns a list of all valid color brewer scheme names.
QString type() const override
Returns a string representing the color ramp type.
double value(int index) const override
Returns relative value between [0,1] of color at specified index.
QString schemeName() const
Returns the name of the color brewer color scheme.
int colors() const
Returns the number of colors in the ramp.
QVariantMap properties() const override
Returns a string map containing all the color ramp's properties.
QgsColorBrewerColorRamp(const QString &schemeName=DEFAULT_COLORBREWER_SCHEMENAME, int colors=DEFAULT_COLORBREWER_COLORS, bool inverted=false)
Constructor for QgsColorBrewerColorRamp.
void loadPalette()
Generates the scheme using the current name and number of colors.
static QStringList listSchemes()
static QList< QColor > listSchemeColors(const QString &schemeName, int colors)
static QList< int > listSchemeVariants(const QString &schemeName)
Abstract base class for color ramps.
Definition: qgscolorramp.h:30
static QString defaultBaseDir()
static QMap< QString, QString > copyingInfo(const QString &fileName)
static QString findFileName(const QString &target, const QString &startDir, const QString &baseDir)
static QMap< double, QPair< QColor, QColor > > gradientColorMap(const QString &fileName)
QgsCptCityColorRamp * clone() const override
Creates a clone of the color ramp.
QgsStringMap copyingInfo() const
QVariantMap properties() const override
Returns a string map containing all the color ramp's properties.
QgsCptCityColorRamp(const QString &schemeName=DEFAULT_CPTCITY_SCHEMENAME, const QString &variantName=DEFAULT_CPTCITY_VARIANTNAME, bool inverted=false, bool doLoadFile=true)
Constructor for QgsCptCityColorRamp.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
QStringList variantList() const
QString fileName() const
void copy(const QgsCptCityColorRamp *other)
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
QString descFileName() const
QgsGradientColorRamp * cloneGradientRamp() const
QString copyingFileName() const
void invert() override
Inverts the ordering of the color ramp.
QString type() const override
Returns a string representing the color ramp type.
QString schemeName() const
QString variantName() const
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
QgsGradientStopsList mStops
void setInfo(const QgsStringMap &info)
Sets additional info to attach to the gradient ramp (e.g., authorship notes)
bool isDiscrete() const
Returns true if the gradient is using discrete interpolation, rather than smoothly interpolating betw...
void setColorSpec(QColor::Spec spec)
Sets the color specification in which the color component interpolation will occur.
QVariantMap properties() const override
Returns a string map containing all the color ramp's properties.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
QgsStringMap info() const
Returns any additional info attached to the gradient ramp (e.g., authorship notes)
void convertToDiscrete(bool discrete)
Converts a gradient with existing color stops to or from discrete interpolation.
Qgis::AngularDirection mDirection
QColor color(double value) const override
Returns the color corresponding to a specified value.
static QString typeString()
Returns the string identifier for QgsGradientColorRamp.
void setStops(const QgsGradientStopsList &stops)
Sets the list of intermediate gradient stops for the ramp.
QString type() const override
Returns a string representing the color ramp type.
QgsGradientColorRamp(const QColor &color1=DEFAULT_GRADIENT_COLOR1, const QColor &color2=DEFAULT_GRADIENT_COLOR2, bool discrete=false, const QgsGradientStopsList &stops=QgsGradientStopsList())
Constructor for QgsGradientColorRamp.
QColor color1() const
Returns the gradient start color.
void setDirection(Qgis::AngularDirection direction)
Sets the direction to traverse the color wheel using when interpolating hue-based color specification...
Qgis::AngularDirection direction() const
Returns the direction to traverse the color wheel using when interpolating hue-based color specificat...
void invert() override
Inverts the ordering of the color ramp.
void addStopsToGradient(QGradient *gradient, double opacity=1) const
Copy color ramp stops to a QGradient.
QgsGradientStopsList stops() const
Returns the list of intermediate gradient stops for the ramp.
double value(int index) const override
Returns relative value between [0,1] of color at specified index.
QgsGradientColorRamp * clone() const override
Creates a clone of the color ramp.
InterpolateColorFunc mFunc
QColor color2() const
Returns the gradient end color.
Represents a color stop within a QgsGradientColorRamp color ramp.
void setColorSpec(QColor::Spec spec)
Sets the color specification in which the color component interpolation will occur.
double offset
Relative positional offset, between 0 and 1.
QgsGradientStop(double offset, const QColor &color)
Constructor for QgsGradientStop.
Constrained random color ramp, which returns random colors based on preset parameters.
static QString typeString()
Returns the string identifier for QgsLimitedRandomColorRamp.
void updateColors()
Must be called after changing the properties of the color ramp to regenerate the list of random color...
static QList< QColor > randomColors(int count, int hueMax=DEFAULT_RANDOM_HUE_MAX, int hueMin=DEFAULT_RANDOM_HUE_MIN, int satMax=DEFAULT_RANDOM_SAT_MAX, int satMin=DEFAULT_RANDOM_SAT_MIN, int valMax=DEFAULT_RANDOM_VAL_MAX, int valMin=DEFAULT_RANDOM_VAL_MIN)
Gets a list of random colors.
int count() const override
Returns number of defined colors, or -1 if undefined.
QColor color(double value) const override
Returns the color corresponding to a specified value.
double value(int index) const override
Returns relative value between [0,1] of color at specified index.
QVariantMap properties() const override
Returns a string map containing all the color ramp's properties.
int valMax() const
Returns the maximum value for generated colors.
QString type() const override
Returns a string representing the color ramp type.
int satMax() const
Returns the maximum saturation for generated colors.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Returns a new QgsLimitedRandomColorRamp color ramp created using the properties encoded in a string m...
QgsLimitedRandomColorRamp * clone() const override
Creates a clone of the color ramp.
int hueMax() const
Returns the maximum hue for generated colors.
int hueMin() const
Returns the minimum hue for generated colors.
int valMin() const
Returns the minimum value for generated colors.
QgsLimitedRandomColorRamp(int count=DEFAULT_RANDOM_COUNT, int hueMin=DEFAULT_RANDOM_HUE_MIN, int hueMax=DEFAULT_RANDOM_HUE_MAX, int satMin=DEFAULT_RANDOM_SAT_MIN, int satMax=DEFAULT_RANDOM_SAT_MAX, int valMin=DEFAULT_RANDOM_VAL_MIN, int valMax=DEFAULT_RANDOM_VAL_MAX)
Constructor for QgsLimitedRandomColorRamp.
int satMin() const
Returns the minimum saturation for generated colors.
A scheme based color ramp consisting of a list of predefined colors.
double value(int index) const override
Returns relative value between [0,1] of color at specified index.
QColor color(double value) const override
Returns the color corresponding to a specified value.
QString type() const override
Returns a string representing the color ramp type.
QList< QColor > colors() const
Returns the list of colors used by the ramp.
static QString typeString()
Returns the string identifier for QgsPresetSchemeColorRamp.
void invert() override
Inverts the ordering of the color ramp.
QVariantMap properties() const override
Returns a string map containing all the color ramp's properties.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Returns a new QgsPresetSchemeColorRamp color ramp created using the properties encoded in a string ma...
int count() const override
Returns number of defined colors, or -1 if undefined.
QgsPresetSchemeColorRamp(const QList< QColor > &colors=QList< QColor >())
Constructor for QgsPresetSchemeColorRamp.
QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor()) override
Gets a list of colors from the scheme.
QgsPresetSchemeColorRamp * clone() const override
Creates a clone of the color ramp.
Totally random color ramp.
double value(int index) const override
Returns relative value between [0,1] of color at specified index.
QList< QColor > mPrecalculatedColors
QgsRandomColorRamp * clone() const override
Creates a clone of the color ramp.
QgsRandomColorRamp()=default
Constructor for QgsRandomColorRamp.
static QString typeString()
Returns the string identifier for QgsRandomColorRamp.
int count() const override
Returns number of defined colors, or -1 if undefined.
QString type() const override
Returns a string representing the color ramp type.
virtual void setTotalColorCount(int colorCount)
Sets the desired total number of unique colors for the resultant ramp.
QVariantMap properties() const override
Returns a string map containing all the color ramp's properties.
QColor color(double value) const override
Returns the color corresponding to a specified value.
static QColor decodeColor(const QString &str)
static QString encodeColor(const QColor &color)
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
Definition: MathUtils.cpp:407
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
QMap< QString, QString > QgsStringMap
Definition: qgis.h:2026
bool stopLessThan(const QgsGradientStop &s1, const QgsGradientStop &s2)
#define DEFAULT_COLORBREWER_COLORS
#define DEFAULT_COLORBREWER_SCHEMENAME
#define DEFAULT_RANDOM_HUE_MAX
#define DEFAULT_CPTCITY_SCHEMENAME
#define DEFAULT_RANDOM_HUE_MIN
#define DEFAULT_RANDOM_COUNT
#define DEFAULT_RANDOM_SAT_MAX
#define DEFAULT_RANDOM_SAT_MIN
#define DEFAULT_CPTCITY_VARIANTNAME
#define DEFAULT_GRADIENT_COLOR1
#define DEFAULT_RANDOM_VAL_MIN
QList< QgsGradientStop > QgsGradientStopsList
List of gradient stops.
#define DEFAULT_GRADIENT_COLOR2
#define DEFAULT_RANDOM_VAL_MAX
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38