Russian Qt Forum

Qt => Общие вопросы => Тема начата: remiznik от Май 21, 2010, 21:04



Название: Посоветуйте как нарисовать большой график ?
Отправлено: remiznik от Май 21, 2010, 21:04
Нужно построить график по точкам ! Посоветуйте как это лучше реализовать ? Что использовать просто QPainter или QGraphicScene  а может стоит попробовать использовать MVC ?


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: andrewshkovskii от Май 21, 2010, 21:54
QwPlot, litePlot2d (вроде) поищи на форуме


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: remiznik от Май 21, 2010, 22:16
Да я читал про них ... я не хочу нечего прикручивать ... хочу сам стандартными средстваим написать ..... не могу определиться как это реализовывать =)


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: sne от Май 21, 2010, 23:30
А большой график это сколько точек? И на сколько быстро нужно загрузить данные, а так же с какой скоростью их отрисовывать?


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: spectre71 от Май 21, 2010, 23:42
Да я читал про них ... я не хочу нечего прикручивать ... хочу сам стандартными средстваим написать ..... не могу определиться как это реализовывать =)

QPainter :)


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: shirushizo от Май 22, 2010, 00:35
QPainter удобней вроде будет, а MVC, думаю, только если из базы тянуть  :)


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: remiznik от Май 24, 2010, 19:58
проблема в том что я QPaintor рисую ... но точек очень много больше 20т и всё сливаеться в кашу ... нужен наверно какойто алгорим выборки ?


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: alexman от Май 24, 2010, 20:54
Нужно просто при зуме прореживать точки, то есть если на один пиксель приходится несколько точек, то рисовать только одну. Кроме того необходимо учитывать bound rect.


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: sne от Май 24, 2010, 23:40
Я рисую QPainter'ом 400 000 точек, разумеется алгоритм не влоб :)

PS
Сливаться все равно будут, это естесственно.


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: remiznik от Май 25, 2010, 09:25
вот я бы хотел узнать .... может кто посоветует как нарисовать большой график  ? алгаритмик какой подскажит =)


Название: Re: Посоветуйте как нарисовать большой график ?
Отправлено: sne от Май 25, 2010, 14:57
Вся хитрость в том чтобы прорисовывать не все точки что есть, а лишь равное кол-ву пикселей. Т.е. берем множество точек которые требуется отобразить, сравниваем его с кол-вом точек доступных для рисования, и если их меньше, вычисляем макс и мин по оси ординат, в то время как абсцисса у нас неизменна. Как только абсцисса изменилась (пошел рисоваться след. пиксел), так мы рисуем вертикальную линию от мин. до макс. (или наоборот :) ) по вычисленным значениям ординат, после чего их сбрасываем и начинаем след. итерацию.

Вот так у меня выглядит отрисовка кривой:

Код:
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.