10 #include "qwt_date_scale_engine.h" 
   12 #include "qwt_interval.h" 
   14 #include <qdatetime.h> 
   18 static inline double qwtMsecsForType( 
int type )
 
   20     static const double msecs[] =
 
   26         24.0 * 3600.0 * 1000.0,
 
   27         7.0 * 24.0 * 3600.0 * 1000.0,
 
   28         30.0 * 24.0 * 3600.0 * 1000.0,
 
   29         365.0 * 24.0 * 3600.0 * 1000.0,
 
   32     if ( type < 0 || type >= 
static_cast< int >( 
sizeof( msecs ) / 
sizeof( msecs[0] ) ) )
 
   38 static inline int qwtAlignValue(
 
   39     double value, 
double stepSize, 
bool up )
 
   41     double d = value / stepSize;
 
   42     d = up ? std::ceil( d ) : std::floor( d );
 
   44     return static_cast< int >( d * stepSize );
 
   47 static double qwtIntervalWidth( 
const QDateTime& minDate,
 
   50     switch( intervalType )
 
   54             return minDate.msecsTo( maxDate );
 
   58             return minDate.secsTo( maxDate );
 
   62             const double secsTo = minDate.secsTo( maxDate );
 
   63             return std::floor( secsTo / 60 );
 
   67             const double secsTo = minDate.secsTo( maxDate );
 
   68             return std::floor( secsTo / 3600 );
 
   72             return minDate.daysTo( maxDate );
 
   76             return std::floor( minDate.daysTo( maxDate ) / 7.0 );
 
   81                 double( maxDate.date().year() ) - minDate.date().year();
 
   83             int months = maxDate.date().month() - minDate.date().month();
 
   84             if ( maxDate.date().day() < minDate.date().day() )
 
   87             return years * 12 + months;
 
   92                 double( maxDate.date().year() ) - minDate.date().year();
 
   94             if ( maxDate.date().month() < minDate.date().month() )
 
  104 static double qwtRoundedIntervalWidth(
 
  105     const QDateTime& minDate, 
const QDateTime& maxDate,
 
  109     const QDateTime maxD = 
QwtDate::ceil( maxDate, intervalType );
 
  111     return qwtIntervalWidth( minD, maxD, intervalType );
 
  114 static inline int qwtStepCount( 
int intervalSize, 
int maxSteps,
 
  115     const int limits[], 
size_t numLimits )
 
  117     for ( uint i = 0; i < numLimits; i++ )
 
  119         const int numSteps = intervalSize / limits[ i ];
 
  121         if ( numSteps > 1 && numSteps <= maxSteps &&
 
  122             numSteps * limits[ i ] == intervalSize )
 
  131 static int qwtStepSize( 
int intervalSize, 
int maxSteps, uint base )
 
  138         for ( 
int numSteps = maxSteps; numSteps > 1; numSteps-- )
 
  140             const double stepSize = double( intervalSize ) / numSteps;
 
  142             const double p = std::floor( std::log( stepSize ) / std::log( 
double( base ) ) );
 
  143             const double fraction = std::pow( base, p );
 
  145             for ( uint n = base; n >= 1; n /= 2 )
 
  147                 if ( qFuzzyCompare( stepSize, n * fraction ) )
 
  148                     return qRound( stepSize );
 
  150                 if ( n == 3 && ( base % 2 ) == 0 )
 
  152                     if ( qFuzzyCompare( stepSize, 2 * fraction ) )
 
  153                         return qRound( stepSize );
 
  162 static int qwtDivideInterval( 
double intervalSize, 
int numSteps,
 
  163     const int limits[], 
size_t numLimits )
 
  165     const int v = qwtCeil( intervalSize / 
double( numSteps ) );
 
  167     for ( uint i = 0; i < numLimits - 1; i++ )
 
  169         if ( v <= limits[i] )
 
  173     return limits[ numLimits - 1 ];
 
  176 static double qwtDivideScale( 
double intervalSize, 
int numSteps,
 
  181         if ( ( intervalSize > numSteps ) &&
 
  182             ( intervalSize <= 2 * numSteps ) )
 
  190     switch( intervalType )
 
  195             static int limits[] = { 1, 2, 5, 10, 15, 20, 30, 60 };
 
  197             stepSize = qwtDivideInterval( intervalSize, numSteps,
 
  198                 limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  204             static int limits[] = { 1, 2, 3, 4, 6, 12, 24 };
 
  206             stepSize = qwtDivideInterval( intervalSize, numSteps,
 
  207                 limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  213             const double v = intervalSize / double( numSteps );
 
  215                 stepSize = std::ceil( v );
 
  217                 stepSize = std::ceil( v / 7 ) * 7;
 
  223             static int limits[] = { 1, 2, 4, 8, 12, 26, 52 };
 
  225             stepSize = qwtDivideInterval( intervalSize, numSteps,
 
  226                 limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  232             static int limits[] = { 1, 2, 3, 4, 6, 12 };
 
  234             stepSize = qwtDivideInterval( intervalSize, numSteps,
 
  235                 limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  244                 intervalSize, numSteps, 10 );
 
  251 static double qwtDivideMajorStep( 
double stepSize, 
int maxMinSteps,
 
  254     double minStepSize = 0.0;
 
  256     switch( intervalType )
 
  260             minStepSize = qwtStepSize( stepSize, maxMinSteps, 10 );
 
  261             if ( minStepSize == 0.0 )
 
  262                 minStepSize = 0.5 * stepSize;
 
  268             static int limits[] = { 1, 2, 5, 10, 15, 20, 30, 60 };
 
  272             if ( stepSize > maxMinSteps )
 
  274                 numSteps = qwtStepCount( stepSize, maxMinSteps,
 
  275                     limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  280                 numSteps = qwtStepCount( stepSize * 60, maxMinSteps,
 
  281                     limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  285                 minStepSize = stepSize / numSteps;
 
  293             if ( stepSize > maxMinSteps )
 
  295                 static int limits[] = { 1, 2, 3, 4, 6, 12, 24, 48, 72 };
 
  297                 numSteps = qwtStepCount( stepSize, maxMinSteps,
 
  298                     limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  302                 static int limits[] = { 1, 2, 5, 10, 15, 20, 30, 60 };
 
  304                 numSteps = qwtStepCount( stepSize * 60, maxMinSteps,
 
  305                     limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  309                 minStepSize = stepSize / numSteps;
 
  317             if ( stepSize > maxMinSteps )
 
  319                 static int limits[] = { 1, 2, 3, 7, 14, 28 };
 
  321                 numSteps = qwtStepCount( stepSize, maxMinSteps,
 
  322                     limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  326                 static int limits[] = { 1, 2, 3, 4, 6, 12, 24, 48, 72 };
 
  328                 numSteps = qwtStepCount( stepSize * 24, maxMinSteps,
 
  329                     limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  333                 minStepSize = stepSize / numSteps;
 
  339             const int daysInStep = stepSize * 7;
 
  341             if ( maxMinSteps >= daysInStep )
 
  344                 minStepSize = 1.0 / 7.0;
 
  351                 const int stepSizeInWeeks = stepSize;
 
  353                 if ( stepSizeInWeeks <= maxMinSteps )
 
  360                         stepSizeInWeeks, maxMinSteps, 10 );
 
  369             if ( stepSize < maxMinSteps )
 
  370                 maxMinSteps = 
static_cast< int >( stepSize );
 
  372             static int limits[] = { 1, 2, 3, 4, 6, 12 };
 
  374             int numSteps = qwtStepCount( stepSize, maxMinSteps,
 
  375                 limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  378                 minStepSize = stepSize / numSteps;
 
  384             if ( stepSize >= maxMinSteps )
 
  387                     stepSize, maxMinSteps, 10 );
 
  393                 static int limits[] = { 1, 2, 3, 4, 6, 12 };
 
  395                 int numSteps = qwtStepCount( 12 * stepSize, maxMinSteps,
 
  396                     limits, 
sizeof( limits ) / 
sizeof( 
int ) );
 
  399                     minStepSize = stepSize / numSteps;
 
  409         && minStepSize == 0.0 )
 
  411         minStepSize = 0.5 * stepSize;
 
  418     int secondsMajor, 
int secondsMinor )
 
  420     if ( secondsMinor <= 0 )
 
  423     QDateTime minDate = dateTime.addSecs( -secondsMajor );
 
  431     while ( minDate < dateTime &&
 
  434         minDate = minDate.addSecs( 3600 );
 
  435         dstMin += 3600 * 1000.0;
 
  439     ticks.reserve( 3600 / secondsMinor);
 
  441     for ( 
int i = 0; i < 3600; i += secondsMinor )
 
  442         ticks += dstMin + i * 1000.0;
 
  448     const QDateTime& minDate, 
const QDateTime& maxDate,
 
  449     double stepSize, 
int maxMinSteps,
 
  453     double minStepSize = 0;
 
  455     if ( maxMinSteps > 1 )
 
  457         minStepSize = qwtDivideMajorStep( stepSize,
 
  458             maxMinSteps, intervalType );
 
  461     bool daylightSaving = 
false;
 
  462     if ( minDate.timeSpec() == Qt::LocalTime )
 
  467             daylightSaving = stepSize > 1;
 
  471     const double s = qwtMsecsForType( intervalType ) / 1000;
 
  472     const int secondsMajor = 
static_cast< int >( stepSize * s );
 
  473     const double secondsMinor = minStepSize * s;
 
  486     for ( QDateTime dt = minDate; dt <= maxDate;
 
  487         dt = dt.addSecs( secondsMajor ) )
 
  494         if ( daylightSaving )
 
  497             majorValue += offset * 1000.0;
 
  499             if ( offset > dstOff )
 
  503                 minorTicks += qwtDstTicks(
 
  504                     dt, secondsMajor, qRound( secondsMinor ) );
 
  510         if ( majorTicks.isEmpty() || majorTicks.last() != majorValue )
 
  511             majorTicks += majorValue;
 
  513         if ( secondsMinor > 0.0 )
 
  515             const int numMinorSteps = qwtFloor( secondsMajor / secondsMinor );
 
  517             for ( 
int i = 1; i < numMinorSteps; i++ )
 
  519                 const QDateTime mt = dt.addMSecs(
 
  520                     qRound64( i * secondsMinor * 1000 ) );
 
  523                 if ( daylightSaving )
 
  526                     minorValue += offset * 1000.0;
 
  529                 if ( minorTicks.isEmpty() || minorTicks.last() != minorValue )
 
  531                     const bool isMedium = ( numMinorSteps % 2 == 0 )
 
  532                         && ( i != 1 ) && ( i == numMinorSteps / 2 );
 
  535                         mediumTicks += minorValue;
 
  537                         minorTicks += minorValue;
 
  556     QDateTime& minDate, 
const QDateTime& maxDate,
 
  557     double stepSize, 
int maxMinSteps )
 
  564     int minStepSize = 0.0;
 
  566     if ( maxMinSteps > 1 )
 
  570             if ( maxMinSteps >= 30 )
 
  572             else if ( maxMinSteps >= 6 )
 
  574             else if ( maxMinSteps >= 3 )
 
  581             minStepSize = qwtDivideMajorStep(
 
  590     for ( QDateTime dt = minDate;
 
  591         dt <= maxDate; dt = dt.addMonths( stepSize ) )
 
  598         if ( minStepDays > 0 )
 
  600             for ( 
int days = minStepDays;
 
  601                 days < 30; days += minStepDays )
 
  605                 if ( days == 15 && minStepDays != 15 )
 
  611         else if ( minStepSize > 0.0 )
 
  613             const int numMinorSteps = qRound( stepSize / (
double) minStepSize );
 
  615             for ( 
int i = 1; i < numMinorSteps; i++ )
 
  617                 const double minorValue =
 
  620                 if ( ( numMinorSteps % 2 == 0 ) && ( i == numMinorSteps / 2 ) )
 
  621                     mediumTicks += minorValue;
 
  623                     minorTicks += minorValue;
 
  640     const QDateTime& minDate, 
const QDateTime& maxDate,
 
  641     double stepSize, 
int maxMinSteps )
 
  647     double minStepSize = 0.0;
 
  649     if ( maxMinSteps > 1 )
 
  651         minStepSize = qwtDivideMajorStep(
 
  655     int numMinorSteps = 0;
 
  656     if ( minStepSize > 0.0 )
 
  657         numMinorSteps = qwtFloor( stepSize / minStepSize );
 
  659     bool dateBC = minDate.date().year() < -1;
 
  661     for ( QDateTime dt = minDate; dt <= maxDate;
 
  662         dt = dt.addYears( stepSize ) )
 
  664         if ( dateBC && dt.date().year() > 1 )
 
  667             dt = dt.addYears( -1 );
 
  676         for ( 
int i = 1; i < numMinorSteps; i++ )
 
  680             const double years = qRound( i * minStepSize );
 
  681             if ( years >= std::numeric_limits< int >::max() / 12 )
 
  683                 tickDate = dt.addYears( years );
 
  687                 tickDate = dt.addMonths( qRound( years * 12 ) );
 
  690             const bool isMedium = ( numMinorSteps > 2 ) &&
 
  691                 ( numMinorSteps % 2 == 0 ) && ( i == numMinorSteps / 2 );
 
  695                 mediumTicks += minorValue;
 
  697                 minorTicks += minorValue;
 
  717 class QwtDateScaleEngine::PrivateData
 
  720     explicit PrivateData( Qt::TimeSpec spec )
 
  750     m_data = 
new PrivateData( 
timeSpec );
 
  776     return m_data->timeSpec;
 
  791     m_data->utcOffset = seconds;
 
  803     return m_data->utcOffset;
 
  826     return m_data->week0Type;
 
  843     m_data->maxWeeks = qMax( weeks, 0 );
 
  853     return m_data->maxWeeks;
 
  866     const QDateTime& minDate, 
const QDateTime& maxDate,
 
  869     const double jdMin = minDate.date().toJulianDay();
 
  870     const double jdMax = maxDate.date().toJulianDay();
 
  872     if ( ( jdMax - jdMin ) / 365 > maxSteps )
 
  875     const int months = qwtRoundedIntervalWidth( minDate, maxDate, 
QwtDate::Month );
 
  876     if ( months > maxSteps * 6 )
 
  879     const int days = qwtRoundedIntervalWidth( minDate, maxDate, 
QwtDate::Day );
 
  880     const int weeks = qwtRoundedIntervalWidth( minDate, maxDate, 
QwtDate::Week );
 
  882     if ( weeks > m_data->maxWeeks )
 
  884         if ( days > 4 * maxSteps * 7 )
 
  888     if ( days > maxSteps * 7 )
 
  891     const int hours = qwtRoundedIntervalWidth( minDate, maxDate, 
QwtDate::Hour );
 
  892     if ( hours > maxSteps * 24 )
 
  895     const int seconds = qwtRoundedIntervalWidth( minDate, maxDate, 
QwtDate::Second );
 
  897     if ( seconds >= maxSteps * 3600 )
 
  900     if ( seconds >= maxSteps * 60 )
 
  903     if ( seconds >= maxSteps )
 
  926     double& x1, 
double& x2, 
double& stepSize )
 const 
  942     if ( interval.
width() == 0.0 )
 
  948     if ( from.isValid() && to.isValid() )
 
  950         if ( maxNumSteps < 1 )
 
  956         const double width = qwtIntervalWidth( from, to, intvType );
 
  958         const double stepWidth = qwtDivideScale( width, maxNumSteps, intvType );
 
  961             const QDateTime d1 = 
alignDate( from, stepWidth, intvType, 
false );
 
  962             const QDateTime d2 = 
alignDate( to, stepWidth, intvType, 
true );
 
  968         stepSize = stepWidth * qwtMsecsForType( intvType );
 
  977         stepSize = -stepSize;
 
  993     int maxMajorSteps, 
int maxMinorSteps, 
double stepSize )
 const 
  995     if ( maxMajorSteps < 1 )
 
  998     const double min = qwtMinF( x1, x2 );
 
  999     const double max = qwtMaxF( x1, x2 );
 
 1007     stepSize = qAbs( stepSize );
 
 1008     if ( stepSize > 0.0 )
 
 1014         maxMajorSteps = qwtCeil( ( max - min ) / stepSize );
 
 1026             maxMajorSteps, maxMinorSteps, stepSize );
 
 1033         scaleDiv = buildScaleDiv( minDate, maxDate,
 
 1034             maxMajorSteps, maxMinorSteps, intvType );
 
 1039         scaleDiv = scaleDiv.
bounded( min, max );
 
 1049     const QDateTime& minDate, 
const QDateTime& maxDate,
 
 1050     int maxMajorSteps, 
int maxMinorSteps,
 
 1054     const double stepSize = qwtDivideScale(
 
 1060     if ( !dt0.isValid() )
 
 1071         scaleDiv = qwtDivideToSeconds( dt0, maxDate,
 
 1078             scaleDiv = qwtDivideToMonths( dt0, maxDate,
 
 1079                 stepSize, maxMinorSteps );
 
 1083             scaleDiv = qwtDivideToYears( dt0, maxDate,
 
 1084                 stepSize, maxMinorSteps );
 
 1109     const QDateTime& dateTime, 
double stepSize,
 
 1114     QDateTime dt = dateTime;
 
 1116     if ( dateTime.timeSpec() == Qt::OffsetFromUTC )
 
 1118 #if QT_VERSION >= 0x050200 
 1119         dt.setOffsetFromUtc( 0 );
 
 1121         dt.setUtcOffset( 0 );
 
 1129             const int ms = qwtAlignValue(
 
 1130                 dt.time().msec(), stepSize, up );
 
 1133             dt = dt.addMSecs( ms );
 
 1139             int second = dt.time().second();
 
 1142                 if ( dt.time().msec() > 0 )
 
 1146             const int s = qwtAlignValue( second, stepSize, up );
 
 1149             dt = dt.addSecs( s );
 
 1155             int minute = dt.time().minute();
 
 1158                 if ( dt.time().msec() > 0 || dt.time().second() > 0 )
 
 1162             const int m = qwtAlignValue( minute, stepSize, up );
 
 1165             dt = dt.addSecs( m * 60 );
 
 1171             int hour = dt.time().hour();
 
 1174                 if ( dt.time().msec() > 0 || dt.time().second() > 0
 
 1175                     || dt.time().minute() > 0 )
 
 1180             const int h = qwtAlignValue( hour, stepSize, up );
 
 1183             dt = dt.addSecs( h * 3600 );
 
 1193             int day = dt.date().dayOfYear();
 
 1196                 if ( dt.time() > QTime( 0, 0 ) )
 
 1200             const int d = qwtAlignValue( day, stepSize, up );
 
 1203             dt = dt.addDays( d - 1 );
 
 1210                 dt.date().year(), m_data->week0Type );
 
 1212             int numWeeks = date.daysTo( dt.date() ) / 7;
 
 1215                 if ( dt.time() > QTime( 0, 0 ) ||
 
 1216                     date.daysTo( dt.date() ) % 7 )
 
 1222             const int d = qwtAlignValue( numWeeks, stepSize, up ) * 7;
 
 1226             dt = dt.addDays( d );
 
 1232             int month = dt.date().month();
 
 1235                 if ( dt.date().day() > 1 ||
 
 1236                     dt.time() > QTime( 0, 0 ) )
 
 1242             const int m = qwtAlignValue( month - 1, stepSize, up );
 
 1245             dt = dt.addMonths( m );
 
 1251             int year = dateTime.date().year();
 
 1254                 if ( dateTime.date().dayOfYear() > 1 ||
 
 1255                     dt.time() > QTime( 0, 0 ) )
 
 1261             const int y = qwtAlignValue( year, stepSize, up );
 
 1267                 dt.setDate( QDate( stepSize, 1, 1 ).addYears( -stepSize ) );
 
 1271                 dt.setDate( QDate( y, 1, 1 ) );
 
 1278     if ( dateTime.timeSpec() == Qt::OffsetFromUTC )
 
 1280 #if QT_VERSION >= 0x050200 
 1281         dt.setOffsetFromUtc( dateTime.offsetFromUtc() );
 
 1283         dt.setUtcOffset( dateTime.utcOffset() );
 
 1301     if ( !dt.isValid() )
 
 1303         const QDate date = ( value <= 0.0 )
 
 1306         dt = QDateTime( date, QTime( 0, 0 ), m_data->timeSpec );
 
 1309     if ( m_data->timeSpec == Qt::OffsetFromUTC )
 
 1311         dt = dt.addSecs( m_data->utcOffset );
 
 1312 #if QT_VERSION >= 0x050200 
 1313         dt.setOffsetFromUtc( m_data->utcOffset );
 
 1315         dt.setUtcOffset( m_data->utcOffset );
 
A collection of methods around date/time values.
static QDateTime floor(const QDateTime &, IntervalType)
static QDateTime toDateTime(double value, Qt::TimeSpec=Qt::UTC)
static QDateTime ceil(const QDateTime &, IntervalType)
static QDate dateOfWeek0(int year, Week0Type)
Date of the first day of the first week for a year.
@ Month
The interval is related to months.
@ Day
The interval is related to days.
@ Millisecond
The interval is related to milliseconds.
@ Minute
The interval is related to minutes.
@ Hour
The interval is related to hours.
@ Second
The interval is related to seconds.
@ Week
The interval is related to weeks.
@ Year
The interval is related to years.
static int utcOffset(const QDateTime &)
static double toDouble(const QDateTime &)
QwtDate::Week0Type week0Type() const
virtual ~QwtDateScaleEngine()
Destructor.
virtual QDateTime alignDate(const QDateTime &, double stepSize, QwtDate::IntervalType, bool up) const
QDateTime toDateTime(double) const
virtual QwtScaleDiv divideScale(double x1, double x2, int maxMajorSteps, int maxMinorSteps, double stepSize=0.0) const override
Calculate a scale division for a date/time interval.
void setUtcOffset(int seconds)
void setWeek0Type(QwtDate::Week0Type)
virtual QwtDate::IntervalType intervalType(const QDateTime &, const QDateTime &, int maxSteps) const
Qt::TimeSpec timeSpec() const
QwtDateScaleEngine(Qt::TimeSpec=Qt::LocalTime)
Constructor.
virtual void autoScale(int maxNumSteps, double &x1, double &x2, double &stepSize) const override
void setTimeSpec(Qt::TimeSpec)
A class representing an interval.
QwtInterval normalized() const
Normalize the limits of the interval.
double width() const
Return the width of an interval.
QwtInterval extend(double value) const
Extend the interval.
QwtInterval symmetrize(double value) const
A scale engine for linear scales.
virtual QwtScaleDiv divideScale(double x1, double x2, int maxMajorSteps, int maxMinorSteps, double stepSize=0.0) const override
Calculate a scale division for an interval.
static double divideInterval(double intervalSize, int numSteps, uint base)
A class representing a scale division.
QwtScaleDiv bounded(double lowerBound, double upperBound) const
void setInterval(double lowerBound, double upperBound)
@ MediumTick
Medium ticks.
void setTicks(int tickType, const QList< double > &)
@ Inverted
Turn the scale upside down.
@ Symmetric
Build a scale which is symmetric to the reference() value.
@ IncludeReference
Build a scale which includes the reference() value.
double upperMargin() const
bool testAttribute(Attribute) const
QwtInterval buildInterval(double value) const
Build an interval around a value.
double lowerMargin() const