OLD | NEW |
| (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 | |
12 static const int kSplitThreshold = 8; | |
13 | |
14 enum { | |
15 kTopLeft, | |
16 kTopRight, | |
17 kBottomLeft, | |
18 kBottomRight, | |
19 }; | |
20 enum { | |
21 kTopLeft_Bit = 1 << kTopLeft, | |
22 kTopRight_Bit = 1 << kTopRight, | |
23 kBottomLeft_Bit = 1 << kBottomLeft, | |
24 kBottomRight_Bit = 1 << kBottomRight, | |
25 }; | |
26 enum { | |
27 kMaskLeft = kTopLeft_Bit | kBottomLeft_Bit, | |
28 kMaskRight = kTopRight_Bit | kBottomRight_Bit, | |
29 kMaskTop = kTopLeft_Bit | kTopRight_Bit, | |
30 kMaskBottom = kBottomLeft_Bit | kBottomRight_Bit, | |
31 }; | |
32 | |
33 static U8CPU child_intersect(const SkIRect& query, const SkIPoint& split) { | |
34 // fast quadrant test | |
35 U8CPU intersect = 0xf; | |
36 if (query.fRight < split.fX) { | |
37 intersect &= ~kMaskRight; | |
38 } else if(query.fLeft >= split.fX) { | |
39 intersect &= ~kMaskLeft; | |
40 } | |
41 if (query.fBottom < split.fY) { | |
42 intersect &= ~kMaskBottom; | |
43 } else if(query.fTop >= split.fY) { | |
44 intersect &= ~kMaskTop; | |
45 } | |
46 return intersect; | |
47 } | |
48 | |
49 SkQuadTree::SkQuadTree(const SkIRect& bounds) : fRoot(NULL) { | |
50 SkASSERT((bounds.width() * bounds.height()) > 0); | |
51 fRootBounds = bounds; | |
52 } | |
53 | |
54 SkQuadTree::~SkQuadTree() { | |
55 } | |
56 | |
57 void SkQuadTree::insert(Node* node, Entry* entry) { | |
58 // does it belong in a child? | |
59 if (NULL != node->fChildren[0]) { | |
60 switch(child_intersect(entry->fBounds, node->fSplitPoint)) { | |
61 case kTopLeft_Bit: | |
62 this->insert(node->fChildren[kTopLeft], entry); | |
63 return; | |
64 case kTopRight_Bit: | |
65 this->insert(node->fChildren[kTopRight], entry); | |
66 return; | |
67 case kBottomLeft_Bit: | |
68 this->insert(node->fChildren[kBottomLeft], entry); | |
69 return; | |
70 case kBottomRight_Bit: | |
71 this->insert(node->fChildren[kBottomRight], entry); | |
72 return; | |
73 default: | |
74 node->fEntries.push(entry); | |
75 return; | |
76 } | |
77 } | |
78 // No children yet, add to this node | |
79 node->fEntries.push(entry); | |
80 // should I split? | |
81 if (node->fEntries.getCount() > kSplitThreshold) { | |
82 this->split(node); | |
83 } | |
84 } | |
85 | |
86 void SkQuadTree::split(Node* node) { | |
87 // Build all the children | |
88 node->fSplitPoint = SkIPoint::Make(node->fBounds.centerX(), | |
89 node->fBounds.centerY()); | |
90 for(int index=0; index<kChildCount; ++index) { | |
91 node->fChildren[index] = fNodePool.acquire(); | |
92 } | |
93 node->fChildren[0]->fBounds = SkIRect::MakeLTRB( | |
94 node->fBounds.fLeft, node->fBounds.fTop, | |
95 node->fSplitPoint.fX, node->fSplitPoint.fY); | |
96 node->fChildren[1]->fBounds = SkIRect::MakeLTRB( | |
97 node->fSplitPoint.fX, node->fBounds.fTop, | |
98 node->fBounds.fRight, node->fSplitPoint.fY); | |
99 node->fChildren[2]->fBounds = SkIRect::MakeLTRB( | |
100 node->fBounds.fLeft, node->fSplitPoint.fY, | |
101 node->fSplitPoint.fX, node->fBounds.fBottom); | |
102 node->fChildren[3]->fBounds = SkIRect::MakeLTRB( | |
103 node->fSplitPoint.fX, node->fSplitPoint.fY, | |
104 node->fBounds.fRight, node->fBounds.fBottom); | |
105 // reinsert all the entries of this node to allow child trickle | |
106 SkTInternalSList<Entry> entries; | |
107 entries.pushAll(&node->fEntries); | |
108 while(!entries.isEmpty()) { | |
109 this->insert(node, entries.pop()); | |
110 } | |
111 } | |
112 | |
113 void SkQuadTree::search(Node* node, const SkIRect& query, | |
114 SkTDArray<void*>* results) const { | |
115 for (Entry* entry = node->fEntries.head(); NULL != entry; | |
116 entry = entry->getSListNext()) { | |
117 if (SkIRect::IntersectsNoEmptyCheck(entry->fBounds, query)) { | |
118 results->push(entry->fData); | |
119 } | |
120 } | |
121 if (NULL == node->fChildren[0]) { | |
122 return; | |
123 } | |
124 U8CPU intersect = child_intersect(query, node->fSplitPoint); | |
125 for(int index=0; index<kChildCount; ++index) { | |
126 if (intersect & (1 << index)) { | |
127 this->search(node->fChildren[index], query, results); | |
128 } | |
129 } | |
130 } | |
131 | |
132 void SkQuadTree::clear(Node* node) { | |
133 // first clear the entries of this node | |
134 fEntryPool.releaseAll(&node->fEntries); | |
135 // recurse into and clear all child nodes | |
136 for(int index=0; index<kChildCount; ++index) { | |
137 Node* child = node->fChildren[index]; | |
138 node->fChildren[index] = NULL; | |
139 if (NULL != child) { | |
140 this->clear(child); | |
141 fNodePool.release(child); | |
142 } | |
143 } | |
144 } | |
145 | |
146 int SkQuadTree::getDepth(Node* node) const { | |
147 int maxDepth = 0; | |
148 if (NULL != node) { | |
149 for(int index=0; index<kChildCount; ++index) { | |
150 maxDepth = SkMax32(maxDepth, getDepth(node->fChildren[index])); | |
151 } | |
152 } | |
153 return maxDepth + 1; | |
154 } | |
155 | |
156 void SkQuadTree::insert(void* data, const SkIRect& bounds, bool) { | |
157 if (bounds.isEmpty()) { | |
158 SkASSERT(false); | |
159 return; | |
160 } | |
161 Entry* entry = fEntryPool.acquire(); | |
162 entry->fData = data; | |
163 entry->fBounds = bounds; | |
164 if (NULL == fRoot) { | |
165 fDeferred.push(entry); | |
166 } else { | |
167 this->insert(fRoot, entry); | |
168 } | |
169 } | |
170 | |
171 void SkQuadTree::search(const SkIRect& query, SkTDArray<void*>* results) const { | |
172 SkASSERT(NULL != fRoot); | |
173 SkASSERT(NULL != results); | |
174 if (SkIRect::Intersects(fRootBounds, query)) { | |
175 this->search(fRoot, query, results); | |
176 } | |
177 } | |
178 | |
179 void SkQuadTree::clear() { | |
180 this->flushDeferredInserts(); | |
181 if (NULL != fRoot) { | |
182 this->clear(fRoot); | |
183 fNodePool.release(fRoot); | |
184 fRoot = NULL; | |
185 } | |
186 SkASSERT(fEntryPool.allocated() == fEntryPool.available()); | |
187 SkASSERT(fNodePool.allocated() == fNodePool.available()); | |
188 } | |
189 | |
190 int SkQuadTree::getDepth() const { | |
191 return this->getDepth(fRoot); | |
192 } | |
193 | |
194 void SkQuadTree::rewindInserts() { | |
195 SkASSERT(fClient); | |
196 // Currently only supports deferred inserts | |
197 SkASSERT(NULL == fRoot); | |
198 SkTInternalSList<Entry> entries; | |
199 entries.pushAll(&fDeferred); | |
200 while(!entries.isEmpty()) { | |
201 Entry* entry = entries.pop(); | |
202 if (fClient->shouldRewind(entry->fData)) { | |
203 entry->fData = NULL; | |
204 fEntryPool.release(entry); | |
205 } else { | |
206 fDeferred.push(entry); | |
207 } | |
208 } | |
209 } | |
210 | |
211 void SkQuadTree::flushDeferredInserts() { | |
212 if (NULL == fRoot) { | |
213 fRoot = fNodePool.acquire(); | |
214 fRoot->fBounds = fRootBounds; | |
215 } | |
216 while(!fDeferred.isEmpty()) { | |
217 this->insert(fRoot, fDeferred.pop()); | |
218 } | |
219 } | |
OLD | NEW |