QGraphicsScene、项目坐标影响性能?

发布于 2024-11-10 03:40:25 字数 1090 浏览 4 评论 0原文

使用下面的代码片段,我创建了一个包含 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;
         ...

With the below code snippet I create a scene with 100.000 rectangles.
The performance is fine; the view responds with no delays.

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

And now the 2nd snippet sucks

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

For the 1st half of scene elements the view delays to respond on mouse and key events, and for the other half it seems to be ok ?!?

The former scene has sceneRect (x, y, w, h) = (0, -1250000, 40, 2499995).
The latter scene has sceneRect (x, y, w, h) = (0, 0, 40, 2499995).

I don't know why the sceneRect affects the performance, since the BSP index is based on relative item coordinates.

Am I missing something? I didn't find any information on the documentation,
plus the Qt demo 40000 Chips also distributes the elements around (0, 0), without explaining the reason for that choice.

 // 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;
         ...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你是暖光i 2024-11-17 03:40:25

我有一个解决方案给你,但保证不要问我为什么这有效,
因为我真的不知道:-)

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

I have a solution for you, but promise to not ask me why is this working,
because I really don't know :-)

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);
野稚 2024-11-17 03:40:25

对于常见情况,默认索引
方法 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);
}
//...

For the common case, the default index
method BspTreeIndex works fine. If
your scene uses many animations and
you are experiencing slowness, you can
disable indexing by calling
setItemIndexMethod(NoIndex). Qt-doc

You will need to call setItemIndexMethod(QGraphicsScene::NoIndex) before insertion:

scene->setItemIndexMethod(QGraphicsScene::NoIndex);

for (int y = 0; y < 100000; y++) {
   scene->addRect(0, y * 25, 40, 20);
}
//...
韬韬不绝 2024-11-17 03:40:25

这可能是由于 float 精度损失造成的。 32 位浮点数有 23 位尾数(或有效数)、1 位符号和 8 位指数。这就像科学记数法。您有 23 个“有效数字”(由于隐式前导 1,实际上是 24 个)和 2^exp 的指数,其中指数范围从 -126 到 127(其他数字用于为您提供诸如 NaN 之类的内容) > 和 Inf)。因此,您可以表示非常大的数字,例如 2^24*2^127 但是 与此类浮点数最接近的浮点数是 (2^24-1)*2^127 或 1700 亿亿十亿远。如果您尝试向这样的数字添加较小的金额(例如 1000),它不会改变。它没有办法表示这一点。

这在计算机图形学中变得很重要,因为您需要留下一些有效数字来构成小数部分。当场景范围达到 1250000.0 时,您可以添加 0.1 并得到 1250000.1。如果您取 2500000.0 + 0.1,您将得到 2500000.0。发生的任何缩放或旋转都会放大该问题。如果您实际上飞到这些坐标并查看场景,这可能会导致明显的视觉问题。

为什么以 0 为中心有帮助?因为浮点表示中有一个单独的符号位。在浮点数中,(-x,+x) 之间的数字比 (0,2x) 之间的数字“更多”。如果我是对的,如果你只是将整个场景缩小 1/2,它也会起作用。这会将最高有效位向下移动,使其在另一端保持精确。

为什么这会导致性能不佳?我只能推测而不阅读 Qt 源代码,但考虑按位置存储对象的数据结构。如果两个对象由于精度损失而接触(或重叠),而您在不重叠时不必这样做,那么您可能需要采取哪些不同的措施?

It could be due to loss of precision with float. A 32 bit float has a 23 bit mantissa (or significand), 1 bit sign and 8 bit exponent. This is like scientific notation. You have 23 "significant digits" (really 24 due to an implicit leading 1) and an exponent of 2^exp where the exponent can range from -126 to 127 (others are used to give you things like NaN and Inf). So you can represent really large numbers like 2^24*2^127 but the next closest floating point number to such a float is (2^24-1)*2^127 or 170 billion billion billion billion away. If you try to add a smaller amount (like 1000) to such a number it doesn't change. It has no way to represent that.

This becomes significant in computer graphics because you need some of your significant digits left over to make a fractional part. When your scene ranges up to 1250000.0 you can add 0.1 to that and get 1250000.1. If you take 2500000.0 + 0.1 you get 2500000.0. The problem is magnified by any scaling or rotation that occurs. This can lead to obvious visual problems if you actually fly out to those coordinates and look at your scene.

Why does centering around 0 help? Because there's a separate sign bit in the floating point representation. In floating point there are "more numbers" between (-x,+x) than there are from (0,2x). If I'm right it would also work if you simply scaled your entire scene down by 1/2. This moves the most significant bit down leaving it free for precision on the other end.

Why would this lead to poor performance? I can only speculate without reading the Qt source, but consider a data structure for storing objects by location. What might you have to do differently if two objects touch (or overlap) due to loss of precision that you didn't have to do when they did not overlap?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文