mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-06 00:07:29 -04:00
Introduce qgsNanCompatibleEquals for readability
This commit is contained in:
parent
c0743d6bef
commit
75eba31996
@ -182,6 +182,16 @@ Returns a string representation of a double
|
||||
:param precision: number of decimal places to retain
|
||||
%End
|
||||
|
||||
bool qgsNanCompatibleEquals( double a, double b );
|
||||
%Docstring
|
||||
Compare two doubles, treating nan values as equal
|
||||
|
||||
:param a: first double
|
||||
:param b: second double
|
||||
|
||||
.. versionadded:: 3.20
|
||||
%End
|
||||
|
||||
bool qgsDoubleNear( double a, double b, double epsilon = 4 * DBL_EPSILON );
|
||||
%Docstring
|
||||
Compare two doubles (but allow some difference)
|
||||
|
@ -1678,9 +1678,7 @@ bool QgsCoordinateReferenceSystem::operator==( const QgsCoordinateReferenceSyste
|
||||
if ( !d->mIsValid || !srs.d->mIsValid )
|
||||
return false;
|
||||
|
||||
if ( std::isnan( d->mCoordinateEpoch ) != std::isnan( srs.d->mCoordinateEpoch ) )
|
||||
return false;
|
||||
else if ( !std::isnan( d->mCoordinateEpoch ) && d->mCoordinateEpoch != srs.d->mCoordinateEpoch )
|
||||
if ( !qgsNanCompatibleEquals( d->mCoordinateEpoch, srs.d->mCoordinateEpoch ) )
|
||||
return false;
|
||||
|
||||
const bool isUser = d->mSrsId >= USER_CRS_START_ID;
|
||||
|
@ -901,13 +901,8 @@ bool QgsCoordinateTransform::setFromCache( const QgsCoordinateReferenceSystem &s
|
||||
{
|
||||
if ( ( *valIt ).coordinateOperation() == coordinateOperationProj
|
||||
&& ( *valIt ).allowFallbackTransforms() == allowFallback
|
||||
|
||||
// careful here, nan != nan, so we need to explicitly handle the case when both crses have nan coordinateEpoch
|
||||
&& ( std::isnan( ( *valIt ).sourceCrs().coordinateEpoch() ) == std::isnan( src.coordinateEpoch() )
|
||||
&& ( std::isnan( src.coordinateEpoch() ) || src.coordinateEpoch() == ( *valIt ).sourceCrs().coordinateEpoch() ) )
|
||||
|
||||
&& ( std::isnan( ( *valIt ).destinationCrs().coordinateEpoch() ) == std::isnan( dest.coordinateEpoch() )
|
||||
&& ( std::isnan( dest.coordinateEpoch() ) || dest.coordinateEpoch() == ( *valIt ).destinationCrs().coordinateEpoch() ) )
|
||||
&& qgsNanCompatibleEquals( src.coordinateEpoch(), ( *valIt ).sourceCrs().coordinateEpoch() )
|
||||
&& qgsNanCompatibleEquals( dest.coordinateEpoch(), ( *valIt ).destinationCrs().coordinateEpoch() )
|
||||
)
|
||||
{
|
||||
// need to save, and then restore the context... we don't want this to be cached or to use the values from the cache
|
||||
|
@ -173,8 +173,7 @@ bool QgsCoordinateTransformPrivate::initialize()
|
||||
: ( mDestIsDynamic && !std::isnan( mDestCoordinateEpoch ) && !mSourceIsDynamic )
|
||||
? mDestCoordinateEpoch : std::numeric_limits< double >::quiet_NaN();
|
||||
|
||||
if ( mSourceIsDynamic && mDestIsDynamic
|
||||
&& !std::isnan( mSourceCoordinateEpoch ) && mSourceCoordinateEpoch != mDestCoordinateEpoch )
|
||||
if ( mSourceIsDynamic && mDestIsDynamic && !qgsNanCompatibleEquals( mSourceCoordinateEpoch, mDestCoordinateEpoch ) )
|
||||
{
|
||||
// transforms from dynamic crs to dynamic crs with different coordinate epochs are not yet supported by PROJ
|
||||
if ( sDynamicCrsToDynamicCrsWarningHandler )
|
||||
|
@ -341,6 +341,22 @@ inline QString qgsDoubleToString( double a, int precision = 17 )
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two doubles, treating nan values as equal
|
||||
* \param a first double
|
||||
* \param b second double
|
||||
* \since QGIS 3.20
|
||||
*/
|
||||
inline bool qgsNanCompatibleEquals( double a, double b )
|
||||
{
|
||||
const bool aIsNan = std::isnan( a );
|
||||
const bool bIsNan = std::isnan( b );
|
||||
if ( aIsNan || bIsNan )
|
||||
return aIsNan && bIsNan;
|
||||
|
||||
return a == b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two doubles (but allow some difference)
|
||||
* \param a first double
|
||||
@ -349,8 +365,10 @@ inline QString qgsDoubleToString( double a, int precision = 17 )
|
||||
*/
|
||||
inline bool qgsDoubleNear( double a, double b, double epsilon = 4 * std::numeric_limits<double>::epsilon() )
|
||||
{
|
||||
if ( std::isnan( a ) || std::isnan( b ) )
|
||||
return std::isnan( a ) && std::isnan( b ) ;
|
||||
const bool aIsNan = std::isnan( a );
|
||||
const bool bIsNan = std::isnan( b );
|
||||
if ( aIsNan || bIsNan )
|
||||
return aIsNan && bIsNan;
|
||||
|
||||
const double diff = a - b;
|
||||
return diff > -epsilon && diff <= epsilon;
|
||||
@ -364,8 +382,10 @@ inline bool qgsDoubleNear( double a, double b, double epsilon = 4 * std::numeric
|
||||
*/
|
||||
inline bool qgsFloatNear( float a, float b, float epsilon = 4 * FLT_EPSILON )
|
||||
{
|
||||
if ( std::isnan( a ) || std::isnan( b ) )
|
||||
return std::isnan( a ) && std::isnan( b ) ;
|
||||
const bool aIsNan = std::isnan( a );
|
||||
const bool bIsNan = std::isnan( b );
|
||||
if ( aIsNan || bIsNan )
|
||||
return aIsNan && bIsNan;
|
||||
|
||||
const float diff = a - b;
|
||||
return diff > -epsilon && diff <= epsilon;
|
||||
@ -374,8 +394,10 @@ inline bool qgsFloatNear( float a, float b, float epsilon = 4 * FLT_EPSILON )
|
||||
//! Compare two doubles using specified number of significant digits
|
||||
inline bool qgsDoubleNearSig( double a, double b, int significantDigits = 10 )
|
||||
{
|
||||
if ( std::isnan( a ) || std::isnan( b ) )
|
||||
return std::isnan( a ) && std::isnan( b ) ;
|
||||
const bool aIsNan = std::isnan( a );
|
||||
const bool bIsNan = std::isnan( b );
|
||||
if ( aIsNan || bIsNan )
|
||||
return aIsNan && bIsNan;
|
||||
|
||||
// The most simple would be to print numbers as %.xe and compare as strings
|
||||
// but that is probably too costly
|
||||
|
@ -47,6 +47,8 @@ class TestQgis : public QObject
|
||||
void signalBlocker();
|
||||
void qVariantCompare_data();
|
||||
void qVariantCompare();
|
||||
void testNanCompatibleEquals_data();
|
||||
void testNanCompatibleEquals();
|
||||
void testQgsAsConst();
|
||||
void testQgsRound();
|
||||
void testQgsVariantEqual();
|
||||
@ -320,6 +322,29 @@ void TestQgis::qVariantCompare()
|
||||
QCOMPARE( qgsVariantGreaterThan( lhs, rhs ), greaterThan );
|
||||
}
|
||||
|
||||
void TestQgis::testNanCompatibleEquals_data()
|
||||
{
|
||||
QTest::addColumn<double>( "lhs" );
|
||||
QTest::addColumn<double>( "rhs" );
|
||||
QTest::addColumn<bool>( "expected" );
|
||||
|
||||
QTest::newRow( "both nan" ) << std::numeric_limits< double >::quiet_NaN() << std::numeric_limits< double >::quiet_NaN() << true;
|
||||
QTest::newRow( "first is nan" ) << std::numeric_limits< double >::quiet_NaN() << 5.0 << false;
|
||||
QTest::newRow( "second is nan" ) << 5.0 << std::numeric_limits< double >::quiet_NaN() << false;
|
||||
QTest::newRow( "two numbers, not equal" ) << 5.0 << 6.0 << false;
|
||||
QTest::newRow( "two numbers, equal" ) << 5.0 << 5.0 << true;
|
||||
}
|
||||
|
||||
void TestQgis::testNanCompatibleEquals()
|
||||
{
|
||||
QFETCH( double, lhs );
|
||||
QFETCH( double, rhs );
|
||||
QFETCH( bool, expected );
|
||||
|
||||
QCOMPARE( qgsNanCompatibleEquals( lhs, rhs ), expected );
|
||||
QCOMPARE( qgsNanCompatibleEquals( rhs, lhs ), expected );
|
||||
}
|
||||
|
||||
class ConstTester
|
||||
{
|
||||
public:
|
||||
|
Loading…
x
Reference in New Issue
Block a user