Подтвердить что ты не робот

QGraphicsScene, координаты элементов влияют на производительность?

С приведенным ниже фрагментом кода я создаю сцену с 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);
}

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

В предыдущей сцене есть 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;
         ...
4b9b3361

Ответ 1

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

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);

Ответ 2

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

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

scene->setItemIndexMethod(QGraphicsScene::NoIndex);

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

Ответ 3

Это может быть связано с потерей точности с помощью float. 32-битный float имеет 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-источник, но рассмотрю структуру данных для хранения объектов по местоположению. Что вы можете сделать по-другому, если два объекта касаются (или перекрываются) из-за потери точности, которые вам не нужно делать, когда они не перекрываются?