QGIS API Documentation 3.39.0-Master (bca3cdb6021)
Loading...
Searching...
No Matches
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"
18#include "qgscptcityarchive.h"
19
20#include "qgscolorutils.h"
21#include "qgslogger.h"
22
23#include <algorithm>
24#include <random>
25
26#include <QTime>
27#include <QDir>
28#include <QFileInfo>
29
31
32
33static QColor _interpolateRgb( const QColor &c1, const QColor &c2, const double value, const Qgis::AngularDirection )
34{
35 if ( std::isnan( value ) )
36 return c2;
37
38 const qreal red1 = c1.redF();
39 const qreal red2 = c2.redF();
40 const qreal red = ( red1 + value * ( red2 - red1 ) );
41
42 const qreal green1 = c1.greenF();
43 const qreal green2 = c2.greenF();
44 const qreal green = ( green1 + value * ( green2 - green1 ) );
45
46 const qreal blue1 = c1.blueF();
47 const qreal blue2 = c2.blueF();
48 const qreal blue = ( blue1 + value * ( blue2 - blue1 ) );
49
50 const qreal alpha1 = c1.alphaF();
51 const qreal alpha2 = c2.alphaF();
52 const qreal alpha = ( alpha1 + value * ( alpha2 - alpha1 ) );
53
54 return QColor::fromRgbF( red, green, blue, alpha );
55}
56
57static QColor _interpolateHsv( const QColor &c1, const QColor &c2, const double value, const Qgis::AngularDirection direction )
58{
59 if ( std::isnan( value ) )
60 return c2;
61
62 qreal hue1 = c1.hsvHueF();
63 qreal hue2 = c2.hsvHueF();
64 qreal hue = 0;
65 if ( hue1 == -1 )
66 hue = hue2;
67 else if ( hue2 == -1 )
68 hue = hue1;
69 else
70 {
71 switch ( direction )
72 {
74 {
75 if ( hue1 < hue2 )
76 hue1 += 1;
77
78 hue = hue1 - value * ( hue1 - hue2 );
79 if ( hue < 0 )
80 hue += 1;
81 if ( hue > 1 )
82 hue -= 1;
83 break;
84 }
85
87 {
88 if ( hue2 < hue1 )
89 hue2 += 1;
90
91 hue = hue1 + value * ( hue2 - hue1 );
92 if ( hue > 1 )
93 hue -= 1;
94 break;
95 }
97 break;
98 }
99 }
100
101 const qreal saturation1 = c1.hsvSaturationF();
102 const qreal saturation2 = c2.hsvSaturationF();
103 const qreal saturation = ( saturation1 + value * ( saturation2 - saturation1 ) );
104
105 const qreal value1 = c1.valueF();
106 const qreal value2 = c2.valueF();
107 const qreal valueOut = ( value1 + value * ( value2 - value1 ) );
108
109 const qreal alpha1 = c1.alphaF();
110 const qreal alpha2 = c2.alphaF();
111 const qreal alpha = ( alpha1 + value * ( alpha2 - alpha1 ) );
112
113 return QColor::fromHsvF( hue > 1 ? hue - 1 : hue, saturation, valueOut, alpha );
114}
115
116static QColor _interpolateHsl( const QColor &c1, const QColor &c2, const double value, const Qgis::AngularDirection direction )
117{
118 if ( std::isnan( value ) )
119 return c2;
120
121 qreal hue1 = c1.hslHueF();
122 qreal hue2 = c2.hslHueF();
123 qreal hue = 0;
124 if ( hue1 == -1 )
125 hue = hue2;
126 else if ( hue2 == -1 )
127 hue = hue1;
128 else
129 {
130 switch ( direction )
131 {
133 {
134 if ( hue1 < hue2 )
135 hue1 += 1;
136
137 hue = hue1 - value * ( hue1 - hue2 );
138 if ( hue < 0 )
139 hue += 1;
140 if ( hue > 1 )
141 hue -= 1;
142 break;
143 }
144
146 {
147 if ( hue2 < hue1 )
148 hue2 += 1;
149
150 hue = hue1 + value * ( hue2 - hue1 );
151 if ( hue > 1 )
152 hue -= 1;
153 break;
154 }
156 break;
157 }
158 }
159
160 const qreal saturation1 = c1.hslSaturationF();
161 const qreal saturation2 = c2.hslSaturationF();
162 const qreal saturation = ( saturation1 + value * ( saturation2 - saturation1 ) );
163
164 const qreal lightness1 = c1.lightnessF();
165 const qreal lightness2 = c2.lightnessF();
166 const qreal lightness = ( lightness1 + value * ( lightness2 - lightness1 ) );
167
168 const qreal alpha1 = c1.alphaF();
169 const qreal alpha2 = c2.alphaF();
170 const qreal alpha = ( alpha1 + value * ( alpha2 - alpha1 ) );
171
172 return QColor::fromHslF( hue > 1 ? hue - 1 : hue, saturation, lightness, alpha );
173}
174
175static QColor interpolateCmyk( const QColor &c1, const QColor &c2, const double value, const Qgis::AngularDirection )
176{
177 if ( std::isnan( value ) )
178 return c2;
179
180 const qreal cyan1 = c1.cyanF();
181 const qreal cyan2 = c2.cyanF();
182 const qreal cyan = ( cyan1 + value * ( cyan2 - cyan1 ) );
183
184 const qreal magenta1 = c1.magentaF();
185 const qreal magenta2 = c2.magentaF();
186 const qreal magenta = ( magenta1 + value * ( magenta2 - magenta1 ) );
187
188 const qreal yellow1 = c1.yellowF();
189 const qreal yellow2 = c2.yellowF();
190 const qreal yellow = ( yellow1 + value * ( yellow2 - yellow1 ) );
191
192 const qreal black1 = c1.blackF();
193 const qreal black2 = c2.blackF();
194 const qreal black = ( black1 + value * ( black2 - black1 ) );
195
196 const qreal alpha1 = c1.alphaF();
197 const qreal alpha2 = c2.alphaF();
198 const qreal alpha = ( alpha1 + value * ( alpha2 - alpha1 ) );
199
200 return QColor::fromCmykF( cyan, magenta, yellow, black, alpha ); // NOLINT(bugprone-narrowing-conversions): TODO QGIS 4 remove the nolint instructions, QColor was qreal (double) and is now float
201}
202
204
205
206QgsGradientStop::QgsGradientStop( double offset, const QColor &color )
207 : offset( offset )
208 , color( color )
209 , mFunc( _interpolateRgb )
210{
211
212}
213
214void QgsGradientStop::setColorSpec( QColor::Spec spec )
215{
216 mColorSpec = spec;
217
218 switch ( mColorSpec )
219 {
220 case QColor::Rgb:
221 case QColor::Invalid:
222 case QColor::ExtendedRgb:
223 mFunc = _interpolateRgb;
224 break;
225 case QColor::Cmyk:
226 mFunc = interpolateCmyk;
227 break;
228 case QColor::Hsv:
229 mFunc = _interpolateHsv;
230 break;
231 case QColor::Hsl:
232 mFunc = _interpolateHsl;
233 break;
234 }
235}
236
237QgsGradientColorRamp::QgsGradientColorRamp( const QColor &color1, const QColor &color2,
238 bool discrete, const QgsGradientStopsList &stops )
239 : mColor1( color1 )
240 , mColor2( color2 )
241 , mDiscrete( discrete )
242 , mStops( stops )
243 , mFunc( _interpolateRgb )
244{
245}
246
247QgsColorRamp *QgsGradientColorRamp::create( const QVariantMap &props )
248{
249 // color1 and color2
252 if ( props.contains( QStringLiteral( "color1" ) ) )
253 color1 = QgsColorUtils::colorFromString( props[QStringLiteral( "color1" )].toString() );
254 if ( props.contains( QStringLiteral( "color2" ) ) )
255 color2 = QgsColorUtils::colorFromString( props[QStringLiteral( "color2" )].toString() );
256
257 //stops
259 if ( props.contains( QStringLiteral( "stops" ) ) )
260 {
261 const thread_local QRegularExpression rx( QStringLiteral( "(?<!,rgb)(?<!,cmyk)(?<!,hsl)(?<!,hsv):" ) );
262 const auto constSplit = props[QStringLiteral( "stops" )].toString().split( rx );
263 for ( const QString &stop : constSplit )
264 {
265 const QStringList parts = stop.split( ';' );
266 if ( parts.size() != 2 && parts.size() != 4 )
267 continue;
268
269 QColor c = QgsColorUtils::colorFromString( parts.at( 1 ) );
270 stops.append( QgsGradientStop( parts.at( 0 ).toDouble(), c ) );
271
272 if ( parts.size() == 4 )
273 {
274 if ( parts.at( 2 ).compare( QLatin1String( "rgb" ) ) == 0 )
275 stops.last().setColorSpec( QColor::Spec::Rgb );
276 else if ( parts.at( 2 ).compare( QLatin1String( "hsv" ) ) == 0 )
277 stops.last().setColorSpec( QColor::Spec::Hsv );
278 else if ( parts.at( 2 ).compare( QLatin1String( "hsl" ) ) == 0 )
279 stops.last().setColorSpec( QColor::Spec::Hsl );
280
281 if ( parts.at( 3 ).compare( QLatin1String( "cw" ) ) == 0 )
282 stops.last().setDirection( Qgis::AngularDirection::Clockwise );
283 else if ( parts.at( 3 ).compare( QLatin1String( "ccw" ) ) == 0 )
284 stops.last().setDirection( Qgis::AngularDirection::CounterClockwise );
285 }
286 }
287 }
288
289 // discrete vs. continuous
290 bool discrete = false;
291 if ( props.contains( QStringLiteral( "discrete" ) ) )
292 {
293 if ( props[QStringLiteral( "discrete" )] == QLatin1String( "1" ) )
294 discrete = true;
295 }
296
297 // search for information keys starting with "info_"
299 for ( QVariantMap::const_iterator it = props.constBegin();
300 it != props.constEnd(); ++it )
301 {
302 if ( it.key().startsWith( QLatin1String( "info_" ) ) )
303 info[ it.key().mid( 5 )] = it.value().toString();
304 }
305
307 r->setInfo( info );
308
309 if ( props.contains( QStringLiteral( "spec" ) ) )
310 {
311 const QString spec = props.value( QStringLiteral( "spec" ) ).toString().trimmed();
312 if ( spec.compare( QLatin1String( "rgb" ) ) == 0 )
313 r->setColorSpec( QColor::Spec::Rgb );
314 else if ( spec.compare( QLatin1String( "hsv" ) ) == 0 )
315 r->setColorSpec( QColor::Spec::Hsv );
316 else if ( spec.compare( QLatin1String( "hsl" ) ) == 0 )
317 r->setColorSpec( QColor::Spec::Hsl );
318 }
319
320 if ( props.contains( QStringLiteral( "direction" ) ) )
321 {
322 const QString direction = props.value( QStringLiteral( "direction" ) ).toString().trimmed();
323 if ( direction.compare( QLatin1String( "ccw" ) ) == 0 )
325 else if ( direction.compare( QLatin1String( "cw" ) ) == 0 )
327 }
328
329 return r;
330}
331
332double QgsGradientColorRamp::value( int index ) const
333{
334 if ( index <= 0 )
335 {
336 return 0;
337 }
338 else if ( index >= mStops.size() + 1 )
339 {
340 return 1;
341 }
342 else
343 {
344 return mStops[index - 1].offset;
345 }
346}
347
348QColor QgsGradientColorRamp::color( double value ) const
349{
350 if ( qgsDoubleNear( value, 0.0 ) || value < 0.0 )
351 {
352 return mColor1;
353 }
354 else if ( qgsDoubleNear( value, 1.0 ) || value > 1.0 )
355 {
356 return mColor2;
357 }
358 else if ( mStops.isEmpty() )
359 {
360 if ( mDiscrete )
361 return mColor1;
362
363 return mFunc( mColor1, mColor2, value, mDirection );
364 }
365 else
366 {
367 double lower = 0, upper = 0;
368 QColor c1 = mColor1, c2;
369 for ( QgsGradientStopsList::const_iterator it = mStops.begin(); it != mStops.end(); ++it )
370 {
371 if ( it->offset > value )
372 {
373 if ( mDiscrete )
374 return c1;
375
376 upper = it->offset;
377 c2 = it->color;
378
379 return qgsDoubleNear( upper, lower ) ? c1 : it->mFunc( c1, c2, ( value - lower ) / ( upper - lower ), it->mDirection );
380 }
381 lower = it->offset;
382 c1 = it->color;
383 }
384
385 if ( mDiscrete )
386 return c1;
387
388 upper = 1;
389 c2 = mColor2;
390 return qgsDoubleNear( upper, lower ) ? c1 : mFunc( c1, c2, ( value - lower ) / ( upper - lower ), mDirection );
391 }
392}
393
395{
397}
398
400{
401 QgsGradientStopsList newStops;
402 newStops.reserve( mStops.size() );
403
404 if ( mDiscrete )
405 {
407 mColor1 = mStops.at( mStops.size() - 1 ).color;
408 for ( int k = mStops.size() - 1; k >= 1; k-- )
409 {
410 newStops << QgsGradientStop( 1 - mStops.at( k ).offset, mStops.at( k - 1 ).color );
411 }
412 newStops << QgsGradientStop( 1 - mStops.at( 0 ).offset, mColor2 );
413 }
414 else
415 {
416 QColor tmpColor = mColor2;
418 mColor1 = tmpColor;
419 for ( int k = mStops.size() - 1; k >= 0; k-- )
420 {
421 newStops << QgsGradientStop( 1 - mStops.at( k ).offset, mStops.at( k ).color );
422 }
423 }
424
425 // transfer color spec, invert directions
426 if ( mStops.empty() )
427 {
428 // reverse direction
430 }
431 else
432 {
433 newStops[0].setColorSpec( mColorSpec );
435 for ( int i = 1, j = mStops.size() - 1; i < mStops.size(); ++i, --j )
436 {
437 newStops[i].setColorSpec( mStops.at( j ).colorSpec() );
439 }
440 mColorSpec = mStops.at( 0 ).colorSpec();
442 }
443
444 mStops = newStops;
445}
446
456
458{
459 QVariantMap map;
460 map[QStringLiteral( "color1" )] = QgsColorUtils::colorToString( mColor1 );
461 map[QStringLiteral( "color2" )] = QgsColorUtils::colorToString( mColor2 );
462 if ( !mStops.isEmpty() )
463 {
464 QStringList lst;
465 lst.reserve( mStops.size() );
466 for ( const QgsGradientStop &stop : mStops )
467 {
468 lst.append( QStringLiteral( "%1;%2;%3;%4" ).arg( stop.offset ).arg( QgsColorUtils::colorToString( stop.color ),
469 stop.colorSpec() == QColor::Rgb ? QStringLiteral( "rgb" )
470 : stop.colorSpec() == QColor::Hsv ? QStringLiteral( "hsv" )
471 : stop.colorSpec() == QColor::Hsl ? QStringLiteral( "hsl" ) : QString(),
472 stop.direction() == Qgis::AngularDirection::CounterClockwise ? QStringLiteral( "ccw" ) : QStringLiteral( "cw" ) ) );
473 }
474 map[QStringLiteral( "stops" )] = lst.join( QLatin1Char( ':' ) );
475 }
476
477 map[QStringLiteral( "discrete" )] = mDiscrete ? "1" : "0";
478
479 for ( QgsStringMap::const_iterator it = mInfo.constBegin();
480 it != mInfo.constEnd(); ++it )
481 {
482 map["info_" + it.key()] = it.value();
483 }
484
485 switch ( mColorSpec )
486 {
487 case QColor::Rgb:
488 map[QStringLiteral( "spec" ) ] = QStringLiteral( "rgb" );
489 break;
490 case QColor::Hsv:
491 map[QStringLiteral( "spec" ) ] = QStringLiteral( "hsv" );
492 break;
493 case QColor::Hsl:
494 map[QStringLiteral( "spec" ) ] = QStringLiteral( "hsl" );
495 break;
496 case QColor::Cmyk:
497 case QColor::Invalid:
498 case QColor::ExtendedRgb:
499 break;
500 }
501
502 switch ( mDirection )
503 {
505 map[QStringLiteral( "direction" ) ] = QStringLiteral( "cw" );
506 break;
508 map[QStringLiteral( "direction" ) ] = QStringLiteral( "ccw" );
509 break;
511 break;
512 }
513
514 map[QStringLiteral( "rampType" )] = type();
515 return map;
516}
518{
519 if ( discrete == mDiscrete )
520 return;
521
522 // if going to/from Discrete, re-arrange stops
523 // this will only work when stops are equally-spaced
524 QgsGradientStopsList newStops;
525 if ( discrete )
526 {
527 // re-arrange stops offset
528 int numStops = mStops.count() + 2;
529 int i = 1;
530 for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
531 it != mStops.constEnd(); ++it )
532 {
533 newStops.append( QgsGradientStop( static_cast< double >( i ) / numStops, it->color ) );
534 if ( i == numStops - 1 )
535 break;
536 i++;
537 }
538 // replicate last color
539 newStops.append( QgsGradientStop( static_cast< double >( i ) / numStops, mColor2 ) );
540 }
541 else
542 {
543 // re-arrange stops offset, remove duplicate last color
544 int numStops = mStops.count() + 2;
545 int i = 1;
546 for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
547 it != mStops.constEnd(); ++it )
548 {
549 newStops.append( QgsGradientStop( static_cast< double >( i ) / ( numStops - 2 ), it->color ) );
550 if ( i == numStops - 3 )
551 break;
552 i++;
553 }
554 }
555 mStops = newStops;
556 mDiscrete = discrete;
557}
558
559bool stopLessThan( const QgsGradientStop &s1, const QgsGradientStop &s2 )
560{
561 return s1.offset < s2.offset;
562}
563
565{
566 mStops = stops;
567
568 //sort stops by offset
569 std::sort( mStops.begin(), mStops.end(), stopLessThan );
570}
571
572void QgsGradientColorRamp::addStopsToGradient( QGradient *gradient, double opacity ) const
573{
574 //copy color ramp stops to a QGradient
575 QColor color1 = mColor1;
576 QColor color2 = mColor2;
577 if ( opacity < 1 )
578 {
579 color1.setAlpha( color1.alpha() * opacity );
580 color2.setAlpha( color2.alpha() * opacity );
581 }
582 gradient->setColorAt( 0, color1 );
583 gradient->setColorAt( 1, color2 );
584
585 double lastOffset = 0;
586 for ( const QgsGradientStop &stop : mStops )
587 {
588
589 QColor rampColor = stop.color;
590 if ( opacity < 1 )
591 {
592 rampColor.setAlpha( rampColor.alpha() * opacity );
593 }
594 gradient->setColorAt( stop.offset, rampColor );
595
596 if ( stop.colorSpec() != QColor::Rgb )
597 {
598 // QGradient only supports RGB interpolation. For other color specs we have
599 // to "fake" things by populating the gradient with additional stops
600 for ( double offset = lastOffset + 0.05; offset < stop.offset; offset += 0.05 )
601 {
602 QColor midColor = color( offset );
603 if ( opacity < 1 )
604 {
605 midColor.setAlpha( midColor.alpha() * opacity );
606 }
607 gradient->setColorAt( offset, midColor );
608 }
609 }
610 lastOffset = stop.offset;
611 }
612
613 if ( mColorSpec != QColor::Rgb )
614 {
615 for ( double offset = lastOffset + 0.05; offset < 1; offset += 0.05 )
616 {
617 QColor midColor = color( offset );
618 if ( opacity < 1 )
619 {
620 midColor.setAlpha( midColor.alpha() * opacity );
621 }
622 gradient->setColorAt( offset, midColor );
623 }
624 }
625}
626
627void QgsGradientColorRamp::setColorSpec( QColor::Spec spec )
628{
629 mColorSpec = spec;
630 switch ( mColorSpec )
631 {
632 case QColor::Rgb:
633 case QColor::Invalid:
634 case QColor::ExtendedRgb:
635 mFunc = _interpolateRgb;
636 break;
637 case QColor::Cmyk:
638 mFunc = interpolateCmyk;
639 break;
640 case QColor::Hsv:
641 mFunc = _interpolateHsv;
642 break;
643 case QColor::Hsl:
644 mFunc = _interpolateHsl;
645 break;
646 }
647}
648
649
651
652
654 int satMin, int satMax, int valMin, int valMax )
655 : mCount( count )
656 , mHueMin( hueMin ), mHueMax( hueMax )
657 , mSatMin( satMin ), mSatMax( satMax )
658 , mValMin( valMin ), mValMax( valMax )
659{
660 updateColors();
661}
662
664{
669
670 if ( props.contains( QStringLiteral( "count" ) ) ) count = props[QStringLiteral( "count" )].toInt();
671 if ( props.contains( QStringLiteral( "hueMin" ) ) ) hueMin = props[QStringLiteral( "hueMin" )].toInt();
672 if ( props.contains( QStringLiteral( "hueMax" ) ) ) hueMax = props[QStringLiteral( "hueMax" )].toInt();
673 if ( props.contains( QStringLiteral( "satMin" ) ) ) satMin = props[QStringLiteral( "satMin" )].toInt();
674 if ( props.contains( QStringLiteral( "satMax" ) ) ) satMax = props[QStringLiteral( "satMax" )].toInt();
675 if ( props.contains( QStringLiteral( "valMin" ) ) ) valMin = props[QStringLiteral( "valMin" )].toInt();
676 if ( props.contains( QStringLiteral( "valMax" ) ) ) valMax = props[QStringLiteral( "valMax" )].toInt();
677
679}
680
681double QgsLimitedRandomColorRamp::value( int index ) const
682{
683 if ( mColors.empty() )
684 return 0;
685 return static_cast< double >( index ) / ( mColors.size() - 1 );
686}
687
688QColor QgsLimitedRandomColorRamp::color( double value ) const
689{
690 if ( value < 0 || value > 1 )
691 return QColor();
692
693 int colorCnt = mColors.count();
694 int colorIdx = std::min( static_cast< int >( value * colorCnt ), colorCnt - 1 );
695
696 if ( colorIdx >= 0 && colorIdx < colorCnt )
697 return mColors.at( colorIdx );
698
699 return QColor();
700}
701
706
711
713{
714 QVariantMap map;
715 map[QStringLiteral( "count" )] = QString::number( mCount );
716 map[QStringLiteral( "hueMin" )] = QString::number( mHueMin );
717 map[QStringLiteral( "hueMax" )] = QString::number( mHueMax );
718 map[QStringLiteral( "satMin" )] = QString::number( mSatMin );
719 map[QStringLiteral( "satMax" )] = QString::number( mSatMax );
720 map[QStringLiteral( "valMin" )] = QString::number( mValMin );
721 map[QStringLiteral( "valMax" )] = QString::number( mValMax );
722 map[QStringLiteral( "rampType" )] = type();
723 return map;
724}
725
727 int hueMax, int hueMin, int satMax, int satMin, int valMax, int valMin )
728{
729 int h, s, v;
730 QList<QColor> colors;
731
732 //normalize values
733 int safeHueMax = std::max( hueMin, hueMax );
734 int safeHueMin = std::min( hueMin, hueMax );
735 int safeSatMax = std::max( satMin, satMax );
736 int safeSatMin = std::min( satMin, satMax );
737 int safeValMax = std::max( valMin, valMax );
738 int safeValMin = std::min( valMin, valMax );
739
740 //start hue at random angle
741 double currentHueAngle = 360.0 * static_cast< double >( std::rand() ) / RAND_MAX;
742
743 colors.reserve( count );
744 for ( int i = 0; i < count; ++i )
745 {
746 //increment hue by golden ratio (approx 137.507 degrees)
747 //as this minimizes hue nearness as count increases
748 //see http://basecase.org/env/on-rainbows for more details
749 currentHueAngle += 137.50776;
750 //scale hue to between hueMax and hueMin
751 h = std::clamp( std::round( ( std::fmod( currentHueAngle, 360.0 ) / 360.0 ) * ( safeHueMax - safeHueMin ) + safeHueMin ), 0.0, 359.0 );
752 s = std::clamp( ( static_cast<int>( std::rand() ) % ( safeSatMax - safeSatMin + 1 ) ) + safeSatMin, 0, 255 );
753 v = std::clamp( ( static_cast<int>( std::rand() ) % ( safeValMax - safeValMin + 1 ) ) + safeValMin, 0, 255 );
754 colors.append( QColor::fromHsv( h, s, v ) );
755 }
756 return colors;
757}
758
763
765
767{
768 return -1;
769}
770
771double QgsRandomColorRamp::value( int index ) const
772{
773 Q_UNUSED( index )
774 return 0.0;
775}
776
777QColor QgsRandomColorRamp::color( double value ) const
778{
779 int minVal = 130;
780 int maxVal = 255;
781
782 //if value is nan, then use last precalculated color
783 if ( std::isnan( value ) )
784 {
785 value = 1.0;
786 }
787 // Caller has converted an index into a value in [0.0, 1.0]
788 // by doing "index / (mTotalColorCount - 1)"; retrieve the original index.
789 int colorIndex = std::round( value * ( mTotalColorCount - 1 ) );
790 if ( mTotalColorCount >= 1 && mPrecalculatedColors.length() > colorIndex )
791 {
792 //use precalculated hue
793 return mPrecalculatedColors.at( colorIndex );
794 }
795
796 //can't use precalculated hues, use a totally random hue
797 int h = static_cast< int >( 360.0 * std::rand() / ( RAND_MAX + 1.0 ) );
798 int s = ( std::rand() % ( DEFAULT_RANDOM_SAT_MAX - DEFAULT_RANDOM_SAT_MIN + 1 ) ) + DEFAULT_RANDOM_SAT_MIN;
799 int v = ( std::rand() % ( maxVal - minVal + 1 ) ) + minVal;
800 return QColor::fromHsv( h, s, v );
801}
802
803void QgsRandomColorRamp::setTotalColorCount( const int colorCount )
804{
805 //calculate colors in advance, so that we can ensure they are more visually distinct than pure random colors
806 mPrecalculatedColors.clear();
807 mTotalColorCount = colorCount;
808
809 //This works OK for low color counts, but for > 10 or so colors there's still a good chance of
810 //similar colors being picked. TODO - investigate alternative "n-visually distinct color" routines
811
812 //random offsets
813 double hueOffset = ( 360.0 * std::rand() / ( RAND_MAX + 1.0 ) );
814
815 //try to maximise difference between hues. this is not an ideal implementation, as constant steps
816 //through the hue wheel are not visually perceived as constant changes in hue
817 //(for instance, we are much more likely to get green hues than yellow hues)
818 double hueStep = 359.0 / colorCount;
819 double currentHue = hueOffset;
820
821 //build up a list of colors
822 for ( int idx = 0; idx < colorCount; ++ idx )
823 {
824 int h = static_cast< int >( std::round( currentHue ) ) % 360;
825 int s = ( std::rand() % ( DEFAULT_RANDOM_SAT_MAX - DEFAULT_RANDOM_SAT_MIN + 1 ) ) + DEFAULT_RANDOM_SAT_MIN;
826 int v = ( std::rand() % ( DEFAULT_RANDOM_VAL_MAX - DEFAULT_RANDOM_VAL_MIN + 1 ) ) + DEFAULT_RANDOM_VAL_MIN;
827 mPrecalculatedColors << QColor::fromHsv( h, s, v );
828 currentHue += hueStep;
829 }
830
831 //lastly, shuffle color list
832 std::random_device rd;
833 std::mt19937 g( rd() );
834 std::shuffle( mPrecalculatedColors.begin(), mPrecalculatedColors.end(), g );
835}
836
838{
840}
841
846
848{
849 return QVariantMap();
850}
851
853
854QgsColorBrewerColorRamp::QgsColorBrewerColorRamp( const QString &schemeName, int colors, bool inverted )
855 : mSchemeName( schemeName )
856 , mColors( colors )
857 , mInverted( inverted )
858{
859 loadPalette();
860}
861
863{
866 bool inverted = false;
867
868 if ( props.contains( QStringLiteral( "schemeName" ) ) )
869 schemeName = props[QStringLiteral( "schemeName" )].toString();
870 if ( props.contains( QStringLiteral( "colors" ) ) )
871 colors = props[QStringLiteral( "colors" )].toInt();
872 if ( props.contains( QStringLiteral( "inverted" ) ) )
873 inverted = props[QStringLiteral( "inverted" )].toInt();
874
875 return new QgsColorBrewerColorRamp( schemeName, colors, inverted );
876}
877
879{
881
882 if ( mInverted )
883 {
884 QList<QColor> tmpPalette;
885
886 for ( int k = mPalette.size() - 1; k >= 0; k-- )
887 {
888 tmpPalette << mPalette.at( k );
889 }
890 mPalette = tmpPalette;
891 }
892}
893
898
899QList<int> QgsColorBrewerColorRamp::listSchemeVariants( const QString &schemeName )
900{
902}
903
904double QgsColorBrewerColorRamp::value( int index ) const
905{
906 if ( mPalette.empty() )
907 return 0;
908 return static_cast< double >( index ) / ( mPalette.size() - 1 );
909}
910
911QColor QgsColorBrewerColorRamp::color( double value ) const
912{
913 if ( mPalette.isEmpty() || value < 0 || value > 1 || std::isnan( value ) )
914 return QColor();
915
916 int paletteEntry = static_cast< int >( value * mPalette.count() );
917 if ( paletteEntry >= mPalette.count() )
918 paletteEntry = mPalette.count() - 1;
919 return mPalette.at( paletteEntry );
920}
921
927
932
934{
935 QVariantMap map;
936 map[QStringLiteral( "schemeName" )] = mSchemeName;
937 map[QStringLiteral( "colors" )] = QString::number( mColors );
938 map[QStringLiteral( "inverted" )] = QString::number( mInverted );
939 map[QStringLiteral( "rampType" )] = type();
940 return map;
941}
942
943
945
946
947QgsCptCityColorRamp::QgsCptCityColorRamp( const QString &schemeName, const QString &variantName,
948 bool inverted, bool doLoadFile )
950 , mSchemeName( schemeName )
951 , mVariantName( variantName )
952 , mInverted( inverted )
953{
954 // TODO replace this with hard-coded data in the default case
955 // don't load file if variant is missing
956 if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
957 loadFile();
958}
959
960QgsCptCityColorRamp::QgsCptCityColorRamp( const QString &schemeName, const QStringList &variantList,
961 const QString &variantName, bool inverted, bool doLoadFile )
963 , mSchemeName( schemeName )
964 , mVariantName( variantName )
965 , mVariantList( variantList )
966 , mInverted( inverted )
967{
969
970 // TODO replace this with hard-coded data in the default case
971 // don't load file if variant is missing
972 if ( doLoadFile && ( variantName != QString() || mVariantList.isEmpty() ) )
973 loadFile();
974}
975
976QgsColorRamp *QgsCptCityColorRamp::create( const QVariantMap &props )
977{
980 bool inverted = false;
981
982 if ( props.contains( QStringLiteral( "schemeName" ) ) )
983 schemeName = props[QStringLiteral( "schemeName" )].toString();
984 if ( props.contains( QStringLiteral( "variantName" ) ) )
985 variantName = props[QStringLiteral( "variantName" )].toString();
986 if ( props.contains( QStringLiteral( "inverted" ) ) )
987 inverted = props[QStringLiteral( "inverted" )].toInt();
988
989 return new QgsCptCityColorRamp( schemeName, variantName, inverted );
990}
991
993{
995}
996
1002
1004{
1005 QgsCptCityColorRamp *ramp = new QgsCptCityColorRamp( QString(), QString(), mInverted, false );
1006 ramp->copy( this );
1007 return ramp;
1008}
1009
1011{
1012 if ( ! other )
1013 return;
1014 mColor1 = other->color1();
1015 mColor2 = other->color2();
1016 mDiscrete = other->isDiscrete();
1017 mStops = other->stops();
1018 mSchemeName = other->mSchemeName;
1019 mVariantName = other->mVariantName;
1020 mVariantList = other->mVariantList;
1021 mFileLoaded = other->mFileLoaded;
1022 mInverted = other->mInverted;
1023}
1024
1026{
1027 QgsGradientColorRamp *ramp =
1029 // add author and copyright information
1030 // TODO also add COPYING.xml file/link?
1032 info[QStringLiteral( "cpt-city-gradient" )] = "<cpt-city>/" + mSchemeName + mVariantName + ".svg";
1033 QString copyingFilename = copyingFileName();
1034 copyingFilename.remove( QgsCptCityArchive::defaultBaseDir() );
1035 info[QStringLiteral( "cpt-city-license" )] = "<cpt-city>" + copyingFilename;
1036 ramp->setInfo( info );
1037 return ramp;
1038}
1039
1040
1042{
1043 QVariantMap map;
1044 map[QStringLiteral( "schemeName" )] = mSchemeName;
1045 map[QStringLiteral( "variantName" )] = mVariantName;
1046 map[QStringLiteral( "inverted" )] = QString::number( mInverted );
1047 map[QStringLiteral( "rampType" )] = type();
1048 return map;
1049}
1050
1051QString QgsCptCityColorRamp::fileNameForVariant( const QString &schema, const QString &variant )
1052{
1053 return QgsCptCityArchive::defaultBaseDir() + QDir::separator() + schema + variant + ".svg";
1054}
1055
1057{
1058 if ( mSchemeName.isEmpty() )
1059 return QString();
1060 else
1061 {
1062 return QgsCptCityArchive::defaultBaseDir() + QDir::separator() + mSchemeName + mVariantName + ".svg";
1063 }
1064}
1065
1067{
1068 return QgsCptCityArchive::findFileName( QStringLiteral( "COPYING.xml" ), QFileInfo( fileName() ).dir().path(),
1070}
1071
1073{
1074 return QgsCptCityArchive::findFileName( QStringLiteral( "DESC.xml" ), QFileInfo( fileName() ).dir().path(),
1076}
1077
1082
1084{
1085 if ( mFileLoaded )
1086 {
1087 QgsDebugMsgLevel( "File already loaded for " + mSchemeName + mVariantName, 2 );
1088 return true;
1089 }
1090
1091 // get filename
1092 QString filename = fileName();
1093 if ( filename.isNull() )
1094 {
1095 return false;
1096 }
1097
1098 QgsDebugMsgLevel( QStringLiteral( "filename= %1 loaded=%2" ).arg( filename ).arg( mFileLoaded ), 2 );
1099
1100 // get color ramp from svg file
1101 QMap< double, QPair<QColor, QColor> > colorMap =
1103
1104 // add colors to palette
1105 mFileLoaded = false;
1106 mStops.clear();
1107 QMap<double, QPair<QColor, QColor> >::const_iterator it, prev;
1108 // first detect if file is gradient is continuous or discrete
1109 // discrete: stop contains 2 colors and first color is identical to previous second
1110 // multi: stop contains 2 colors and no relation with previous stop
1111 mDiscrete = false;
1112 mMultiStops = false;
1113 it = prev = colorMap.constBegin();
1114 while ( it != colorMap.constEnd() )
1115 {
1116 // look for stops that contain multiple values
1117 if ( it != colorMap.constBegin() && ( it.value().first != it.value().second ) )
1118 {
1119 if ( it.value().first == prev.value().second )
1120 {
1121 mDiscrete = true;
1122 break;
1123 }
1124 else
1125 {
1126 mMultiStops = true;
1127 break;
1128 }
1129 }
1130 prev = it;
1131 ++it;
1132 }
1133
1134 // fill all stops
1135 it = prev = colorMap.constBegin();
1136 while ( it != colorMap.constEnd() )
1137 {
1138 if ( mDiscrete )
1139 {
1140 // mPalette << qMakePair( it.key(), it.value().second );
1141 mStops.append( QgsGradientStop( it.key(), it.value().second ) );
1142 }
1143 else
1144 {
1145 // mPalette << qMakePair( it.key(), it.value().first );
1146 mStops.append( QgsGradientStop( it.key(), it.value().first ) );
1147 if ( ( mMultiStops ) &&
1148 ( it.key() != 0.0 && it.key() != 1.0 ) )
1149 {
1150 mStops.append( QgsGradientStop( it.key(), it.value().second ) );
1151 }
1152 }
1153 prev = it;
1154 ++it;
1155 }
1156
1157 // remove first and last items (mColor1 and mColor2)
1158 if ( ! mStops.isEmpty() && mStops.at( 0 ).offset == 0.0 )
1159 mColor1 = mStops.takeFirst().color;
1160 if ( ! mStops.isEmpty() && mStops.last().offset == 1.0 )
1161 mColor2 = mStops.takeLast().color;
1162
1163 if ( mInverted )
1164 {
1166 }
1167
1168 mFileLoaded = true;
1169 return true;
1170}
1171
1172
1173//
1174// QgsPresetColorRamp
1175//
1176
1178{
1179 const auto constColors = colors;
1180 for ( const QColor &color : constColors )
1181 {
1182 mColors << qMakePair( color, color.name() );
1183 }
1184 // need at least one color
1185 if ( mColors.isEmpty() )
1186 mColors << qMakePair( QColor( 250, 75, 60 ), QStringLiteral( "#fa4b3c" ) );
1187}
1188
1190 : mColors( colors )
1191{
1192 // need at least one color
1193 if ( mColors.isEmpty() )
1194 mColors << qMakePair( QColor( 250, 75, 60 ), QStringLiteral( "#fa4b3c" ) );
1195}
1196
1197QgsColorRamp *QgsPresetSchemeColorRamp::create( const QVariantMap &properties )
1198{
1200
1201 int i = 0;
1202 QString colorString = properties.value( QStringLiteral( "preset_color_%1" ).arg( i ), QString() ).toString();
1203 QString colorName = properties.value( QStringLiteral( "preset_color_name_%1" ).arg( i ), QString() ).toString();
1204 while ( !colorString.isEmpty() )
1205 {
1206 colors << qMakePair( QgsColorUtils::colorFromString( colorString ), colorName );
1207 i++;
1208 colorString = properties.value( QStringLiteral( "preset_color_%1" ).arg( i ), QString() ).toString();
1209 colorName = properties.value( QStringLiteral( "preset_color_name_%1" ).arg( i ), QString() ).toString();
1210 }
1211
1212 return new QgsPresetSchemeColorRamp( colors );
1213}
1214
1216{
1217 QList< QColor > l;
1218 l.reserve( mColors.count() );
1219 for ( int i = 0; i < mColors.count(); ++i )
1220 {
1221 l << mColors.at( i ).first;
1222 }
1223 return l;
1224}
1225
1226double QgsPresetSchemeColorRamp::value( int index ) const
1227{
1228 if ( mColors.empty() )
1229 return 0;
1230 return static_cast< double >( index ) / ( mColors.size() - 1 );
1231}
1232
1233QColor QgsPresetSchemeColorRamp::color( double value ) const
1234{
1235 if ( value < 0 || value > 1 )
1236 return QColor();
1237
1238 int colorCnt = mColors.count();
1239 int colorIdx = std::min( static_cast< int >( value * colorCnt ), colorCnt - 1 );
1240
1241 if ( colorIdx >= 0 && colorIdx < colorCnt )
1242 return mColors.at( colorIdx ).first;
1243
1244 return QColor();
1245}
1246
1251
1253{
1254 QgsNamedColorList tmpColors;
1255
1256 for ( int k = mColors.size() - 1; k >= 0; k-- )
1257 {
1258 tmpColors << mColors.at( k );
1259 }
1260 mColors = tmpColors;
1261}
1262
1267
1269{
1270 QVariantMap props;
1271 for ( int i = 0; i < mColors.count(); ++i )
1272 {
1273 props.insert( QStringLiteral( "preset_color_%1" ).arg( i ), QgsColorUtils::colorToString( mColors.at( i ).first ) );
1274 props.insert( QStringLiteral( "preset_color_name_%1" ).arg( i ), mColors.at( i ).second );
1275 }
1276 props[QStringLiteral( "rampType" )] = type();
1277 return props;
1278}
1279
1281{
1282 return mColors.count();
1283}
1284
1286{
1287 return mColors;
1288}
AngularDirection
Angular directions.
Definition qgis.h:3174
@ NoOrientation
Unknown orientation or sentinel value.
@ 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.
virtual double value(int index) const =0
Returns relative value between [0,1] of color at specified index.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
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)
A color ramp from the CPT City collection.
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
void copy(const QgsCptCityColorRamp *other)
static QString fileNameForVariant(const QString &schema, const QString &variant)
Returns the source file name for a CPT schema and variant.
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
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.
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
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:5883
QMap< QString, QString > QgsStringMap
Definition qgis.h:6421
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