QGraphicsScene, координаты элементов влияют на производительность? - PullRequest
13 голосов
/ 29 мая 2011

С помощью приведенного ниже фрагмента кода я создаю сцену с 100 000 прямоугольников.
Производительность в порядке; представление отвечает без задержек.

QGraphicsScene * scene = new QGraphicsScene;
for (int y = -50000; y < 50000; y++) {
   scene->addRect(0, y * 25, 40, 20);
}
...
view->setScene(scene);

А теперь второй фрагмент отстой

for (int y = 0; y < 100000; y++) {
   scene->addRect(0, y * 25, 40, 20);
}

Для 1-й половины элементов сцены вид задерживается, чтобы реагировать на события мыши и клавиши, а для другой половины это нормально?!?

Предыдущая сцена имеет sceneRect (x, y, w, h) = (0, -1250000, 40, 2499995).
Последняя сцена имеет sceneRect (x, y, w, h) = (0, 0, 40, 2499995).

Я не знаю, почему sceneRect влияет на производительность, поскольку индекс BSP основан на относительных координатах элемента.

Я что-то упустил? Я не нашел никакой информации в документации, плюс демо Qt 40000 Chips также распределяет элементы вокруг (0, 0), не объясняя причину этого выбора.

 // Populate scene
 int xx = 0;
 int nitems = 0;
 for (int i = -11000; i < 11000; i += 110) {
     ++xx;
     int yy = 0;
     for (int j = -7000; j < 7000; j += 70) {
         ++yy;
         qreal x = (i + 11000) / 22000.0;
         qreal y = (j + 7000) / 14000.0;
         ...

Ответы [ 3 ]

6 голосов
/ 01 июня 2011

У меня есть решение для вас, но обещаю не спрашивать меня, почему это работает, потому что я действительно не знаю: -)

QGraphicsScene * scene = new QGraphicsScene;
// Define a fake symetrical scene-rectangle
scene->setSceneRect(0, -(25*100000+20), 40, 2 * (25*100000+20) );

for (int y = 0; y < 100000; y++) {
    scene->addRect(0, y * 25, 40, 20);
}
view->setScene(scene);
// Tell the view to display only the actual scene-objects area
view->setSceneRect(0, 0, 40, 25*100000+20);
0 голосов
/ 06 июня 2011

Это может быть связано с потерей точности с float. 32-битное число с плавающей запятой имеет 23-битную мантиссу (или значение и ), 1-битный знак и 8-битную экспоненту. Это похоже на научную запись. У вас есть 23 "значащие цифры" (на самом деле 24 из-за неявного начального 1) и показатель степени 2 ^ exp, где показатель степени может варьироваться от -126 до 127 (другие используются, чтобы дать вам такие вещи, как NaN и Inf ). Таким образом, вы можете представить действительно большие числа, такие как 2 ^ 24 * 2 ^ 127 , но следующее число ближайших чисел с плавающей запятой, равное (2 ^ 24-1) * 2 ^ 127 или 170 миллиардов миллиардов миллиардов миллиардов далеко. Если вы попытаетесь добавить меньшее количество (например, 1000) к такому числу, оно не изменится. Он не может это представить.

Это становится значительным в компьютерной графике, потому что вам нужно, чтобы некоторые из значимых цифр оставались для дробной части. Когда ваша сцена достигает 1250000.0, вы можете добавить к ней 0.1 и получить 1250000.1. Если вы возьмете 2500000.0 + 0.1, вы получите 2500000.0. Проблема усугубляется любым масштабированием или вращением, которое происходит. Это может привести к очевидным визуальным проблемам, если вы действительно полетите к этим координатам и посмотрите на свою сцену.

Почему центрирование вокруг 0 ​​помогает? Потому что в представлении с плавающей точкой есть отдельный бит знака. В плавающей точке между (-x, + x) "больше чисел", чем из (0,2x). Если я прав, это также сработает, если вы просто уменьшите всю свою сцену на 1/2. Это перемещает наиболее значимый бит вниз, оставляя его свободным для точности на другом конце.

Почему это может привести к снижению производительности? Я могу только строить догадки, не читая источник Qt, но рассмотрим структуру данных для хранения объектов по местоположению. Что вы могли бы сделать по-разному, если два объекта соприкасаются (или перекрываются) из-за потери точности, которую вам не нужно было делать, когда они не перекрывались?

0 голосов
/ 01 июня 2011

Для общего случая индекс по умолчанию Метод BspTreeIndex работает отлично. Если ваша сцена использует много анимаций и вы испытываете медлительность, вы можете отключить индексацию по телефону setItemIndexMethod (NoIndex). Qt-документ

Вам нужно будет позвонить setItemIndexMethod(QGraphicsScene::NoIndex) перед вставкой:

scene->setItemIndexMethod(QGraphicsScene::NoIndex);

for (int y = 0; y < 100000; y++) {
   scene->addRect(0, y * 25, 40, 20);
}
//...
...