QGIS API Documentation  2.14.11-Essen
qgsvectorcolorrampv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorcolorrampv2.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 "qgsvectorcolorrampv2.h"
17 #include "qgscolorbrewerpalette.h"
18 #include "qgscptcityarchive.h"
19 
20 #include "qgssymbollayerv2utils.h"
21 #include "qgsapplication.h"
22 #include "qgslogger.h"
23 
24 #include <stdlib.h> // for random()
25 #include <algorithm>
26 
27 #include <QTime>
28 
30 
31 static QColor _interpolate( const QColor& c1, const QColor& c2, const double value )
32 {
33  if ( qIsNaN( value ) ) return c2;
34  int r = static_cast< int >( c1.red() + value * ( c2.red() - c1.red() ) );
35  int g = static_cast< int >( c1.green() + value * ( c2.green() - c1.green() ) );
36  int b = static_cast< int >( c1.blue() + value * ( c2.blue() - c1.blue() ) );
37  int a = static_cast< int >( c1.alpha() + value * ( c2.alpha() - c1.alpha() ) );
38 
39  return QColor::fromRgb( r, g, b, a );
40 }
41 
43 
45  bool discrete, const QgsGradientStopsList& stops )
46  : mColor1( color1 ), mColor2( color2 ), mDiscrete( discrete ), mStops( stops )
47 {
48 }
49 
51 {
52  // color1 and color2
55  if ( props.contains( "color1" ) )
56  color1 = QgsSymbolLayerV2Utils::decodeColor( props["color1"] );
57  if ( props.contains( "color2" ) )
58  color2 = QgsSymbolLayerV2Utils::decodeColor( props["color2"] );
59 
60  //stops
62  if ( props.contains( "stops" ) )
63  {
64  Q_FOREACH ( const QString& stop, props["stops"].split( ':' ) )
65  {
66  int i = stop.indexOf( ';' );
67  if ( i == -1 )
68  continue;
69 
70  QColor c = QgsSymbolLayerV2Utils::decodeColor( stop.mid( i + 1 ) );
71  stops.append( QgsGradientStop( stop.left( i ).toDouble(), c ) );
72  }
73  }
74 
75  // discrete vs. continuous
76  bool discrete = false;
77  if ( props.contains( "discrete" ) )
78  {
79  if ( props["discrete"] == "1" )
80  discrete = true;
81  }
82 
83  // search for information keys starting with "info_"
85  for ( QgsStringMap::const_iterator it = props.constBegin();
86  it != props.constEnd(); ++it )
87  {
88  if ( it.key().startsWith( "info_" ) )
89  info[ it.key().mid( 5 )] = it.value();
90  }
91 
92  QgsVectorGradientColorRampV2* r = new QgsVectorGradientColorRampV2( color1, color2, discrete, stops );
93  r->setInfo( info );
94  return r;
95 }
96 
98 {
99  if ( index <= 0 )
100  {
101  return 0;
102  }
103  else if ( index >= mStops.size() + 1 )
104  {
105  return 1;
106  }
107  else
108  {
109  return mStops[index-1].offset;
110  }
111 }
112 
114 {
115  if ( qgsDoubleNear( value, 0.0 ) || value < 0.0 )
116  {
117  return mColor1;
118  }
119  else if ( qgsDoubleNear( value, 1.0 ) || value > 1.0 )
120  {
121  return mColor2;
122  }
123  else if ( mStops.isEmpty() )
124  {
125  if ( mDiscrete )
126  return mColor1;
127 
128  return _interpolate( mColor1, mColor2, value );
129  }
130  else
131  {
132  double lower = 0, upper = 0;
133  QColor c1 = mColor1, c2;
134  for ( QgsGradientStopsList::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
135  {
136  if ( it->offset > value )
137  {
138  if ( mDiscrete )
139  return c1;
140 
141  upper = it->offset;
142  c2 = it->color;
143 
144  return qgsDoubleNear( upper, lower ) ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
145  }
146  lower = it->offset;
147  c1 = it->color;
148  }
149 
150  if ( mDiscrete )
151  return c1;
152 
153  upper = 1;
154  c2 = mColor2;
155  return qgsDoubleNear( upper, lower ) ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
156  }
157 }
158 
160 {
162  mDiscrete, mStops );
163  r->setInfo( mInfo );
164  return r;
165 }
166 
168 {
169  QgsStringMap map;
170  map["color1"] = QgsSymbolLayerV2Utils::encodeColor( mColor1 );
171  map["color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
172  if ( !mStops.isEmpty() )
173  {
174  QStringList lst;
175  for ( QgsGradientStopsList::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
176  {
177  lst.append( QString( "%1;%2" ).arg( it->offset ).arg( QgsSymbolLayerV2Utils::encodeColor( it->color ) ) );
178  }
179  map["stops"] = lst.join( ":" );
180  }
181 
182  map["discrete"] = mDiscrete ? "1" : "0";
183 
185  it != mInfo.constEnd(); ++it )
186  {
187  map["info_" + it.key()] = it.value();
188  }
189 
190  return map;
191 }
193 {
194  if ( discrete == mDiscrete )
195  return;
196 
197  // if going to/from Discrete, re-arrange stops
198  // this will only work when stops are equally-spaced
199  QgsGradientStopsList newStops;
200  if ( discrete )
201  {
202  // re-arrange stops offset
203  int numStops = mStops.count() + 2;
204  int i = 1;
205  for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
206  it != mStops.constEnd(); ++it )
207  {
208  newStops.append( QgsGradientStop( static_cast< double >( i ) / numStops, it->color ) );
209  if ( i == numStops - 1 )
210  break;
211  i++;
212  }
213  // replicate last color
214  newStops.append( QgsGradientStop( static_cast< double >( i ) / numStops, mColor2 ) );
215  }
216  else
217  {
218  // re-arrange stops offset, remove duplicate last color
219  int numStops = mStops.count() + 2;
220  int i = 1;
221  for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
222  it != mStops.constEnd(); ++it )
223  {
224  newStops.append( QgsGradientStop( static_cast< double >( i ) / ( numStops - 2 ), it->color ) );
225  if ( i == numStops - 3 )
226  break;
227  i++;
228  }
229  }
230  mStops = newStops;
231  mDiscrete = discrete;
232 }
233 
235 {
236  //copy color ramp stops to a QGradient
239  if ( alpha < 1 )
240  {
241  color1.setAlpha( color1.alpha() * alpha );
242  color2.setAlpha( color2.alpha() * alpha );
243  }
244  gradient->setColorAt( 0, color1 );
245  gradient->setColorAt( 1, color2 );
246 
247  for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
248  it != mStops.constEnd(); ++it )
249  {
250  QColor rampColor = it->color;
251  if ( alpha < 1 )
252  {
253  rampColor.setAlpha( rampColor.alpha() * alpha );
254  }
255  gradient->setColorAt( it->offset, rampColor );
256  }
257 }
258 
259 
261 
262 
264  int satMin, int satMax, int valMin, int valMax )
265  : mCount( count )
266  , mHueMin( hueMin ), mHueMax( hueMax )
267  , mSatMin( satMin ), mSatMax( satMax )
268  , mValMin( valMin ), mValMax( valMax )
269 {
270  updateColors();
271 }
272 
274 {
279 
280  if ( props.contains( "count" ) ) count = props["count"].toInt();
281  if ( props.contains( "hueMin" ) ) hueMin = props["hueMin"].toInt();
282  if ( props.contains( "hueMax" ) ) hueMax = props["hueMax"].toInt();
283  if ( props.contains( "satMin" ) ) satMin = props["satMin"].toInt();
284  if ( props.contains( "satMax" ) ) satMax = props["satMax"].toInt();
285  if ( props.contains( "valMin" ) ) valMin = props["valMin"].toInt();
286  if ( props.contains( "valMax" ) ) valMax = props["valMax"].toInt();
287 
288  return new QgsVectorRandomColorRampV2( count, hueMin, hueMax, satMin, satMax, valMin, valMax );
289 }
290 
292 {
293  if ( mColors.size() < 1 ) return 0;
294  return static_cast< double >( index ) / ( mColors.size() - 1 );
295 }
296 
298 {
299  if ( value < 0 || value > 1 )
300  return QColor();
301 
302  int colorCnt = mColors.count();
303  int colorIdx = qMin( static_cast< int >( value * colorCnt ), colorCnt - 1 );
304 
305  if ( colorIdx >= 0 && colorIdx < colorCnt )
306  return mColors.at( colorIdx );
307 
308  return QColor();
309 }
310 
312 {
314 }
315 
317 {
318  QgsStringMap map;
319  map["count"] = QString::number( mCount );
320  map["hueMin"] = QString::number( mHueMin );
321  map["hueMax"] = QString::number( mHueMax );
322  map["satMin"] = QString::number( mSatMin );
323  map["satMax"] = QString::number( mSatMax );
324  map["valMin"] = QString::number( mValMin );
325  map["valMax"] = QString::number( mValMax );
326  return map;
327 }
328 
330  int hueMax, int hueMin, int satMax, int satMin, int valMax, int valMin )
331 {
332  int h, s, v;
333  QList<QColor> colors;
334 
335  //normalize values
336  int safeHueMax = qMax( hueMin, hueMax );
337  int safeHueMin = qMin( hueMin, hueMax );
338  int safeSatMax = qMax( satMin, satMax );
339  int safeSatMin = qMin( satMin, satMax );
340  int safeValMax = qMax( valMin, valMax );
341  int safeValMin = qMin( valMin, valMax );
342 
343  //start hue at random angle
344  double currentHueAngle = 360.0 * static_cast< double >( qrand() ) / RAND_MAX;
345 
346  colors.reserve( count );
347  for ( int i = 0; i < count; ++i )
348  {
349  //increment hue by golden ratio (approx 137.507 degrees)
350  //as this minimises hue nearness as count increases
351  //see http://basecase.org/env/on-rainbows for more details
352  currentHueAngle += 137.50776;
353  //scale hue to between hueMax and hueMin
354  h = qBound( 0, qRound(( fmod( currentHueAngle, 360.0 ) / 360.0 ) * ( safeHueMax - safeHueMin ) + safeHueMin ), 359 );
355  s = qBound( 0, ( qrand() % ( safeSatMax - safeSatMin + 1 ) ) + safeSatMin, 255 );
356  v = qBound( 0, ( qrand() % ( safeValMax - safeValMin + 1 ) ) + safeValMin, 255 );
357  colors.append( QColor::fromHsv( h, s, v ) );
358  }
359  return colors;
360 }
361 
363 {
365 }
366 
368 
370  : mTotalColorCount( 0 )
371 {
372 }
373 
375 {
376 
377 }
378 
380 {
381  return -1;
382 }
383 
384 double QgsRandomColorsV2::value( int index ) const
385 {
386  Q_UNUSED( index );
387  return 0.0;
388 }
389 
391 {
392  int minVal = 130;
393  int maxVal = 255;
394 
395  //if value is nan, then use last precalculated color
396  int colorIndex = ( !qIsNaN( value ) ? value : 1 ) * ( mTotalColorCount - 1 );
397  if ( mTotalColorCount >= 1 && mPrecalculatedColors.length() > colorIndex )
398  {
399  //use precalculated hue
400  return mPrecalculatedColors.at( colorIndex );
401  }
402 
403  //can't use precalculated hues, use a totally random hue
404  int h = static_cast< int >( 360.0 * qrand() / ( RAND_MAX + 1.0 ) );
405  int s = ( qrand() % ( DEFAULT_RANDOM_SAT_MAX - DEFAULT_RANDOM_SAT_MIN + 1 ) ) + DEFAULT_RANDOM_SAT_MIN;
406  int v = ( qrand() % ( maxVal - minVal + 1 ) ) + minVal;
407  return QColor::fromHsv( h, s, v );
408 }
409 
410 void QgsRandomColorsV2::setTotalColorCount( const int colorCount )
411 {
412  //calculate colors in advance, so that we can ensure they are more visually distinct than pure random colors
414  mTotalColorCount = colorCount;
415 
416  //This works ok for low color counts, but for > 10 or so colors there's still a good chance of
417  //similar colors being picked. TODO - investigate alternative "n-visually distinct color" routines
418 
419  //random offsets
420  double hueOffset = ( 360.0 * qrand() / ( RAND_MAX + 1.0 ) );
421 
422  //try to maximise difference between hues. this is not an ideal implementation, as constant steps
423  //through the hue wheel are not visually perceived as constant changes in hue
424  //(for instance, we are much more likely to get green hues than yellow hues)
425  double hueStep = 359.0 / colorCount;
426  double currentHue = hueOffset;
427 
428  //build up a list of colors
429  for ( int idx = 0; idx < colorCount; ++ idx )
430  {
431  int h = qRound( currentHue ) % 360;
432  int s = ( qrand() % ( DEFAULT_RANDOM_SAT_MAX - DEFAULT_RANDOM_SAT_MIN + 1 ) ) + DEFAULT_RANDOM_SAT_MIN;
433  int v = ( qrand() % ( DEFAULT_RANDOM_VAL_MAX - DEFAULT_RANDOM_VAL_MIN + 1 ) ) + DEFAULT_RANDOM_VAL_MIN;
435  currentHue += hueStep;
436  }
437 
438  //lastly, shuffle color list
439  std::random_shuffle( mPrecalculatedColors.begin(), mPrecalculatedColors.end() );
440 }
441 
443 {
444  return "randomcolors";
445 }
446 
448 {
449  return new QgsRandomColorsV2();
450 }
451 
453 {
454  return QgsStringMap();
455 }
456 
458 
460  : mSchemeName( schemeName ), mColors( colors )
461 {
462  loadPalette();
463 }
464 
466 {
469 
470  if ( props.contains( "schemeName" ) )
471  schemeName = props["schemeName"];
472  if ( props.contains( "colors" ) )
473  colors = props["colors"].toInt();
474 
475  return new QgsVectorColorBrewerColorRampV2( schemeName, colors );
476 }
477 
479 {
481 }
482 
484 {
486 }
487 
489 {
490  return QgsColorBrewerPalette::listSchemeVariants( schemeName );
491 }
492 
494 {
495  if ( mPalette.size() < 1 ) return 0;
496  return static_cast< double >( index ) / ( mPalette.size() - 1 );
497 }
498 
500 {
501  if ( mPalette.isEmpty() || value < 0 || value > 1 )
502  return QColor();
503 
504  int paletteEntry = static_cast< int >( value * mPalette.count() );
505  if ( paletteEntry >= mPalette.count() )
506  paletteEntry = mPalette.count() - 1;
507  return mPalette.at( paletteEntry );
508 }
509 
511 {
513 }
514 
516 {
517  QgsStringMap map;
518  map["schemeName"] = mSchemeName;
519  map["colors"] = QString::number( mColors );
520  return map;
521 }
522 
523 
525 
526 
528  bool doLoadFile )
530  , mSchemeName( schemeName ), mVariantName( variantName )
531  , mVariantList( QStringList() ), mFileLoaded( false ), mMultiStops( false )
532 {
533  // TODO replace this with hard-coded data in the default case
534  // don't load file if variant is missing
535  if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
536  loadFile();
537 }
538 
540  const QString& variantName, bool doLoadFile )
542  , mSchemeName( schemeName ), mVariantName( variantName )
543  , mVariantList( variantList ), mFileLoaded( false ), mMultiStops( false )
544 {
546 
547  // TODO replace this with hard-coded data in the default case
548  // don't load file if variant is missing
549  if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
550  loadFile();
551 }
552 
554 {
557 
558  if ( props.contains( "schemeName" ) )
559  schemeName = props["schemeName"];
560  if ( props.contains( "variantName" ) )
561  variantName = props["variantName"];
562 
563  return new QgsCptCityColorRampV2( schemeName, variantName );
564 }
565 
567 {
568  QgsCptCityColorRampV2* ramp = new QgsCptCityColorRampV2( "", "", false );
569  ramp->copy( this );
570  return ramp;
571 }
572 
574 {
575  if ( ! other )
576  return;
577  mColor1 = other->color1();
578  mColor2 = other->color2();
579  mDiscrete = other->isDiscrete();
580  mStops = other->stops();
581  mSchemeName = other->mSchemeName;
582  mVariantName = other->mVariantName;
583  mVariantList = other->mVariantList;
584  mFileLoaded = other->mFileLoaded;
585 }
586 
588 {
591  // add author and copyright information
592  // TODO also add COPYING.xml file/link?
594  info["cpt-city-gradient"] = "<cpt-city>/" + mSchemeName + mVariantName + ".svg";
595  QString copyingFilename = copyingFileName();
596  copyingFilename.remove( QgsCptCityArchive::defaultBaseDir() );
597  info["cpt-city-license"] = "<cpt-city>" + copyingFilename;
598  ramp->setInfo( info );
599  return ramp;
600 }
601 
602 
604 {
605  QgsStringMap map;
606  map["schemeName"] = mSchemeName;
607  map["variantName"] = mVariantName;
608  return map;
609 }
610 
611 
613 {
614  if ( mSchemeName == "" )
615  return QString();
616  else
617  {
619  }
620 }
621 
623 {
624  return QgsCptCityArchive::findFileName( "COPYING.xml", QFileInfo( fileName() ).dir().path(),
626 }
627 
629 {
630  return QgsCptCityArchive::findFileName( "DESC.xml", QFileInfo( fileName() ).dir().path(),
632 }
633 
635 {
637 }
638 
640 {
641  if ( mFileLoaded )
642  {
643  QgsDebugMsg( "File already loaded for " + mSchemeName + mVariantName );
644  return true;
645  }
646 
647  // get filename
648  QString filename = fileName();
649  if ( filename.isNull() )
650  {
651  QgsDebugMsg( "Couldn't get fileName() for " + mSchemeName + mVariantName );
652  return false;
653  }
654 
655  QgsDebugMsg( QString( "filename= %1 loaded=%2" ).arg( filename ).arg( mFileLoaded ) );
656 
657  // get color ramp from svg file
660 
661  // add colors to palette
662  mFileLoaded = false;
663  mStops.clear();
664  QMap<double, QPair<QColor, QColor> >::const_iterator it, prev;
665  // first detect if file is gradient is continuous or dicrete
666  // discrete: stop contains 2 colors and first color is identical to previous second
667  // multi: stop contains 2 colors and no relation with previous stop
668  mDiscrete = false;
669  mMultiStops = false;
670  it = prev = colorMap.constBegin();
671  while ( it != colorMap.constEnd() )
672  {
673  // look for stops that contain multiple values
674  if ( it != colorMap.constBegin() && ( it.value().first != it.value().second ) )
675  {
676  if ( it.value().first == prev.value().second )
677  {
678  mDiscrete = true;
679  break;
680  }
681  else
682  {
683  mMultiStops = true;
684  break;
685  }
686  }
687  prev = it;
688  ++it;
689  }
690 
691  // fill all stops
692  it = prev = colorMap.constBegin();
693  while ( it != colorMap.constEnd() )
694  {
695  if ( mDiscrete )
696  {
697  // mPalette << qMakePair( it.key(), it.value().second );
698  mStops.append( QgsGradientStop( it.key(), it.value().second ) );
699  }
700  else
701  {
702  // mPalette << qMakePair( it.key(), it.value().first );
703  mStops.append( QgsGradientStop( it.key(), it.value().first ) );
704  if (( mMultiStops ) &&
705  ( it.key() != 0.0 && it.key() != 1.0 ) )
706  {
707  mStops.append( QgsGradientStop( it.key(), it.value().second ) );
708  }
709  }
710  prev = it;
711  ++it;
712  }
713 
714  // remove first and last items (mColor1 and mColor2)
715  if ( ! mStops.isEmpty() && mStops.at( 0 ).offset == 0.0 )
716  mColor1 = mStops.takeFirst().color;
717  if ( ! mStops.isEmpty() && mStops.last().offset == 1.0 )
718  mColor2 = mStops.takeLast().color;
719 
720  mFileLoaded = true;
721  return true;
722 }
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
virtual QColor color(double value) const override
void clear()
QgsStringMap copyingInfo() const
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
static unsigned index
int count() const override
Returns number of defined colors, or -1 if undefined.
QgsRandomColorsV2 * clone() const override
bool contains(const Key &key) const
#define DEFAULT_CPTCITY_VARIANTNAME
virtual QgsVectorRandomColorRampV2 * clone() const override
void copy(const QgsCptCityColorRampV2 *other)
int length() const
int count() const override
Returns number of defined colors, or -1 if undefined.
virtual QgsVectorColorBrewerColorRampV2 * clone() const override
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setColorAt(qreal position, const QColor &color)
void reserve(int alloc)
static QString defaultBaseDir()
static QString encodeColor(const QColor &color)
#define DEFAULT_COLORBREWER_SCHEMENAME
#define DEFAULT_RANDOM_HUE_MIN
const_iterator constBegin() const
const T & at(int i) const
void setInfo(const QgsStringMap &info)
virtual QgsVectorGradientColorRampV2 * clone() const override
virtual QgsCptCityColorRampV2 * clone() const override
void setAlpha(int alpha)
virtual void setTotalColorCount(const int colorCount)
Sets the desired total number of unique colors for the resultant ramp.
QgsVectorGradientColorRampV2 * cloneGradientRamp() const
QString join(const QString &separator) const
QString & remove(int position, int n)
#define DEFAULT_CPTCITY_SCHEMENAME
double toDouble(bool *ok) const
static QList< QColor > listSchemeColors(const QString &schemeName, int colors)
QChar separator()
QMap< QString, QString > QgsStringMap
Definition: qgis.h:392
#define DEFAULT_RANDOM_SAT_MAX
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
int size() const
bool isNull() const
QgsCptCityColorRampV2(const QString &schemeName=DEFAULT_CPTCITY_SCHEMENAME, const QString &variantName=DEFAULT_CPTCITY_VARIANTNAME, bool doLoadFile=true)
QColor fromHsv(int h, int s, int v, int a)
static QList< int > listSchemeVariants(const QString &schemeName)
virtual QgsStringMap properties() const override
virtual int count() const override
Returns number of defined colors, or -1 if undefined.
QColor fromRgb(QRgb rgb)
QString number(int n, int base)
int count(const T &value) const
void append(const T &value)
#define DEFAULT_GRADIENT_COLOR2
virtual QgsStringMap properties() const override
QgsVectorRandomColorRampV2(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)
virtual QColor color(double value) const override
int red() const
static QColor _interpolate(const QColor &c1, const QColor &c2, const double value)
bool isEmpty() const
#define DEFAULT_GRADIENT_COLOR1
const_iterator constEnd() const
#define DEFAULT_RANDOM_VAL_MAX
virtual QgsStringMap properties() const override
static QMap< QString, QString > copyingInfo(const QString &fileName)
const QgsGradientStopsList & stops() const
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)
Get a list of random colors.
QgsVectorGradientColorRampV2(const QColor &color1=DEFAULT_GRADIENT_COLOR1, const QColor &color2=DEFAULT_GRADIENT_COLOR2, bool discrete=false, const QgsGradientStopsList &stops=QgsGradientStopsList())
virtual QgsStringMap properties() const override
QString type() const override
int alpha() const
int green() const
iterator end()
#define DEFAULT_RANDOM_SAT_MIN
virtual double value(int index) const override
Returns relative value between [0,1] of color at specified index.
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
QgsStringMap properties() const override
virtual QColor color(double value) const override
const Key key(const T &value) const
int blue() const
int ANALYSIS_EXPORT lower(int n, int i)
Lower function.
T takeLast()
QString mid(int position, int n) const
virtual double value(int index) const override
Returns relative value between [0,1] of color at specified index.
T takeFirst()
#define DEFAULT_COLORBREWER_COLORS
static QStringList listSchemes()
QColor color(double value) const override
T & last()
double value(int index) const override
Returns relative value between [0,1] of color at specified index.
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
QList< QColor > mPrecalculatedColors
#define DEFAULT_RANDOM_HUE_MAX
QString left(int n) const
QgsVectorColorBrewerColorRampV2(const QString &schemeName=DEFAULT_COLORBREWER_SCHEMENAME, int colors=DEFAULT_COLORBREWER_COLORS)
static QColor decodeColor(const QString &str)
static QList< int > listSchemeVariants(const QString &schemeName)
virtual double value(int index) const override
Returns relative value between [0,1] of color at specified index.
static QMap< double, QPair< QColor, QColor > > gradientColorMap(const QString &fileName)
const_iterator constEnd() const
const_iterator constBegin() const
#define DEFAULT_RANDOM_VAL_MIN
void addStopsToGradient(QGradient *gradient, double alpha=1)
Copy color ramp stops to a QGradient.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
iterator begin()
#define DEFAULT_RANDOM_COUNT
static QString findFileName(const QString &target, const QString &startDir, const QString &baseDir)
QStringList variantList() const
const T value(const Key &key) const