Skip to content
Snippets Groups Projects
Commit a531f73b authored by Matthew D Jones's avatar Matthew D Jones
Browse files

Re #11422 Added PowerScaleEngine; a new ScaleEngine for X^n scales

parent 66bceb82
No related merge requests found
/***************************************************************************
File : PowerScaleEngine.cpp
Project : QtiPlot
--------------------------------------------------------------------
Copyright : (C) 2009 by Ion Vasilief
Email (use @ for *) : ion_vasilief*yahoo.fr
Description : Return a transformation for reciprocal (1/t) scales
***************************************************************************/
/***************************************************************************
* *
* 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 *
* *
***************************************************************************/
#include "PowerScaleEngine.h"
/*!
Return a dummy transformation
*/
QwtScaleTransformation *PowerScaleEngine::transformation() const
{
return new QwtScaleTransformation(QwtScaleTransformation::Other);
}
/*!
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)
*/
void PowerScaleEngine::autoScale(int maxNumSteps,
double &x1, double &x2, double &stepSize) const
{
QwtDoubleInterval interval(x1, x2);
interval = interval.normalized();
interval.setMinValue(interval.minValue() - lowerMargin());
interval.setMaxValue(interval.maxValue() + upperMargin());
if (testAttribute(QwtScaleEngine::Symmetric))
interval = interval.symmetrize(reference());
if (testAttribute(QwtScaleEngine::IncludeReference))
interval = interval.extend(reference());
if (interval.width() == 0.0)
interval = buildInterval(interval.minValue());
stepSize = divideInterval(interval.width(), qwtMax(maxNumSteps, 1));
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(), QwtScaleEngine::subDivide()
*/
QwtScaleDiv PowerScaleEngine::divideScale(double x1, double x2,
int maxMajSteps, int maxMinSteps, double stepSize) const
{
QwtDoubleInterval interval = QwtDoubleInterval(x1, x2).normalized();
if (interval.width() <= 0 )
return QwtScaleDiv();
stepSize = qwtAbs(stepSize);
if ( stepSize == 0.0 )
{
if ( maxMajSteps < 1 )
maxMajSteps = 1;
stepSize = divideInterval(interval.width(), maxMajSteps);
}
QwtScaleDiv scaleDiv;
if ( stepSize != 0.0 )
{
QwtValueList ticks[QwtScaleDiv::NTickTypes];
buildTicks(interval, stepSize, maxMinSteps, ticks);
scaleDiv = QwtScaleDiv(interval, ticks);
}
if ( x1 > x2 )
scaleDiv.invert();
return scaleDiv;
}
void PowerScaleEngine::buildTicks(
const QwtDoubleInterval& interval, double stepSize, int maxMinSteps,
QwtValueList ticks[QwtScaleDiv::NTickTypes]) const
{
const QwtDoubleInterval boundingInterval =
align(interval, stepSize);
ticks[QwtScaleDiv::MajorTick] =
buildMajorTicks(boundingInterval, stepSize);
if ( maxMinSteps > 0 )
{
buildMinorTicks(ticks[QwtScaleDiv::MajorTick], maxMinSteps, stepSize,
ticks[QwtScaleDiv::MinorTick], ticks[QwtScaleDiv::MediumTick]);
}
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
{
ticks[i] = strip(ticks[i], interval);
// ticks very close to 0.0 are
// explicitely set to 0.0
for ( int j = 0; j < (int)ticks[i].count(); j++ )
{
if ( QwtScaleArithmetic::compareEps(ticks[i][j], 0.0, stepSize) == 0 )
ticks[i][j] = 0.0;
}
}
}
QwtValueList PowerScaleEngine::buildMajorTicks(
const QwtDoubleInterval &interval, double stepSize) const
{
int numTicks = qRound(interval.width() / stepSize) + 1;
if ( numTicks > 10000 )
numTicks = 10000;
QwtValueList ticks;
ticks += interval.minValue();
for (int i = 1; i < numTicks - 1; i++)
ticks += interval.minValue() + i * stepSize;
ticks += interval.maxValue();
return ticks;
}
void PowerScaleEngine::buildMinorTicks(
const QwtValueList& majorTicks,
int maxMinSteps, double stepSize,
QwtValueList &minorTicks,
QwtValueList &mediumTicks) const
{
double minStep = divideInterval(stepSize, maxMinSteps);
if (minStep == 0.0)
return;
// # ticks per interval
int numTicks = (int)::ceil(qwtAbs(stepSize / minStep)) - 1;
// Do the minor steps fit into the interval?
if ( QwtScaleArithmetic::compareEps((numTicks + 1) * qwtAbs(minStep),
qwtAbs(stepSize), stepSize) > 0)
{
numTicks = 1;
minStep = stepSize * 0.5;
}
int medIndex = -1;
if ( numTicks % 2 )
medIndex = numTicks / 2;
// calculate minor ticks
for (int i = 0; i < (int)majorTicks.count(); i++)
{
double val = majorTicks[i];
for (int k = 0; k < numTicks; k++)
{
val += minStep;
double alignedValue = val;
if (QwtScaleArithmetic::compareEps(val, 0.0, stepSize) == 0)
alignedValue = 0.0;
if ( k == medIndex )
mediumTicks += alignedValue;
else
minorTicks += alignedValue;
}
}
}
/*!
\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 PowerScaleEngine::align(
const QwtDoubleInterval &interval, double stepSize) const
{
const double x1 =
QwtScaleArithmetic::floorEps(interval.minValue(), stepSize);
const double x2 =
QwtScaleArithmetic::ceilEps(interval.maxValue(), stepSize);
return QwtDoubleInterval(x1, x2);
}
//! Create a clone of the transformation
QwtScaleTransformation *PowerScaleTransformation::copy() const
{
return new PowerScaleTransformation(d_engine);
}
double PowerScaleTransformation::xForm(
double s, double s1, double s2, double p1, double p2) const
{
return p1 + (p2 - p1) * s2 * (s1 - s)/(s * (s1 - s2));
}
double PowerScaleTransformation::invXForm(double p, double p1, double p2,
double s1, double s2) const
{
return s1*s2*(p2 - p1)/(s2*(p2 - p) + s1*(p - p1));
}
/***************************************************************************
File : PowerScaleEngine.h
Project : QtiPlot
--------------------------------------------------------------------
Copyright : (C) 2009 by Ion Vasilief
Email (use @ for *) : ion_vasilief*yahoo.fr
Description : Return a transformation for reciprocal (1/t) scales
***************************************************************************/
/***************************************************************************
* *
* 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 *
* *
***************************************************************************/
#ifndef RECIPROCAL_SCALE_ENGINE_H
#define RECIPROCAL_SCALE_ENGINE_H
#include <qwt_scale_engine.h>
#include <qwt_scale_map.h>
#include "ScaleEngine.h"
class PowerScaleTransformation: public ScaleTransformation
{
public:
PowerScaleTransformation(const ScaleEngine *engine):ScaleTransformation(engine){};
virtual double xForm(double x, double, double, double p1, double p2) const;
virtual double invXForm(double x, double s1, double s2, double p1, double p2) const;
QwtScaleTransformation* copy() const;
};
/*!
\brief A scale engine for reciprocal (1/t) scales
*/
class PowerScaleEngine: 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 align(const QwtDoubleInterval&,
double stepSize) const;
private:
void buildTicks(
const QwtDoubleInterval &, double stepSize, int maxMinSteps,
QwtValueList ticks[QwtScaleDiv::NTickTypes]) const;
void buildMinorTicks(
const QwtValueList& majorTicks,
int maxMinMark, double step,
QwtValueList &, QwtValueList &) const;
QwtValueList buildMajorTicks(
const QwtDoubleInterval &interval, double stepSize) const;
};
#endif
...@@ -26,8 +26,9 @@ ...@@ -26,8 +26,9 @@
* Boston, MA 02110-1301 USA * * Boston, MA 02110-1301 USA *
* * * *
***************************************************************************/ ***************************************************************************/
#include "qwt_compat.h"
#include "ScaleEngine.h" #include "ScaleEngine.h"
#include "PowerScaleEngine.h"
#include <limits.h>
QwtScaleTransformation* ScaleEngine::transformation() const QwtScaleTransformation* ScaleEngine::transformation() const
{ {
...@@ -36,12 +37,13 @@ QwtScaleTransformation* ScaleEngine::transformation() const ...@@ -36,12 +37,13 @@ QwtScaleTransformation* ScaleEngine::transformation() const
double ScaleTransformation::invXForm(double p, double p1, double p2, double s1, double s2) const double ScaleTransformation::invXForm(double p, double p1, double p2, double s1, double s2) const
{ {
if (!d_engine->hasBreak()){ if (!d_engine->hasBreak()){
QwtScaleTransformation tr(d_engine->type()); QwtScaleTransformation *tr = newScaleTransformation();
double res = tr.invXForm(p, p1, p2, s1, s2); double res = tr->invXForm(p, p1, p2, s1, s2);
return res; delete tr;
} return res;
}
const int d_break_space = d_engine->breakWidth(); const int d_break_space = d_engine->breakWidth();
const double lb = d_engine->axisBreakLeft(); const double lb = d_engine->axisBreakLeft();
const double rb = d_engine->axisBreakRight(); const double rb = d_engine->axisBreakRight();
...@@ -57,31 +59,31 @@ double ScaleTransformation::invXForm(double p, double p1, double p2, double s1, ...@@ -57,31 +59,31 @@ double ScaleTransformation::invXForm(double p, double p1, double p2, double s1,
if (p > pml && p < pmr) if (p > pml && p < pmr)
return pm; return pm;
bool invertedScale = d_engine->testAttribute(QwtScaleEngine::Inverted); bool invertedScale = d_engine->testAttribute(QwtScaleEngine::Inverted);
QwtScaleTransformation::Type d_type = d_engine->type(); ScaleTransformation::Type d_type = d_engine->type();
if (invertedScale){ if (invertedScale){
if ((p2 > p1 && p <= pml) || (p2 < p1 && p >= pml)){ if ((p2 > p1 && p <= pml) || (p2 < p1 && p >= pml)){
if (d_engine->log10ScaleAfterBreak()) if (d_engine->log10ScaleAfterBreak())
return s1*exp((p - p1)/(pml - p1)*log(rb/s1)); return s1*exp((p - p1)/(pml - p1)*log(rb/s1));
else else
return s1 + (rb - s1)/(pml - p1)*(p - p1); return s1 + (rb - s1)/(pml - p1)*(p - p1);
} }
if ((p2 > p1 && p >= pmr) || (p2 < p1 && p <= pmr)){ if ((p2 > p1 && p >= pmr) || (p2 < p1 && p <= pmr)){
if (d_type == QwtScaleTransformation::Log10) if (d_type == ScaleTransformation::Log10)
return lb * exp((p - pmr)/(p2 - pmr)*log(s2/lb)); return lb * exp((p - pmr)/(p2 - pmr)*log(s2/lb));
else if (d_type == QwtScaleTransformation::Linear) else if (d_type == ScaleTransformation::Linear)
return lb + (p - pmr)/(p2 - pmr)*(s2 - lb); return lb + (p - pmr)/(p2 - pmr)*(s2 - lb);
} }
} }
if ((p2 > p1 && p <= pml) || (p2 < p1 && p >= pml)){ if ((p2 > p1 && p <= pml) || (p2 < p1 && p >= pml)){
if (d_type == QwtScaleTransformation::Linear) if (d_type == ScaleTransformation::Linear)
return s1 + (lb - s1)*(p - p1)/(pml - p1); return s1 + (lb - s1)*(p - p1)/(pml - p1);
else if (d_type == QwtScaleTransformation::Log10) else if (d_type == ScaleTransformation::Log10)
return s1 * exp((p - p1)/(pml - p1)*log(lb/s1)); return s1 * exp((p - p1)/(pml - p1)*log(lb/s1));
} }
...@@ -97,23 +99,23 @@ double ScaleTransformation::invXForm(double p, double p1, double p2, double s1, ...@@ -97,23 +99,23 @@ double ScaleTransformation::invXForm(double p, double p1, double p2, double s1,
double ScaleTransformation::xForm(double s, double s1, double s2, double p1, double p2) const double ScaleTransformation::xForm(double s, double s1, double s2, double p1, double p2) const
{ {
if ((d_engine->type() != ScaleTransformation::Linear) && s <= 0.0){ if ((d_engine->type() == ScaleTransformation::Log10) && s < 0.0){
double maxScreenCoord = 1e4; if (p1 < p2){
if (p1 < p2){ if (d_engine->testAttribute(QwtScaleEngine::Inverted))
if (d_engine->testAttribute(QwtScaleEngine::Inverted)) return DBL_MAX;
return maxScreenCoord; return -DBL_MAX;
return -DBL_MAX; }
}
if (d_engine->testAttribute(QwtScaleEngine::Inverted)) if (d_engine->testAttribute(QwtScaleEngine::Inverted))
return -DBL_MAX; return -DBL_MAX;
return maxScreenCoord; return DBL_MAX;
} }
if (!d_engine->hasBreak()){ if (!d_engine->hasBreak()){
QwtScaleTransformation tr(d_engine->type()); QwtScaleTransformation *tr = newScaleTransformation();
double res = tr.xForm(s, s1, s2, p1, p2); double res = tr->xForm(s, s1, s2, p1, p2);
delete tr;
return res; return res;
} }
...@@ -134,17 +136,17 @@ double ScaleTransformation::xForm(double s, double s1, double s2, double p1, dou ...@@ -134,17 +136,17 @@ double ScaleTransformation::xForm(double s, double s1, double s2, double p1, dou
return pm; return pm;
bool invertedScale = d_engine->testAttribute(QwtScaleEngine::Inverted); bool invertedScale = d_engine->testAttribute(QwtScaleEngine::Inverted);
QwtScaleTransformation::Type d_type = d_engine->type(); ScaleTransformation::Type d_type = d_engine->type();
if (invertedScale){ if (invertedScale){
if (s <= lb){ if (s <= lb){
if (d_type == QwtScaleTransformation::Linear) if (d_type == ScaleTransformation::Linear)
return pmr + (lb - s)/(lb - s2)*(p2 - pmr); return pmr + (lb - s)/(lb - s2)*(p2 - pmr);
else if (d_type == QwtScaleTransformation::Log10){ else if (d_type == ScaleTransformation::Log10){
return pmr + log(lb/s)/log(lb/s2)*(p2 - pmr); return pmr + log(lb/s)/log(lb/s2)*(p2 - pmr);
} }
} }
if (s >= rb){ if (s >= rb){
if (d_engine->log10ScaleAfterBreak()) if (d_engine->log10ScaleAfterBreak())
return p1 + log(s1/s)/log(s1/rb)*(pml - p1); return p1 + log(s1/s)/log(s1/rb)*(pml - p1);
...@@ -155,9 +157,9 @@ double ScaleTransformation::xForm(double s, double s1, double s2, double p1, dou ...@@ -155,9 +157,9 @@ double ScaleTransformation::xForm(double s, double s1, double s2, double p1, dou
} }
if (s <= lb){ if (s <= lb){
if (d_type == QwtScaleTransformation::Linear) if (d_type == ScaleTransformation::Linear)
return p1 + (s - s1)/(lb - s1)*(pml - p1); return p1 + (s - s1)/(lb - s1)*(pml - p1);
else if (d_type == QwtScaleTransformation::Log10) else if (d_type == ScaleTransformation::Log10)
return p1 + log(s/s1)/log(lb/s1)*(pml - p1); return p1 + log(s/s1)/log(lb/s1)*(pml - p1);
} }
...@@ -176,13 +178,31 @@ QwtScaleTransformation *ScaleTransformation::copy() const ...@@ -176,13 +178,31 @@ QwtScaleTransformation *ScaleTransformation::copy() const
return new ScaleTransformation(d_engine); return new ScaleTransformation(d_engine);
} }
QwtScaleTransformation* ScaleTransformation::newScaleTransformation() const
{
QwtScaleTransformation *transform = NULL;
switch (d_engine->type()){
case ScaleTransformation::Log10:
transform = new QwtScaleTransformation(QwtScaleTransformation::Log10);
break;
case ScaleTransformation::Power:
transform = new PowerScaleTransformation(d_engine);
break;
case ScaleTransformation::Linear:
default:
transform = new QwtScaleTransformation (QwtScaleTransformation::Linear);
}
return transform;
}
/***************************************************************************** /*****************************************************************************
* *
* Class ScaleEngine * Class ScaleEngine
* *
*****************************************************************************/ *****************************************************************************/
ScaleEngine::ScaleEngine(QwtScaleTransformation::Type type,double left_break, double right_break): QwtScaleEngine(), ScaleEngine::ScaleEngine(ScaleTransformation::Type type,double left_break, double right_break): QwtScaleEngine(),
d_type(type), d_type(type),
d_break_left(left_break), d_break_left(left_break),
d_break_right(right_break), d_break_right(right_break),
...@@ -231,7 +251,7 @@ double ScaleEngine::stepAfterBreak() const ...@@ -231,7 +251,7 @@ double ScaleEngine::stepAfterBreak() const
return d_step_after; return d_step_after;
} }
QwtScaleTransformation::Type ScaleEngine::type() const ScaleTransformation::Type ScaleEngine::type() const
{ {
return d_type; return d_type;
} }
...@@ -258,19 +278,19 @@ bool ScaleEngine::hasBreakDecoration() const ...@@ -258,19 +278,19 @@ bool ScaleEngine::hasBreakDecoration() const
void ScaleEngine::clone(const ScaleEngine *engine) void ScaleEngine::clone(const ScaleEngine *engine)
{ {
d_type = engine->type(); d_type = engine->type();
d_break_left = engine->axisBreakLeft(); d_break_left = engine->axisBreakLeft();
d_break_right = engine->axisBreakRight(); d_break_right = engine->axisBreakRight();
d_break_pos = engine->breakPosition(); d_break_pos = engine->breakPosition();
d_step_before = engine->stepBeforeBreak(); d_step_before = engine->stepBeforeBreak();
d_step_after = engine->stepAfterBreak(); d_step_after = engine->stepAfterBreak();
d_minor_ticks_before = engine->minTicksBeforeBreak(); d_minor_ticks_before = engine->minTicksBeforeBreak();
d_minor_ticks_after = engine->minTicksAfterBreak(); d_minor_ticks_after = engine->minTicksAfterBreak();
d_log10_scale_after = engine->log10ScaleAfterBreak(); d_log10_scale_after = engine->log10ScaleAfterBreak();
d_break_width = engine->breakWidth(); d_break_width = engine->breakWidth();
d_break_decoration = engine->hasBreakDecoration(); d_break_decoration = engine->hasBreakDecoration();
setAttributes(engine->attributes()); setAttributes(engine->attributes());
setMargins(engine->loMargin(), engine->hiMargin()); setMargins(engine->lowerMargin(), engine->upperMargin());
} }
QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps, QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps,
...@@ -278,10 +298,7 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps, ...@@ -278,10 +298,7 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps,
{ {
QwtScaleEngine *engine; QwtScaleEngine *engine;
if (!hasBreak()){ if (!hasBreak()){
if (d_type == QwtScaleTransformation::Log10) engine = newScaleEngine();
engine = new QwtLog10ScaleEngine();
else
engine = new QwtLinearScaleEngine();
QwtScaleDiv div = engine->divideScale(x1, x2, maxMajSteps, maxMinSteps, stepSize); QwtScaleDiv div = engine->divideScale(x1, x2, maxMajSteps, maxMinSteps, stepSize);
delete engine; delete engine;
return div; return div;
...@@ -300,10 +317,8 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps, ...@@ -300,10 +317,8 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps,
engine = new QwtLog10ScaleEngine(); engine = new QwtLog10ScaleEngine();
else else
engine = new QwtLinearScaleEngine(); engine = new QwtLinearScaleEngine();
} else if (d_type == QwtScaleTransformation::Log10) } else
engine = new QwtLog10ScaleEngine(); engine = newScaleEngine();
else
engine = new QwtLinearScaleEngine();
int max_min_intervals = d_minor_ticks_before; int max_min_intervals = d_minor_ticks_before;
if (d_minor_ticks_before == 1) if (d_minor_ticks_before == 1)
...@@ -320,15 +335,12 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps, ...@@ -320,15 +335,12 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps,
max_min_intervals = d_minor_ticks_after + 1; max_min_intervals = d_minor_ticks_after + 1;
delete engine; delete engine;
if (testAttribute(QwtScaleEngine::Inverted)){ if (testAttribute(QwtScaleEngine::Inverted))
if (d_type == QwtScaleTransformation::Log10) engine = newScaleEngine();
engine = new QwtLog10ScaleEngine(); else if (d_log10_scale_after)
else engine = new QwtLog10ScaleEngine();
engine = new QwtLinearScaleEngine(); else
} else if (d_log10_scale_after) engine = new QwtLinearScaleEngine();
engine = new QwtLog10ScaleEngine();
else
engine = new QwtLinearScaleEngine();
QwtScaleDiv div2 = engine->divideScale(rb, x2, maxMajSteps/2, max_min_intervals, step2); QwtScaleDiv div2 = engine->divideScale(rb, x2, maxMajSteps/2, max_min_intervals, step2);
...@@ -344,29 +356,27 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps, ...@@ -344,29 +356,27 @@ QwtScaleDiv ScaleEngine::divideScale(double x1, double x2, int maxMajSteps,
void ScaleEngine::autoScale (int maxNumSteps, double &x1, double &x2, double &stepSize) const void ScaleEngine::autoScale (int maxNumSteps, double &x1, double &x2, double &stepSize) const
{ {
if (!hasBreak() || testAttribute(QwtScaleEngine::Inverted)){ if (!hasBreak() || testAttribute(QwtScaleEngine::Inverted)){
QwtScaleEngine *engine; QwtScaleEngine *engine = newScaleEngine();
if (d_type == QwtScaleTransformation::Log10)
engine = new QwtLog10ScaleEngine();
else
engine = new QwtLinearScaleEngine();
engine->setAttributes(attributes()); engine->setAttributes(attributes());
engine->setReference(reference()); engine->setReference(reference());
engine->setMargins(loMargin(), hiMargin()); engine->setMargins(lowerMargin(), upperMargin());
if (type() == ScaleTransformation::Log10){
if (x1 <= 0.0)
x1 = 1e-4;
if (x2 <= 0.0)
x2 = 1e-3;
}
engine->autoScale(maxNumSteps, x1, x2, stepSize); engine->autoScale(maxNumSteps, x1, x2, stepSize);
delete engine; delete engine;
} else { } else {
QwtScaleEngine *engine; QwtScaleEngine *engine = newScaleEngine();
if (d_type == QwtScaleTransformation::Log10)
engine = new QwtLog10ScaleEngine();
else
engine = new QwtLinearScaleEngine();
engine->setAttributes(attributes()); engine->setAttributes(attributes());
double breakLeft = d_break_left; double breakLeft = d_break_left;
engine->autoScale(maxNumSteps, x1, breakLeft, stepSize); engine->autoScale(maxNumSteps, x1, breakLeft, stepSize);
delete engine; delete engine;
engine = new QwtLinearScaleEngine(); engine = new QwtLinearScaleEngine();
engine->setAttributes(attributes()); engine->setAttributes(attributes());
double breakRight = d_break_right; double breakRight = d_break_right;
...@@ -374,3 +384,22 @@ void ScaleEngine::autoScale (int maxNumSteps, double &x1, double &x2, double &st ...@@ -374,3 +384,22 @@ void ScaleEngine::autoScale (int maxNumSteps, double &x1, double &x2, double &st
delete engine; delete engine;
} }
} }
QwtScaleEngine *ScaleEngine::newScaleEngine() const
{
QwtScaleEngine *engine = NULL;
switch (d_type){
case ScaleTransformation::Log10:
engine = new QwtLog10ScaleEngine();
break;
case ScaleTransformation::Power:
engine = new PowerScaleEngine();
break;
case ScaleTransformation::Linear:
default:
engine = new QwtLinearScaleEngine();
}
return engine;
}
...@@ -33,10 +33,28 @@ ...@@ -33,10 +33,28 @@
#include <qwt_scale_map.h> #include <qwt_scale_map.h>
#include <float.h> #include <float.h>
class ScaleEngine;
class ScaleTransformation: public QwtScaleTransformation
{
public:
enum Type{Linear, Log10, Power};
ScaleTransformation(const ScaleEngine *engine):QwtScaleTransformation(Other), d_engine(engine){};
virtual double xForm(double x, double, double, double p1, double p2) const;
virtual double invXForm(double x, double s1, double s2, double p1, double p2) const;
QwtScaleTransformation* copy() const;
protected:
QwtScaleTransformation* newScaleTransformation() const;
//! The scale engine that generates the transformation
const ScaleEngine* d_engine;
};
class ScaleEngine: public QwtScaleEngine class ScaleEngine: public QwtScaleEngine
{ {
public: public:
ScaleEngine(QwtScaleTransformation::Type type = QwtScaleTransformation::Linear, ScaleEngine(ScaleTransformation::Type type = ScaleTransformation::Linear,
double left_break = -DBL_MAX, double right_break = DBL_MAX); double left_break = -DBL_MAX, double right_break = DBL_MAX);
QwtScaleTransformation* transformation() const; QwtScaleTransformation* transformation() const;
virtual QwtScaleDiv divideScale(double x1, double x2, int maxMajSteps, virtual QwtScaleDiv divideScale(double x1, double x2, int maxMajSteps,
...@@ -68,8 +86,8 @@ public: ...@@ -68,8 +86,8 @@ public:
bool log10ScaleAfterBreak() const; bool log10ScaleAfterBreak() const;
void setLog10ScaleAfterBreak(bool on){d_log10_scale_after = on;}; void setLog10ScaleAfterBreak(bool on){d_log10_scale_after = on;};
QwtScaleTransformation::Type type() const; ScaleTransformation::Type type() const;
void setType(QwtScaleTransformation::Type type){d_type = type;}; void setType(ScaleTransformation::Type type){d_type = type;};
bool hasBreak() const; bool hasBreak() const;
void clone(const ScaleEngine *engine); void clone(const ScaleEngine *engine);
...@@ -78,7 +96,10 @@ public: ...@@ -78,7 +96,10 @@ public:
void drawBreakDecoration(bool draw){d_break_decoration = draw;}; void drawBreakDecoration(bool draw){d_break_decoration = draw;};
private: private:
QwtScaleTransformation::Type d_type;
QwtScaleEngine *newScaleEngine() const;
ScaleTransformation::Type d_type;
double d_break_left, d_break_right; double d_break_left, d_break_right;
//! Position of axis break (% of axis length) //! Position of axis break (% of axis length)
int d_break_pos; int d_break_pos;
...@@ -94,17 +115,4 @@ private: ...@@ -94,17 +115,4 @@ private:
bool d_break_decoration; bool d_break_decoration;
}; };
class ScaleTransformation: public QwtScaleTransformation
{
public:
ScaleTransformation(const ScaleEngine *engine):QwtScaleTransformation(Other), d_engine(engine){};
virtual double xForm(double x, double, double, double p1, double p2) const;
virtual double invXForm(double x, double s1, double s2, double p1, double p2) const;
QwtScaleTransformation* copy() const;
private:
//! The scale engine that generates the transformation
const ScaleEngine* d_engine;
};
#endif #endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment