Skip to content

Commit

Permalink
[api] Split tolerance into separate values for red, green, blue channels
Browse files Browse the repository at this point in the history
Makes the API more flexible for future use. We only expose a single
tolerance value in the UI, but in future we could expose the
separate tolerances if desired (but be wary of UI bloat!!)
  • Loading branch information
nyalldawson committed Jul 29, 2024
1 parent 19fdd21 commit 4a24737
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ transparent when rendering rasters.
struct TransparentThreeValuePixel
{

TransparentThreeValuePixel( double red = 0, double green = 0, double blue = 0, double opacity = 0, double fuzzyTolerance = 4 * DBL_EPSILON );
TransparentThreeValuePixel( double red = 0, double green = 0, double blue = 0, double opacity = 0, double fuzzyToleranceRed = 4 * DBL_EPSILON, double fuzzyToleranceGreen = 4 * DBL_EPSILON, double fuzzyToleranceBlue = 4 * DBL_EPSILON );
%Docstring
Constructor for TransparentThreeValuePixel.

:param red: red pixel value
:param green: green pixel value
:param blue: blue pixel value
:param opacity: opacity for pixel, between 0 and 1.0
:param fuzzyTolerance: (since QGIS 3.40) allows specifying a tolerance for the color components, where the pixel's red, green or blue component can deviate from values specified here by a maximum of this tolerance amount
:param fuzzyToleranceRed: (since QGIS 3.40) allows specifying a tolerance for the red color component, where the pixel's red component can deviate from values specified here by a maximum of this tolerance amount
:param fuzzyToleranceGreen: (since QGIS 3.40) allows specifying a tolerance for the green color component, where the pixel's green component can deviate from values specified here by a maximum of this tolerance amount
:param fuzzyToleranceBlue: (since QGIS 3.40) allows specifying a tolerance for the blue color component, where the pixel's blue component can deviate from values specified here by a maximum of this tolerance amount

.. versionadded:: 3.38
%End
Expand All @@ -46,16 +48,20 @@ Constructor for TransparentThreeValuePixel.

double opacity;

double fuzzyTolerance;
double fuzzyToleranceRed;

double fuzzyToleranceGreen;

double fuzzyToleranceBlue;

bool operator==( const QgsRasterTransparency::TransparentThreeValuePixel &other ) const;
bool operator!=( const QgsRasterTransparency::TransparentThreeValuePixel &other ) const;

SIP_PYOBJECT __repr__();
%MethodCode
QString str;
if ( !qgsDoubleNear( sipCpp->fuzzyTolerance, 0 ) )
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4, %5>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity ).arg( sipCpp->fuzzyTolerance );
if ( !qgsDoubleNear( sipCpp->fuzzyToleranceRed, 0 ) || !qgsDoubleNear( sipCpp->fuzzyToleranceGreen, 0 ) || !qgsDoubleNear( sipCpp->fuzzyToleranceBlue, 0 ) )
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4, %5, %6, %7>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity ).arg( sipCpp->fuzzyToleranceRed ).arg( sipCpp->fuzzyToleranceGreen ).arg( sipCpp->fuzzyToleranceBlue );
else
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
Expand Down
16 changes: 11 additions & 5 deletions python/core/auto_generated/raster/qgsrastertransparency.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ transparent when rendering rasters.
struct TransparentThreeValuePixel
{

TransparentThreeValuePixel( double red = 0, double green = 0, double blue = 0, double opacity = 0, double fuzzyTolerance = 4 * DBL_EPSILON );
TransparentThreeValuePixel( double red = 0, double green = 0, double blue = 0, double opacity = 0, double fuzzyToleranceRed = 4 * DBL_EPSILON, double fuzzyToleranceGreen = 4 * DBL_EPSILON, double fuzzyToleranceBlue = 4 * DBL_EPSILON );
%Docstring
Constructor for TransparentThreeValuePixel.

:param red: red pixel value
:param green: green pixel value
:param blue: blue pixel value
:param opacity: opacity for pixel, between 0 and 1.0
:param fuzzyTolerance: (since QGIS 3.40) allows specifying a tolerance for the color components, where the pixel's red, green or blue component can deviate from values specified here by a maximum of this tolerance amount
:param fuzzyToleranceRed: (since QGIS 3.40) allows specifying a tolerance for the red color component, where the pixel's red component can deviate from values specified here by a maximum of this tolerance amount
:param fuzzyToleranceGreen: (since QGIS 3.40) allows specifying a tolerance for the green color component, where the pixel's green component can deviate from values specified here by a maximum of this tolerance amount
:param fuzzyToleranceBlue: (since QGIS 3.40) allows specifying a tolerance for the blue color component, where the pixel's blue component can deviate from values specified here by a maximum of this tolerance amount

.. versionadded:: 3.38
%End
Expand All @@ -46,16 +48,20 @@ Constructor for TransparentThreeValuePixel.

double opacity;

double fuzzyTolerance;
double fuzzyToleranceRed;

double fuzzyToleranceGreen;

double fuzzyToleranceBlue;

bool operator==( const QgsRasterTransparency::TransparentThreeValuePixel &other ) const;
bool operator!=( const QgsRasterTransparency::TransparentThreeValuePixel &other ) const;

SIP_PYOBJECT __repr__();
%MethodCode
QString str;
if ( !qgsDoubleNear( sipCpp->fuzzyTolerance, 0 ) )
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4, %5>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity ).arg( sipCpp->fuzzyTolerance );
if ( !qgsDoubleNear( sipCpp->fuzzyToleranceRed, 0 ) || !qgsDoubleNear( sipCpp->fuzzyToleranceGreen, 0 ) || !qgsDoubleNear( sipCpp->fuzzyToleranceBlue, 0 ) )
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4, %5, %6, %7>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity ).arg( sipCpp->fuzzyToleranceRed ).arg( sipCpp->fuzzyToleranceGreen ).arg( sipCpp->fuzzyToleranceBlue );
else
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
Expand Down
27 changes: 19 additions & 8 deletions src/core/raster/qgsrastertransparency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ double QgsRasterTransparency::opacityForRgbValues( double redValue, double green
//Search through the transparency list looking for a match
auto it = std::find_if( mTransparentThreeValuePixelList.constBegin(), mTransparentThreeValuePixelList.constEnd(), [redValue, greenValue, blueValue]( const TransparentThreeValuePixel & p )
{
return qgsDoubleNear( p.red, redValue, p.fuzzyTolerance )
&& qgsDoubleNear( p.green, greenValue, p.fuzzyTolerance )
&& qgsDoubleNear( p.blue, blueValue, p.fuzzyTolerance );
return qgsDoubleNear( p.red, redValue, p.fuzzyToleranceRed )
&& qgsDoubleNear( p.green, greenValue, p.fuzzyToleranceGreen )
&& qgsDoubleNear( p.blue, blueValue, p.fuzzyToleranceBlue );
} );

if ( it != mTransparentThreeValuePixelList.constEnd() )
Expand Down Expand Up @@ -153,8 +153,12 @@ void QgsRasterTransparency::writeXml( QDomDocument &doc, QDomElement &parentElem
pixelListElement.setAttribute( QStringLiteral( "green" ), QgsRasterBlock::printValue( it->green ) );
pixelListElement.setAttribute( QStringLiteral( "blue" ), QgsRasterBlock::printValue( it->blue ) );
pixelListElement.setAttribute( QStringLiteral( "percentTransparent" ), QString::number( 100.0 * ( 1 - it->opacity ) ) );
if ( !qgsDoubleNear( it->fuzzyTolerance, 0 ) )
pixelListElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( it->fuzzyTolerance ) );
if ( !qgsDoubleNear( it->fuzzyToleranceRed, 0 ) )
pixelListElement.setAttribute( QStringLiteral( "toleranceRed" ), QString::number( it->fuzzyToleranceRed ) );
if ( !qgsDoubleNear( it->fuzzyToleranceGreen, 0 ) )
pixelListElement.setAttribute( QStringLiteral( "toleranceGreen" ), QString::number( it->fuzzyToleranceGreen ) );
if ( !qgsDoubleNear( it->fuzzyToleranceBlue, 0 ) )
pixelListElement.setAttribute( QStringLiteral( "toleranceBlue" ), QString::number( it->fuzzyToleranceBlue ) );
threeValuePixelListElement.appendChild( pixelListElement );
}
rasterTransparencyElem.appendChild( threeValuePixelListElement );
Expand Down Expand Up @@ -207,9 +211,16 @@ void QgsRasterTransparency::readXml( const QDomElement &elem )
const double green = currentEntryElem.attribute( QStringLiteral( "green" ) ).toDouble();
const double blue = currentEntryElem.attribute( QStringLiteral( "blue" ) ).toDouble();
const double opacity = 1.0 - currentEntryElem.attribute( QStringLiteral( "percentTransparent" ) ).toDouble() / 100.0;
bool ok = false;
const double tolerance = currentEntryElem.attribute( QStringLiteral( "tolerance" ) ).toDouble( &ok );
mTransparentThreeValuePixelList.append( TransparentThreeValuePixel( red, green, blue, opacity, ok ? tolerance : 4 * std::numeric_limits<double>::epsilon() ) );
bool redOk = false;
const double toleranceRed = currentEntryElem.attribute( QStringLiteral( "toleranceRed" ) ).toDouble( &redOk );
bool greenOk = false;
const double toleranceGreen = currentEntryElem.attribute( QStringLiteral( "toleranceGreen" ) ).toDouble( &greenOk );
bool blueOk = false;
const double toleranceBlue = currentEntryElem.attribute( QStringLiteral( "toleranceBlue" ) ).toDouble( &blueOk );
mTransparentThreeValuePixelList.append( TransparentThreeValuePixel( red, green, blue, opacity,
redOk ? toleranceRed : 4 * std::numeric_limits<double>::epsilon(),
greenOk ? toleranceGreen : 4 * std::numeric_limits<double>::epsilon(),
blueOk ? toleranceBlue : 4 * std::numeric_limits<double>::epsilon() ) );
}
}
}
52 changes: 42 additions & 10 deletions src/core/raster/qgsrastertransparency.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,19 @@ class CORE_EXPORT QgsRasterTransparency
* \param green green pixel value
* \param blue blue pixel value
* \param opacity opacity for pixel, between 0 and 1.0
* \param fuzzyTolerance (since QGIS 3.40) allows specifying a tolerance for the color components, where the pixel's red, green or blue component can deviate from values specified here by a maximum of this tolerance amount
* \param fuzzyToleranceRed (since QGIS 3.40) allows specifying a tolerance for the red color component, where the pixel's red component can deviate from values specified here by a maximum of this tolerance amount
* \param fuzzyToleranceGreen (since QGIS 3.40) allows specifying a tolerance for the green color component, where the pixel's green component can deviate from values specified here by a maximum of this tolerance amount
* \param fuzzyToleranceBlue (since QGIS 3.40) allows specifying a tolerance for the blue color component, where the pixel's blue component can deviate from values specified here by a maximum of this tolerance amount
* \since QGIS 3.38
*/
TransparentThreeValuePixel( double red = 0, double green = 0, double blue = 0, double opacity = 0, double fuzzyTolerance = 4 * std::numeric_limits<double>::epsilon() )
TransparentThreeValuePixel( double red = 0, double green = 0, double blue = 0, double opacity = 0, double fuzzyToleranceRed = 4 * std::numeric_limits<double>::epsilon(), double fuzzyToleranceGreen = 4 * std::numeric_limits<double>::epsilon(), double fuzzyToleranceBlue = 4 * std::numeric_limits<double>::epsilon() )
: red( red )
, green( green )
, blue( blue )
, opacity( opacity )
, fuzzyTolerance( fuzzyTolerance )
, fuzzyToleranceRed( fuzzyToleranceRed )
, fuzzyToleranceGreen( fuzzyToleranceGreen )
, fuzzyToleranceBlue( fuzzyToleranceBlue )
{}

