Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(592)

Side by Side Diff: src/core/SkQuadTree.cpp

Issue 187233002: Fast implementation of QuadTree (Closed) Base URL: https://skia.googlesource.com/skia.git@bbh_select
Patch Set: I give up, stoopid compiler Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkQuadTree.h ('k') | src/core/SkQuadTreePicture.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkQuadTree.h" 8 #include "SkQuadTree.h"
9 #include "SkTSort.h" 9 #include "SkTSort.h"
10 #include <stdio.h> 10 #include <stdio.h>
11 #include <vector> 11 #include <vector>
12 12
13 class SkQuadTree::QuadTreeNode { 13 static const int kSplitThreshold = 8;
14 public: 14 static const int kMinDimensions = 128;
15 struct Data {
16 Data(const SkIRect& bounds, void* data) : fBounds(bounds), fInnerBounds( bounds), fData(data) {}
17 SkIRect fBounds;
18 SkIRect fInnerBounds;
19 void* fData;
20 };
21
22 QuadTreeNode(const SkIRect& bounds)
23 : fBounds(bounds)
24 , fTopLeft(NULL)
25 , fTopRight(NULL)
26 , fBottomLeft(NULL)
27 , fBottomRight(NULL)
28 , fCanSubdivide((fBounds.width() * fBounds.height()) > 0) {}
29
30 ~QuadTreeNode() {
31 clear();
32 }
33
34 void clear() {
35 SkDELETE(fTopLeft);
36 fTopLeft = NULL;
37 SkDELETE(fTopRight);
38 fTopRight = NULL;
39 SkDELETE(fBottomLeft);
40 fBottomLeft = NULL;
41 SkDELETE(fBottomRight);
42 fBottomRight = NULL;
43 fData.reset();
44 }
45
46 const SkIRect& getBounds() const { return fBounds; }
47
48 // Insert data into the QuadTreeNode
49 bool insert(Data& data) {
50 // Ignore objects which do not belong in this quad tree
51 return data.fInnerBounds.intersect(fBounds) && doInsert(data);
52 }
53
54 // Find all data which appear within a range
55 void queryRange(const SkIRect& range, SkTDArray<void*>* dataInRange) const {
56 // Automatically abort if the range does not collide with this quad
57 if (!SkIRect::Intersects(fBounds, range)) {
58 return; // nothing added to the list
59 }
60
61 // Check objects at this quad level
62 for (int i = 0; i < fData.count(); ++i) {
63 if (SkIRect::Intersects(fData[i].fBounds, range)) {
64 dataInRange->push(fData[i].fData);
65 }
66 }
67
68 // Terminate here, if there are no children
69 if (!hasChildren()) {
70 return;
71 }
72
73 // Otherwise, add the data from the children
74 fTopLeft->queryRange(range, dataInRange);
75 fTopRight->queryRange(range, dataInRange);
76 fBottomLeft->queryRange(range, dataInRange);
77 fBottomRight->queryRange(range, dataInRange);
78 }
79
80 int getDepth(int i = 1) const {
81 if (hasChildren()) {
82 int depthTL = fTopLeft->getDepth(++i);
83 int depthTR = fTopRight->getDepth(i);
84 int depthBL = fBottomLeft->getDepth(i);
85 int depthBR = fBottomRight->getDepth(i);
86 return SkTMax(SkTMax(depthTL, depthTR), SkTMax(depthBL, depthBR));
87 }
88 return i;
89 }
90
91 void rewindInserts(SkBBoxHierarchyClient* client) {
92 for (int i = fData.count() - 1; i >= 0; --i) {
93 if (client->shouldRewind(fData[i].fData)) {
94 fData.remove(i);
95 }
96 }
97 if (hasChildren()) {
98 fTopLeft->rewindInserts(client);
99 fTopRight->rewindInserts(client);
100 fBottomLeft->rewindInserts(client);
101 fBottomRight->rewindInserts(client);
102 }
103 }
104
105 private:
106 // create four children which fully divide this quad into four quads of equa l area
107 void subdivide() {
108 if (!hasChildren() && fCanSubdivide) {
109 SkIPoint center = SkIPoint::Make(fBounds.centerX(), fBounds.centerY( ));
110 fTopLeft = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
111 fBounds.fLeft, fBounds.fTop, center.fX, center.fY)));
112 fTopRight = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
113 center.fX, fBounds.fTop, fBounds.fRight, center.fY)));
114 fBottomLeft = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
115 fBounds.fLeft, center.fY, center.fX, fBounds.fBottom)));
116 fBottomRight = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
117 center.fX, center.fY, fBounds.fRight, fBounds.fBottom)));
118
119 // If any of the data can fit entirely into a subregion, move it dow n now
120 for (int i = fData.count() - 1; i >= 0; --i) {
121 // If the data fits entirely into one of the 4 subregions, move that data
122 // down to that subregion.
123 if (fTopLeft->doInsert(fData[i]) ||
124 fTopRight->doInsert(fData[i]) ||
125 fBottomLeft->doInsert(fData[i]) ||
126 fBottomRight->doInsert(fData[i])) {
127 fData.remove(i);
128 }
129 }
130 }
131 }
132
133 bool doInsert(const Data& data) {
134 if (!fBounds.contains(data.fInnerBounds)) {
135 return false;
136 }
137
138 if (fData.count() > kQuadTreeNodeCapacity) {
139 subdivide();
140 }
141
142 // If there is space in this quad tree, add the object here
143 // If this quadtree can't be subdivided, we have no choice but to add it here
144 if ((fData.count() <= kQuadTreeNodeCapacity) || !fCanSubdivide) {
145 if (fData.isEmpty()) {
146 fData.setReserve(kQuadTreeNodeCapacity);
147 }
148 fData.push(data);
149 } else if (!fTopLeft->doInsert(data) && !fTopRight->doInsert(data) &&
150 !fBottomLeft->doInsert(data) && !fBottomRight->doInsert(data) ) {
151 // Can't be pushed down to children ? keep it here
152 fData.push(data);
153 }
154
155 return true;
156 }
157
158 bool hasChildren() const {
159 return (NULL != fTopLeft);
160 }
161
162 // Arbitrary constant to indicate how many elements can be stored in this qu ad tree node
163 enum { kQuadTreeNodeCapacity = 4 };
164
165 // Bounds of this quad tree
166 SkIRect fBounds;
167
168 // Data in this quad tree node
169 SkTDArray<Data> fData;
170
171 // Children
172 QuadTreeNode* fTopLeft;
173 QuadTreeNode* fTopRight;
174 QuadTreeNode* fBottomLeft;
175 QuadTreeNode* fBottomRight;
176
177 // Whether or not this node can have children
178 bool fCanSubdivide;
179 };
180
181 //////////////////////////////////////////////////////////////////////////////// ///////////////////
182
183 SkQuadTree* SkQuadTree::Create(const SkIRect& bounds) {
184 return new SkQuadTree(bounds);
185 }
186 15
187 SkQuadTree::SkQuadTree(const SkIRect& bounds) 16 SkQuadTree::SkQuadTree(const SkIRect& bounds)
188 : fCount(0) 17 : fEntryCount(0)
189 , fRoot(SkNEW_ARGS(QuadTreeNode, (bounds))) { 18 , fRoot(NULL) {
190 SkASSERT((bounds.width() * bounds.height()) > 0); 19 SkASSERT((bounds.width() * bounds.height()) > 0);
20 fRoot = fNodePool.acquire();
21 fRoot->fBounds = bounds;
191 } 22 }
192 23
193 SkQuadTree::~SkQuadTree() { 24 SkQuadTree::~SkQuadTree() {
194 SkDELETE(fRoot); 25 }
26
27 SkQuadTree::Node* SkQuadTree::pickChild(Node* node,
28 const SkIRect& bounds) const {
29 // is it entirely to the left?
30 int index = 0;
31 if (bounds.fRight < node->fSplitPoint.fX) {
32 // Inside the left side
33 } else if(bounds.fLeft >= node->fSplitPoint.fX) {
34 // Inside the right side
35 index |= 1;
36 } else {
37 // Not inside any children
38 return NULL;
39 }
40 if (bounds.fBottom < node->fSplitPoint.fY) {
41 // Inside the top side
42 } else if(bounds.fTop >= node->fSplitPoint.fY) {
43 // Inside the bottom side
44 index |= 2;
45 } else {
46 // Not inside any children
47 return NULL;
48 }
49 return node->fChildren[index];
50 }
51
52 void SkQuadTree::insert(Node* node, Entry* entry) {
53 // does it belong in a child?
54 if (NULL != node->fChildren[0]) {
55 Node* child = pickChild(node, entry->fBounds);
56 if (NULL != child) {
57 insert(child, entry);
58 } else {
59 node->fEntries.push(entry);
60 }
61 return;
62 }
63 // No children yet, add to this node
64 node->fEntries.push(entry);
65 // should I split?
66 if (node->fEntries.getCount() < kSplitThreshold) {
67 return;
68 }
69
70 if ((node->fBounds.width() < kMinDimensions) ||
71 (node->fBounds.height() < kMinDimensions)) {
72 return;
73 }
74
75 // Build all the children
76 node->fSplitPoint = SkIPoint::Make(node->fBounds.centerX(),
77 node->fBounds.centerY());
78 for(int index=0; index<kChildCount; ++index) {
79 node->fChildren[index] = fNodePool.acquire();
80 }
81 node->fChildren[0]->fBounds = SkIRect::MakeLTRB(
82 node->fBounds.fLeft, node->fBounds.fTop,
83 node->fSplitPoint.fX, node->fSplitPoint.fY);
84 node->fChildren[1]->fBounds = SkIRect::MakeLTRB(
85 node->fSplitPoint.fX, node->fBounds.fTop,
86 node->fBounds.fRight, node->fSplitPoint.fY);
87 node->fChildren[2]->fBounds = SkIRect::MakeLTRB(
88 node->fBounds.fLeft, node->fSplitPoint.fY,
89 node->fSplitPoint.fX, node->fBounds.fBottom);
90 node->fChildren[3]->fBounds = SkIRect::MakeLTRB(
91 node->fSplitPoint.fX, node->fSplitPoint.fY,
92 node->fBounds.fRight, node->fBounds.fBottom);
93 // reinsert all the entries of this node to allow child trickle
94 SkTInternalSList<Entry> entries;
95 entries.pushAll(&node->fEntries);
96 while(!entries.isEmpty()) {
97 insert(node, entries.pop());
98 }
99 }
100
101 void SkQuadTree::search(Node* node, const SkIRect& query,
102 SkTDArray<void*>* results) const {
103 for (Entry* entry = node->fEntries.head(); NULL != entry;
104 entry = entry->getSListNext()) {
105 if (SkIRect::IntersectsNoEmptyCheck(entry->fBounds, query)) {
106 results->push(entry->fData);
107 }
108 }
109 if (NULL == node->fChildren[0]) {
110 return;
111 }
112 // fast quadrant test
113 bool left = true;
114 bool right = true;
115 if (query.fRight < node->fSplitPoint.fX) {
116 right = false;
117 } else if(query.fLeft >= node->fSplitPoint.fX) {
118 left = false;
119 }
120 bool top = true;
121 bool bottom = true;
122 if (query.fBottom < node->fSplitPoint.fY) {
123 bottom = false;
124 } else if(query.fTop >= node->fSplitPoint.fY) {
125 top = false;
126 }
127 // search all the active quadrants
128 if (top && left) {
129 search(node->fChildren[0], query, results);
130 }
131 if (top && right) {
132 search(node->fChildren[1], query, results);
133 }
134 if (bottom && left) {
135 search(node->fChildren[2], query, results);
136 }
137 if (bottom && right) {
138 search(node->fChildren[3], query, results);
139 }
140 }
141
142 void SkQuadTree::clear(Node* node) {
143 // first clear the entries of this node
144 fEntryPool.releaseAll(&node->fEntries);
145 // recurse into and clear all child nodes
146 for(int index=0; index<kChildCount; ++index) {
147 Node* child = node->fChildren[index];
148 node->fChildren[index] = NULL;
149 if (NULL != child) {
150 clear(child);
151 fNodePool.release(child);
152 }
153 }
154 }
155
156 int SkQuadTree::getDepth(Node* node) const {
157 int maxDepth = 0;
158 if (NULL != node->fChildren[0]) {
159 for(int index=0; index<kChildCount; ++index) {
160 maxDepth = SkMax32(maxDepth, getDepth(node->fChildren[index]));
161 }
162 }
163 return maxDepth + 1;
195 } 164 }
196 165
197 void SkQuadTree::insert(void* data, const SkIRect& bounds, bool) { 166 void SkQuadTree::insert(void* data, const SkIRect& bounds, bool) {
198 if (bounds.isEmpty()) { 167 if (bounds.isEmpty()) {
199 SkASSERT(false); 168 SkASSERT(false);
200 return; 169 return;
201 } 170 }
202 171 Entry* entry = fEntryPool.acquire();
203 QuadTreeNode::Data quadTreeData(bounds, data); 172 entry->fData = data;
204 fRoot->insert(quadTreeData); 173 entry->fBounds = bounds;
205 ++fCount; 174 ++fEntryCount;
175 if (fRoot->fEntries.isEmpty() && (NULL == fRoot->fChildren[0])) {
176 fDeferred.push(entry);
177 } else {
178 insert(fRoot, entry);
179 }
206 } 180 }
207 181
208 void SkQuadTree::search(const SkIRect& query, SkTDArray<void*>* results) { 182 void SkQuadTree::search(const SkIRect& query, SkTDArray<void*>* results) {
183 SkASSERT(fDeferred.isEmpty());
209 SkASSERT(NULL != results); 184 SkASSERT(NULL != results);
210 fRoot->queryRange(query, results); 185 if (SkIRect::Intersects(fRoot->fBounds, query)) {
186 search(fRoot, query, results);
187 }
211 } 188 }
212 189
213 void SkQuadTree::clear() { 190 void SkQuadTree::clear() {
214 fCount = 0; 191 fEntryCount = 0;
215 fRoot->clear(); 192 clear(fRoot);
216 } 193 }
217 194
218 int SkQuadTree::getDepth() const { 195 int SkQuadTree::getDepth() const {
219 return fRoot->getDepth(); 196 return getDepth(fRoot);
220 } 197 }
221 198
222 void SkQuadTree::rewindInserts() { 199 void SkQuadTree::rewindInserts() {
223 SkASSERT(fClient); 200 SkASSERT(fClient);
224 fRoot->rewindInserts(fClient); 201 // Currently only supports deferred inserts
202 SkASSERT(fRoot->fEntries.isEmpty() && fRoot->fChildren[0] == NULL);
203 SkTInternalSList<Entry> entries;
204 entries.pushAll(&fDeferred);
205 while(!entries.isEmpty()) {
206 Entry* entry = entries.pop();
207 if (fClient->shouldRewind(entry->fData)) {
208 entry->fData = NULL;
209 fEntryPool.release(entry);
210 --fEntryCount;
211 } else {
212 fDeferred.push(entry);
213 }
214 }
225 } 215 }
216
217 void SkQuadTree::flushDeferredInserts() {
218 while(!fDeferred.isEmpty()) {
219 insert(fRoot, fDeferred.pop());
220 }
221 }
OLDNEW
« no previous file with comments | « src/core/SkQuadTree.h ('k') | src/core/SkQuadTreePicture.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698