Russian Qt Forum
Ноябрь 25, 2024, 01:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [SOLVED]Тормозит отрисовка окружностей большого радиуса  (Прочитано 14810 раз)
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« : Сентябрь 10, 2009, 21:15 »

Изначально при запуске ничего особо не тормозит, т.е. можно передвигать при нажатой правой кнопке мыши, зумиться по колесику, и все будет плавно.

Но если призумиться на самую маленькую окружность, то все начинает заметно тормозить. Из за чего возникают тормоза? Как от них избавиться?

Widget.h:
Код:
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QList>

struct circle {
    QPointF c;
    qreal r;
    circle(QPointF center, qreal radius): c(center), r(radius) {}
};

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);

protected:
    void paintEvent(QPaintEvent *event);

    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

    void wheelEvent(QWheelEvent *event);

private:
    QList<circle> circles;
    QPointF shift;
    qreal scale;
    QPoint previous;
    bool isDragging;
};

#endif // WIDGET_H

Widget.cpp:
Код:
#include "widget.h"

#include <math.h>
#include <QPainter>
#include <QMouseEvent>
#include <QWheelEvent>

circle tangent2(const circle &c1, const circle &c2, qreal r, const QPointF &p)
{
    qreal r1 = c1.r + r;
    qreal r2 = c2.r + r;
    qreal d = c1.r + c2.r;
    qreal dx = (d*d - r2*r2 + r1*r1)/(2*d);
    qreal dy = sqrt(r1*r1 - dx*dx);
    QPointF v = (c2.c - c1.c)/d;
    QPointF n(-v.y(), v.x());
    QPointF pv = p - c1.c;
    if (pv.x()*n.x() + pv.y()*n.y() < 0)
        n = -n;
    QPointF c = c1.c + dx*v + dy*n;
    return circle(c, r);
}

circle tangent3(const circle &c1, const circle &c2, const circle &c3)
{
    qreal k1 = 1/c1.r;
    qreal k2 = 1/c2.r;
    qreal k3 = 1/c3.r;
    qreal a = k1 + k2 + k3;
    qreal b = 2*sqrt(k1*k2 + k2*k3 + k3*k1);
    qreal k = qMax(qAbs(a - b), a + b);
    return tangent2(c1, c2, 1/k, c3.c);
}

Widget::Widget(QWidget *parent)
    : QWidget(parent), shift(300, 400), scale(30), isDragging(false)
{
    setAutoFillBackground(false);
    circle c1(QPointF(0, 0), 5);
    circle c2(QPointF(8, 0), 3);
    circle c3 = tangent2(c1, c2, 4, QPointF(0, -1));
    circles << c1 << c2 << c3;
    for (int i = 0; i < 6; ++i) {
        circle c = tangent3(c1, c2, c3);
        circles << c;
        c1 = c2;
        c2 = c3;
        c3 = c;
    }
}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.fillRect(0, 0, width(), height(), Qt::darkGray);
    painter.setBrush(Qt::NoBrush);
    painter.setPen(QPen(QBrush(Qt::white), 1.5));
    painter.setRenderHint(QPainter::Antialiasing, true);
    foreach(const circle &c, circles)
        painter.drawEllipse(c.c * scale + shift, c.r * scale, c.r * scale);
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    if (!isDragging && event->button() == Qt::RightButton) {
        isDragging = true;
        previous = event->pos();
    }
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    if (isDragging && event->button() == Qt::RightButton) {
        isDragging = false;
    }
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    if (isDragging) {
        shift += event->pos() - previous;
        previous = event->pos();
        repaint();
    }
}

void Widget::wheelEvent(QWheelEvent *event)
{
    int numDegrees = event->delta() / 8;
    int numTicks = numDegrees / 15;
    qreal factor = pow(1.2, -numTicks);
    shift += (1 - factor) * (event->pos() - shift);
    scale *= factor;
    repaint();
}

main.cpp
Код:
#include <QtGui/QApplication>
#include "widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.resize(800, 600);
    w.show();
    return a.exec();
}
« Последнее редактирование: Сентябрь 22, 2009, 10:51 от kamre » Записан
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #1 : Сентябрь 12, 2009, 20:56 »

Хоть у кого-нибудь проблема с этим кодом воспроизводится?
Записан
ufna
Гость
« Ответ #2 : Сентябрь 12, 2009, 21:06 »

ну, так то тут по-моему очевидно, что если ты отсечки никакой не делаешь, то эллипс у тебя рисуется каждый раз во всем объеме. Вот и представь какие у этого всего получаются объемы и размеры.