/**
Expand All @@ -84,16 +88,42 @@ class CORE_EXPORT QgsRasterTransparency
double opacity = 0;

/**
* Fuzzy tolerance for red, green and blue values.
* Fuzzy tolerance for red values.
*
* If non zero, the pixel's red, green or blue component can deviate from values specified in this object by a maximum of this tolerance amount.
* If non zero, the pixel's red component can deviate from values specified in this object by a maximum of this tolerance amount.
*
* \since QGIS 3.40
*/
#ifndef SIP_RUN
double fuzzyTolerance = 4 * std::numeric_limits<double>::epsilon();
double fuzzyToleranceRed = 4 * std::numeric_limits<double>::epsilon();
#else
double fuzzyTolerance;
double fuzzyToleranceRed;
#endif

/**
* Fuzzy tolerance for green values.
*
* If non zero, the pixel's green component can deviate from values specified in this object by a maximum of this tolerance amount.
*
* \since QGIS 3.40
*/
#ifndef SIP_RUN
double fuzzyToleranceGreen = 4 * std::numeric_limits<double>::epsilon();
#else
double fuzzyToleranceGreen;
#endif

/**
* Fuzzy tolerance for blue values.
*
* If non zero, the pixel's blue component can deviate from values specified in this object by a maximum of this tolerance amount.
*
* \since QGIS 3.40
*/
#ifndef SIP_RUN
double fuzzyToleranceBlue = 4 * std::numeric_limits<double>::epsilon();
#else
double fuzzyToleranceBlue;
#endif

