Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgraphicsscene_bsp.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// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qstring.h>
8#include <private/qgraphicsitem_p.h>
9
11
12
13QGraphicsSceneBspTree::QGraphicsSceneBspTree()
14 : leafCnt(0)
15{
16}
17
21
22void QGraphicsSceneBspTree::initialize(const QRectF &rect, int depth)
23{
24 this->rect = rect;
25 leafCnt = 0;
26 nodes.resize((1 << (depth + 1)) - 1);
27 nodes.fill(Node());
28 leaves.resize(1ll << depth);
29 leaves.fill(QList<QGraphicsItem *>());
30
31 initialize(rect, depth, 0);
32}
33
35{
36 leafCnt = 0;
37 nodes.clear();
38 leaves.clear();
39}
40
41void QGraphicsSceneBspTree::insertItem(QGraphicsItem *item, const QRectF &rect)
42{
43 climbTree([item](QList<QGraphicsItem *> *items){
44 items->prepend(item);
45 }, rect);
46}
47
48void QGraphicsSceneBspTree::removeItem(QGraphicsItem *item, const QRectF &rect)
49{
50 climbTree([item](QList<QGraphicsItem *> *items){
51 items->removeAll(item);
52 }, rect);
53}
54
55void QGraphicsSceneBspTree::removeItems(const QSet<QGraphicsItem *> &items)
56{
57 for (int i = 0; i < leaves.size(); ++i) {
58 QList<QGraphicsItem *> newItemList;
59 const QList<QGraphicsItem *> &oldItemList = leaves[i];
60 for (int j = 0; j < oldItemList.size(); ++j) {
61 QGraphicsItem *item = oldItemList.at(j);
62 if (!items.contains(item))
63 newItemList << item;
64 }
65 leaves[i] = newItemList;
66 }
67}
68
69QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QRectF &rect, bool onlyTopLevelItems) const
70{
71 QList<QGraphicsItem *> foundItems;
72 climbTree([&foundItems, onlyTopLevelItems](QList<QGraphicsItem *> *items) {
73 for (int i = 0; i < items->size(); ++i) {
74 QGraphicsItem *item = items->at(i);
75 if (onlyTopLevelItems && item->d_ptr->parent)
76 item = item->topLevelItem();
77 if (!item->d_func()->itemDiscovered && item->d_ptr->visible) {
78 item->d_func()->itemDiscovered = 1;
79 foundItems.prepend(item);
80 }
81 }
82 }, rect);
83 // Reset discovery bits.
84 for (const auto &foundItem : std::as_const(foundItems))
85 foundItem->d_ptr->itemDiscovered = 0;
86 return foundItems;
87}
88
90{
91 return leafCnt;
92}
93
95{
96 const Node *node = &nodes.at(index);
97
98 QString tmp;
99 if (node->type == Node::Leaf) {
100 QRectF rect = rectForIndex(index);
101 if (!leaves[node->leafIndex].isEmpty()) {
102 tmp += QString::fromLatin1("[%1, %2, %3, %4] contains %5 items\n")
103 .arg(rect.left()).arg(rect.top())
104 .arg(rect.width()).arg(rect.height())
105 .arg(leaves[node->leafIndex].size());
106 }
107 } else {
108 if (node->type == Node::Horizontal) {
109 tmp += debug(firstChildIndex(index));
110 tmp += debug(firstChildIndex(index) + 1);
111 } else {
112 tmp += debug(firstChildIndex(index));
113 tmp += debug(firstChildIndex(index) + 1);
114 }
115 }
116
117 return tmp;
118}
119
120void QGraphicsSceneBspTree::initialize(const QRectF &rect, int depth, int index)
121{
122 Node *node = &nodes[index];
123 if (index == 0) {
125 node->offset = rect.center().y();
126 }
127
128 if (depth) {
129 Node::Type type;
130 QRectF rect1, rect2;
131 qreal offset1, offset2;
132
133 if (node->type == Node::Horizontal) {
134 type = Node::Vertical;
135 rect1.setRect(rect.left(), rect.top(), rect.width(), rect.height() / 2);
136 rect2.setRect(rect1.left(), rect1.bottom(), rect1.width(), rect.height() - rect1.height());
137 offset1 = rect1.center().x();
138 offset2 = rect2.center().x();
139 } else {
140 type = Node::Horizontal;
141 rect1.setRect(rect.left(), rect.top(), rect.width() / 2, rect.height());
142 rect2.setRect(rect1.right(), rect1.top(), rect.width() - rect1.width(), rect1.height());
143 offset1 = rect1.center().y();
144 offset2 = rect2.center().y();
145 }
146
147 int childIndex = firstChildIndex(index);
148
149 Node *child = &nodes[childIndex];
150 child->offset = offset1;
151 child->type = type;
152
153 child = &nodes[childIndex + 1];
154 child->offset = offset2;
155 child->type = type;
156
157 initialize(rect1, depth - 1, childIndex);
158 initialize(rect2, depth - 1, childIndex + 1);
159 } else {
160 node->type = Node::Leaf;
161 node->leafIndex = leafCnt++;
162 }
163}
164
165template<typename Visitor>
166void QGraphicsSceneBspTree::climbTree(Visitor &&visitor, const QRectF &rect, int index) const
167{
168 if (nodes.isEmpty())
169 return;
170
171 const Node &node = nodes.at(index);
172 const int childIndex = firstChildIndex(index);
173
174 switch (node.type) {
175 case Node::Leaf: {
176 visitor(const_cast<QList<QGraphicsItem*>*>(&leaves[node.leafIndex]));
177 break;
178 }
179 case Node::Vertical:
180 if (rect.left() < node.offset) {
181 climbTree(visitor, rect, childIndex);
182 if (rect.right() >= node.offset)
183 climbTree(visitor, rect, childIndex + 1);
184 } else {
185 climbTree(visitor, rect, childIndex + 1);
186 }
187 break;
188 case Node::Horizontal:
189 if (rect.top() < node.offset) {
190 climbTree(visitor, rect, childIndex);
191 if (rect.bottom() >= node.offset)
192 climbTree(visitor, rect, childIndex + 1);
193 } else {
194 climbTree(visitor, rect, childIndex + 1);
195 }
196 }
197}
198
199QRectF QGraphicsSceneBspTree::rectForIndex(int index) const
200{
201 if (index <= 0)
202 return rect;
203
204 int parentIdx = parentIndex(index);
205 QRectF rect = rectForIndex(parentIdx);
206 const Node *parent = &nodes.at(parentIdx);
207
208 if (parent->type == Node::Vertical) {
209 if (index & 1)
210 rect.setRight(parent->offset);
211 else
212 rect.setLeft(parent->offset);
213 } else {
214 if (index & 1)
215 rect.setBottom(parent->offset);
216 else
217 rect.setTop(parent->offset);
218 }
219
220 return rect;
221}
222
223QT_END_NAMESPACE
void removeItem(QGraphicsItem *item, const QRectF &rect)
void removeItems(const QSet< QGraphicsItem * > &items)
int firstChildIndex(int index) const
void initialize(const QRectF &rect, int depth)
int parentIndex(int index) const
QList< QGraphicsItem * > items(const QRectF &rect, bool onlyTopLevelItems=false) const
void insertItem(QGraphicsItem *item, const QRectF &rect)
QString debug(int index) const