имхо, стоит сделать отсечку clip region'а, в самую первую очередь (см. demo кутяшное, где еще Артур Плагин юзается).
Записан
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #3 : Сентябрь 12, 2009, 22:57 »

имхо, стоит сделать отсечку clip region'а, в самую первую очередь (см. demo кутяшное, где еще Артур Плагин юзается).

Если добавить clipRect вот так:
Код:
void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.fillRect(0, 0, width(), height(), Qt::darkGray);
    painter.setClipRect(0, 0, width(), height());  // <<<<<< added
    painter.setBrush(Qt::NoBrush);
    painter.setPen(QPen(QBrush(Qt::white), 1.5));
    painter.setRenderHint(QPainter::Antialiasing, true);
    foreach(const circle &c, circles)
        painter.drawEllipse(c.c * scale + shift, c.r * scale, c.r * scale);
}
то ничего не меняется и тормозит точно также. По идее такую "отсечку" должен делать сам QPainter, т.к. ему заранее известны размеры QWidget.

Какая-то другая "отсечка" имелась ввиду?
« Последнее редактирование: Сентябрь 12, 2009, 22:59 от kamre » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Сентябрь 13, 2009, 12:43 »

Хоть у кого-нибудь проблема с этим кодом воспроизводится?
У меня не воспроизводится, никаких тормозов не наблюдаю
Примечание: в следующий раз прикрепите zip'чик с файлами чтобы не выдирать их copy/paste
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #5 : Сентябрь 13, 2009, 12:46 »

kamre, протестируй Valgrind'ом на предмет потери производительности
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #6 : Сентябрь 13, 2009, 13:02 »

У меня не воспроизводится, никаких тормозов не наблюдаю
Нужно призумиться так, чтобы самая маленькая окружность была почти на все окно. После этого появляются тормоза.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Сентябрь 13, 2009, 13:21 »

Нужно призумиться так, чтобы самая маленькая окружность была почти на все окно. После этого появляются тормоза.
Делал, не тормозит (платформа Mac)
Записан
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #8 : Сентябрь 13, 2009, 14:06 »

Делал, не тормозит (платформа Mac)
Я только на Windows/Linux пробовал, и на обоих тормозит.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #9 : Сентябрь 13, 2009, 14:56 »

Я только на Windows/Linux пробовал, и на обоих тормозит.


Повторюсь. Глянь профайлером где проблема
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #10 : Сентябрь 15, 2009, 07:13 »

Повторюсь. Глянь профайлером где проблема

Глянул в Linux с помощью valgrind.

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


А вот так получается, когда зум большой и появляются тормоза:


Т.е. получается, что проблема возникает при вызове QPainterPath::intersected.
И как мне теперь с этим бороться?
Записан
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #11 : Сентябрь 15, 2009, 07:24 »

Вот, кстати, тот же самый пример на Java. Ничего не тормозит, ни при каком зуме.
Неужели отрисовка в Qt получается тормознее чем в Java2D?
Записан
Rcus
Гость
« Ответ #12 : Сентябрь 15, 2009, 09:17 »

Интересно... первые 10 минут рассматривания графов и тестов. Очень интересно после пересборки с отладочной версией Qt. И совсем неинтересно после чтения QOutlineMapper::endOutline() (Qt4.5.2 src/gui/painting/qoutlinemapper.cpp line: 257)
Записан
kamre
Частый гость
***
Offline Offline

Сообщений: 233


Просмотр профиля
« Ответ #13 : Сентябрь 15, 2009, 09:45 »

И совсем неинтересно после чтения QOutlineMapper::endOutline() (Qt4.5.2 src/gui/painting/qoutlinemapper.cpp line: 257)
Вот такая константа:
Код:
// This limitations comes from qgrayraster.c. Any higher and
// rasterization of shapes will produce incorrect results.
const int QT_RASTER_COORD_LIMIT = 32767;
Получается, что растеризатор в Qt какой-то ограниченный что ли? Ведь в Java2D нет таких проблем с растеризацией.
А если получается больше по размерам, то делается clip, который ужасно тормозной? И как с этим бороться?

Записан
Rcus
Гость
« Ответ #14 : Сентябрь 15, 2009, 10:00 »

Ага, а можно назвать специалированным и заточенным под рисование виджетов Улыбающийся. Попробуйте лучше Graphics View Framework.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.108 секунд. Запросов: 23.