bool operator==( const QgsRasterTransparency::TransparentThreeValuePixel &other ) const
Expand All @@ -102,7 +132,9 @@ class CORE_EXPORT QgsRasterTransparency
&& qgsDoubleNear( green, other.green )
&& qgsDoubleNear( blue, other.blue )
&& qgsDoubleNear( opacity, other.opacity )
&& qgsDoubleNear( fuzzyTolerance, other.fuzzyTolerance );
&& qgsDoubleNear( fuzzyToleranceRed, other.fuzzyToleranceRed )
&& qgsDoubleNear( fuzzyToleranceGreen, other.fuzzyToleranceGreen )
&& qgsDoubleNear( fuzzyToleranceBlue, other.fuzzyToleranceBlue );
}
bool operator!=( const QgsRasterTransparency::TransparentThreeValuePixel &other ) const
{
Expand All @@ -113,8 +145,8 @@ class CORE_EXPORT QgsRasterTransparency
SIP_PYOBJECT __repr__();
% MethodCode
QString str;
if ( !qgsDoubleNear( sipCpp->fuzzyTolerance, 0 ) )
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4, %5>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity ).arg( sipCpp->fuzzyTolerance );
if ( !qgsDoubleNear( sipCpp->fuzzyToleranceRed, 0 ) || !qgsDoubleNear( sipCpp->fuzzyToleranceGreen, 0 ) || !qgsDoubleNear( sipCpp->fuzzyToleranceBlue, 0 ) )
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4, %5, %6, %7>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity ).arg( sipCpp->fuzzyToleranceRed ).arg( sipCpp->fuzzyToleranceGreen ).arg( sipCpp->fuzzyToleranceBlue );
else
str = QStringLiteral( "<QgsRasterTransparency.TransparentThreeValuePixel: %1, %2, %3, %4>" ).arg( sipCpp->red ).arg( sipCpp->green ).arg( sipCpp->blue ).arg( sipCpp->opacity );
sipRes = PyUnicode_FromString( str.toUtf8().constData() );
Expand Down
9 changes: 7 additions & 2 deletions src/gui/raster/qgsrastertransparencywidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,10 @@ void QgsRasterTransparencyWidget::applyToRasterRenderer( QgsRasterRenderer *rast
const double opacity = 1.0 - transparencyCellValue( myListRunner, static_cast< int >( RgbBandTableColumns::Opacity ) ) / 100.0;
const double tolerance = transparencyCellValue( myListRunner, static_cast< int >( RgbBandTableColumns::Tolerance ) );
myTransparentThreeValuePixelList.append(
QgsRasterTransparency::TransparentThreeValuePixel( red, green, blue, opacity, !qgsDoubleNear( tolerance, 0 ) ? tolerance : 4 * std::numeric_limits<double>::epsilon() )
QgsRasterTransparency::TransparentThreeValuePixel( red, green, blue, opacity,
!qgsDoubleNear( tolerance, 0 ) ? tolerance : 4 * std::numeric_limits<double>::epsilon(),
!qgsDoubleNear( tolerance, 0 ) ? tolerance : 4 * std::numeric_limits<double>::epsilon(),
!qgsDoubleNear( tolerance, 0 ) ? tolerance : 4 * std::numeric_limits<double>::epsilon() )
);
}
rasterTransparency->setTransparentThreeValuePixelList( myTransparentThreeValuePixelList );
Expand Down Expand Up @@ -712,7 +715,9 @@ void QgsRasterTransparencyWidget::populateTransparencyTable( QgsRasterRenderer *
setTransparencyCell( i, static_cast< int >( RgbBandTableColumns::Green ), pixelList[i].green );
setTransparencyCell( i, static_cast< int >( RgbBandTableColumns::Blue ), pixelList[i].blue );
setTransparencyCell( i, static_cast< int >( RgbBandTableColumns::Opacity ), 100 * ( 1 - pixelList[i].opacity ) );
setTransparencyCell( i, static_cast< int >( RgbBandTableColumns::Tolerance ), !qgsDoubleNear( pixelList[i].fuzzyTolerance, 0 ) ? pixelList[i].fuzzyTolerance : 0 );
// while the API supports different tolerances for red/green/blue channels, we only expose a single value here
// If needed, we could expose the three separate tolerances in future... but be wary of UI bloat!
setTransparencyCell( i, static_cast< int >( RgbBandTableColumns::Tolerance ), !qgsDoubleNear( pixelList[i].fuzzyToleranceRed, 0 ) ? pixelList[i].fuzzyToleranceRed : 0 );
}
break;
}
Expand Down
Loading

0 comments on commit 4a24737

Please sign in to comment.