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

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: Merged RTree and QuadTree tests and added QuadTree to SampleApp 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::QuadTree {
Justin Novosad 2014/01/28 21:26:13 I find SkQuadTree vs. QuadTree confusing. Why is
sugoi1 2014/01/29 15:29:08 Renamed to QuadTreeNode
14 public:
15 QuadTree(const SkIRect& boundary)
16 : fBoundary(boundary)
17 , fNorthWest(NULL)
Justin Novosad 2014/01/28 21:26:13 We use top/left/right/bottom in skia.
sugoi1 2014/01/29 15:29:08 Done.
18 , fNorthEast(NULL)
19 , fSouthWest(NULL)
20 , fSouthEast(NULL)
21 , fCanSubdivide((fBoundary.width() * fBoundary.height()) > 0) {}
22
23 ~QuadTree() {
24 clear();
25 }
26
27 void clear() {
28 SkDELETE(fNorthWest);
29 fNorthWest = NULL;
30 SkDELETE(fNorthEast);
31 fNorthEast = NULL;
32 SkDELETE(fSouthWest);
33 fSouthWest = NULL;
34 SkDELETE(fSouthEast);
35 fSouthEast = NULL;
36 fData.reset();
37 }
38
39 const SkIRect& getBoundary() const { return fBoundary; }
Justin Novosad 2014/01/28 21:26:13 Bondary -> Bounds, to be consistent with rest of s
sugoi1 2014/01/29 15:29:08 Done.
40
41 // Insert data into the QuadTree
42 bool insert(SkQuadTree::Data& data) {
43 // Ignore objects which do not belong in this quad tree
44 return data.fInnerBounds.intersect(fBoundary) && 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(fBoundary, range)) {
51 return; // nothing added to the list
52 }
53
54 // Check objects at this quad level
55 for (int p = 0; p < fData.count(); ++p) {
56 if (SkIRect::Intersects(fData[p].fBounds, range)) {
57 dataInRange->push(fData[p].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 fNorthWest->queryRange(range, dataInRange);
68 fNorthEast->queryRange(range, dataInRange);
69 fSouthWest->queryRange(range, dataInRange);
70 fSouthEast->queryRange(range, dataInRange);
71 }
72
73 int getDepth(int i = 1) const {
74 if (hasChildren()) {
75 int depthNW = fNorthWest->getDepth(++i);
76 int depthNE = fNorthWest->getDepth(i);
77 int depthSW = fNorthWest->getDepth(i);
78 int depthSE = fNorthWest->getDepth(i);
79 return SkTMax(SkTMax(depthNW, depthNE), SkTMax(depthSW, depthSE));
80 }
81 return i;
82 }
83
84 private:
85 // create four children which fully divide this quad into four quads of equa l area
86 void subdivide() {
87 if (!hasChildren() && fCanSubdivide) {
88 SkPoint center = SkPoint::Make(fBoundary.centerX(), fBoundary.center Y());
89 fNorthWest = SkNEW_ARGS(QuadTree, (SkIRect::MakeLTRB(
90 fBoundary.fLeft, fBoundary.fTop, center.fX, center.fY)));
91 fNorthEast = SkNEW_ARGS(QuadTree, (SkIRect::MakeLTRB(
92 center.fX, fBoundary.fTop, fBoundary.fRight, center.fY)));
93 fSouthWest = SkNEW_ARGS(QuadTree, (SkIRect::MakeLTRB(
94 fBoundary.fLeft, center.fY, center.fX, fBoundary.fBottom)));
95 fSouthEast = SkNEW_ARGS(QuadTree, (SkIRect::MakeLTRB(
96 center.fX, center.fY, fBoundary.fRight, fBoundary.fBottom)));
97
98 // If any of the data can fit entirely into a subregion, move it dow n now
99 for (int i = fData.count() - 1; i >= 0; --i) {
100 // If the data fits entirely into one of the 4 subregions, move that data
101 // down to that subregion.
102 if (fNorthWest->doInsert(fData[i]) ||
103 fNorthEast->doInsert(fData[i]) ||
104 fSouthWest->doInsert(fData[i]) ||
105 fSouthEast->doInsert(fData[i])) {
106 fData.remove(i);
107 }
108 }
109 }
110 }
111
112 bool doInsert(const SkQuadTree::Data& data) {
113 if (!fBoundary.contains(data.fInnerBounds)) {
114 return false;
115 }
116
117 if (fData.count() > QT_NODE_CAPACITY) {
118 subdivide();
119 }
120
121 // If there is space in this quad tree, add the object here
122 // If this quadtree can't be subdivided, we have no choice but to add it here
123 if ((fData.count() <= QT_NODE_CAPACITY) || !fCanSubdivide) {
124 if (fData.isEmpty()) {
125 fData.setReserve(QT_NODE_CAPACITY);
126 }
127 fData.push(data);
128 } else if (!fNorthWest->doInsert(data) && !fNorthEast->doInsert(data) &&
129 !fSouthWest->doInsert(data) && !fSouthEast->doInsert(data)) {
130 // Can't be pushed down to children ? keep it here
131 fData.push(data);
132 }
133
134 return true;
135 }
136
137 bool hasChildren() const {
138 return (NULL != fNorthWest);
139 }
140
141 // Arbitrary constant to indicate how many elements can be stored in this qu ad tree node
142 static const int QT_NODE_CAPACITY = 4;
143
144 // Axis-aligned bounding box stored as a center with half-dimensions
145 // to represent the boundaries of this quad tree
146 SkIRect fBoundary;
147
148 // Data in this quad tree node
149 SkTDArray<SkQuadTree::Data> fData;
150
151 // Children
152 QuadTree* fNorthWest;
153 QuadTree* fNorthEast;
154 QuadTree* fSouthWest;
155 QuadTree* fSouthEast;
156 bool fCanSubdivide;
157 };
158
159 //////////////////////////////////////////////////////////////////////////////// ///////////////////
160
161 SkQuadTree* SkQuadTree::Create(const SkIRect& bounds) {
162 return new SkQuadTree(bounds);
163 }
164
165 SkQuadTree::SkQuadTree(const SkIRect& bounds)
166 : fCount(0)
167 , fQuadTree(SkNEW_ARGS(QuadTree, (bounds))) {
168 SkASSERT((bounds.width() * bounds.height()) > 0);
169 }
170
171 SkQuadTree::~SkQuadTree() {
172 }
173
174 void SkQuadTree::insert(void* data, const SkIRect& bounds, bool) {
175 if (bounds.isEmpty()) {
176 SkASSERT(false);
177 return;
178 }
179
180 SkQuadTree::Data quadTreeData(bounds, data);
181 fQuadTree->insert(quadTreeData);
182 ++fCount;
183 }
184
185 void SkQuadTree::search(const SkIRect& query, SkTDArray<void*>* results) {
186 SkASSERT(NULL != results);
187 fQuadTree->queryRange(query, results);
188 }
189
190 void SkQuadTree::clear() {
191 fCount = 0;
192 fQuadTree->clear();
193 }
194
195 int SkQuadTree::getDepth() const {
196 return fQuadTree->getDepth();
197 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698