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
|
:param precision: number of decimal places to retain
|
||||||
%End
|
%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 );
|
bool qgsDoubleNear( double a, double b, double epsilon = 4 * DBL_EPSILON );
|
||||||
%Docstring
|
%Docstring
|
||||||
Compare two doubles (but allow some difference)
|
Compare two doubles (but allow some difference)
|
||||||
|
@ -1678,9 +1678,7 @@ bool QgsCoordinateReferenceSystem::operator==( const QgsCoordinateReferenceSyste
|
|||||||
if ( !d->mIsValid || !srs.d->mIsValid )
|
if ( !d->mIsValid || !srs.d->mIsValid )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ( std::isnan( d->mCoordinateEpoch ) != std::isnan( srs.d->mCoordinateEpoch ) )
|
if ( !qgsNanCompatibleEquals( d->mCoordinateEpoch, srs.d->mCoordinateEpoch ) )
|
||||||
return false;
|
|
||||||
else if ( !std::isnan( d->mCoordinateEpoch ) && d->mCoordinateEpoch != srs.d->mCoordinateEpoch )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const bool isUser = d->mSrsId >= USER_CRS_START_ID;
|
const bool isUser = d->mSrsId >= USER_CRS_START_ID;
|
||||||
|
@ -901,13 +901,8 @@ bool QgsCoordinateTransform::setFromCache( const QgsCoordinateReferenceSystem &s
|
|||||||
{
|
{
|
||||||
if ( ( *valIt ).coordinateOperation() == coordinateOperationProj
|
if ( ( *valIt ).coordinateOperation() == coordinateOperationProj
|
||||||
&& ( *valIt ).allowFallbackTransforms() == allowFallback
|
&& ( *valIt ).allowFallbackTransforms() == allowFallback
|
||||||
|
&& qgsNanCompatibleEquals( src.coordinateEpoch(), ( *valIt ).sourceCrs().coordinateEpoch() )
|
||||||
// careful here, nan != nan, so we need to explicitly handle the case when both crses have nan coordinateEpoch
|
&& qgsNanCompatibleEquals( dest.coordinateEpoch(), ( *valIt ).destinationCrs().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() ) )
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// need to save, and then restore the context... we don't want this to be cached or to use the values from the cache
|
// 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 )
|
: ( mDestIsDynamic && !std::isnan( mDestCoordinateEpoch ) && !mSourceIsDynamic )
|
||||||
? mDestCoordinateEpoch : std::numeric_limits< double >::quiet_NaN();
|
? mDestCoordinateEpoch : std::numeric_limits< double >::quiet_NaN();
|
||||||
|
|
||||||
if ( mSourceIsDynamic && mDestIsDynamic
|
if ( mSourceIsDynamic && mDestIsDynamic && !qgsNanCompatibleEquals( mSourceCoordinateEpoch, mDestCoordinateEpoch ) )
|
||||||
&& !std::isnan( mSourceCoordinateEpoch ) && mSourceCoordinateEpoch != mDestCoordinateEpoch )
|
|
||||||
{
|
{
|
||||||
// transforms from dynamic crs to dynamic crs with different coordinate epochs are not yet supported by PROJ
|
// transforms from dynamic crs to dynamic crs with different coordinate epochs are not yet supported by PROJ
|
||||||
if ( sDynamicCrsToDynamicCrsWarningHandler )
|
if ( sDynamicCrsToDynamicCrsWarningHandler )
|
||||||
|
@ -341,6 +341,22 @@ inline QString qgsDoubleToString( double a, int precision = 17 )
|
|||||||
return str;
|
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)
|
* Compare two doubles (but allow some difference)
|
||||||
* \param a first double
|
* \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() )
|
inline bool qgsDoubleNear( double a, double b, double epsilon = 4 * std::numeric_limits<double>::epsilon() )
|
||||||
{
|
{
|
||||||
if ( std::isnan( a ) || std::isnan( b ) )
|
const bool aIsNan = std::isnan( a );
|
||||||
return std::isnan( a ) && std::isnan( b ) ;
|
const bool bIsNan = std::isnan( b );
|
||||||
|
if ( aIsNan || bIsNan )
|
||||||
|
return aIsNan && bIsNan;
|
||||||
|
|
||||||
const double diff = a - b;
|
const double diff = a - b;
|
||||||
return diff > -epsilon && diff <= epsilon;
|
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 )
|
inline bool qgsFloatNear( float a, float b, float epsilon = 4 * FLT_EPSILON )
|
||||||
{
|
{
|
||||||
if ( std::isnan( a ) || std::isnan( b ) )
|
const bool aIsNan = std::isnan( a );
|
||||||
return std::isnan( a ) && std::isnan( b ) ;
|
const bool bIsNan = std::isnan( b );
|
||||||
|
if ( aIsNan || bIsNan )
|
||||||
|
return aIsNan && bIsNan;
|
||||||
|
|
||||||
const float diff = a - b;
|
const float diff = a - b;
|
||||||
return diff > -epsilon && diff <= epsilon;
|
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
|
//! Compare two doubles using specified number of significant digits
|
||||||
inline bool qgsDoubleNearSig( double a, double b, int significantDigits = 10 )
|
inline bool qgsDoubleNearSig( double a, double b, int significantDigits = 10 )
|
||||||
{
|
{
|
||||||
if ( std::isnan( a ) || std::isnan( b ) )
|
const bool aIsNan = std::isnan( a );
|
||||||
return std::isnan( a ) && std::isnan( b ) ;
|
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
|
// The most simple would be to print numbers as %.xe and compare as strings
|
||||||
// but that is probably too costly
|
// but that is probably too costly
|
||||||
|
@ -47,6 +47,8 @@ class TestQgis : public QObject
|
|||||||
void signalBlocker();
|
void signalBlocker();
|
||||||
void qVariantCompare_data();
|
void qVariantCompare_data();
|
||||||
void qVariantCompare();
|
void qVariantCompare();
|
||||||
|
void testNanCompatibleEquals_data();
|
||||||
|
void testNanCompatibleEquals();
|
||||||
void testQgsAsConst();
|
void testQgsAsConst();
|
||||||
void testQgsRound();
|
void testQgsRound();
|
||||||
void testQgsVariantEqual();
|
void testQgsVariantEqual();
|
||||||
@ -320,6 +322,29 @@ void TestQgis::qVariantCompare()
|
|||||||
QCOMPARE( qgsVariantGreaterThan( lhs, rhs ), greaterThan );
|
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
|
class ConstTester
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user