Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgraphicsscenebsptreeindex.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
39#include <QtCore/qglobal.h>
40
41#include <private/qgraphicsscene_p.h>
42#include <private/qgraphicsscenebsptreeindex_p.h>
43#include <private/qgraphicssceneindex_p.h>
44
45#include <QtCore/qmath.h>
46#include <QtCore/qdebug.h>
47
48#include <algorithm>
49
51
52static inline int intmaxlog(int n)
53{
54 return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
55}
56
62 bspTreeDepth(0),
63 indexTimerId(0),
64 restartIndexTimer(false),
65 regenerateIndex(true),
66 lastItemCount(0),
67 purgePending(false),
68 sortCacheEnabled(false),
69 updatingSortCache(false)
70{
71}
72
73
83{
85 if (!indexTimerId)
86 return;
87
88 q->killTimer(indexTimerId);
89 indexTimerId = 0;
90
92
93 // Add unindexedItems to indexedItems
94 for (int i = 0; i < unindexedItems.size(); ++i) {
97 if (!freeItemIndexes.isEmpty()) {
98 int freeIndex = freeItemIndexes.takeFirst();
99 item->d_func()->index = freeIndex;
100 indexedItems[freeIndex] = item;
101 } else {
102 item->d_func()->index = indexedItems.size();
104 }
105 }
106 }
107
108 // Determine whether we should regenerate the BSP tree.
109 if (bspTreeDepth == 0) {
110 int oldDepth = intmaxlog(lastItemCount);
112 static const int slack = 100;
113 if (bsp.leafCount() == 0 || (oldDepth != bspTreeDepth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
114 // ### Crude algorithm.
115 regenerateIndex = true;
116 }
117 }
118
119 // Regenerate the tree.
120 if (regenerateIndex) {
121 regenerateIndex = false;
125 }
126
127 // Insert all unindexed items into the tree.
128 for (int i = 0; i < unindexedItems.size(); ++i) {
132 continue;
133 }
136 continue;
137
139 }
140 }
142}
143
144
151{
153 return;
154
155 // Remove stale items from the BSP tree.
157 // Purge this list.
160 for (int i = 0; i < indexedItems.size(); ++i) {
161 if (!indexedItems.at(i))
163 }
164 purgePending = false;
165}
166
173{
175 if (indexTimerId) {
176 restartIndexTimer = true;
177 } else {
178 indexTimerId = q->startTimer(interval);
179 }
180}
181
201
206{
207 if (!item->d_ptr->children.isEmpty()) {
208 QList<QGraphicsItem *> childList = item->d_ptr->children;
209 std::sort(childList.begin(), childList.end(), qt_closestLeaf);
210 for (int i = 0; i < childList.size(); ++i) {
211 QGraphicsItem *item = childList.at(i);
213 climbTree(childList.at(i), stackingOrder);
214 }
215 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
216 for (int i = 0; i < childList.size(); ++i) {
217 QGraphicsItem *item = childList.at(i);
219 climbTree(childList.at(i), stackingOrder);
220 }
221 } else {
222 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
223 }
224}
225
230{
233
235 return;
236
237 updatingSortCache = false;
238 int stackingOrder = 0;
239
240 QList<QGraphicsItem *> topLevels;
241 const QList<QGraphicsItem *> items = q->items();
242 for (int i = 0; i < items.size(); ++i) {
244 if (item && !item->d_ptr->parent)
245 topLevels << item;
246 }
247
248 std::sort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
249 for (int i = 0; i < topLevels.size(); ++i)
250 climbTree(topLevels.at(i), &stackingOrder);
251}
252
265
267{
268 if (!item)
269 return;
270
271 // Prevent reusing a recently deleted pointer: purge all removed item from our lists.
273
274 // Invalidate any sort caching; arrival of a new item means we need to resort.
275 // Update the scene's sort cache settings.
278
279 // Indexing requires sceneBoundingRect(), but because \a item might
280 // not be completely constructed at this point, we need to store it in
281 // a temporary list and schedule an indexing for later.
282 if (item->d_ptr->index == -1) {
286 } else {
288 qWarning("QGraphicsSceneBspTreeIndex::addItem: item has already been added to this BSP");
289 }
290
291 if (recursive) {
292 for (int i = 0; i < item->d_ptr->children.size(); ++i)
293 addItem(item->d_ptr->children.at(i), recursive);
294 }
295}
296
298 bool moveToUnindexedItems)
299{
300 if (!item)
301 return;
302
303 if (item->d_ptr->index != -1) {
309 item->d_ptr->index = -1;
310
313 } else if (item->d_ptr->inDestructor) {
314 // Avoid virtual function calls from the destructor.
315 purgePending = true;
320 }
321 } else {
323 }
324 invalidateSortCache(); // ### Only do this when removing from BSP?
325
326 Q_ASSERT(item->d_ptr->index == -1);
330
331 if (moveToUnindexedItems)
332 addItem(item);
333
334 if (recursive) {
335 for (int i = 0; i < item->d_ptr->children.size(); ++i)
336 removeItem(item->d_ptr->children.at(i), recursive, moveToUnindexedItems);
337 }
338}
339
341 bool onlyTopLevelItems)
342{
344 if (onlyTopLevelItems && rect.isNull())
345 return q->QGraphicsSceneIndex::estimateTopLevelItems(rect, order);
346
350
351 QList<QGraphicsItem *> rectItems = bsp.items(rect, onlyTopLevelItems);
352 if (onlyTopLevelItems) {
353 for (int i = 0; i < untransformableItems.size(); ++i) {
355 if (!item->d_ptr->parent) {
356 rectItems << item;
357 } else {
359 if (!rectItems.contains(item))
360 rectItems << item;
361 }
362 }
363 } else {
364 rectItems += untransformableItems;
365 }
366
367 sortItems(&rectItems, order, sortCacheEnabled, onlyTopLevelItems);
368 return rectItems;
369}
370
377 bool sortCacheEnabled, bool onlyTopLevelItems)
378{
379 if (order == Qt::SortOrder(-1))
380 return;
381
382 if (onlyTopLevelItems) {
384 std::sort(itemList->begin(), itemList->end(), qt_closestLeaf);
385 else if (order == Qt::AscendingOrder)
386 std::sort(itemList->begin(), itemList->end(), qt_notclosestLeaf);
387 return;
388 }
389
390 if (sortCacheEnabled) {
391 if (order == Qt::DescendingOrder) {
392 std::sort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
393 } else if (order == Qt::AscendingOrder) {
394 std::sort(itemList->begin(), itemList->end(), closestItemLast_withCache);
395 }
396 } else {
397 if (order == Qt::DescendingOrder) {
398 std::sort(itemList->begin(), itemList->end(), qt_closestItemFirst);
399 } else if (order == Qt::AscendingOrder) {
400 std::sort(itemList->begin(), itemList->end(), qt_closestItemLast);
401 }
402 }
403}
404
413
415{
417 for (int i = 0; i < d->indexedItems.size(); ++i) {
418 // Ensure item bits are reset properly.
419 if (QGraphicsItem *item = d->indexedItems.at(i)) {
421 item->d_ptr->index = -1;
422 }
423 }
424}
425
431{
433 d->bsp.clear();
434 d->lastItemCount = 0;
435 d->freeItemIndexes.clear();
436 for (int i = 0; i < d->indexedItems.size(); ++i) {
437 // Ensure item bits are reset properly.
438 if (QGraphicsItem *item = d->indexedItems.at(i)) {
440 item->d_ptr->index = -1;
441 }
442 }
443 d->indexedItems.clear();
444 d->unindexedItems.clear();
445 d->untransformableItems.clear();
446 d->regenerateIndex = true;
447}
448
457
466
472{
473 if (!item)
474 return;
475
479 return; // Item is not in BSP tree; nothing to do.
480 }
481
483 QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
484 d->removeItem(thatItem, /*recursive=*/false, /*moveToUnindexedItems=*/true);
485 for (int i = 0; i < item->d_ptr->children.size(); ++i) // ### Do we really need this?
487}
488
497{
500}
501
503{
505 return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order, /*onlyTopLevels=*/true);
506}
507
514{
516 const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->purgeRemovedItems();
517 QList<QGraphicsItem *> itemList;
518 itemList.reserve(d->indexedItems.size() + d->unindexedItems.size());
519
520 // Rebuild the list of items to avoid holes. ### We could also just
521 // compress the item lists at this point.
522 QGraphicsItem *null = nullptr; // work-around for (at least) MSVC 2012 emitting
523 // warning C4100 for its own header <algorithm>
524 // when passing nullptr directly to remove_copy:
525 std::remove_copy(d->indexedItems.cbegin(), d->indexedItems.cend(),
526 std::back_inserter(itemList), null);
527 std::remove_copy(d->unindexedItems.cbegin(), d->unindexedItems.cend(),
528 std::back_inserter(itemList), null);
529
530 d->sortItems(&itemList, order, d->sortCacheEnabled);
531 return itemList;
532}
533
562{
564 return d->bspTreeDepth;
565}
566
568{
570 if (d->bspTreeDepth == depth)
571 return;
572 d->bspTreeDepth = depth;
573 d->resetIndex();
574}
575
583{
585 d->sceneRect = rect;
586 d->resetIndex();
587}
588
596{
598 switch (change) {
600 // Handle ItemIgnoresTransformations
601 QGraphicsItem::GraphicsItemFlags newFlags = *static_cast<const QGraphicsItem::GraphicsItemFlags *>(value);
602 bool ignoredTransform = item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations;
603 bool willIgnoreTransform = newFlags & QGraphicsItem::ItemIgnoresTransformations;
606 bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape
608 if ((ignoredTransform != willIgnoreTransform) || (clipsChildren != willClipChildren)) {
609 QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
610 // Remove item and its descendants from the index and append
611 // them to the list of unindexed items. Then, when the index
612 // is updated, they will be put into the bsp-tree or the list
613 // of untransformable items.
614 d->removeItem(thatItem, /*recursive=*/true, /*moveToUnidexedItems=*/true);
615 }
616 break;
617 }
619 d->invalidateSortCache();
620 break;
622 d->invalidateSortCache();
623 // Handle ItemIgnoresTransformations
624 const QGraphicsItem *newParent = static_cast<const QGraphicsItem *>(value);
625 bool ignoredTransform = item->d_ptr->itemIsUntransformable();
626 bool willIgnoreTransform = (item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations)
627 || (newParent && newParent->d_ptr->itemIsUntransformable());
630 bool ancestorWillClipChildren = newParent
635 if ((ignoredTransform != willIgnoreTransform) || (ancestorClippedChildren != ancestorWillClipChildren)) {
636 QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
637 // Remove item and its descendants from the index and append
638 // them to the list of unindexed items. Then, when the index
639 // is updated, they will be put into the bsp-tree or the list
640 // of untransformable items.
641 d->removeItem(thatItem, /*recursive=*/true, /*moveToUnidexedItems=*/true);
642 }
643 break;
644 }
645 default:
646 break;
647 }
648}
657{
659 if (event->type() == QEvent::Timer) {
660 if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
661 if (d->restartIndexTimer) {
662 d->restartIndexTimer = false;
663 } else {
664 // this call will kill the timer
665 d->_q_updateIndex();
666 }
667 }
668 }
669 return QObject::event(event);
670}
671
673
674#include "moc_qgraphicsscenebsptreeindex_p.cpp"
\inmodule QtCore
Definition qcoreevent.h:45
bool itemIsUntransformable() const
QList< QGraphicsItem * > children
QRectF sceneEffectiveBoundingRect() const
QGraphicsItem * parent
The QGraphicsItem class is the base class for all graphical items in a QGraphicsScene.
GraphicsItemChange
This enum describes the state changes that are notified by QGraphicsItem::itemChange().
QScopedPointer< QGraphicsItemPrivate > d_ptr
@ ItemContainsChildrenInShape
QGraphicsItem * topLevelItem() const
Returns this item's top-level item.
GraphicsItemFlags flags() const
Returns this item's flags.
void removeItem(QGraphicsItem *item, bool recursive=false, bool moveToUnindexedItems=false)
QGraphicsSceneBspTreeIndexPrivate(QGraphicsScene *scene)
Constructs a private scene bsp index.
void addItem(QGraphicsItem *item, bool recursive=false)
void startIndexTimer(int interval=QGRAPHICSSCENE_INDEXTIMER_TIMEOUT)
QList< QGraphicsItem * > estimateItems(const QRectF &, Qt::SortOrder, bool b=false)
void _q_updateIndex()
This method will update the BSP index by removing the items from the temporary unindexed list and add...
static void sortItems(QList< QGraphicsItem * > *itemList, Qt::SortOrder order, bool cached, bool onlyTopLevelItems=false)
Sort a list of itemList in a specific order and use the cache if requested.
static bool closestItemFirst_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
static bool closestItemLast_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
static void climbTree(QGraphicsItem *item, int *stackingOrder)
The QGraphicsSceneBspTreeIndex class provides an implementation of a BSP indexing algorithm for disco...
void removeItem(QGraphicsItem *item) override
Remove the item from the BSP index.
void updateSceneRect(const QRectF &rect) override
void itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change, const void *const value) override
QList< QGraphicsItem * > estimateItems(const QRectF &rect, Qt::SortOrder order) const override
Returns an estimation visible items that are either inside or intersect with the specified rect and r...
int bspTreeDepth
the depth of the BSP index tree
QList< QGraphicsItem * > estimateTopLevelItems(const QRectF &rect, Qt::SortOrder order) const override
QList< QGraphicsItem * > items(Qt::SortOrder order=Qt::DescendingOrder) const override
Return all items in the BSP index and sort them using order.
void prepareBoundingRectChange(const QGraphicsItem *item) override
void addItem(QGraphicsItem *item) override
Add the item into the BSP index.
bool event(QEvent *event) override
\reimp
void removeItem(QGraphicsItem *item, const QRectF &rect)
void removeItems(const QSet< QGraphicsItem * > &items)
void initialize(const QRectF &rect, int depth)
QList< QGraphicsItem * > items(const QRectF &rect, bool onlyTopLevelItems=false) const
void insertItem(QGraphicsItem *item, const QRectF &rect)
The QGraphicsSceneIndex class provides a base class to implement a custom indexing algorithm for disc...
friend class QGraphicsSceneBspTreeIndex
The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
bool removeOne(const AT &t)
Definition qlist.h:598
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
value_type takeFirst()
Definition qlist.h:566
void clear()
Definition qlist.h:434
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
\inmodule QtCore\reentrant
Definition qrect.h:484
bool isEmpty() const
Definition qset.h:52
void clear()
Definition qset.h:61
\inmodule QtCore
Definition qcoreevent.h:366
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition qcoreevent.h:370
rect
[4]
Combined button and popup list for selecting options.
SortOrder
Definition qnamespace.h:121
@ DescendingOrder
Definition qnamespace.h:123
@ AscendingOrder
Definition qnamespace.h:122
@ QueuedConnection
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qt_closestItemLast(const QGraphicsItem *item1, const QGraphicsItem *item2)
Returns true if item2 is on top of item1.
bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
bool qt_notclosestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2)
Returns true if item1 is on top of item2.
static QT_BEGIN_NAMESPACE int intmaxlog(int n)
#define qWarning
Definition qlogging.h:166
auto qLn(T v)
Definition qmath.h:168
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLint GLenum GLsizei GLsizei GLsizei depth
GLfloat n
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfixed GLfixed GLint GLint order
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
double qreal
Definition qtypes.h:187
QGraphicsScene scene
[0]
QGraphicsItem * item
QList< QTreeWidgetItem * > items
bool contains(const AT &t) const noexcept
Definition qlist.h:45
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...