source: trunk/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp@ 573

Last change on this file since 573 was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 24.0 KB
RevLine 
[556]1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \class QGraphicsSceneBspTreeIndex
44 \brief The QGraphicsSceneBspTreeIndex class provides an implementation of
45 a BSP indexing algorithm for discovering items in QGraphicsScene.
46 \since 4.6
47 \ingroup graphicsview-api
48
49 \internal
50
51 QGraphicsSceneBspTreeIndex index use a BSP(Binary Space Partitioning)
52 implementation to discover items quickly. This implementation is
53 very efficient for static scene. It has a depth that you can set.
54 The depth directly affects performance and memory usage; the latter
55 growing exponentially with the depth of the tree. With an optimal tree
56 depth, the index can instantly determine the locality of items, even
57 for scenes with thousands or millions of items. This also greatly improves
58 rendering performance.
59
60 By default, the value is 0, in which case Qt will guess a reasonable
61 default depth based on the size, location and number of items in the
62 scene. If these parameters change frequently, however, you may experience
63 slowdowns as the index retunes the depth internally. You can avoid
64 potential slowdowns by fixating the tree depth through setting this
65 property.
66
67 The depth of the tree and the size of the scene rectangle decide the
68 granularity of the scene's partitioning. The size of each scene segment is
69 determined by the following algorithm:
70
71 The BSP tree has an optimal size when each segment contains between 0 and
72 10 items.
73
74 \sa QGraphicsScene, QGraphicsView, QGraphicsSceneIndex
75*/
76
77#include <QtCore/qglobal.h>
78
79#ifndef QT_NO_GRAPHICSVIEW
80
81#include <private/qgraphicsscene_p.h>
82#include <private/qgraphicsscenebsptreeindex_p.h>
83#include <private/qgraphicssceneindex_p.h>
84
85#include <QtCore/qmath.h>
86#include <QtCore/qdebug.h>
87
88QT_BEGIN_NAMESPACE
89
90static inline int intmaxlog(int n)
91{
92 return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
93}
94
95/*!
96 Constructs a private scene bsp index.
97*/
98QGraphicsSceneBspTreeIndexPrivate::QGraphicsSceneBspTreeIndexPrivate(QGraphicsScene *scene)
99 : QGraphicsSceneIndexPrivate(scene),
100 bspTreeDepth(0),
101 indexTimerId(0),
102 restartIndexTimer(false),
103 regenerateIndex(true),
104 lastItemCount(0),
105 purgePending(false),
106 sortCacheEnabled(false),
107 updatingSortCache(false)
108{
109}
110
111
112/*!
113 This method will update the BSP index by removing the items from the temporary
114 unindexed list and add them in the indexedItems list. This will also
115 update the growingItemsBoundingRect if needed. This will update the BSP
116 implementation as well.
117
118 \internal
119*/
120void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex()
121{
122 Q_Q(QGraphicsSceneBspTreeIndex);
123 if (!indexTimerId)
124 return;
125
126 q->killTimer(indexTimerId);
127 indexTimerId = 0;
128
129 purgeRemovedItems();
130
131 // Add unindexedItems to indexedItems
132 for (int i = 0; i < unindexedItems.size(); ++i) {
133 if (QGraphicsItem *item = unindexedItems.at(i)) {
134 Q_ASSERT(!item->d_ptr->itemDiscovered);
135 if (!freeItemIndexes.isEmpty()) {
136 int freeIndex = freeItemIndexes.takeFirst();
137 item->d_func()->index = freeIndex;
138 indexedItems[freeIndex] = item;
139 } else {
140 item->d_func()->index = indexedItems.size();
141 indexedItems << item;
142 }
143 }
144 }
145
146 // Determine whether we should regenerate the BSP tree.
147 if (bspTreeDepth == 0) {
148 int oldDepth = intmaxlog(lastItemCount);
149 bspTreeDepth = intmaxlog(indexedItems.size());
150 static const int slack = 100;
151 if (bsp.leafCount() == 0 || (oldDepth != bspTreeDepth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
152 // ### Crude algorithm.
153 regenerateIndex = true;
154 }
155 }
156
157 // Regenerate the tree.
158 if (regenerateIndex) {
159 regenerateIndex = false;
160 bsp.initialize(sceneRect, bspTreeDepth);
161 unindexedItems = indexedItems;
162 lastItemCount = indexedItems.size();
163 }
164
165 // Insert all unindexed items into the tree.
166 for (int i = 0; i < unindexedItems.size(); ++i) {
167 if (QGraphicsItem *item = unindexedItems.at(i)) {
168 if (item->d_ptr->itemIsUntransformable()) {
169 untransformableItems << item;
170 continue;
171 }
172 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
173 continue;
174
175 bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect());
176 }
177 }
178 unindexedItems.clear();
179}
180
181
182/*!
183 \internal
184
185 Removes stale pointers from all data structures.
186*/
187void QGraphicsSceneBspTreeIndexPrivate::purgeRemovedItems()
188{
189 if (!purgePending && removedItems.isEmpty())
190 return;
191
192 // Remove stale items from the BSP tree.
193 bsp.removeItems(removedItems);
194 // Purge this list.
195 removedItems.clear();
196 freeItemIndexes.clear();
197 for (int i = 0; i < indexedItems.size(); ++i) {
198 if (!indexedItems.at(i))
199 freeItemIndexes << i;
200 }
201 purgePending = false;
202}
203
204/*!
205 \internal
206
207 Starts or restarts the timer used for reindexing unindexed items.
208*/
209void QGraphicsSceneBspTreeIndexPrivate::startIndexTimer(int interval)
210{
211 Q_Q(QGraphicsSceneBspTreeIndex);
212 if (indexTimerId) {
213 restartIndexTimer = true;
214 } else {
215 indexTimerId = q->startTimer(interval);
216 }
217}
218
219/*!
220 \internal
221*/
222void QGraphicsSceneBspTreeIndexPrivate::resetIndex()
223{
224 purgeRemovedItems();
225 for (int i = 0; i < indexedItems.size(); ++i) {
226 if (QGraphicsItem *item = indexedItems.at(i)) {
227 item->d_ptr->index = -1;
228 Q_ASSERT(!item->d_ptr->itemDiscovered);
229 unindexedItems << item;
230 }
231 }
232 indexedItems.clear();
233 freeItemIndexes.clear();
234 untransformableItems.clear();
235 regenerateIndex = true;
236 startIndexTimer();
237}
238
239/*!
240 \internal
241*/
242void QGraphicsSceneBspTreeIndexPrivate::climbTree(QGraphicsItem *item, int *stackingOrder)
243{
244 if (!item->d_ptr->children.isEmpty()) {
245 QList<QGraphicsItem *> childList = item->d_ptr->children;
246 qSort(childList.begin(), childList.end(), qt_closestLeaf);
247 for (int i = 0; i < childList.size(); ++i) {
248 QGraphicsItem *item = childList.at(i);
249 if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))