Вся хитрость в том чтобы прорисовывать не все точки что есть, а лишь равное кол-ву пикселей. Т.е. берем множество точек которые требуется отобразить, сравниваем его с кол-вом точек доступных для рисования, и если их меньше, вычисляем макс и мин по оси ординат, в то время как абсцисса у нас неизменна. Как только абсцисса изменилась (пошел рисоваться след. пиксел), так мы рисуем вертикальную линию от мин. до макс. (или наоборот
) по вычисленным значениям ординат, после чего их сбрасываем и начинаем след. итерацию.
Вот так у меня выглядит отрисовка кривой:
void CurveData::paint(QPainter *painter)
{
if (!m_visible || !m_parent || !painter)
return;
painter->save();
const double a11 = double(m_parent->plotRect().width()) / m_parent->scaleX()->width();
const double a12 = m_parent->plotRect().x() - m_parent->scaleX()->min() * a11;
const double a21 = double(-m_parent->plotRect().height()) / m_parent->scaleY()->width();
const double a22 = m_parent->plotRect().y() - m_parent->scaleY()->max() * a21;
const qreal scaleXMin = m_parent->scaleX()->min();
const qreal scaleXMax = m_parent->scaleX()->max();
painter->setPen(m_pen);
if (m_parent->antialiasing())
painter->setRenderHint(QPainter::Antialiasing, true);
int rangeStart = -1;
int rangeEnd = -1;
for (int i = 0; i < _data.size(); i++) {
if (_data.at(i).x() >= scaleXMin && rangeStart == -1) {
rangeStart = i;
}
else if (_data.at(i).x() <= scaleXMax) {
rangeEnd = i;
}
else {
break;
}
}
if (rangeStart != -1 && rangeEnd != -1
&& rangeEnd - rangeStart > 1) {
m_visibleMin = _data.at(rangeStart).y();
m_visibleMax = m_visibleMin;
int prev_x = a11 * _data.at(rangeStart).x() + a12;
qreal min_y = a21 * _data.at(rangeStart).y() + a22;
qreal max_y = min_y;
for (int i = rangeStart; i < rangeEnd; i++) {
const qreal x1 = _data.at(i).x();
const qreal y1 = _data.at(i).y();
const qreal x2 = _data.at(i + 1).x();
const qreal y2 = _data.at(i + 1).y();
if (a11 >= 1) {
painter->drawLine(a11 * x1 + a12, a21 * y1 + a22,
a11 * x2 + a12, a21 * y2 + a22);
}
else {
int cur_x = a11 * x2 + a12;
if (prev_x != cur_x) {
painter->drawLine(prev_x, min_y,
prev_x, max_y);
painter->drawLine(prev_x, a21 * y1 + a22,
cur_x, a21 * y2 + a22);
min_y = a21 * y2 + a22;
max_y = min_y;
prev_x = cur_x;
}
else {
qreal cur_y = a21 * y2 + a22;
if (cur_y < min_y) { min_y = cur_y; }
if (cur_y > max_y) { max_y = cur_y; }
}
}
// calculate visible max and min values, by Y-axis
if (m_visibleMin > y2)
m_visibleMin = y2;
if (m_visibleMax < y2)
m_visibleMax = y2;
}
}
if (m_parent->antialiasing())
painter->setRenderHint(QPainter::Antialiasing, false);
painter->restore();
}
За кривость кода ногами не бить
Попозже может быть выложу целиком проект с чуть переделанной бородатой версией Plot2D.