LimeReport/limereport/lraxisdata.cpp

350 lines
9.1 KiB
C++
Raw Normal View History

#include "lraxisdata.h"
2022-03-09 01:44:49 +03:00
#include <cmath>
#include <QDebug>
namespace LimeReport {
AxisData::AxisData(AxisType type, QObject *parent)
2022-03-09 01:44:49 +03:00
: QObject(parent), m_rangeMin(0), m_rangeMax(0),
m_minValue(0), m_maxValue(0), m_step(0),
2022-03-09 01:44:49 +03:00
m_delta(0), m_segmentCount(4), m_calculateAxisScale(false),
m_reverseDirection(false), m_manualMaximum(0),
m_manualMinimum(0), m_manualStep(0), m_isMaximumAutomatic(true),
m_isMinimumAutomatic(true), m_isStepAutomatic(true),
m_type(type)
{
2022-03-09 01:44:49 +03:00
}
2022-03-13 09:02:52 +03:00
QString AxisData::toString() const
{
// Just for debug purposes
QString str;
QTextStream stream(&str);
stream << "{ "
<< "min: " << m_minValue << ", max: " << m_maxValue << ", step: " << m_step
<< ", range min: " << m_rangeMin << ", range max: " << m_rangeMax << ", segments: " << m_segmentCount
<< ", reverseDiection: " << m_reverseDirection << ", calculateAxisScale: " << m_calculateAxisScale
<< ", manualMaxEnabled: " << !m_isMaximumAutomatic << ", manualMinEnabled: " << !m_isMinimumAutomatic
<< ", manualStepEnabled: " << !m_isStepAutomatic << ", manualMax: " << m_manualMaximum
<< ", manualMin: " << m_manualMinimum << ", manualStep: " << m_manualStep
<< " }";
return str;
}
2022-03-09 01:44:49 +03:00
void AxisData::copy(AxisData *other)
{
m_calculateAxisScale = other->calculateAxisScale();
m_reverseDirection = other->reverseDirection();
m_manualMaximum = other->manualMaximum();
m_manualMinimum = other->manualMinimum();
m_manualStep = other->manualStep();
m_isMaximumAutomatic = other->isMaximumAutomatic();
m_isMinimumAutomatic = other->isMinimumAutomatic();
m_isStepAutomatic = other->isStepAutomatic();
}
2022-03-09 01:44:49 +03:00
void AxisData::update()
{
if (m_calculateAxisScale) {
calculateRoundedAxisScale();
} else {
calculateSimpleAxisScale();
}
m_delta = m_step * m_segmentCount;
// Update manual values if they are automatic
if (m_isStepAutomatic) {
m_manualStep = m_step;
}
if (m_isMinimumAutomatic) {
m_manualMinimum = m_rangeMin;
}
if (m_isMaximumAutomatic) {
m_manualMaximum = m_rangeMax;
}
2022-03-09 01:44:49 +03:00
}
void AxisData::update(qreal minValue, qreal maxValue)
{
m_minValue = minValue;
m_maxValue = maxValue;
2022-03-09 01:44:49 +03:00
update();
}
2022-03-10 22:35:48 +03:00
void AxisData::updateForDesignMode()
{
m_minValue = 0;
m_maxValue = 40;
const bool tmp = m_calculateAxisScale;
2022-03-10 22:35:48 +03:00
m_calculateAxisScale = false;
update();
m_calculateAxisScale = tmp;
}
int AxisData::segmentCount() const
{
return m_segmentCount;
}
2022-03-09 01:44:49 +03:00
bool AxisData::calculateAxisScale() const
{
return m_calculateAxisScale;
}
qreal AxisData::rangeMin() const
{
return m_rangeMin;
}
qreal AxisData::rangeMax() const
{
return m_rangeMax;
}
qreal AxisData::minValue() const
{
return m_minValue;
}
qreal AxisData::maxValue() const
{
return m_maxValue;
}
qreal AxisData::step() const
{
return m_step;
}
qreal AxisData::delta() const
{
return m_delta;
}
2022-03-09 01:44:49 +03:00
void AxisData::calculateRoundedAxisScale()
{
const int maximumSegmentCount = 10;
bool calculateStep = isStepAutomatic();
const bool calculateMinimum = isMinimumAutomatic();
const bool calculateMaximum = isMaximumAutomatic();
2022-03-13 09:02:52 +03:00
qreal temporaryMin = 0;
qreal temporaryMax = 0;
if (calculateMinimum) {
2022-03-14 12:04:13 +03:00
temporaryMin = qMin(0.0, minValue());
2022-03-13 09:02:52 +03:00
} else {
temporaryMin = qMin(manualMinimum(), minValue());
}
if (calculateMaximum) {
temporaryMax = maxValue();
} else {
temporaryMax = qMax(manualMaximum(), maxValue());
}
2022-03-09 01:44:49 +03:00
m_step = calculateStep ? 0 : manualStep();
if (temporaryMax == temporaryMin) {
if (temporaryMax == 0) {
temporaryMax = 1;
} else {
temporaryMax *= 2;
}
}
const qreal minAndMaxSpacingOffset = 0.95;
qreal stepMagnitude = 0.0;
qreal normalizedStep = 0.0;
bool isStepNormalized = false;
bool isLoopFinished = false;
// Calculate until segment count is below maximum
while( !isLoopFinished ) {
if (calculateStep) {
if(isStepNormalized) {
if( normalizedStep == 1.0 ) {
normalizedStep = 2.0;
} else if( normalizedStep == 2.0 ) {
normalizedStep = 5.0;
} else {
normalizedStep = 1.0;
stepMagnitude *= 10;
}
} else {
const double startingStep = (temporaryMax - temporaryMin) / maximumSegmentCount;
const int exponent = static_cast< int >( floor( log10( startingStep ) ) );
stepMagnitude = pow(10.0, static_cast<double>(exponent));
normalizedStep = startingStep / stepMagnitude;
if( normalizedStep <= 1.0 ) {
normalizedStep = 1.0;
} else if( normalizedStep <= 2.0 ) {
normalizedStep = 2.0;
} else if( normalizedStep <= 5.0 ) {
normalizedStep = 5.0;
} else {
normalizedStep = 1.0;
stepMagnitude *= 10;
}
isStepNormalized = true;
}
m_step = normalizedStep * stepMagnitude;
}
qreal currentAxisMinimum = temporaryMin;
qreal currentAxisMaximum = temporaryMax;
if (calculateMinimum) {
currentAxisMinimum = calculateNewMinimum(currentAxisMinimum, m_step);
const qreal currentDelta = currentAxisMaximum - currentAxisMinimum;
const qreal actualDelta = currentAxisMaximum - minValue();
if ((currentAxisMinimum != 0.0) && ((actualDelta / currentDelta) > minAndMaxSpacingOffset)) {
currentAxisMinimum -= m_step;
}
}
if (calculateMaximum) {
currentAxisMaximum = calculateNewMaximum(currentAxisMaximum, m_step);
const qreal currentDelta = currentAxisMaximum - currentAxisMinimum;
const qreal actualDelta = maxValue() - currentAxisMinimum;
if ((currentAxisMaximum != 0.0) && ((actualDelta / currentDelta) > minAndMaxSpacingOffset)) {
currentAxisMaximum += m_step;
}
}
m_segmentCount = static_cast<int>(round((currentAxisMaximum - currentAxisMinimum) / m_step));
m_rangeMin = currentAxisMinimum;
m_rangeMax = currentAxisMaximum;
2022-03-14 12:04:13 +03:00
// Check also if step is correctly calucalted. It is possible for float steps that
// there might be a difference. Recalculate the step in that case.
const qreal tmpStep = (m_rangeMax - m_rangeMin) / m_segmentCount;
isLoopFinished = m_segmentCount <= maximumSegmentCount && qFuzzyCompare(tmpStep, m_step);
2022-03-09 01:44:49 +03:00
if (!isLoopFinished) {
// Configured step may be invalid, calculating it automatically
calculateStep = true;
}
}
}
void AxisData::calculateSimpleAxisScale()
{
2022-03-14 12:04:13 +03:00
qreal min = 0;
if (m_minValue < 0) {
min = minValue();
}
2022-03-09 01:44:49 +03:00
m_segmentCount = 4;
2022-03-14 12:04:13 +03:00
const int delta = maxValue() - min;
int max = delta;
2022-03-09 01:44:49 +03:00
while (max % m_segmentCount != 0){
max++;
}
m_rangeMax = minValue() + max;
2022-03-09 01:44:49 +03:00
m_step = max / m_segmentCount;
m_rangeMin = minValue();
}
double AxisData::calculateNewMinimum(qreal min, qreal step) const
{
if (step <= 0.0)
return min;
double ret = floor(min / step) * step;
if (ret > min && !qFuzzyCompare(ret, min)) {
ret -= step;
}
return ret;
}
2022-03-09 01:44:49 +03:00
double AxisData::calculateNewMaximum(qreal max, qreal step) const
{
if (step <= 0.0)
return max;
double ret = floor(max / step) * step;
if (ret < max && !qFuzzyCompare(ret, max)) {
ret += step;
}
return ret;
}
void AxisData::setCalculateAxisScale(bool newCalculateAxisScale)
{
m_calculateAxisScale = newCalculateAxisScale;
}
bool AxisData::reverseDirection() const
{
return m_reverseDirection;
}
void AxisData::setReverseDirection(bool reverseDirection)
{
m_reverseDirection = reverseDirection;
}
qreal AxisData::manualMaximum() const
{
return m_manualMaximum;
}
void AxisData::setManualMaximum(qreal newManualMaximum)
{
m_manualMaximum = newManualMaximum;
}
qreal AxisData::manualMinimum() const
{
return m_manualMinimum;
}
void AxisData::setManualMinimum(qreal newManualMinimum)
{
m_manualMinimum = newManualMinimum;
}
qreal AxisData::manualStep() const
{
return m_manualStep;
}
void AxisData::setManualStep(qreal newManualStep)
{
m_manualStep = newManualStep;
}
bool AxisData::isMaximumAutomatic() const
{
return m_isMaximumAutomatic;
}
void AxisData::setIsMaximumAutomatic(bool newIsMaximumAutomatic)
{
m_isMaximumAutomatic = newIsMaximumAutomatic;
}
bool AxisData::isMinimumAutomatic() const
{
return m_isMinimumAutomatic;
}
void AxisData::setIsMinimumAutomatic(bool newIsMinimumAutomatic)
{
m_isMinimumAutomatic = newIsMinimumAutomatic;
}
bool AxisData::isStepAutomatic() const
{
return m_isStepAutomatic;
}
void AxisData::setIsStepAutomatic(bool newIsStepAutomatic)
{
m_isStepAutomatic = newIsStepAutomatic;
}
AxisData::AxisType AxisData::type() const
{
return m_type;
}
}