Skip to content

Commit

Permalink
Fix conversion of non rgb gradients to QGradient
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 10, 2021
1 parent 19984d1 commit b8e4eee
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 7 deletions.
2 changes: 1 addition & 1 deletion python/core/auto_generated/qgscolorrampimpl.sip.in
Expand Up @@ -254,7 +254,7 @@ Sets additional info to attach to the gradient ramp (e.g., authorship notes)
.. seealso:: :py:func:`info`
%End

void addStopsToGradient( QGradient *gradient, double opacity = 1 );
void addStopsToGradient( QGradient *gradient, double opacity = 1 ) const;
%Docstring
Copy color ramp stops to a QGradient

Expand Down
40 changes: 35 additions & 5 deletions src/core/qgscolorrampimpl.cpp
Expand Up @@ -516,7 +516,7 @@ void QgsGradientColorRamp::setStops( const QgsGradientStopsList &stops )
std::sort( mStops.begin(), mStops.end(), stopLessThan );
}

void QgsGradientColorRamp::addStopsToGradient( QGradient *gradient, double opacity )
void QgsGradientColorRamp::addStopsToGradient( QGradient *gradient, double opacity ) const
{
//copy color ramp stops to a QGradient
QColor color1 = mColor1;
Expand All @@ -529,15 +529,45 @@ void QgsGradientColorRamp::addStopsToGradient( QGradient *gradient, double opaci
gradient->setColorAt( 0, color1 );
gradient->setColorAt( 1, color2 );

for ( QgsGradientStopsList::const_iterator it = mStops.constBegin();
it != mStops.constEnd(); ++it )
double lastOffset = 0;
for ( const QgsGradientStop &stop : mStops )
{
QColor rampColor = it->color;

QColor rampColor = stop.color;
if ( opacity < 1 )
{
rampColor.setAlpha( rampColor.alpha() * opacity );
}
gradient->setColorAt( it->offset, rampColor );
gradient->setColorAt( stop.offset, rampColor );

if ( stop.colorSpec() != QColor::Rgb )
{
// QGradient only supports RGB interpolation. For other color specs we have
// to "fake" things by populating the gradient with additional stops
for ( double offset = lastOffset + 0.05; offset < stop.offset; offset += 0.05 )
{
QColor midColor = color( offset );
if ( opacity < 1 )
{
midColor.setAlpha( midColor.alpha() * opacity );
}
gradient->setColorAt( offset, midColor );
}
}
lastOffset = stop.offset;
}

if ( mColorSpec != QColor::Rgb )
{
for ( double offset = lastOffset + 0.05; offset < 1; offset += 0.05 )
{
QColor midColor = color( offset );
if ( opacity < 1 )
{
midColor.setAlpha( midColor.alpha() * opacity );
}
gradient->setColorAt( offset, midColor );
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/qgscolorrampimpl.h
Expand Up @@ -259,7 +259,7 @@ class CORE_EXPORT QgsGradientColorRamp : public QgsColorRamp
* by this factor before adding to the gradient.
* \since QGIS 2.1
*/
void addStopsToGradient( QGradient *gradient, double opacity = 1 );
void addStopsToGradient( QGradient *gradient, double opacity = 1 ) const;

/**
* Returns the color specification in which the color component interpolation will occur.
Expand Down
59 changes: 59 additions & 0 deletions tests/src/python/test_qgscolorramp.py
Expand Up @@ -331,6 +331,65 @@ def testQgsGradientColorRamp(self):
self.assertEqual(g.stops()[2], (0.9, QColor(40, 60, 100, 127)))
self.assertEqual(g.stops()[3], (1.0, QColor(0, 200, 0, 127)))

# add to gradient, non-RGB color model
g = QGradient()
rr = QgsGradientColorRamp(QColor.fromHsvF(0.2, 0.3, 0.4), QColor.fromHsvF(0.8, 1.0, 0.6))
rr.setColorSpec(QColor.Hsv)
rr.addStopsToGradient(g, 0.5)
res = [(round(stop[0], 2), round(stop[1].hsvHueF(), 2), round(stop[1].hsvSaturationF(), 2),
round(stop[1].valueF(), 2), round(stop[1].alphaF(), 2)) for stop in g.stops()]
self.assertEqual(res, [(0.0, 0.2, 0.3, 0.4, 0.5),
(0.05, 0.23, 0.34, 0.41, 0.5),
(0.1, 0.26, 0.37, 0.42, 0.5),
(0.15, 0.29, 0.41, 0.43, 0.5),
(0.2, 0.32, 0.44, 0.44, 0.5),
(0.25, 0.35, 0.48, 0.45, 0.5),
(0.3, 0.38, 0.51, 0.46, 0.5),
(0.35, 0.41, 0.55, 0.47, 0.5),
(0.4, 0.44, 0.58, 0.48, 0.5),
(0.45, 0.47, 0.61, 0.49, 0.5),
(0.5, 0.5, 0.65, 0.5, 0.5),
(0.55, 0.53, 0.69, 0.51, 0.5),
(0.6, 0.56, 0.72, 0.52, 0.5),
(0.65, 0.59, 0.76, 0.53, 0.5),
(0.7, 0.62, 0.79, 0.54, 0.5),
(0.75, 0.65, 0.83, 0.55, 0.5),
(0.8, 0.68, 0.86, 0.56, 0.5),
(0.85, 0.71, 0.9, 0.57, 0.5),
(0.9, 0.74, 0.93, 0.58, 0.5),
(0.95, 0.77, 0.96, 0.59, 0.5),
(1.0, 0.8, 1.0, 0.6, 0.5)])
# with stops
stop = QgsGradientStop(0.6, QColor.fromHsvF(0.1, 0.7, 0.3, 0.4))
stop.setColorSpec(QColor.Hsl)
stop.setDirection(Qgis.AngularDirection.Clockwise)
rr.setStops([stop])
g = QGradient()
rr.addStopsToGradient(g, 0.5)
res = [(round(stop[0], 2), round(stop[1].hsvHueF(), 2), round(stop[1].hsvSaturationF(), 2),
round(stop[1].valueF(), 2), round(stop[1].alphaF(), 2)) for stop in g.stops()]
self.assertEqual(res, [(0.0, 0.2, 0.3, 0.4, 0.5),
(0.05, 0.19, 0.34, 0.4, 0.47),
(0.1, 0.18, 0.38, 0.39, 0.45),
(0.15, 0.17, 0.42, 0.38, 0.42),
(0.2, 0.17, 0.46, 0.38, 0.4),
(0.25, 0.16, 0.49, 0.37, 0.37),
(0.3, 0.15, 0.53, 0.36, 0.35),
(0.35, 0.14, 0.56, 0.35, 0.33),
(0.4, 0.13, 0.59, 0.35, 0.3),
(0.45, 0.12, 0.62, 0.33, 0.27),
(0.5, 0.12, 0.65, 0.32, 0.25),
(0.55, 0.11, 0.67, 0.31, 0.22),
(0.6, 0.1, 0.7, 0.3, 0.2),
(0.65, 0.19, 0.74, 0.34, 0.24),
(0.7, 0.28, 0.78, 0.38, 0.27),
(0.75, 0.36, 0.81, 0.41, 0.31),
(0.8, 0.45, 0.85, 0.45, 0.35),
(0.85, 0.54, 0.89, 0.49, 0.39),
(0.9, 0.62, 0.93, 0.53, 0.42),
(0.95, 0.71, 0.96, 0.56, 0.46),
(1.0, 0.8, 1.0, 0.6, 0.5)])

# test that stops are ordered when setting them
# first add some out-of-order stops
r.setStops([QgsGradientStop(0.4, QColor(100, 100, 40)),
Expand Down

0 comments on commit b8e4eee

Please sign in to comment.