diff options
author | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2013-04-16 10:07:13 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2013-04-17 10:14:43 +0300 |
commit | f494279b6366b06e3eeeb4f8c006ce76b08f10d7 (patch) | |
tree | 26951efa14e26eb0791d13ea32624e9afcf48851 /src/domain | |
parent | 56fd46a395765db6818f890676e42cc59a9f4a81 (diff) |
Add Polar chart support
This commit also heavily refactors things as polar chart needs
separate implementation of various classes that previously
only needed one, such as ChartAxis and ChartLayout.
Task-number: QTRD-1757
Change-Id: I3d3db23920314987ceef3ae92879960b833b7136
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com>
Diffstat (limited to 'src/domain')
-rw-r--r-- | src/domain/abstractdomain.cpp | 37 | ||||
-rw-r--r-- | src/domain/abstractdomain_p.h | 20 | ||||
-rw-r--r-- | src/domain/domain.pri | 14 | ||||
-rw-r--r-- | src/domain/logxlogydomain.cpp | 31 | ||||
-rw-r--r-- | src/domain/logxlogydomain_p.h | 6 | ||||
-rw-r--r-- | src/domain/logxlogypolardomain.cpp | 267 | ||||
-rw-r--r-- | src/domain/logxlogypolardomain_p.h | 81 | ||||
-rw-r--r-- | src/domain/logxydomain.cpp | 26 | ||||
-rw-r--r-- | src/domain/logxydomain_p.h | 6 | ||||
-rw-r--r-- | src/domain/logxypolardomain.cpp | 236 | ||||
-rw-r--r-- | src/domain/logxypolardomain_p.h | 77 | ||||
-rw-r--r-- | src/domain/polardomain.cpp | 91 | ||||
-rw-r--r-- | src/domain/polardomain_p.h | 62 | ||||
-rw-r--r-- | src/domain/xlogydomain.cpp | 26 | ||||
-rw-r--r-- | src/domain/xlogydomain_p.h | 6 | ||||
-rw-r--r-- | src/domain/xlogypolardomain.cpp | 231 | ||||
-rw-r--r-- | src/domain/xlogypolardomain_p.h | 77 | ||||
-rw-r--r-- | src/domain/xydomain.cpp | 10 | ||||
-rw-r--r-- | src/domain/xydomain_p.h | 2 | ||||
-rw-r--r-- | src/domain/xypolardomain.cpp | 178 | ||||
-rw-r--r-- | src/domain/xypolardomain_p.h | 65 |
21 files changed, 1476 insertions, 73 deletions
diff --git a/src/domain/abstractdomain.cpp b/src/domain/abstractdomain.cpp index bcaa5164..277472d1 100644 --- a/src/domain/abstractdomain.cpp +++ b/src/domain/abstractdomain.cpp @@ -38,7 +38,7 @@ AbstractDomain::~AbstractDomain() { } -void AbstractDomain::setSize(const QSizeF& size) +void AbstractDomain::setSize(const QSizeF &size) { if(m_size!=size) { @@ -122,9 +122,9 @@ void AbstractDomain::handleHorizontalAxisRangeChanged(qreal min, qreal max) void AbstractDomain::blockRangeSignals(bool block) { - if(m_signalsBlocked!=block){ + if (m_signalsBlocked!=block) { m_signalsBlocked=block; - if(!block) { + if (!block) { emit rangeHorizontalChanged(m_minX,m_maxX); emit rangeVerticalChanged(m_minY,m_maxY); } @@ -165,14 +165,14 @@ qreal AbstractDomain::niceNumber(qreal x, bool ceiling) return q * z; } -bool AbstractDomain::attachAxis(QAbstractAxis* axis) +bool AbstractDomain::attachAxis(QAbstractAxis *axis) { - if(axis->orientation()==Qt::Vertical) { + if (axis->orientation() == Qt::Vertical) { QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleVerticalAxisRangeChanged(qreal,qreal))); QObject::connect(this, SIGNAL(rangeVerticalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); } - if(axis->orientation()==Qt::Horizontal) { + if (axis->orientation() == Qt::Horizontal) { QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleHorizontalAxisRangeChanged(qreal,qreal))); QObject::connect(this, SIGNAL(rangeHorizontalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); } @@ -180,14 +180,14 @@ bool AbstractDomain::attachAxis(QAbstractAxis* axis) return true; } -bool AbstractDomain::detachAxis(QAbstractAxis* axis) +bool AbstractDomain::detachAxis(QAbstractAxis *axis) { - if(axis->orientation()==Qt::Vertical) { + if (axis->orientation() == Qt::Vertical) { QObject::disconnect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleVerticalAxisRangeChanged(qreal,qreal))); QObject::disconnect(this, SIGNAL(rangeVerticalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); } - if(axis->orientation()==Qt::Horizontal) { + if (axis->orientation() == Qt::Horizontal) { QObject::disconnect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleHorizontalAxisRangeChanged(qreal,qreal))); QObject::disconnect(this, SIGNAL(rangeHorizontalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal))); } @@ -199,10 +199,10 @@ bool AbstractDomain::detachAxis(QAbstractAxis* axis) bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const AbstractDomain &domain1, const AbstractDomain &domain2) { - return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) && - qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) && - qFuzzyIsNull(domain1.m_minX - domain2.m_minX) && - qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); + return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) + && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) + && qFuzzyIsNull(domain1.m_minX - domain2.m_minX) + && qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); } @@ -218,6 +218,17 @@ QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const AbstractDo return dbg.maybeSpace(); } +// This function adjusts min/max ranges to failsafe values if negative/zero values are attempted. +void AbstractDomain::adjustLogDomainRanges(qreal &min, qreal &max) +{ + if (min <= 0) { + min = 1.0; + if (max <= min) + max = min + 1.0; + } +} + + #include "moc_abstractdomain_p.cpp" QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/abstractdomain_p.h b/src/domain/abstractdomain_p.h index 907cccff..cf7c2bac 100644 --- a/src/domain/abstractdomain_p.h +++ b/src/domain/abstractdomain_p.h @@ -42,12 +42,20 @@ class QTCOMMERCIALCHART_AUTOTEST_EXPORT AbstractDomain: public QObject { Q_OBJECT public: - enum DomainType { UndefinedDomain, XYDomain, XLogYDomain, LogXYDomain, LogXLogYDomain }; + enum DomainType { UndefinedDomain, + XYDomain, + XLogYDomain, + LogXYDomain, + LogXLogYDomain, + XYPolarDomain, + XLogYPolarDomain, + LogXYPolarDomain, + LogXLogYPolarDomain }; public: explicit AbstractDomain(QObject *object = 0); virtual ~AbstractDomain(); - void setSize(const QSizeF& size); + virtual void setSize(const QSizeF &size); QSizeF size() const; virtual DomainType type() = 0; @@ -82,10 +90,10 @@ public: virtual QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const = 0; virtual QPointF calculateDomainPoint(const QPointF &point) const = 0; - virtual QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const = 0; + virtual QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const = 0; - virtual bool attachAxis(QAbstractAxis* axis); - virtual bool detachAxis(QAbstractAxis* axis); + virtual bool attachAxis(QAbstractAxis *axis); + virtual bool detachAxis(QAbstractAxis *axis); static void looseNiceNumbers(qreal &min, qreal &max, int &ticksCount); static qreal niceNumber(qreal x, bool ceiling); @@ -100,6 +108,8 @@ public Q_SLOTS: void handleHorizontalAxisRangeChanged(qreal min,qreal max); protected: + void adjustLogDomainRanges(qreal &min, qreal &max); + qreal m_minX; qreal m_maxX; qreal m_minY; diff --git a/src/domain/domain.pri b/src/domain/domain.pri index 1d5823d1..ab4fcfce 100644 --- a/src/domain/domain.pri +++ b/src/domain/domain.pri @@ -5,14 +5,24 @@ DEPENDPATH += $$PWD SOURCES += \ $$PWD/abstractdomain.cpp \ + $$PWD/polardomain.cpp \ $$PWD/xydomain.cpp \ + $$PWD/xypolardomain.cpp \ $$PWD/xlogydomain.cpp \ + $$PWD/xlogypolardomain.cpp \ $$PWD/logxydomain.cpp \ - $$PWD/logxlogydomain.cpp + $$PWD/logxypolardomain.cpp \ + $$PWD/logxlogydomain.cpp \ + $$PWD/logxlogypolardomain.cpp PRIVATE_HEADERS += \ $$PWD/abstractdomain_p.h \ + $$PWD/polardomain_p.h \ $$PWD/xydomain_p.h \ + $$PWD/xypolardomain_p.h \ $$PWD/xlogydomain_p.h \ + $$PWD/xlogypolardomain_p.h \ $$PWD/logxydomain_p.h \ - $$PWD/logxlogydomain_p.h + $$PWD/logxypolardomain_p.h \ + $$PWD/logxlogydomain_p.h \ + $$PWD/logxlogypolardomain_p.h diff --git a/src/domain/logxlogydomain.cpp b/src/domain/logxlogydomain.cpp index 7032d137..adb9bc1d 100644 --- a/src/domain/logxlogydomain.cpp +++ b/src/domain/logxlogydomain.cpp @@ -45,6 +45,9 @@ void LogXLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) bool axisXChanged = false; bool axisYChanged = false; + adjustLogDomainRanges(minX, maxX); + adjustLogDomainRanges(minY, maxY); + if (!qFuzzyIsNull(m_minX - minX) || !qFuzzyIsNull(m_maxX - maxX)) { m_minX = minX; m_maxX = maxX; @@ -65,7 +68,7 @@ void LogXLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) qreal logMaxY = log10(m_maxY) / log10(m_logBaseY); m_logLeftY = logMinY < logMaxY ? logMinY : logMaxY; m_logRightY = logMinY > logMaxY ? logMinY : logMaxY; - if(!m_signalsBlocked) + if (!m_signalsBlocked) emit rangeVerticalChanged(m_minY, m_maxY); } @@ -141,13 +144,13 @@ QPointF LogXLogYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) c ok = true; return QPointF(x, y); } else { - qWarning() << "Logarithm of negative value is undefined. Empty layout returned"; + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; ok = false; return QPointF(); } } -QVector<QPointF> LogXLogYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const +QVector<QPointF> LogXLogYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const { const qreal deltaX = m_size.width() / qAbs(m_logRightX - m_logLeftX); const qreal deltaY = m_size.height() / qAbs(m_logRightY - m_logLeftY); @@ -162,7 +165,7 @@ QVector<QPointF> LogXLogYDomain::calculateGeometryPoints(const QList<QPointF>& v result[i].setX(x); result[i].setY(y); } else { - qWarning() << "Logarithm of negative value is undefined. Empty layout returned"; + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; return QVector<QPointF>(); } } @@ -178,17 +181,17 @@ QPointF LogXLogYDomain::calculateDomainPoint(const QPointF &point) const return QPointF(x, y); } -bool LogXLogYDomain::attachAxis(QAbstractAxis* axis) +bool LogXLogYDomain::attachAxis(QAbstractAxis *axis) { AbstractDomain::attachAxis(axis); QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); - if(logAxis && logAxis->orientation()==Qt::Vertical) { + if (logAxis && logAxis->orientation() == Qt::Vertical) { QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); handleVerticalAxisBaseChanged(logAxis->base()); } - if(logAxis && logAxis->orientation()==Qt::Horizontal) { + if (logAxis && logAxis->orientation() == Qt::Horizontal) { QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); handleHorizontalAxisBaseChanged(logAxis->base()); } @@ -196,15 +199,15 @@ bool LogXLogYDomain::attachAxis(QAbstractAxis* axis) return true; } -bool LogXLogYDomain::detachAxis(QAbstractAxis* axis) +bool LogXLogYDomain::detachAxis(QAbstractAxis *axis) { AbstractDomain::detachAxis(axis); QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); - if(logAxis && logAxis->orientation()==Qt::Vertical) + if (logAxis && logAxis->orientation() == Qt::Vertical) QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); - if(logAxis && logAxis->orientation()==Qt::Horizontal) + if (logAxis && logAxis->orientation() == Qt::Horizontal) QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); return true; @@ -234,10 +237,10 @@ void LogXLogYDomain::handleHorizontalAxisBaseChanged(qreal baseX) bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXLogYDomain &domain1, const LogXLogYDomain &domain2) { - return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) && - qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) && - qFuzzyIsNull(domain1.m_minX - domain2.m_minX) && - qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); + return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) + && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) + && qFuzzyIsNull(domain1.m_minX - domain2.m_minX) + && qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); } diff --git a/src/domain/logxlogydomain_p.h b/src/domain/logxlogydomain_p.h index 2d604163..014bf803 100644 --- a/src/domain/logxlogydomain_p.h +++ b/src/domain/logxlogydomain_p.h @@ -56,10 +56,10 @@ public: QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const; QPointF calculateDomainPoint(const QPointF &point) const; - QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const; + QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const; - bool attachAxis(QAbstractAxis* axis); - bool detachAxis(QAbstractAxis* axis); + bool attachAxis(QAbstractAxis *axis); + bool detachAxis(QAbstractAxis *axis); public Q_SLOTS: void handleVerticalAxisBaseChanged(qreal baseY); diff --git a/src/domain/logxlogypolardomain.cpp b/src/domain/logxlogypolardomain.cpp new file mode 100644 index 00000000..a193ce11 --- /dev/null +++ b/src/domain/logxlogypolardomain.cpp @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "logxlogypolardomain_p.h" +#include "qabstractaxis_p.h" +#include "qlogvalueaxis.h" +#include <qmath.h> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +LogXLogYPolarDomain::LogXLogYPolarDomain(QObject *parent) + : PolarDomain(parent), + m_logLeftX(0), + m_logRightX(1), + m_logBaseX(10), + m_logInnerY(0), + m_logOuterY(1), + m_logBaseY(10) +{ +} + +LogXLogYPolarDomain::~LogXLogYPolarDomain() +{ +} + +void LogXLogYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) +{ + bool axisXChanged = false; + bool axisYChanged = false; + + adjustLogDomainRanges(minX, maxX); + adjustLogDomainRanges(minY, maxY); + + if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) { + m_minX = minX; + m_maxX = maxX; + axisXChanged = true; + qreal logMinX = log10(m_minX) / log10(m_logBaseX); + qreal logMaxX = log10(m_maxX) / log10(m_logBaseX); + m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX; + m_logRightX = logMinX > logMaxX ? logMinX : logMaxX; + if (!m_signalsBlocked) + emit rangeHorizontalChanged(m_minX, m_maxX); + } + + if (!qFuzzyIsNull(m_minY - minY) || !qFuzzyIsNull(m_maxY - maxY)) { + m_minY = minY; + m_maxY = maxY; + axisYChanged = true; + qreal logMinY = log10(m_minY) / log10(m_logBaseY); + qreal logMaxY = log10(m_maxY) / log10(m_logBaseY); + m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY; + m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY; + if (!m_signalsBlocked) + emit rangeVerticalChanged(m_minY, m_maxY); + } + + if (axisXChanged || axisYChanged) + emit updated(); +} + +void LogXLogYPolarDomain::zoomIn(const QRectF &rect) +{ + qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + qreal leftX = qPow(m_logBaseX, logLeftX); + qreal rightX = qPow(m_logBaseX, logRightX); + qreal minX = leftX < rightX ? leftX : rightX; + qreal maxX = leftX > rightX ? leftX : rightX; + + qreal logLeftY = m_logOuterY - rect.bottom() * (m_logOuterY - m_logInnerY) / m_size.height(); + qreal logRightY = m_logOuterY - rect.top() * (m_logOuterY - m_logInnerY) / m_size.height(); + qreal leftY = qPow(m_logBaseY, logLeftY); + qreal rightY = qPow(m_logBaseY, logRightY); + qreal minY = leftY < rightY ? leftY : rightY; + qreal maxY = leftY > rightY ? leftY : rightY; + + setRange(minX, maxX, minY, maxY); +} + +void LogXLogYPolarDomain::zoomOut(const QRectF &rect) +{ + const qreal factorX = m_size.width() / rect.width(); + + qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 - factorX); + qreal logRIghtX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 + factorX); + qreal leftX = qPow(m_logBaseX, logLeftX); + qreal rightX = qPow(m_logBaseX, logRIghtX); + qreal minX = leftX < rightX ? leftX : rightX; + qreal maxX = leftX > rightX ? leftX : rightX; + + const qreal factorY = m_size.height() / rect.height(); + qreal newLogMinY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 - factorY); + qreal newLogMaxY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 + factorY); + qreal leftY = qPow(m_logBaseY, newLogMinY); + qreal rightY = qPow(m_logBaseY, newLogMaxY); + qreal minY = leftY < rightY ? leftY : rightY; + qreal maxY = leftY > rightY ? leftY : rightY; + + setRange(minX, maxX, minY, maxY); +} + +void LogXLogYPolarDomain::move(qreal dx, qreal dy) +{ + qreal stepX = dx * (m_logRightX - m_logLeftX) / m_size.width(); + qreal leftX = qPow(m_logBaseX, m_logLeftX + stepX); + qreal rightX = qPow(m_logBaseX, m_logRightX + stepX); + qreal minX = leftX < rightX ? leftX : rightX; + qreal maxX = leftX > rightX ? leftX : rightX; + + qreal stepY = dy * (m_logOuterY - m_logInnerY) / m_radius; + qreal leftY = qPow(m_logBaseY, m_logInnerY + stepY); + qreal rightY = qPow(m_logBaseY, m_logOuterY + stepY); + qreal minY = leftY < rightY ? leftY : rightY; + qreal maxY = leftY > rightY ? leftY : rightY; + + setRange(minX, maxX, minY, maxY); +} + +qreal LogXLogYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const +{ + qreal retVal; + if (value <= 0) { + ok = false; + retVal = 0.0; + } else { + ok = true; + const qreal tickSpan = 360.0 / qAbs(m_logRightX - m_logLeftX); + const qreal logValue = log10(value) / log10(m_logBaseX); + const qreal valueDelta = logValue - m_logLeftX; + + retVal = valueDelta * tickSpan; + } + return retVal; +} + +qreal LogXLogYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const +{ + qreal retVal; + if (value <= 0) { + ok = false; + retVal = 0.0; + } else { + ok = true; + const qreal tickSpan = m_radius / qAbs(m_logOuterY - m_logInnerY); + const qreal logValue = log10(value) / log10(m_logBaseY); + const qreal valueDelta = logValue - m_logInnerY; + + retVal = valueDelta * tickSpan; + + if (retVal < 0.0) + retVal = 0.0; + } + return retVal; +} + +QPointF LogXLogYPolarDomain::calculateDomainPoint(const QPointF &point) const +{ + if (point == m_center) + return QPointF(0.0, m_minY); + + QLineF line(m_center, point); + qreal a = 90.0 - line.angle(); + if (a < 0.0) + a += 360.0; + + const qreal deltaX = 360.0 / qAbs(m_logRightX - m_logLeftX); + a = qPow(m_logBaseX, m_logLeftX + (a / deltaX)); + + const qreal deltaY = m_radius / qAbs(m_logOuterY - m_logInnerY); + qreal r = qPow(m_logBaseY, m_logInnerY + (line.length() / deltaY)); + + return QPointF(a, r); +} + +bool LogXLogYPolarDomain::attachAxis(QAbstractAxis *axis) +{ + AbstractDomain::attachAxis(axis); + QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); + + if (logAxis && logAxis->orientation() == Qt::Horizontal) { + QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); + handleHorizontalAxisBaseChanged(logAxis->base()); + } else if (logAxis && logAxis->orientation() == Qt::Vertical){ + QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); + handleVerticalAxisBaseChanged(logAxis->base()); + } + + return true; +} + +bool LogXLogYPolarDomain::detachAxis(QAbstractAxis *axis) +{ + AbstractDomain::detachAxis(axis); + QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); + + if (logAxis && logAxis->orientation() == Qt::Horizontal) + QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); + else if (logAxis && logAxis->orientation() == Qt::Vertical) + QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); + + return true; +} + +void LogXLogYPolarDomain::handleHorizontalAxisBaseChanged(qreal baseX) +{ + m_logBaseX = baseX; + qreal logMinX = log10(m_minX) / log10(m_logBaseX); + qreal logMaxX = log10(m_maxX) / log10(m_logBaseX); + m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX; + m_logRightX = logMinX > logMaxX ? logMinX : logMaxX; + emit updated(); +} + +void LogXLogYPolarDomain::handleVerticalAxisBaseChanged(qreal baseY) +{ + m_logBaseY = baseY; + qreal logMinY = log10(m_minY) / log10(m_logBaseY); + qreal logMaxY = log10(m_maxY) / log10(m_logBaseY); + m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY; + m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY; + emit updated(); +} + +// operators + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2) +{ + return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) + && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) + && qFuzzyIsNull(domain1.m_minX - domain2.m_minX) + && qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); +} + + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2) +{ + return !(domain1 == domain2); +} + + +QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXLogYPolarDomain &domain) +{ + dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size; + return dbg.maybeSpace(); +} + +#include "moc_logxlogypolardomain_p.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/logxlogypolardomain_p.h b/src/domain/logxlogypolardomain_p.h new file mode 100644 index 00000000..106f58a6 --- /dev/null +++ b/src/domain/logxlogypolardomain_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the QtCommercial Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef LOGXLOGYPOLARDOMAIN_H +#define LOGXLOGYPOLARDOMAIN_H +#include "polardomain_p.h" +#include <QRectF> +#include <QSizeF> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_AUTOTEST_EXPORT LogXLogYPolarDomain: public PolarDomain +{ + Q_OBJECT +public: + explicit LogXLogYPolarDomain(QObject *object = 0); + virtual ~LogXLogYPolarDomain(); + + DomainType type() { return AbstractDomain::LogXLogYPolarDomain; } + + void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY); + + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2); + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2); + friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXLogYPolarDomain &domain); + + void zoomIn(const QRectF &rect); + void zoomOut(const QRectF &rect); + void move(qreal dx, qreal dy); + + QPointF calculateDomainPoint(const QPointF &point) const; + + bool attachAxis(QAbstractAxis *axis); + bool detachAxis(QAbstractAxis *axis); + +public Q_SLOTS: + void handleVerticalAxisBaseChanged(qreal baseY); + void handleHorizontalAxisBaseChanged(qreal baseX); + +protected: + qreal toAngularCoordinate(qreal value, bool &ok) const; + qreal toRadialCoordinate(qreal value, bool &ok) const; + +private: + qreal m_logLeftX; + qreal m_logRightX; + qreal m_logBaseX; + qreal m_logInnerY; + qreal m_logOuterY; + qreal m_logBaseY; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // LOGXLOGYPOLARDOMAIN_H diff --git a/src/domain/logxydomain.cpp b/src/domain/logxydomain.cpp index ffa739bf..da6e210a 100644 --- a/src/domain/logxydomain.cpp +++ b/src/domain/logxydomain.cpp @@ -42,6 +42,8 @@ void LogXYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) bool axisXChanged = false; bool axisYChanged = false; + adjustLogDomainRanges(minX, maxX); + if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) { m_minX = minX; m_maxX = maxX; @@ -58,7 +60,7 @@ void LogXYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) m_minY = minY; m_maxY = maxY; axisYChanged = true; - if(!m_signalsBlocked) + if (!m_signalsBlocked) emit rangeVerticalChanged(m_minY, m_maxY); } @@ -137,13 +139,13 @@ QPointF LogXYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) cons ok = true; return QPointF(x, y); } else { - qWarning() << "Logarithm of negative value is undefined. Empty layout returned"; + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; ok = false; return QPointF(); } } -QVector<QPointF> LogXYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const +QVector<QPointF> LogXYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const { const qreal deltaX = m_size.width() / (m_logRightX - m_logLeftX); const qreal deltaY = m_size.height() / (m_maxY - m_minY); @@ -158,7 +160,7 @@ QVector<QPointF> LogXYDomain::calculateGeometryPoints(const QList<QPointF>& vect result[i].setX(x); result[i].setY(y); } else { - qWarning() << "Logarithm of negative value is undefined. Empty layout returned"; + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; return QVector<QPointF>(); } } @@ -174,12 +176,12 @@ QPointF LogXYDomain::calculateDomainPoint(const QPointF &point) const return QPointF(x, y); } -bool LogXYDomain::attachAxis(QAbstractAxis* axis) +bool LogXYDomain::attachAxis(QAbstractAxis *axis) { AbstractDomain::attachAxis(axis); QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); - if(logAxis && logAxis->orientation()==Qt::Horizontal) { + if (logAxis && logAxis->orientation() == Qt::Horizontal) { QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); handleHorizontalAxisBaseChanged(logAxis->base()); } @@ -187,12 +189,12 @@ bool LogXYDomain::attachAxis(QAbstractAxis* axis) return true; } -bool LogXYDomain::detachAxis(QAbstractAxis* axis) +bool LogXYDomain::detachAxis(QAbstractAxis *axis) { AbstractDomain::detachAxis(axis); QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); - if(logAxis && logAxis->orientation()==Qt::Horizontal) + if (logAxis && logAxis->orientation() == Qt::Horizontal) QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); return true; @@ -212,10 +214,10 @@ void LogXYDomain::handleHorizontalAxisBaseChanged(qreal baseX) bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXYDomain &domain1, const LogXYDomain &domain2) { - return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) && - qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) && - qFuzzyIsNull(domain1.m_minX - domain2.m_minX) && - qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); + return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) + && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) + && qFuzzyIsNull(domain1.m_minX - domain2.m_minX) + && qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); } diff --git a/src/domain/logxydomain_p.h b/src/domain/logxydomain_p.h index cbc59e18..2f0e49ea 100644 --- a/src/domain/logxydomain_p.h +++ b/src/domain/logxydomain_p.h @@ -56,10 +56,10 @@ public: QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const; QPointF calculateDomainPoint(const QPointF &point) const; - QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const; + QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const; - bool attachAxis(QAbstractAxis* axis); - bool detachAxis(QAbstractAxis* axis); + bool attachAxis(QAbstractAxis *axis); + bool detachAxis(QAbstractAxis *axis); public Q_SLOTS: void handleHorizontalAxisBaseChanged(qreal baseX); diff --git a/src/domain/logxypolardomain.cpp b/src/domain/logxypolardomain.cpp new file mode 100644 index 00000000..b08f6a04 --- /dev/null +++ b/src/domain/logxypolardomain.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "logxypolardomain_p.h" +#include "qabstractaxis_p.h" +#include "qlogvalueaxis.h" +#include <qmath.h> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +LogXYPolarDomain::LogXYPolarDomain(QObject *parent) + : PolarDomain(parent), + m_logLeftX(0), + m_logRightX(1), + m_logBaseX(10) +{ +} + +LogXYPolarDomain::~LogXYPolarDomain() +{ +} + +void LogXYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) +{ + bool axisXChanged = false; + bool axisYChanged = false; + + adjustLogDomainRanges(minX, maxX); + + if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) { + m_minX = minX; + m_maxX = maxX; + axisXChanged = true; + qreal logMinX = log10(m_minX) / log10(m_logBaseX); + qreal logMaxX = log10(m_maxX) / log10(m_logBaseX); + m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX; + m_logRightX = logMinX > logMaxX ? logMinX : logMaxX; + if (!m_signalsBlocked) + emit rangeHorizontalChanged(m_minX, m_maxX); + } + + if (!qFuzzyIsNull(m_minY - minY) || !qFuzzyIsNull(m_maxY - maxY)) { + m_minY = minY; + m_maxY = maxY; + axisYChanged = true; + if (!m_signalsBlocked) + emit rangeVerticalChanged(m_minY, m_maxY); + } + + if (axisXChanged || axisYChanged) + emit updated(); +} + +void LogXYPolarDomain::zoomIn(const QRectF &rect) +{ + qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX; + qreal leftX = qPow(m_logBaseX, logLeftX); + qreal rightX = qPow(m_logBaseX, logRightX); + qreal minX = leftX < rightX ? leftX : rightX; + qreal maxX = leftX > rightX ? leftX : rightX; + + qreal dy = spanY() / m_size.height(); + qreal minY = m_minY; + qreal maxY = m_maxY; + + minY = maxY - dy * rect.bottom(); + maxY = maxY - dy * rect.top(); + + setRange(minX, maxX, minY, maxY); +} + +void LogXYPolarDomain::zoomOut(const QRectF &rect) +{ + const qreal factorX = m_size.width() / rect.width(); + + qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 - factorX); + qreal logRIghtX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 + factorX); + qreal leftX = qPow(m_logBaseX, logLeftX); + qreal rightX = qPow(m_logBaseX, logRIghtX); + qreal minX = leftX < rightX ? leftX : rightX; + qreal maxX = leftX > rightX ? leftX : rightX; + + qreal dy = spanY() / rect.height(); + qreal minY = m_minY; + qreal maxY = m_maxY; + + maxY = minY + dy * rect.bottom(); + minY = maxY - dy * m_size.height(); + + setRange(minX, maxX, minY, maxY); +} + +void LogXYPolarDomain::move(qreal dx, qreal dy) +{ + qreal stepX = dx * (m_logRightX - m_logLeftX) / m_size.width(); + qreal leftX = qPow(m_logBaseX, m_logLeftX + stepX); + qreal rightX = qPow(m_logBaseX, m_logRightX + stepX); + qreal minX = leftX < rightX ? leftX : rightX; + qreal maxX = leftX > rightX ? leftX : rightX; + + qreal y = spanY() / m_radius; + qreal minY = m_minY; + qreal maxY = m_maxY; + + if (dy != 0) { + minY = minY + y * dy; + maxY = maxY + y * dy; + } + setRange(minX, maxX, minY, maxY); +} + +qreal LogXYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const +{ + qreal retVal; + if (value <= 0) { + ok = false; + retVal = 0.0; + } else { + ok = true; + const qreal tickSpan = 360.0 / qAbs(m_logRightX - m_logLeftX); + const qreal logValue = log10(value) / log10(m_logBaseX); + const qreal valueDelta = logValue - m_logLeftX; + + retVal = valueDelta * tickSpan; + } + return retVal; +} + +qreal LogXYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const +{ + ok = true; + if (value < m_minY) + value = m_minY; + + // Dont limit the max. The drawing should clip the stuff that goes out of the grid + qreal f = (value - m_minY) / (m_maxY - m_minY); + + return f * m_radius; +} + +QPointF LogXYPolarDomain::calculateDomainPoint(const QPointF &point) const +{ + if (point == m_center) + return QPointF(0.0, m_minY); + + QLineF line(m_center, point); + qreal a = 90.0 - line.angle(); + if (a < 0.0) + a += 360.0; + + const qreal deltaX = 360.0 / qAbs(m_logRightX - m_logLeftX); + a = qPow(m_logBaseX, m_logLeftX + (a / deltaX)); + + qreal r = m_minY + ((m_maxY - m_minY) * (line.length() / m_radius)); + + return QPointF(a, r); +} + +bool LogXYPolarDomain::attachAxis(QAbstractAxis *axis) +{ + AbstractDomain::attachAxis(axis); + QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); + + if (logAxis && logAxis->orientation() == Qt::Horizontal) { + QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); + handleHorizontalAxisBaseChanged(logAxis->base()); + } + + return true; +} + +bool LogXYPolarDomain::detachAxis(QAbstractAxis *axis) +{ + AbstractDomain::detachAxis(axis); + QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); + + if (logAxis && logAxis->orientation() == Qt::Horizontal) + QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal))); + + return true; +} + +void LogXYPolarDomain::handleHorizontalAxisBaseChanged(qreal baseX) +{ + m_logBaseX = baseX; + qreal logMinX = log10(m_minX) / log10(m_logBaseX); + qreal logMaxX = log10(m_maxX) / log10(m_logBaseX); + m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX; + m_logRightX = logMinX > logMaxX ? logMinX : logMaxX; + emit updated(); +} + +// operators + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2) +{ + return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) + && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) + && qFuzzyIsNull(domain1.m_minX - domain2.m_minX) + && qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); +} + + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2) +{ + return !(domain1 == domain2); +} + + +QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXYPolarDomain &domain) +{ + dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size; + return dbg.maybeSpace(); +} + +#include "moc_logxypolardomain_p.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/logxypolardomain_p.h b/src/domain/logxypolardomain_p.h new file mode 100644 index 00000000..c7468ab9 --- /dev/null +++ b/src/domain/logxypolardomain_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the QtCommercial Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef LOGXYPOLARDOMAIN_H +#define LOGXYPOLARDOMAIN_H +#include "polardomain_p.h" +#include <QRectF> +#include <QSizeF> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_AUTOTEST_EXPORT LogXYPolarDomain: public PolarDomain +{ + Q_OBJECT +public: + explicit LogXYPolarDomain(QObject *object = 0); + virtual ~LogXYPolarDomain(); + + DomainType type() { return AbstractDomain::LogXYPolarDomain; } + + void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY); + + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2); + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2); + friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXYPolarDomain &domain); + + void zoomIn(const QRectF &rect); + void zoomOut(const QRectF &rect); + void move(qreal dx, qreal dy); + + QPointF calculateDomainPoint(const QPointF &point) const; + + bool attachAxis(QAbstractAxis *axis); + bool detachAxis(QAbstractAxis *axis); + +public Q_SLOTS: + void handleHorizontalAxisBaseChanged(qreal baseX); + +protected: + qreal toAngularCoordinate(qreal value, bool &ok) const; + qreal toRadialCoordinate(qreal value, bool &ok) const; + +private: + qreal m_logLeftX; + qreal m_logRightX; + qreal m_logBaseX; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // LOGXYPOLARDOMAIN_H diff --git a/src/domain/polardomain.cpp b/src/domain/polardomain.cpp new file mode 100644 index 00000000..d9a9d48f --- /dev/null +++ b/src/domain/polardomain.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "polardomain_p.h" +#include "qabstractaxis_p.h" +#include <qmath.h> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +PolarDomain::PolarDomain(QObject *parent) + : AbstractDomain(parent) +{ +} + +PolarDomain::~PolarDomain() +{ +} + +void PolarDomain::setSize(const QSizeF &size) +{ + Q_ASSERT(size.width() == size.height()); + m_radius = size.height() / 2; + m_center = QPointF(m_radius, m_radius); + AbstractDomain::setSize(size); +} + +QPointF PolarDomain::calculateGeometryPoint(const QPointF &point, bool &ok) const +{ + qreal r; + qreal a = toAngularCoordinate(point.x(), ok); + if (ok) + r = toRadialCoordinate(point.y(), ok); + if (ok) { + return m_center + polarCoordinateToPoint(a, r); + } else { + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; + return QPointF(); + } +} + +QVector<QPointF> PolarDomain::calculateGeometryPoints(const QList<QPointF> &vector) const +{ + QVector<QPointF> result; + result.resize(vector.count()); + bool ok; + qreal r; + qreal a; + + for (int i = 0; i < vector.count(); ++i) { + a = toAngularCoordinate(vector[i].x(), ok); + if (ok) + r = toRadialCoordinate(vector[i].y(), ok); + if (ok) { + result[i] = m_center + polarCoordinateToPoint(a, r); + } else { + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; + return QVector<QPointF>(); + } + } + + return result; +} + +QPointF PolarDomain::polarCoordinateToPoint(qreal angularCoordinate, qreal radialCoordinate) const +{ + qreal dx = qSin(angularCoordinate * (M_PI / 180)) * radialCoordinate; + qreal dy = qCos(angularCoordinate * (M_PI / 180)) * radialCoordinate; + + return QPointF(dx, -dy); +} + +#include "moc_polardomain_p.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/polardomain_p.h b/src/domain/polardomain_p.h new file mode 100644 index 00000000..81e921d5 --- /dev/null +++ b/src/domain/polardomain_p.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the QtCommercial Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef POLARDOMAIN_H +#define POLARDOMAIN_H +#include "abstractdomain_p.h" +#include <QRectF> +#include <QSizeF> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_AUTOTEST_EXPORT PolarDomain: public AbstractDomain +{ + Q_OBJECT +public: + explicit PolarDomain(QObject *object = 0); + virtual ~PolarDomain(); + + void setSize(const QSizeF &size); + + QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const; + QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const; + + virtual qreal toAngularCoordinate(qreal value, bool &ok) const = 0; + virtual qreal toRadialCoordinate(qreal value, bool &ok) const = 0; + +protected: + QPointF polarCoordinateToPoint(qreal angularCoordinate, qreal radialCoordinate) const; + + QPointF m_center; + qreal m_radius; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // POLARDOMAIN_H diff --git a/src/domain/xlogydomain.cpp b/src/domain/xlogydomain.cpp index 42e7edae..850eb99b 100644 --- a/src/domain/xlogydomain.cpp +++ b/src/domain/xlogydomain.cpp @@ -42,6 +42,8 @@ void XLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) bool axisXChanged = false; bool axisYChanged = false; + adjustLogDomainRanges(minY, maxY); + if (!qFuzzyIsNull(m_minX - minX) || !qFuzzyIsNull(m_maxX - maxX)) { m_minX = minX; m_maxX = maxX; @@ -58,7 +60,7 @@ void XLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) qreal logMaxY = log10(m_maxY) / log10(m_logBaseY); m_logLeftY = logMinY < logMaxY ? logMinY : logMaxY; m_logRightY = logMinY > logMaxY ? logMinY : logMaxY; - if(!m_signalsBlocked) + if (!m_signalsBlocked) emit rangeVerticalChanged(m_minY, m_maxY); } @@ -136,13 +138,13 @@ QPointF XLogYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) cons ok = true; return QPointF(x, y); } else { - qWarning() << "Logarithm of negative value is undefined. Empty layout returned"; + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; ok = false; return QPointF(); } } -QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const +QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const { const qreal deltaX = m_size.width() / (m_maxX - m_minX); const qreal deltaY = m_size.height() / qAbs(m_logRightY - m_logLeftY); @@ -157,7 +159,7 @@ QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QList<QPointF>& vect result[i].setX(x); result[i].setY(y); } else { - qWarning() << "Logarithm of negative value is undefined. Empty layout returned"; + qWarning() << "Logarithm of negative value is undefined. Empty layout returned."; return QVector<QPointF>(); } } @@ -173,22 +175,22 @@ QPointF XLogYDomain::calculateDomainPoint(const QPointF &point) const return QPointF(x, y); } -bool XLogYDomain::attachAxis(QAbstractAxis* axis) +bool XLogYDomain::attachAxis(QAbstractAxis *axis) { QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); - if(logAxis && logAxis->orientation()==Qt::Vertical){ + if (logAxis && logAxis->orientation() == Qt::Vertical) { QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); handleVerticalAxisBaseChanged(logAxis->base()); } return AbstractDomain::attachAxis(axis); } -bool XLogYDomain::detachAxis(QAbstractAxis* axis) +bool XLogYDomain::detachAxis(QAbstractAxis *axis) { QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); - if(logAxis && logAxis->orientation()==Qt::Vertical) + if (logAxis && logAxis->orientation() == Qt::Vertical) QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); return AbstractDomain::detachAxis(axis); @@ -208,10 +210,10 @@ void XLogYDomain::handleVerticalAxisBaseChanged(qreal baseY) bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XLogYDomain &domain1, const XLogYDomain &domain2) { - return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) && - qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) && - qFuzzyIsNull(domain1.m_minX - domain2.m_minX) && - qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); + return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) + && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) + && qFuzzyIsNull(domain1.m_minX - domain2.m_minX) + && qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); } diff --git a/src/domain/xlogydomain_p.h b/src/domain/xlogydomain_p.h index 88dd989f..68ac6f81 100644 --- a/src/domain/xlogydomain_p.h +++ b/src/domain/xlogydomain_p.h @@ -56,10 +56,10 @@ public: QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const; QPointF calculateDomainPoint(const QPointF &point) const; - QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const; + QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const; - bool attachAxis(QAbstractAxis* axis); - bool detachAxis(QAbstractAxis* axis); + bool attachAxis(QAbstractAxis *axis); + bool detachAxis(QAbstractAxis *axis); public Q_SLOTS: void handleVerticalAxisBaseChanged(qreal baseY); diff --git a/src/domain/xlogypolardomain.cpp b/src/domain/xlogypolardomain.cpp new file mode 100644 index 00000000..730a9dcd --- /dev/null +++ b/src/domain/xlogypolardomain.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "xlogypolardomain_p.h" +#include "qabstractaxis_p.h" +#include "qlogvalueaxis.h" +#include <qmath.h> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +XLogYPolarDomain::XLogYPolarDomain(QObject *parent) + : PolarDomain(parent), + m_logInnerY(0), + m_logOuterY(1), + m_logBaseY(10) +{ +} + +XLogYPolarDomain::~XLogYPolarDomain() +{ +} + +void XLogYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) +{ + bool axisXChanged = false; + bool axisYChanged = false; + + adjustLogDomainRanges(minY, maxY); + + if (!qFuzzyIsNull(m_minX - minX) || !qFuzzyIsNull(m_maxX - maxX)) { + m_minX = minX; + m_maxX = maxX; + axisXChanged = true; + if (!m_signalsBlocked) + emit rangeHorizontalChanged(m_minX, m_maxX); + } + + if (!qFuzzyIsNull(m_minY - minY) || !qFuzzyIsNull(m_maxY - maxY)) { + m_minY = minY; + m_maxY = maxY; + axisYChanged = true; + qreal logMinY = log10(m_minY) / log10(m_logBaseY); + qreal logMaxY = log10(m_maxY) / log10(m_logBaseY); + m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY; + m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY; + if (!m_signalsBlocked) + emit rangeVerticalChanged(m_minY, m_maxY); + } + + if (axisXChanged || axisYChanged) + emit updated(); +} + +void XLogYPolarDomain::zoomIn(const QRectF &rect) +{ + qreal dx = spanX() / m_size.width(); + qreal maxX = m_maxX; + qreal minX = m_minX; + + maxX = minX + dx * rect.right(); + minX = minX + dx * rect.left(); + + qreal logLeftY = m_logOuterY - rect.bottom() * (m_logOuterY - m_logInnerY) / m_size.height(); + qreal logRightY = m_logOuterY - rect.top() * (m_logOuterY - m_logInnerY) / m_size.height(); + qreal leftY = qPow(m_logBaseY, logLeftY); + qreal rightY = qPow(m_logBaseY, logRightY); + qreal minY = leftY < rightY ? leftY : rightY; + qreal maxY = leftY > rightY ? leftY : rightY; + + setRange(minX, maxX, minY, maxY); +} + +void XLogYPolarDomain::zoomOut(const QRectF &rect) +{ + qreal dx = spanX() / rect.width(); + qreal maxX = m_maxX; + qreal minX = m_minX; + + minX = maxX - dx * rect.right(); + maxX = minX + dx * m_size.width(); + + const qreal factorY = m_size.height() / rect.height(); + qreal newLogMinY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 - factorY); + qreal newLogMaxY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 + factorY); + qreal leftY = qPow(m_logBaseY, newLogMinY); + qreal rightY = qPow(m_logBaseY, newLogMaxY); + qreal minY = leftY < rightY ? leftY : rightY; + qreal maxY = leftY > rightY ? leftY : rightY; + + setRange(minX, maxX, minY, maxY); +} + +void XLogYPolarDomain::move(qreal dx, qreal dy) +{ + qreal x = spanX() / 360.0; + + qreal maxX = m_maxX; + qreal minX = m_minX; + + if (dx != 0) { + minX = minX + x * dx; + maxX = maxX + x * dx; + } + + qreal stepY = dy * (m_logOuterY - m_logInnerY) / m_radius; + qreal leftY = qPow(m_logBaseY, m_logInnerY + stepY); + qreal rightY = qPow(m_logBaseY, m_logOuterY + stepY); + qreal minY = leftY < rightY ? leftY : rightY; + qreal maxY = leftY > rightY ? leftY : rightY; + + setRange(minX, maxX, minY, maxY); +} + +qreal XLogYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const +{ + ok = true; + qreal f = (value - m_minX) / (m_maxX - m_minX); + return f * 360.0; +} + +qreal XLogYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const +{ + qreal retVal; + if (value <= 0) { + ok = false; + retVal = 0.0; + } else { + ok = true; + const qreal tickSpan = m_radius / qAbs(m_logOuterY - m_logInnerY); + const qreal logValue = log10(value) / log10(m_logBaseY); + const qreal valueDelta = logValue - m_logInnerY; + + retVal = valueDelta * tickSpan; + + if (retVal < 0.0) + retVal = 0.0; + } + return retVal; +} + +QPointF XLogYPolarDomain::calculateDomainPoint(const QPointF &point) const +{ + if (point == m_center) + return QPointF(0.0, m_minY); + + QLineF line(m_center, point); + qreal a = 90.0 - line.angle(); + if (a < 0.0) + a += 360.0; + a = ((a / 360.0) * (m_maxX - m_minX)) + m_minX; + + const qreal deltaY = m_radius / qAbs(m_logOuterY - m_logInnerY); + qreal r = qPow(m_logBaseY, m_logInnerY + (line.length() / deltaY)); + + return QPointF(a, r); +} + +bool XLogYPolarDomain::attachAxis(QAbstractAxis *axis) +{ + QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); + + if (logAxis && logAxis->orientation() == Qt::Vertical) { + QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); + handleVerticalAxisBaseChanged(logAxis->base()); + } + return AbstractDomain::attachAxis(axis); +} + +bool XLogYPolarDomain::detachAxis(QAbstractAxis *axis) +{ + QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis); + + if (logAxis && logAxis->orientation() == Qt::Vertical) + QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal))); + + return AbstractDomain::detachAxis(axis); +} + +void XLogYPolarDomain::handleVerticalAxisBaseChanged(qreal baseY) +{ + m_logBaseY = baseY; + qreal logMinY = log10(m_minY) / log10(m_logBaseY); + qreal logMaxY = log10(m_maxY) / log10(m_logBaseY); + m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY; + m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY; + emit updated(); +} + +// operators + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2) +{ + return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) + && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) + && qFuzzyIsNull(domain1.m_minX - domain2.m_minX) + && qFuzzyIsNull(domain1.m_minY - domain2.m_minY)); +} + + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2) +{ + return !(domain1 == domain2); +} + + +QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XLogYPolarDomain &domain) +{ + dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size; + return dbg.maybeSpace(); +} + +#include "moc_xlogypolardomain_p.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/xlogypolardomain_p.h b/src/domain/xlogypolardomain_p.h new file mode 100644 index 00000000..3c3a45b7 --- /dev/null +++ b/src/domain/xlogypolardomain_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the QtCommercial Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef XLOGYPOLARDOMAIN_H +#define XLOGYPOLARDOMAIN_H +#include "polardomain_p.h" +#include <QRectF> +#include <QSizeF> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_AUTOTEST_EXPORT XLogYPolarDomain: public PolarDomain +{ + Q_OBJECT +public: + explicit XLogYPolarDomain(QObject *object = 0); + virtual ~XLogYPolarDomain(); + + DomainType type() { return AbstractDomain::XLogYPolarDomain; } + + void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY); + + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2); + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2); + friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XLogYPolarDomain &domain); + + void zoomIn(const QRectF &rect); + void zoomOut(const QRectF &rect); + void move(qreal dx, qreal dy); + + QPointF calculateDomainPoint(const QPointF &point) const; + + bool attachAxis(QAbstractAxis *axis); + bool detachAxis(QAbstractAxis *axis); + +public Q_SLOTS: + void handleVerticalAxisBaseChanged(qreal baseY); + +protected: + qreal toAngularCoordinate(qreal value, bool &ok) const; + qreal toRadialCoordinate(qreal value, bool &ok) const; + +private: + qreal m_logInnerY; + qreal m_logOuterY; + qreal m_logBaseY; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // XLOGYPOLARDOMAIN_H diff --git a/src/domain/xydomain.cpp b/src/domain/xydomain.cpp index 26f82a15..8ac1f0a0 100644 --- a/src/domain/xydomain.cpp +++ b/src/domain/xydomain.cpp @@ -126,7 +126,7 @@ QPointF XYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) const return QPointF(x, y); } -QVector<QPointF> XYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const +QVector<QPointF> XYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const { const qreal deltaX = m_size.width() / (m_maxX - m_minX); const qreal deltaY = m_size.height() / (m_maxY - m_minY); @@ -156,10 +156,10 @@ QPointF XYDomain::calculateDomainPoint(const QPointF &point) const bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XYDomain &domain1, const XYDomain &domain2) { - return (qFuzzyCompare(domain1.m_maxX, domain2.m_maxX) && - qFuzzyCompare(domain1.m_maxY, domain2.m_maxY) && - qFuzzyCompare(domain1.m_minX, domain2.m_minX) && - qFuzzyCompare(domain1.m_minY, domain2.m_minY)); + return (qFuzzyCompare(domain1.m_maxX, domain2.m_maxX) + && qFuzzyCompare(domain1.m_maxY, domain2.m_maxY) + && qFuzzyCompare(domain1.m_minX, domain2.m_minX) + && qFuzzyCompare(domain1.m_minY, domain2.m_minY)); } diff --git a/src/domain/xydomain_p.h b/src/domain/xydomain_p.h index 0a990388..657377b2 100644 --- a/src/domain/xydomain_p.h +++ b/src/domain/xydomain_p.h @@ -56,7 +56,7 @@ public: QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const; QPointF calculateDomainPoint(const QPointF &point) const; - QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const; + QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const; }; QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/xypolardomain.cpp b/src/domain/xypolardomain.cpp new file mode 100644 index 00000000..e9471293 --- /dev/null +++ b/src/domain/xypolardomain.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "xypolardomain_p.h" +#include "qabstractaxis_p.h" +#include <qmath.h> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +XYPolarDomain::XYPolarDomain(QObject *parent) + : PolarDomain(parent) +{ +} + +XYPolarDomain::~XYPolarDomain() +{ +} + +void XYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY) +{ + bool axisXChanged = false; + bool axisYChanged = false; + + if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) { + m_minX = minX; + m_maxX = maxX; + axisXChanged = true; + if (!m_signalsBlocked) + emit rangeHorizontalChanged(m_minX, m_maxX); + } + + if (!qFuzzyCompare(m_minY, minY) || !qFuzzyCompare(m_maxY, maxY)) { + m_minY = minY; + m_maxY = maxY; + axisYChanged = true; + if (!m_signalsBlocked) + emit rangeVerticalChanged(m_minY, m_maxY); + } + + if (axisXChanged || axisYChanged) + emit updated(); +} + + +void XYPolarDomain::zoomIn(const QRectF &rect) +{ + qreal dx = spanX() / m_size.width(); + qreal dy = spanY() / m_size.height(); + + qreal maxX = m_maxX; + qreal minX = m_minX; + qreal minY = m_minY; + qreal maxY = m_maxY; + + maxX = minX + dx * rect.right(); + minX = minX + dx * rect.left(); + minY = maxY - dy * rect.bottom(); + maxY = maxY - dy * rect.top(); + + setRange(minX, maxX, minY, maxY); +} + +void XYPolarDomain::zoomOut(const QRectF &rect) +{ + qreal dx = spanX() / rect.width(); + qreal dy = spanY() / rect.height(); + + qreal maxX = m_maxX; + qreal minX = m_minX; + qreal minY = m_minY; + qreal maxY = m_maxY; + + minX = maxX - dx * rect.right(); + maxX = minX + dx * m_size.width(); + maxY = minY + dy * rect.bottom(); + minY = maxY - dy * m_size.height(); + + setRange(minX, maxX, minY, maxY); +} + +void XYPolarDomain::move(qreal dx, qreal dy) +{ + // One unit scrolls one degree angular and one pixel radial + qreal x = spanX() / 360.0; + qreal y = spanY() / m_radius; + + qreal maxX = m_maxX; + qreal minX = m_minX; + qreal minY = m_minY; + qreal maxY = m_maxY; + + if (dx != 0) { + minX = minX + x * dx; + maxX = maxX + x * dx; + } + if (dy != 0) { + minY = minY + y * dy; + maxY = maxY + y * dy; + } + setRange(minX, maxX, minY, maxY); +} + +QPointF XYPolarDomain::calculateDomainPoint(const QPointF &point) const +{ + if (point == m_center) + return QPointF(0.0, m_minX); + + QLineF line(m_center, point); + qreal a = 90.0 - line.angle(); + if (a < 0.0) + a += 360.0; + a = ((a / 360.0) * (m_maxX - m_minX)) + m_minX; + qreal r = m_minY + ((m_maxY - m_minY) * (line.length() / m_radius)); + return QPointF(a, r); +} + +qreal XYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const +{ + ok = true; + qreal f = (value - m_minX) / (m_maxX - m_minX); + return f * 360.0; +} + +qreal XYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const +{ + ok = true; + if (value < m_minY) + value = m_minY; + + // Dont limit the max. The drawing should clip the stuff that goes out of the grid + qreal f = (value - m_minY) / (m_maxY - m_minY); + + return f * m_radius; +} + +// operators + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XYPolarDomain &domain1, const XYPolarDomain &domain2) +{ + return (qFuzzyCompare(domain1.m_maxX, domain2.m_maxX) + && qFuzzyCompare(domain1.m_maxY, domain2.m_maxY) + && qFuzzyCompare(domain1.m_minX, domain2.m_minX) + && qFuzzyCompare(domain1.m_minY, domain2.m_minY)); +} + + +bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XYPolarDomain &domain1, const XYPolarDomain &domain2) +{ + return !(domain1 == domain2); +} + + +QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XYPolarDomain &domain) +{ + dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size; + return dbg.maybeSpace(); +} + +#include "moc_xypolardomain_p.cpp" + +QTCOMMERCIALCHART_END_NAMESPACE diff --git a/src/domain/xypolardomain_p.h b/src/domain/xypolardomain_p.h new file mode 100644 index 00000000..662cc5ee --- /dev/null +++ b/src/domain/xypolardomain_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc +** All rights reserved. +** For any questions to Digia, please use contact form at http://qt.digia.com +** +** This file is part of the Qt Commercial Charts Add-on. +** +** $QT_BEGIN_LICENSE$ +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. +** +** If you have questions regarding the use of this file, please use +** contact form at http://qt.digia.com +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// W A R N I N G +// ------------- +// +// This file is not part of the QtCommercial Chart API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef XYPOLARDOMAIN_H +#define XYPOLARDOMAIN_H +#include "polardomain_p.h" +#include <QRectF> + +QTCOMMERCIALCHART_BEGIN_NAMESPACE + +class QTCOMMERCIALCHART_AUTOTEST_EXPORT XYPolarDomain: public PolarDomain +{ + Q_OBJECT +public: + explicit XYPolarDomain(QObject *object = 0); + virtual ~XYPolarDomain(); + + DomainType type(){ return AbstractDomain::XYPolarDomain;} + + void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY); + + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XYPolarDomain &Domain1, const XYPolarDomain &Domain2); + friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XYPolarDomain &Domain1, const XYPolarDomain &Domain2); + friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XYPolarDomain &AbstractDomain); + + void zoomIn(const QRectF &rect); + void zoomOut(const QRectF &rect); + void move(qreal dx, qreal dy); + + QPointF calculateDomainPoint(const QPointF &point) const; + +protected: + qreal toAngularCoordinate(qreal value, bool &ok) const; + qreal toRadialCoordinate(qreal value, bool &ok) const; +}; + +QTCOMMERCIALCHART_END_NAMESPACE + +#endif // XYPOLARDOMAIN_H |