/* BEGIN COPYRIGHT * * This file is part of Noted. * * Copyright ©2011, 2012, Lancaster Logic Response Limited. * * Noted 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. * * Noted 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 Noted. If not, see . */ #include #include "GraphParameters.h" #include "Grapher.h" using namespace std; using namespace lb; void Grapher::init(QPainter* _p, std::pair _xRange, std::pair _yRange, std::function _xLabel, std::function _yLabel, std::function _pLabel, int _leftGutter, int _bottomGutter) { fontPixelSize = QFontInfo(QFont("Ubuntu", 10)).pixelSize(); if (_leftGutter) _leftGutter = max(_leftGutter, fontPixelSize * 2); if (_bottomGutter) _bottomGutter = max(_bottomGutter, fontPixelSize * 1.25); QRect a(_leftGutter, 0, _p->viewport().width() - _leftGutter, _p->viewport().height() - _bottomGutter); init(_p, _xRange, _yRange, _xLabel, _yLabel, _pLabel, a); } bool Grapher::drawAxes(bool _x, bool _y) const { int w = active.width(); int h = active.height(); int l = active.left(); int r = active.right(); int t = active.top(); int b = active.bottom(); p->setFont(QFont("Ubuntu", 10)); p->fillRect(p->viewport(), qRgb(255, 255, 255)); static const int c_markLength = 2; static const int c_markSpacing = 2; static const int c_xSpacing = fontPixelSize * 3; static const int c_ySpacing = fontPixelSize * 1.25; if (w < c_xSpacing || h < c_ySpacing || !p->viewport().contains(active)) return false; if (_y) { GraphParameters yParams(yRange, h / c_ySpacing, 1.f); float dy = fabs(yRange.second - yRange.first); if (dy > .001) for (float f = yParams.from; f < yParams.to; f += yParams.incr) { int y = b - h * (f - yParams.from) / dy; if (yParams.isMajor(f)) { p->setPen(QColor(208, 208, 208)); p->drawLine(l - c_markLength, y, r, y); if (l > p->viewport().left()) { p->setPen(QColor(144, 144, 144)); p->drawText(QRect(0, y - c_ySpacing / 2, l - c_markLength - c_markSpacing, c_ySpacing), Qt::AlignRight|Qt::AlignVCenter, QString::fromStdString(yLabel(round(f * 100000) / 100000))); } } else { p->setPen(QColor(236, 236, 236)); p->drawLine(l, y, r, y); } } p->setPen(QColor(192,192,192)); p->drawLine(l - c_markSpacing, b, r, b); } if (_x) { GraphParameters xParams(xRange, w / c_xSpacing, 1.f); float dx = fabs(xRange.second - xRange.first); for (float f = xParams.from; f < xParams.to; f += xParams.incr) { int x = l + w * (f - xParams.from) / dx; if (xParams.isMajor(f)) { p->setPen(QColor(208, 208, 208)); p->drawLine(x, t, x, b + c_markLength); if (b < p->viewport().bottom()) { p->setPen(QColor(144, 144, 144)); p->drawText(QRect(x - c_xSpacing / 2, b + c_markLength + c_markSpacing, c_xSpacing, p->viewport().height() - (b + c_markLength + c_markSpacing)), Qt::AlignHCenter|Qt::AlignTop, QString::fromStdString(xLabel(f))); } } else { p->setPen(QColor(236, 236, 236)); p->drawLine(x, t, x, b); } } } p->setClipRect(active); return true; } void Grapher::drawLineGraph(vector const& _data, QColor _color, QBrush const& _fillToZero, float _width) const { int s = _data.size(); QPoint l; for (int i = 0; i < s; ++i) { int zy = yP(0.f); QPoint h(xTP(i), yTP(_data[i])); if (i) { if (_fillToZero != Qt::NoBrush) { p->setPen(Qt::NoPen); p->setBrush(_fillToZero); p->drawPolygon(QPolygon(QVector() << QPoint(h.x(), zy) << h << l << QPoint(l.x(), zy))); } p->setPen(QPen(_color, _width)); p->drawLine(QLine(l, h)); } l = h; } } void Grapher::ruleY(float _x, QColor _color, float _width) const { p->setPen(QPen(_color, _width)); p->drawLine(xTP(_x), active.top(), xTP(_x), active.bottom()); } void Grapher::drawLineGraph(std::function const& _f, QColor _color, QBrush const& _fillToZero, float _width) const { QPoint l; for (int x = active.left(); x < active.right(); x += 2) { int zy = yP(0.f); QPoint h(x, yTP(_f(xRU(x)))); if (x != active.left()) { if (_fillToZero != Qt::NoBrush) { p->setPen(Qt::NoPen); p->setBrush(_fillToZero); p->drawPolygon(QPolygon(QVector() << QPoint(h.x(), zy) << h << l << QPoint(l.x(), zy))); } p->setPen(QPen(_color, _width)); p->drawLine(QLine(l, h)); } l = h; } } void Grapher::labelYOrderedPoints(map const& _data, int _maxCount, float _minFactor) const { int ly = active.top() + 6; int pc = 0; if (_data.empty()) return; float smallestAllowed = prev(_data.end())->first * _minFactor; for (auto peaki = _data.rbegin(); peaki != _data.rend(); ++peaki) if ((peaki->first > smallestAllowed || _minFactor == 0) && pc < _maxCount) { auto peak = *peaki; int x = xTP(peak.second); int y = yTP(peak.first); p->setPen(QColor::fromHsvF(float(pc) / _maxCount, 1.f, 0.5f, 0.5f)); p->drawEllipse(QPoint(x, y), 4, 4); p->drawLine(x, y - 4, x, ly + 6); QString f = QString::fromStdString(pLabel(xT(peak.second), yT(peak.first))); int fw = p->fontMetrics().width(f); p->drawLine(x + 16 + fw + 2, ly + 6, x, ly + 6); p->setPen(QColor::fromHsvF(0, 0.f, .35f)); p->fillRect(QRect(x+12, ly-6, fw + 8, 12), QBrush(QColor(255, 255, 255, 160))); p->drawText(QRect(x+16, ly-6, 160, 12), Qt::AlignVCenter, f); ly += 14; ++pc; } }