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

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

Issue 131343011: Initial QuadTree implementation (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fixed comments Created 6 years, 10 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
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkQuadTree.h"
9 #include "SkTSort.h"
10 #include <stdio.h>
11 #include <vector>
12
13 class SkQuadTree::QuadTreeNode {
14 public:
15 QuadTreeNode(const SkIRect& bounds)
sugoi1 2014/01/29 15:29:08 Renamed QuadTree to QuadTreeNode
16 : fBounds(bounds)
17 , fTopLeft(NULL)
18 , fTopRight(NULL)
19 , fBottomLeft(NULL)
20 , fBottomRight(NULL)
21 , fCanSubdivide((fBounds.width() * fBounds.height()) > 0) {}
22
23 ~QuadTreeNode() {
24 clear();
25 }
26
27 void clear() {
28 SkDELETE(fTopLeft);
29 fTopLeft = NULL;
30 SkDELETE(fTopRight);
31 fTopRight = NULL;
32 SkDELETE(fBottomLeft);
33 fBottomLeft = NULL;
34 SkDELETE(fBottomRight);
35 fBottomRight = NULL;
36 fData.reset();
37 }
38
39 const SkIRect& getBounds() const { return fBounds; }
40
41 // Insert data into the QuadTreeNode
42 bool insert(SkQuadTree::Data& data) {
43 // Ignore objects which do not belong in this quad tree
44 return data.fInnerBounds.intersect(fBounds) && doInsert(data);
45 }
46
47 // Find all data which appear within a range
48 void queryRange(const SkIRect& range, SkTDArray<void*>* dataInRange) const {
49 // Automatically abort if the range does not collide with this quad
50 if (!SkIRect::Intersects(fBounds, range)) {
51 return; // nothing added to the list
52 }
53
54 // Check objects at this quad level
55 for (int i = 0; i < fData.count(); ++i) {
56 if (SkIRect::Intersects(fData[i].fBounds, range)) {
57 dataInRange->push(fData[i].fData);
58 }
59 }
60
61 // Terminate here, if there are no children
62 if (!hasChildren()) {
63 return;
64 }
65
66 // Otherwise, add the data from the children
67 fTopLeft->queryRange(range, dataInRange);
68 fTopRight->queryRange(range, dataInRange);
69 fBottomLeft->queryRange(range, dataInRange);
70 fBottomRight->queryRange(range, dataInRange);
71 }
72
73 int getDepth(int i = 1) const {
74 if (hasChildren()) {
75 int depthTL = fTopLeft->getDepth(++i);
76 int depthTR = fTopRight->getDepth(i);
77 int depthBL = fBottomLeft->getDepth(i);
78 int depthBR = fBottomRight->getDepth(i);
sugoi1 2014/01/29 15:29:08 Fixed an issue here (fNorthWest was use in every c
79 return SkTMax(SkTMax(depthTL, depthTR), SkTMax(depthBL, depthBR));
80 }
81 return i;
82 }
83
84 void rewindInserts(SkBBoxHierarchyClient* client) {
sugoi1 2014/01/29 15:29:08 Implemented recursive rewindInserts for QuadTreeNo
85 for (int i = fData.count() - 1; i >= 0; --i) {
86 if (client->shouldRewind(fData[i].fData)) {
87 fData.remove(i);
88 }
89 }
90 if (hasChildren()) {
91 fTopLeft->rewindInserts(client);
92 fTopRight->rewindInserts(client);
93 fBottomLeft->rewindInserts(client);
94 fBottomRight->rewindInserts(client);
95 }
96 }
97
98 private:
99 // create four children which fully divide this quad into four quads of equa l area
100 void subdivide() {
101 if (!hasChildren() && fCanSubdivide) {
102 SkPoint center = SkPoint::Make(fBounds.centerX(), fBounds.centerY()) ;
103 fTopLeft = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
104 fBounds.fLeft, fBounds.fTop, center.fX, center.fY)));
105 fTopRight = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
106 center.fX, fBounds.fTop, fBounds.fRight, center.fY)));
107 fBottomLeft = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
108 fBounds.fLeft, center.fY, center.fX, fBounds.fBottom)));
109 fBottomRight = SkNEW_ARGS(QuadTreeNode, (SkIRect::MakeLTRB(
110 center.fX, center.fY, fBounds.fRight, fBounds.fBottom)));
111
112 // If any of the data can fit entirely into a subregion, move it dow n now
113 for (int i = fData.count() - 1; i >= 0; --i) {
114 // If the data fits entirely into one of the 4 subregions, move that data
115 // down to that subregion.
116 if (fTopLeft->doInsert(fData[i]) ||
117 fTopRight->doInsert(fData[i]) ||
118 fBottomLeft->doInsert(fData[i]) ||
119 fBottomRight->doInsert(fData[i])) {
120 fData.remove(i);
121 }
122 }
123 }
124 }
125
126 bool doInsert(const SkQuadTree::Data& data) {
127 if (!fBounds.contains(data.fInnerBounds)) {
128 return false;
129 }
130
131 if (fData.count() > QT_NODE_CAPACITY) {
132 subdivide();
133 }
134
135 // If there is space in this quad tree, add the object here
136 // If this quadtree can't be subdivided, we have no choice but to add it here
137 if ((fData.count() <= QT_NODE_CAPACITY) || !fCanSubdivide) {
138 if (fData.isEmpty()) {
139 fData.setReserve(QT_NODE_CAPACITY);
140 }
141 fData.push(data);
142 } else if (!fTopLeft->doInsert(data) && !fTopRight->doInsert(data) &&
143 !fBottomLeft->doInsert(data) && !fBottomRight->doInsert(data) ) {
144 // Can't be pushed down to children ? keep it here
145 fData.push(data);
146 }
147
148 return true;
149 }
150
151 bool hasChildren() const {
152 return (NULL != fTopLeft);
153 }
154
155 // Arbitrary constant to indicate how many elements can be stored in this qu ad tree node
156 static const int QT_NODE_CAPACITY = 4;
157
158 // Bounds of this quad tree
159 SkIRect fBounds;
sugoi1 2014/01/29 15:29:08 Renamed Boundary to Bounds
160
161 // Data in this quad tree node
162 SkTDArray<SkQuadTree::Data> fData;
163
164 // Children
165 QuadTreeNode* fTopLeft;
166 QuadTreeNode* fTopRight;
167 QuadTreeNode* fBottomLeft;
168 QuadTreeNode* fBottomRight;
sugoi1 2014/01/29 15:29:08 Renamed North/South/West/East to Top/Bottom/Left/R
169
170 // Whether or not this node can have children
171 bool fCanSubdivide;
172 };
173
174 //////////////////////////////////////////////////////////////////////////////// ///////////////////
175
176 SkQuadTree* SkQuadTree::Create(const SkIRect& bounds) {
177 return new SkQuadTree(bounds);
178 }
179
180 SkQuadTree::SkQuadTree(const SkIRect& bounds)
181 : fCount(0)
182 , fRoot(SkNEW_ARGS(QuadTreeNode, (bounds))) {
183 SkASSERT((bounds.width() * bounds.height()) > 0);
184 }
185
186 SkQuadTree::~SkQuadTree() {
187 }
188
189 void SkQuadTree::insert(void* data, const SkIRect& bounds, bool) {
190 if (bounds.isEmpty()) {
191 SkASSERT(false);
192 return;
193 }
194
195 SkQuadTree::Data quadTreeData(bounds, data);
196 fRoot->insert(quadTreeData);
197 ++fCount;
198 }
199
200 void SkQuadTree::search(const SkIRect& query, SkTDArray<void*>* results) {
201 SkASSERT(NULL != results);
202 fRoot->queryRange(query, results);
203 }
204
205 void SkQuadTree::clear() {
206 fCount = 0;
207 fRoot->clear();
208 }
209
210 int SkQuadTree::getDepth() const {
211 return fRoot->getDepth();
212 }
213
214 void SkQuadTree::rewindInserts() {
215 SkASSERT(fClient);
216 fRoot->rewindInserts(fClient);
217 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698