legible axis labels in cpint plot

This commit is contained in:
Sean C. Rhea
2006-09-18 18:53:58 +00:00
parent d8a1ece836
commit 9bee1e11dd
6 changed files with 523 additions and 28 deletions

View File

@@ -28,16 +28,19 @@ extern "C" {
#include <qwt_legend.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_grid.h>
#include <qwt_scale_engine.h>
#include "LogTimeScaleDraw.h"
#include "LogTimeScaleEngine.h"
CpintPlot::CpintPlot(QString p) : path(p), allCurve(NULL), thisCurve(NULL),
grid(NULL)
CpintPlot::CpintPlot(QString p) :
progress(NULL), path(p), allCurve(NULL), thisCurve(NULL), grid(NULL)
{
insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
setCanvasBackground(Qt::white);
setAxisTitle(yLeft, "Average Power (watts)");
setAxisTitle(xBottom, "Interval Length (minutes)");
setAxisScaleEngine(xBottom, new QwtLog10ScaleEngine);
setAxisTitle(xBottom, "Interval Length");
setAxisScaleDraw(xBottom, new LogTimeScaleDraw);
setAxisScaleEngine(xBottom, new LogTimeScaleEngine);
setAxisScale(xBottom, 0.021, 60);
}
static int
@@ -75,33 +78,34 @@ CpintPlot::calculate(QString fileName, QDateTime dateTime)
progress = new QProgressDialog(
QString(tr("Computing critical power intervals.\n"
"This may take a while.\n")),
tr("Abort"), 0, count, this);
tr("Abort"), 0, count + 1, this);
int endingOffset = progress->labelText().size();
tmp = head;
progress->show();
count = 0;
while (tmp) {
if (count) {
tmp = head;
count = 1;
while (tmp) {
QString existing = progress->labelText();
existing.chop(progress->labelText().size() - endingOffset);
progress->setLabelText(
existing + QString(tr("Processing %1...")).arg(tmp->file));
progress->setValue(count++);
update_cpi_file(tmp, cancel_cb, this);
QCoreApplication::processEvents();
if (progress->wasCanceled()) {
aborted = true;
break;
}
tmp = tmp->next;
}
free_cpi_file_info(head);
}
if (!aborted) {
QString existing = progress->labelText();
existing.chop(progress->labelText().size() - endingOffset);
progress->setLabelText(
existing + QString(tr("Processing %1...")).arg(tmp->file));
progress->setValue(count++);
update_cpi_file(tmp, cancel_cb, this);
QCoreApplication::processEvents();
if (progress->wasCanceled()) {
aborted = true;
break;
}
tmp = tmp->next;
}
free_cpi_file_info(head);
if (head && !aborted) {
QString existing = progress->labelText();
existing.chop(progress->labelText().size() - endingOffset);
progress->setValue(count++);
progress->setLabelText(existing
+ tr("Aggregating over all files."));
existing + tr("Aggregating over all files."));
progress->show();
int i;
double *bests;
int bestlen;

View File

@@ -16,6 +16,8 @@ HEADERS += \
ChooseCyclistDialog.h \
CpintPlot.h \
DownloadRideDialog.h \
LogTimeScaleDraw.h \
LogTimeScaleEngine.h \
MainWindow.h \
RawFile.h \
RideItem.h
@@ -24,6 +26,8 @@ SOURCES += \
ChooseCyclistDialog.cpp \
CpintPlot.cpp \
DownloadRideDialog.cpp \
LogTimeScaleDraw.cpp \
LogTimeScaleEngine.cpp \
MainWindow.cpp \
RawFile.cpp \
RideItem.cpp \

View File

@@ -0,0 +1,111 @@
/*
* $Id: LogTimeScaleDraw.h,v 1.2 2006/07/12 02:13:57 srhea Exp $
*
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*
*/
#include "LogTimeScaleDraw.h"
#include <qpen.h>
#include <qpainter.h>
#include "qwt_math.h"
#include "qwt_painter.h"
#include "qwt_scale_div.h"
#include "qwt_scale_map.h"
#include "qwt_scale_draw.h"
#if QT_VERSION < 0x040000
#include <qwmatrix.h>
#define QwtMatrix QWMatrix
#define QwtPointArray QPointArray
#else
#include <qmatrix.h>
#define QwtMatrix QMatrix
#define QwtPointArray QPolygon
#endif
struct tick_info_t {
double x;
char *label;
};
extern tick_info_t tick_info[];
void
LogTimeScaleDraw::drawLabel(QPainter *painter, double value) const
{
QwtText lbl = tickLabel(painter->font(), value);
if ( lbl.isEmpty() )
return;
const QPoint pos = labelPosition(value);
QSize labelSize = lbl.textSize(painter->font());
if ( labelSize.height() % 2 )
labelSize.setHeight(labelSize.height() + 1);
const QwtMatrix m = labelMatrix( pos, labelSize);
painter->save();
#if QT_VERSION < 0x040000
painter->setWorldMatrix(m, true);
#else
painter->setMatrix(m, true);
#endif
lbl.draw (painter, QRect(QPoint(0, 0), labelSize) );
painter->restore();
}
const QwtText &
LogTimeScaleDraw::tickLabel(const QFont &font, double value) const
{
QMap<double, QwtText>::const_iterator it = labelCache.find(value);
if ( it == labelCache.end() )
{
QwtText lbl;
tick_info_t *walker = tick_info;
while (walker->label) {
if (walker->x == value)
break;
++walker;
}
if (walker->label)
lbl = QwtText(QString(walker->label));
else
lbl = label(value);
lbl.setFlags(0);
lbl.setLayoutAttributes(QwtText::MinimumLayout);
(void)lbl.textSize(font); // initialize the internal cache
it = labelCache.insert(value, lbl);
}
return (*it);
}

View File

@@ -0,0 +1,46 @@
/*
* $Id: LogTimeScaleDraw.h,v 1.2 2006/07/12 02:13:57 srhea Exp $
*
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*
*/
#ifndef _GC_LogTimeScaleDraw_h
#define _GC_LogTimeScaleDraw_h 1
#include "qwt_scale_draw.h"
#include <qmap.h>
class LogTimeScaleDraw : public QwtScaleDraw
{
protected:
virtual void drawLabel(QPainter *p, double val) const;
virtual const QwtText & tickLabel(const QFont &font, double value) const;
mutable QMap<double, QwtText> labelCache;
};
#endif // _GC_LogTimeScaleDraw_h

View File

@@ -0,0 +1,263 @@
/*
* $Id: LogTimeScaleEngine.h,v 1.2 2006/07/12 02:13:57 srhea Exp $
*
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*
*/
#include "LogTimeScaleEngine.h"
#include "qwt_math.h"
#include "qwt_scale_map.h"
/*!
Return a transformation, for logarithmic (base 10) scales
*/
QwtScaleTransformation LogTimeScaleEngine::transformation() const
{
return QwtScaleTransformation(QwtScaleTransformation::log10XForm,
QwtScaleTransformation::log10InvXForm);
}
/*!
Align and divide an interval
\param maxNumSteps Max. number of steps
\param x1 First limit of the interval (In/Out)
\param x2 Second limit of the interval (In/Out)
\param stepSize Step size (Out)
\sa QwtScaleEngine::setAttribute
*/
void LogTimeScaleEngine::autoScale(int maxNumSteps,
double &x1, double &x2, double &stepSize) const
{
if ( x1 > x2 )
qSwap(x1, x2);
QwtDoubleInterval interval(x1 / pow(10.0, loMargin()),
x2 * pow(10.0, hiMargin()) );
double logRef = 1.0;
if (reference() > LOG_MIN / 2)
logRef = qwtMin(reference(), LOG_MAX / 2);
if (testAttribute(QwtScaleEngine::Symmetric))
{
const double delta = qwtMax(interval.maxValue() / logRef,
logRef / interval.minValue());
interval.setInterval(logRef / delta, logRef * delta);
}
if (testAttribute(QwtScaleEngine::IncludeReference))
interval = interval.extend(logRef);
interval = interval.limit(LOG_MIN, LOG_MAX);
if (interval.width() == 0.0)
interval = buildInterval(interval.minValue());
stepSize = divideInterval(log10(interval).width(), qwtMax(maxNumSteps, 1));
if ( stepSize < 1.0 )
stepSize = 1.0;
if (!testAttribute(QwtScaleEngine::Floating))
interval = align(interval, stepSize);
x1 = interval.minValue();
x2 = interval.maxValue();
if (testAttribute(QwtScaleEngine::Inverted))
{
qSwap(x1, x2);
stepSize = -stepSize;
}
}
/*!
\brief Calculate a scale division
\param x1 First interval limit
\param x2 Second interval limit
\param maxMajSteps Maximum for the number of major steps
\param maxMinSteps Maximum number of minor steps
\param stepSize Step size. If stepSize == 0, the scaleEngine
calculates one.
\sa QwtScaleEngine::stepSize, LogTimeScaleEngine::subDivide
*/
QwtScaleDiv LogTimeScaleEngine::divideScale(double x1, double x2,
int maxMajSteps, int maxMinSteps, double stepSize) const
{
QwtDoubleInterval interval = QwtDoubleInterval(x1, x2).normalized();
interval = interval.limit(LOG_MIN, LOG_MAX);
if (interval.width() <= 0 )
return QwtScaleDiv();
if (interval.maxValue() / interval.minValue() < 10.0)
{
// scale width is less than one decade -> build linear scale
QwtLinearScaleEngine linearScaler;
linearScaler.setAttributes(attributes());
linearScaler.setReference(reference());
linearScaler.setMargins(loMargin(), hiMargin());
return linearScaler.divideScale(x1, x2,
maxMajSteps, maxMinSteps, stepSize);
}
stepSize = qwtAbs(stepSize);
if ( stepSize == 0.0 )
{
if ( maxMajSteps < 1 )
maxMajSteps = 1;
stepSize = divideInterval(log10(interval).width(), maxMajSteps);
if ( stepSize < 1.0 )
stepSize = 1.0; // major step must be >= 1 decade
}
QwtScaleDiv scaleDiv;
if ( stepSize != 0.0 )
{
QwtTickList ticks[QwtScaleDiv::NTickTypes];
buildTicks(interval, stepSize, maxMinSteps, ticks);
scaleDiv = QwtScaleDiv(interval, ticks);
}
if ( x1 > x2 )
scaleDiv.invert();
return scaleDiv;
}
void LogTimeScaleEngine::buildTicks(
const QwtDoubleInterval& interval, double stepSize, int maxMinSteps,
QwtTickList ticks[QwtScaleDiv::NTickTypes]) const
{
const QwtDoubleInterval boundingInterval =
align(interval, stepSize);
ticks[QwtScaleDiv::MajorTick] =
buildMajorTicks(boundingInterval, stepSize);
if ( maxMinSteps > 0 )
{
ticks[QwtScaleDiv::MinorTick] = buildMinorTicks(
ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize);
}
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
ticks[i] = strip(ticks[i], interval);
}
struct tick_info_t {
double x;
char *label;
};
tick_info_t tick_info[] = {
{ 0.021, "1.26s" },
{ 5.0/60.0, "5s" },
{ 15.0/60.0, "15s" },
{ 0.5, "30s" },
{ 1.0, "1m" },
{ 2.0, "2m" },
{ 3.0, "3m" },
{ 5.0, "5m" },
{ 10.0, "10m" },
{ 20.0, "20m" },
{ 30.0, "30m" },
{ 60.0, "1h" },
{ 120.0, "2h" },
{ 180.0, "3h" },
{ 300.0, "5h" },
{ -1.0, NULL }
};
QwtTickList LogTimeScaleEngine::buildMajorTicks(
const QwtDoubleInterval &interval, double stepSize) const
{
QwtTickList ticks;
tick_info_t *walker = tick_info;
while (walker->label) {
ticks += walker->x;
++walker;
}
return ticks;
}
QwtTickList LogTimeScaleEngine::buildMinorTicks(
const QwtTickList &majorTicks,
int maxMinSteps, double stepSize) const
{
QwtTickList minorTicks;
return minorTicks;
}
/*!
\brief Align an interval to a step size
The limits of an interval are aligned that both are integer
multiples of the step size.
\param interval Interval
\param stepSize Step size
\return Aligned interval
*/
QwtDoubleInterval LogTimeScaleEngine::align(
const QwtDoubleInterval &interval, double stepSize) const
{
const QwtDoubleInterval intv = log10(interval);
const double x1 = QwtScaleArithmetic::floorEps(intv.minValue(), stepSize);
const double x2 = QwtScaleArithmetic::ceilEps(intv.maxValue(), stepSize);
return pow10(QwtDoubleInterval(x1, x2));
}
/*!
Return the interval [log10(interval.minValue(), log10(interval.maxValue]
*/
QwtDoubleInterval LogTimeScaleEngine::log10(
const QwtDoubleInterval &interval) const
{
return QwtDoubleInterval(::log10(interval.minValue()),
::log10(interval.maxValue()));
}
/*!
Return the interval [pow10(interval.minValue(), pow10(interval.maxValue]
*/
QwtDoubleInterval LogTimeScaleEngine::pow10(
const QwtDoubleInterval &interval) const
{
return QwtDoubleInterval(pow(10.0, interval.minValue()),
pow(10.0, interval.maxValue()));
}

View File

@@ -0,0 +1,67 @@
/*
* $Id: LogTimeScaleEngine.h,v 1.2 2006/07/12 02:13:57 srhea Exp $
*
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*
*/
#ifndef _GC_LogTimeScaleEngine_h
#define _GC_LogTimeScaleEngine_h 1
#include "qwt_scale_engine.h"
class LogTimeScaleEngine : public QwtScaleEngine
{
public:
virtual void autoScale(int maxSteps, double &x1, double &x2,
double &stepSize) const;
virtual QwtScaleDiv divideScale(double x1, double x2,
int numMajorSteps, int numMinorSteps,
double stepSize = 0.0) const;
virtual QwtScaleTransformation transformation() const;
protected:
QwtDoubleInterval log10(const QwtDoubleInterval&) const;
QwtDoubleInterval pow10(const QwtDoubleInterval&) const;
private:
QwtDoubleInterval align(const QwtDoubleInterval&,
double stepSize) const;
void buildTicks(
const QwtDoubleInterval &, double stepSize, int maxMinSteps,
QwtTickList ticks[QwtScaleDiv::NTickTypes]) const;
QwtTickList buildMinorTicks(
const QwtTickList& majorTicks,
int maxMinMark, double step) const;
QwtTickList buildMajorTicks(
const QwtDoubleInterval &interval, double stepSize) const;
};
#endif // _GC_LogTimeScaleEngine_h