QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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( QColor c1, QColor c2, double value )
32 {
33  if ( qIsNaN( value ) ) value = 1;
34  int r = ( int )( c1.red() + value * ( c2.red() - c1.red() ) );
35  int g = ( int )( c1.green() + value * ( c2.green() - c1.green() ) );
36  int b = ( int )( c1.blue() + value * ( c2.blue() - c1.blue() ) );
37  int a = ( int )( c1.alpha() + value * ( c2.alpha() - c1.alpha() ) );
38 
39  return QColor::fromRgb( r, g, b, a );
40 }
41 
43 
45  bool discrete, 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  foreach ( 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 
113 QColor QgsVectorGradientColorRampV2::color( double value ) const
114 {
115  if ( mStops.isEmpty() )
116  {
117  if ( mDiscrete )
118  return mColor1;
119  return _interpolate( mColor1, mColor2, value );
120  }
121  else
122  {
123  double lower = 0, upper = 0;
124  QColor c1 = mColor1, c2;
125  for ( QgsGradientStopsList::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
126  {
127  if ( it->offset > value )
128  {
129  if ( mDiscrete )
130  return c1;
131 
132  upper = it->offset;
133  c2 = it->color;
134 
135  return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
136  }
137  lower = it->offset;
138  c1 = it->color;
139  }
140 
141  if ( mDiscrete )
142  return c1;
143 
144  upper = 1;
145  c2 = mColor2;
146  return upper == lower ? c1 : _interpolate( c1, c2, ( value - lower ) / ( upper - lower ) );
147  }
148 }
149 
151 {
153  mDiscrete, mStops );
154  r->setInfo( mInfo );
155  return r;
156 }
157 
159 {
160  QgsStringMap map;
161  map["color1"] = QgsSymbolLayerV2Utils::encodeColor( mColor1 );
162  map["color2"] = QgsSymbolLayerV2Utils::encodeColor( mColor2 );
163  if ( !mStops.isEmpty() )
164  {
165  QStringList lst;
166  for ( QgsGradientStopsList::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
167  {
168  lst.append( QString( "%1;%2" ).arg( it->offset ).arg( QgsSymbolLayerV2Utils::encodeColor( it->color ) ) );
169  }
170  map["stops"] = lst.join( ":" );
171  }
172 
173  map["discrete"] = mDiscrete ? "1" : "0";
174 
175  for ( QgsStringMap::const_iterator it = mInfo.constBegin();
176  it != mInfo.constEnd(); ++it )
177  {
178  map["info_" + it.key()] = it.value();
179  }
180 
181  return map;
182 }
184 {
185  if ( discrete == mDiscrete )
186  return;
187 
188  // if going to/from Discrete, re-arrange stops
189  // this will only work when stops are equally-spaced
190  QgsGradientStopsList newStops;
191  if ( discrete )
192  {
193  // re-arrange stops offset
194  int numStops = mStops.count() + 2;
195  int i = 1;
196  for ( QgsGradientStopsList::const_iterator it = mStops.begin();
197  it != mStops.end(); ++it )
198  {
199  newStops.append( QgsGradientStop(( double ) i / numStops, it->color ) );
200  if ( i == numStops - 1 )
201  break;
202  i++;
203  }
204  // replicate last color
205  newStops.append( QgsGradientStop(( double ) i / numStops, mColor2 ) );
206  }
207  else
208  {
209  // re-arrange stops offset, remove duplicate last color
210  int numStops = mStops.count() + 2;
211  int i = 1;
212  for ( QgsGradientStopsList::const_iterator it = mStops.begin();
213  it != mStops.end(); ++it )
214  {
215  newStops.append( QgsGradientStop(( double ) i / ( numStops - 2 ), it->color ) );
216  if ( i == numStops - 3 )
217  break;
218  i++;
219  }
220  }
221  mStops = newStops;
222  mDiscrete = discrete;
223 }
224 
225 void QgsVectorGradientColorRampV2::addStopsToGradient( QGradient* gradient, double alpha )
226 {
227  //copy color ramp stops to a QGradient
228  QColor color1 = mColor1;
229  QColor color2 = mColor2;
230  if ( alpha < 1 )
231  {
232  color1.setAlpha( color1.alpha() * alpha );
233  color2.setAlpha( color2.alpha() * alpha );
234  }
235  gradient->setColorAt( 0, color1 );
236  gradient->setColorAt( 1, color2 );
237 
238  for ( QgsGradientStopsList::const_iterator it = mStops.begin();
239  it != mStops.end(); ++it )
240  {
241  QColor rampColor = it->color;
242  if ( alpha < 1 )
243  {
244  rampColor.setAlpha( rampColor.alpha() * alpha );
245  }
246  gradient->setColorAt( it->offset, rampColor );
247  }
248 }
249 
250 
252 
253 
255  int satMin, int satMax, int valMin, int valMax )
256  : mCount( count ), mHueMin( hueMin ), mHueMax( hueMax ),
257  mSatMin( satMin ), mSatMax( satMax ), mValMin( valMin ), mValMax( valMax )
258 {
259  updateColors();
260 }
261 
263 {
268 
269  if ( props.contains( "count" ) ) count = props["count"].toInt();
270  if ( props.contains( "hueMin" ) ) hueMin = props["hueMin"].toInt();
271  if ( props.contains( "hueMax" ) ) hueMax = props["hueMax"].toInt();
272  if ( props.contains( "satMin" ) ) satMin = props["satMin"].toInt();
273  if ( props.contains( "satMax" ) ) satMax = props["satMax"].toInt();
274  if ( props.contains( "valMin" ) ) valMin = props["valMin"].toInt();
275  if ( props.contains( "valMax" ) ) valMax = props["valMax"].toInt();
276 
277  return new QgsVectorRandomColorRampV2( count, hueMin, hueMax, satMin, satMax, valMin, valMax );
278 }
279 
281 {
282  if ( mColors.size() < 1 ) return 0;
283  return index / mColors.size() - 1;
284 }
285 
286 QColor QgsVectorRandomColorRampV2::color( double value ) const
287 {
288  int colorCnt = mColors.count();
289  int colorIdx = ( int )( value * colorCnt );
290 
291  if ( colorIdx >= 0 && colorIdx < colorCnt )
292  return mColors.at( colorIdx );
293 
294  return QColor();
295 }
296 
298 {
300 }
301 
303 {
304  QgsStringMap map;
305  map["count"] = QString::number( mCount );
306  map["hueMin"] = QString::number( mHueMin );
307  map["hueMax"] = QString::number( mHueMax );
308  map["satMin"] = QString::number( mSatMin );
309  map["satMax"] = QString::number( mSatMax );
310  map["valMin"] = QString::number( mValMin );
311  map["valMax"] = QString::number( mValMax );
312  return map;
313 }
314 
316  int hueMax, int hueMin, int satMax, int satMin, int valMax, int valMin )
317 {
318  int h, s, v;
319  QList<QColor> colors;
320 
321  //normalize values
322  int safeHueMax = qMax( hueMin, hueMax );
323  int safeHueMin = qMin( hueMin, hueMax );
324  int safeSatMax = qMax( satMin, satMax );
325  int safeSatMin = qMin( satMin, satMax );
326  int safeValMax = qMax( valMin, valMax );
327  int safeValMin = qMin( valMin, valMax );
328 
329  //start hue at random angle
330  double currentHueAngle = 360.0 * ( double )rand() / RAND_MAX;
331 
332  for ( int i = 0; i < count; i++ )
333  {
334  //increment hue by golden ratio (approx 137.507 degrees)
335  //as this minimises hue nearness as count increases
336  //see http://basecase.org/env/on-rainbows for more details
337  currentHueAngle += 137.50776;
338  //scale hue to between hueMax and hueMin
339  h = qBound( 0, qRound(( fmod( currentHueAngle, 360.0 ) / 360.0 ) * ( safeHueMax - safeHueMin ) + safeHueMin ), 359 );
340  s = qBound( 0, ( rand() % ( safeSatMax - safeSatMin + 1 ) ) + safeValMax, 255 );
341  v = qBound( 0, ( rand() % ( safeValMax - safeValMin + 1 ) ) + safeValMin, 255 );
342  colors.append( QColor::fromHsv( h, s, v ) );
343  }
344  return colors;
345 }
346 
348 {
350 }
351 
353 
355 {
356  srand( QTime::currentTime().msec() );
357 }
358 
360 {
361 
362 }
363 
365 {
366  return INT_MAX;
367 }
368 
369 double QgsRandomColorsV2::value( int index ) const
370 {
371  Q_UNUSED( index );
372  return 0.0;
373 }
374 
375 QColor QgsRandomColorsV2::color( double value ) const
376 {
377  int minVal = 130;
378  int maxVal = 255;
379 
380  //if value is nan, then use last precalculated color
381  int colorIndex = ( !qIsNaN( value ) ? value : 1 ) * ( mTotalColorCount - 1 );
382  if ( mTotalColorCount >= 1 && mPrecalculatedColors.length() > colorIndex )
383  {
384  //use precalculated hue
385  return mPrecalculatedColors.at( colorIndex );
386  }
387 
388  //can't use precalculated hues, use a totally random hue
389  int h = 1 + ( int )( 360.0 * rand() / ( RAND_MAX + 1.0 ) );
391  int v = ( rand() % ( maxVal - minVal + 1 ) ) + minVal;
392  return QColor::fromHsv( h, s, v );
393 }
394 
395 void QgsRandomColorsV2::setTotalColorCount( const int colorCount )
396 {
397  //calculate colors in advance, so that we can ensure they are more visually distinct than pure random colors
398  mPrecalculatedColors.clear();
399  mTotalColorCount = colorCount;
400 
401  //This works ok for low color counts, but for > 10 or so colors there's still a good chance of
402  //similar colors being picked. TODO - investigate alternative "n-visually distinct color" routines
403 
404  //random offsets
405  double hueOffset = ( 360.0 * rand() / ( RAND_MAX + 1.0 ) );
406 
407  //try to maximise difference between hues. this is not an ideal implementation, as constant steps
408  //through the hue wheel are not visually perceived as constant changes in hue
409  //(for instance, we are much more likely to get green hues than yellow hues)
410  double hueStep = 359.0 / colorCount;
411  double currentHue = hueOffset;
412 
413  //build up a list of colors
414  for ( int idx = 0; idx < colorCount; ++ idx )
415  {
416  int h = qRound( currentHue ) % 360;
419  mPrecalculatedColors << QColor::fromHsv( h, s, v );
420  currentHue += hueStep;
421  }
422 
423  //lastly, shuffle color list
424  std::random_shuffle( mPrecalculatedColors.begin(), mPrecalculatedColors.end() );
425 }
426 
427 QString QgsRandomColorsV2::type() const
428 {
429  return "randomcolors";
430 }
431 
433 {
434  return new QgsRandomColorsV2();
435 }
436 
438 {
439  return QgsStringMap();
440 }
441 
443 
445  : mSchemeName( schemeName ), mColors( colors )
446 {
447  loadPalette();
448 }
449 
451 {
454 
455  if ( props.contains( "schemeName" ) )
456  schemeName = props["schemeName"];
457  if ( props.contains( "colors" ) )
458  colors = props["colors"].toInt();
459 
460  return new QgsVectorColorBrewerColorRampV2( schemeName, colors );
461 }
462 
464 {
466 }
467 
469 {
471 }
472 
474 {
475  return QgsColorBrewerPalette::listSchemeVariants( schemeName );
476 }
477 
479 {
480  if ( mPalette.size() < 1 ) return 0;
481  return index / mPalette.size() - 1;
482 }
483 
484 QColor QgsVectorColorBrewerColorRampV2::color( double value ) const
485 {
486  if ( mPalette.isEmpty() || value < 0 || value > 1 )
487  return QColor( 255, 0, 0 ); // red color as a warning :)
488 
489  int paletteEntry = ( int )( value * mPalette.count() );
490  if ( paletteEntry >= mPalette.count() )
491  paletteEntry = mPalette.count() - 1;
492  return mPalette.at( paletteEntry );
493 }
494 
496 {
498 }
499 
501 {
502  QgsStringMap map;
503  map["schemeName"] = mSchemeName;
504  map["colors"] = QString::number( mColors );
505  return map;
506 }
507 
508 
510 
511 
512 QgsCptCityColorRampV2::QgsCptCityColorRampV2( QString schemeName, QString variantName,
513  bool doLoadFile )
515  mSchemeName( schemeName ), mVariantName( variantName ),
516  mVariantList( QStringList() ), mFileLoaded( false ), mMultiStops( false )
517 {
518  // TODO replace this with hard-coded data in the default case
519  // don't load file if variant is missing
520  if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
521  loadFile();
522 }
523 
524 QgsCptCityColorRampV2::QgsCptCityColorRampV2( QString schemeName, QStringList variantList,
525  QString variantName, bool doLoadFile )
527  mSchemeName( schemeName ), mVariantName( variantName ),
528  mVariantList( variantList ), mFileLoaded( false ), mMultiStops( false )
529 {
531 
532  // TODO replace this with hard-coded data in the default case
533  // don't load file if variant is missing
534  if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
535  loadFile();
536 }
537 
539 {
542 
543  if ( props.contains( "schemeName" ) )
544  schemeName = props["schemeName"];
545  if ( props.contains( "variantName" ) )
546  variantName = props["variantName"];
547 
548  return new QgsCptCityColorRampV2( schemeName, variantName );
549 }
550 
552 {
553  QgsCptCityColorRampV2* ramp = new QgsCptCityColorRampV2( "", "", false );
554  ramp->copy( this );
555  return ramp;
556 }
557 
559 {
560  if ( ! other )
561  return;
562  mColor1 = other->color1();
563  mColor2 = other->color2();
564  mDiscrete = other->isDiscrete();
565  mStops = other->stops();
566  mSchemeName = other->mSchemeName;
567  mVariantName = other->mVariantName;
568  mVariantList = other->mVariantList;
569  mFileLoaded = other->mFileLoaded;
570 }
571 
573 {
576  // add author and copyright information
577  // TODO also add COPYING.xml file/link?
579  info["cpt-city-gradient"] = "<cpt-city>/" + mSchemeName + mVariantName + ".svg";
580  QString copyingFilename = copyingFileName();
581  copyingFilename.remove( QgsCptCityArchive::defaultBaseDir() );
582  info["cpt-city-license"] = "<cpt-city>" + copyingFilename;
583  ramp->setInfo( info );
584  return ramp;
585 }
586 
587 
589 {
590  QgsStringMap map;
591  map["schemeName"] = mSchemeName;
592  map["variantName"] = mVariantName;
593  return map;
594 }
595 
596 
598 {
599  if ( mSchemeName == "" )
600  return QString();
601  else
602  {
603  return QgsCptCityArchive::defaultBaseDir() + QDir::separator() + mSchemeName + mVariantName + ".svg";
604  }
605 }
606 
608 {
609  return QgsCptCityArchive::findFileName( "COPYING.xml", QFileInfo( fileName() ).dir().path(),
611 }
612 
614 {
615  return QgsCptCityArchive::findFileName( "DESC.xml", QFileInfo( fileName() ).dir().path(),
617 }
618 
620 {
622 }
623 
625 {
626  if ( mFileLoaded )
627  {
628  QgsDebugMsg( "File already loaded for " + mSchemeName + mVariantName );
629  return true;
630  }
631 
632  // get filename
633  QString filename = fileName();
634  if ( filename.isNull() )
635  {
636  QgsDebugMsg( "Couldn't get fileName() for " + mSchemeName + mVariantName );
637  return false;
638  }
639 
640  QgsDebugMsg( QString( "filename= %1 loaded=%2" ).arg( filename ).arg( mFileLoaded ) );
641 
642  // get color ramp from svg file
643  QMap< double, QPair<QColor, QColor> > colorMap =
645 
646  // add colors to palette
647  mFileLoaded = false;
648  mStops.clear();
649  QMap<double, QPair<QColor, QColor> >::const_iterator it, prev;
650  // first detect if file is gradient is continuous or dicrete
651  // discrete: stop contains 2 colors and first color is identical to previous second
652  // multi: stop contains 2 colors and no relation with previous stop
653  mDiscrete = false;
654  mMultiStops = false;
655  it = prev = colorMap.constBegin();
656  while ( it != colorMap.constEnd() )
657  {
658  // look for stops that contain multiple values
659  if ( it != colorMap.constBegin() && ( it.value().first != it.value().second ) )
660  {
661  if ( it.value().first == prev.value().second )
662  {
663  mDiscrete = true;
664  break;
665  }
666  else
667  {
668  mMultiStops = true;
669  break;
670  }
671  }
672  prev = it;
673  ++it;
674  }
675 
676  // fill all stops
677  it = prev = colorMap.constBegin();
678  while ( it != colorMap.constEnd() )
679  {
680  if ( mDiscrete )
681  {
682  // mPalette << qMakePair( it.key(), it.value().second );
683  mStops.append( QgsGradientStop( it.key(), it.value().second ) );
684  }
685  else
686  {
687  // mPalette << qMakePair( it.key(), it.value().first );
688  mStops.append( QgsGradientStop( it.key(), it.value().first ) );
689  if (( mMultiStops ) &&
690  ( it.key() != 0.0 && it.key() != 1.0 ) )
691  {
692  mStops.append( QgsGradientStop( it.key(), it.value().second ) );
693  }
694  }
695  prev = it;
696  ++it;
697  }
698 
699  // remove first and last items (mColor1 and mColor2)
700  if ( ! mStops.isEmpty() && mStops.first().offset == 0.0 )
701  mColor1 = mStops.takeFirst().color;
702  if ( ! mStops.isEmpty() && mStops.last().offset == 1.0 )
703  mColor2 = mStops.takeLast().color;
704 
705  mFileLoaded = true;
706  return true;
707 }
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
static unsigned index
#define DEFAULT_CPTCITY_VARIANTNAME
double value(int index) const
QgsVectorGradientColorRampV2(QColor color1=DEFAULT_GRADIENT_COLOR1, QColor color2=DEFAULT_GRADIENT_COLOR2, bool discrete=false, QgsGradientStopsList stops=QgsGradientStopsList())
void copy(const QgsCptCityColorRampV2 *other)
static QList< int > listSchemeVariants(QString schemeName)
QgsVectorColorRampV2 * clone() const
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
static QString defaultBaseDir()
#define DEFAULT_COLORBREWER_SCHEMENAME
#define DEFAULT_RANDOM_HUE_MIN
static QColor _interpolate(QColor c1, QColor c2, double value)
void setInfo(const QgsStringMap &info)
static QList< int > listSchemeVariants(QString schemeName)
virtual void setTotalColorCount(const int colorCount)
static QColor decodeColor(QString str)
#define DEFAULT_CPTCITY_SCHEMENAME
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
#define DEFAULT_RANDOM_SAT_MAX
static QString encodeColor(QColor color)
virtual QgsStringMap properties() const
virtual QgsStringMap properties() const
QString variantName() const
virtual QColor color(double value) const
QStringList variantList() const
#define DEFAULT_GRADIENT_COLOR2
static QList< QColor > listSchemeColors(QString schemeName, int colors)
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)
QColor color(double value) const
#define DEFAULT_GRADIENT_COLOR1
#define DEFAULT_RANDOM_VAL_MAX
QgsStringMap copyingInfo() const
virtual double value(int index) const
static QMap< QString, QString > copyingInfo(const QString &fileName)
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
virtual QgsStringMap properties() const
virtual double value(int index) const
virtual QgsStringMap properties() const
#define DEFAULT_RANDOM_SAT_MIN
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
virtual QColor color(double value) const
virtual QgsVectorColorRampV2 * clone() const
QgsVectorGradientColorRampV2 * cloneGradientRamp() const
int ANALYSIS_EXPORT lower(int n, int i)
lower function
QList< QgsGradientStop > QgsGradientStopsList
virtual double value(int index) const
#define DEFAULT_COLORBREWER_COLORS
static QStringList listSchemes()
const QgsGradientStopsList & stops() const
virtual QgsVectorColorRampV2 * clone() const
static QgsVectorColorRampV2 * create(const QgsStringMap &properties=QgsStringMap())
QList< QColor > mPrecalculatedColors
#define DEFAULT_RANDOM_HUE_MAX
virtual QgsVectorColorRampV2 * clone() const
QgsCptCityColorRampV2(QString schemeName=DEFAULT_CPTCITY_SCHEMENAME, QString variantName=DEFAULT_CPTCITY_VARIANTNAME, bool doLoadFile=true)
QgsStringMap properties() const
static QMap< double, QPair< QColor, QColor > > gradientColorMap(const QString &fileName)
note not available in python bindings
QgsVectorColorBrewerColorRampV2(QString schemeName=DEFAULT_COLORBREWER_SCHEMENAME, int colors=DEFAULT_COLORBREWER_COLORS)
virtual QColor color(double value) const
#define DEFAULT_RANDOM_VAL_MIN
void addStopsToGradient(QGradient *gradient, double alpha=1)
copy color ramp stops to a QGradient
QString copyingFileName() const
#define DEFAULT_RANDOM_COUNT
static QString findFileName(const QString &target, const QString &startDir, const QString &baseDir)
virtual QgsVectorColorRampV2 * clone() const