working on QskGraduation
This commit is contained in:
parent
54761e5a64
commit
7197c89533
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace
|
namespace Engine
|
||||||
{
|
{
|
||||||
// What about using qskFuzzyCompare and friends ???
|
// What about using qskFuzzyCompare and friends ???
|
||||||
|
|
||||||
|
@ -46,61 +46,9 @@ namespace
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ceilEps( double value, double intervalSize )
|
|
||||||
{
|
|
||||||
const double eps = _eps * intervalSize;
|
|
||||||
|
|
||||||
value = ( value - eps ) / intervalSize;
|
|
||||||
return std::ceil( value ) * intervalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
double floorEps( double value, double intervalSize )
|
|
||||||
{
|
|
||||||
const double eps = _eps * intervalSize;
|
|
||||||
|
|
||||||
value = ( value + eps ) / intervalSize;
|
|
||||||
return std::floor( value ) * intervalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
double suggestedStepSize( double intervalSize, int numSteps )
|
|
||||||
{
|
|
||||||
if ( numSteps <= 0 )
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
const auto v = intervalSize / numSteps;
|
|
||||||
if ( qFuzzyIsNull( v ) )
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
constexpr double base = 10.0;
|
|
||||||
|
|
||||||
// the same as std::log10( std::fabs( v ) );
|
|
||||||
const double lx = std::log( std::fabs( v ) ) / std::log( base );
|
|
||||||
const double p = std::floor( lx );
|
|
||||||
|
|
||||||
const double fraction = std::pow( base, lx - p );
|
|
||||||
|
|
||||||
double stepSize = std::pow( base, p );
|
|
||||||
if ( v < 0 )
|
|
||||||
stepSize = -stepSize;
|
|
||||||
|
|
||||||
for ( const double f : { 2.0, 2.5, 5.0, 10.0 } )
|
|
||||||
{
|
|
||||||
if ( fraction <= f || qFuzzyCompare( fraction, f ) )
|
|
||||||
{
|
|
||||||
stepSize *= f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stepSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Engine
|
|
||||||
{
|
|
||||||
double minorStepSize( double intervalSize, int maxSteps )
|
double minorStepSize( double intervalSize, int maxSteps )
|
||||||
{
|
{
|
||||||
const double minStep = suggestedStepSize( intervalSize, maxSteps );
|
const double minStep = QskGraduation::stepSize( intervalSize, maxSteps );
|
||||||
|
|
||||||
if ( minStep != 0.0 )
|
if ( minStep != 0.0 )
|
||||||
{
|
{
|
||||||
|
@ -132,42 +80,17 @@ namespace Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector< qreal > strippedTicks;
|
QVector< qreal > strippedTicks;
|
||||||
for ( int i = 0; i < ticks.count(); i++ )
|
strippedTicks.reserve( ticks.count() );
|
||||||
|
|
||||||
|
for ( const auto tick : ticks )
|
||||||
{
|
{
|
||||||
if ( fuzzyContains( interval, ticks[i] ) )
|
if ( fuzzyContains( interval, tick ) )
|
||||||
strippedTicks += ticks[i];
|
strippedTicks += tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
return strippedTicks;
|
return strippedTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
QskIntervalF align( const QskIntervalF& interval, qreal stepSize )
|
|
||||||
{
|
|
||||||
auto x1 = interval.lowerBound();
|
|
||||||
auto x2 = interval.upperBound();
|
|
||||||
|
|
||||||
// when there is no rounding beside some effect, when
|
|
||||||
// calculating with doubles, we keep the original value
|
|
||||||
|
|
||||||
const auto max = std::numeric_limits< qreal >::max();
|
|
||||||
|
|
||||||
if ( -max + stepSize <= x1 )
|
|
||||||
{
|
|
||||||
const auto x = floorEps( x1, stepSize );
|
|
||||||
if ( qFuzzyIsNull( x ) || !qFuzzyCompare( x1, x ) )
|
|
||||||
x1 = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( max - stepSize >= x2 )
|
|
||||||
{
|
|
||||||
const auto x = ceilEps( x2, stepSize );
|
|
||||||
if ( qFuzzyIsNull( x ) || !qFuzzyCompare( x2, x ) )
|
|
||||||
x2 = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
return QskIntervalF( x1, x2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
QVector< qreal > buildMajorTicks(
|
QVector< qreal > buildMajorTicks(
|
||||||
const QskIntervalF& interval, qreal stepSize )
|
const QskIntervalF& interval, qreal stepSize )
|
||||||
{
|
{
|
||||||
|
@ -227,7 +150,7 @@ namespace Engine
|
||||||
{
|
{
|
||||||
using T = QskTickmarks;
|
using T = QskTickmarks;
|
||||||
|
|
||||||
const auto boundingInterval = align( interval, stepSize );
|
const auto boundingInterval = interval.fuzzyAligned( stepSize );
|
||||||
|
|
||||||
QVector< qreal > ticks[3];
|
QVector< qreal > ticks[3];
|
||||||
ticks[T::MajorTick] = buildMajorTicks( boundingInterval, stepSize );
|
ticks[T::MajorTick] = buildMajorTicks( boundingInterval, stepSize );
|
||||||
|
@ -252,12 +175,7 @@ namespace Engine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QskTickmarks tickmarks;
|
return { ticks[T::MinorTick], ticks[T::MediumTick], ticks[T::MajorTick] };
|
||||||
tickmarks.setMinorTicks( ticks[T::MinorTick] );
|
|
||||||
tickmarks.setMediumTicks( ticks[T::MediumTick] );
|
|
||||||
tickmarks.setMajorTicks( ticks[T::MajorTick] );
|
|
||||||
|
|
||||||
return tickmarks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -275,58 +193,52 @@ QskTickmarks QskGraduation::divideInterval(
|
||||||
return tickmarks;
|
return tickmarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( interval.width() <= 0 )
|
if ( interval.width() <= 0.0 || stepSize < 0.0 )
|
||||||
return tickmarks;
|
return tickmarks;
|
||||||
|
|
||||||
stepSize = qAbs( stepSize );
|
|
||||||
if ( stepSize == 0.0 )
|
if ( stepSize == 0.0 )
|
||||||
{
|
{
|
||||||
if ( maxMajorSteps < 1 )
|
if ( maxMajorSteps < 1 )
|
||||||
maxMajorSteps = 1;
|
maxMajorSteps = 1;
|
||||||
|
|
||||||
stepSize = suggestedStepSize( interval.width(), maxMajorSteps );
|
stepSize = QskGraduation::stepSize( interval.width(), maxMajorSteps );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( stepSize != 0.0 )
|
if ( stepSize != 0.0 )
|
||||||
{
|
|
||||||
tickmarks = Engine::buildTicks( interval, stepSize, maxMinorSteps );
|
tickmarks = Engine::buildTicks( interval, stepSize, maxMinorSteps );
|
||||||
}
|
|
||||||
|
|
||||||
if ( x1 > x2 )
|
|
||||||
tickmarks.invert();
|
|
||||||
|
|
||||||
return tickmarks;
|
return tickmarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskGraduation::calculate( Attributes attributes, int maxNumSteps,
|
qreal QskGraduation::stepSize( double length, int numSteps )
|
||||||
qreal& x1, qreal& x2, qreal& stepSize)
|
|
||||||
{
|
{
|
||||||
auto interval = QskIntervalF::normalized( x1, x2 );
|
if ( numSteps <= 0 )
|
||||||
|
|
||||||
interval.setLowerBound( interval.lowerBound() );
|
|
||||||
interval.setUpperBound( interval.upperBound() );
|
|
||||||
|
|
||||||
stepSize = suggestedStepSize( interval.width(), qMax( maxNumSteps, 1 ) );
|
|
||||||
|
|
||||||
if ( !( attributes & Floating ) )
|
|
||||||
interval = Engine::align( interval, stepSize );
|
|
||||||
|
|
||||||
x1 = interval.lowerBound();
|
|
||||||
x2 = interval.upperBound();
|
|
||||||
|
|
||||||
if ( attributes & Inverted )
|
|
||||||
{
|
|
||||||
qSwap( x1, x2 );
|
|
||||||
stepSize = -stepSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
qreal QskGraduation::alignedStepSize( double intervalSize, int numSteps )
|
|
||||||
{
|
|
||||||
if ( intervalSize <= 0.0 )
|
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
return suggestedStepSize( intervalSize, numSteps );
|
const auto v = length / numSteps;
|
||||||
|
if ( qFuzzyIsNull( v ) )
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
constexpr double base = 10.0;
|
||||||
|
|
||||||
|
// the same as std::log10( std::fabs( v ) );
|
||||||
|
const double lx = std::log( std::fabs( v ) ) / std::log( base );
|
||||||
|
const double p = std::floor( lx );
|
||||||
|
|
||||||
|
const double fraction = std::pow( base, lx - p );
|
||||||
|
|
||||||
|
double stepSize = std::pow( base, p );
|
||||||
|
if ( v < 0 )
|
||||||
|
stepSize = -stepSize;
|
||||||
|
|
||||||
|
for ( const double f : { 2.0, 2.5, 5.0, 10.0 } )
|
||||||
|
{
|
||||||
|
if ( fraction <= f || qFuzzyCompare( fraction, f ) )
|
||||||
|
{
|
||||||
|
stepSize *= f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_QskGraduation.cpp"
|
return stepSize;
|
||||||
|
}
|
||||||
|
|
|
@ -15,24 +15,10 @@ namespace QskGraduation
|
||||||
{
|
{
|
||||||
Q_NAMESPACE_EXPORT( QSK_EXPORT )
|
Q_NAMESPACE_EXPORT( QSK_EXPORT )
|
||||||
|
|
||||||
enum Attribute
|
|
||||||
{
|
|
||||||
Inverted = 1 << 0,
|
|
||||||
Floating = 1 << 1
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_ENUM_NS( Attribute )
|
|
||||||
|
|
||||||
Q_DECLARE_FLAGS( Attributes, Attribute )
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS( Attributes )
|
|
||||||
|
|
||||||
QskTickmarks divideInterval( qreal x1, qreal x2,
|
QskTickmarks divideInterval( qreal x1, qreal x2,
|
||||||
int maxMajorSteps, int maxMinorSteps, qreal stepSize = 0.0 );
|
int maxMajorSteps, int maxMinorSteps, qreal stepSize = 0.0 );
|
||||||
|
|
||||||
void calculate( Attributes, int maxNumSteps,
|
qreal stepSize( double length, int numSteps );
|
||||||
qreal& x1, qreal& x2, qreal& stepSize );
|
|
||||||
|
|
||||||
qreal alignedStepSize( double intervalSize, int numSteps );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -187,6 +187,30 @@ void QskIntervalF::spanFromUpperBound( qreal value ) noexcept
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QskIntervalF QskIntervalF::fuzzyAligned( qreal stepSize ) const
|
||||||
|
{
|
||||||
|
auto v1 = m_lowerBound;
|
||||||
|
auto v2 = m_upperBound;
|
||||||
|
|
||||||
|
const auto max = std::numeric_limits< qreal >::max();
|
||||||
|
|
||||||
|
if ( -max + stepSize <= v1 )
|
||||||
|
{
|
||||||
|
const auto v = qskFuzzyFloor( v1, stepSize );
|
||||||
|
if ( !qskFuzzyCompare( v1, v ) )
|
||||||
|
v1 = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( max - stepSize >= v2 )
|
||||||
|
{
|
||||||
|
const auto v = qskFuzzyCeil( v2, stepSize );
|
||||||
|
if ( !qskFuzzyCompare( v2, v ) )
|
||||||
|
v2 = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QskIntervalF( v1, v2 );
|
||||||
|
}
|
||||||
|
|
||||||
bool QskIntervalF::fuzzyContains( qreal value ) const
|
bool QskIntervalF::fuzzyContains( qreal value ) const
|
||||||
{
|
{
|
||||||
if ( !isValid() )
|
if ( !isValid() )
|
||||||
|
|
|
@ -75,6 +75,8 @@ class QSK_EXPORT QskIntervalF
|
||||||
QskIntervalF operator|( qreal ) const noexcept;
|
QskIntervalF operator|( qreal ) const noexcept;
|
||||||
QskIntervalF& operator|=( qreal ) noexcept;
|
QskIntervalF& operator|=( qreal ) noexcept;
|
||||||
|
|
||||||
|
QskIntervalF fuzzyAligned( qreal stepSize ) const;
|
||||||
|
|
||||||
constexpr bool isValid() const noexcept;
|
constexpr bool isValid() const noexcept;
|
||||||
constexpr bool isNull() const noexcept;
|
constexpr bool isNull() const noexcept;
|
||||||
constexpr bool isEmpty() const noexcept;
|
constexpr bool isEmpty() const noexcept;
|
||||||
|
|
|
@ -21,6 +21,12 @@ QskTickmarks::QskTickmarks()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QskTickmarks::QskTickmarks( const QVector< qreal >& minorTicks,
|
||||||
|
const QVector< qreal >& mediumTicks, const QVector< qreal >& majorTicks )
|
||||||
|
: m_ticks{ minorTicks, mediumTicks, majorTicks }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QskTickmarks::~QskTickmarks()
|
QskTickmarks::~QskTickmarks()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,9 @@ class QSK_EXPORT QskTickmarks
|
||||||
Q_ENUM( TickType )
|
Q_ENUM( TickType )
|
||||||
|
|
||||||
QskTickmarks();
|
QskTickmarks();
|
||||||
|
QskTickmarks( const QVector< qreal >& minorTicks,
|
||||||
|
const QVector< qreal >& mediumTicks, const QVector< qreal >& majorTicks );
|
||||||
|
|
||||||
~QskTickmarks();
|
~QskTickmarks();
|
||||||
|
|
||||||
bool operator==( const QskTickmarks& ) const noexcept;
|
bool operator==( const QskTickmarks& ) const noexcept;
|
||||||
|
|
Loading…
Reference in New Issue