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 #include <vector> |
| 12 |
| 13 class SkQuadTree::QuadTreeNode { |
| 14 public: |
| 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 |
| 187 SkQuadTree::SkQuadTree(const SkIRect& bounds) |
| 188 : fCount(0) |
| 189 , fRoot(SkNEW_ARGS(QuadTreeNode, (bounds))) { |
| 190 SkASSERT((bounds.width() * bounds.height()) > 0); |
| 191 } |
| 192 |
| 193 SkQuadTree::~SkQuadTree() { |
| 194 } |
| 195 |
| 196 void SkQuadTree::insert(void* data, const SkIRect& bounds, bool) { |
| 197 if (bounds.isEmpty()) { |
| 198 SkASSERT(false); |
| 199 return; |
| 200 } |
| 201 |
| 202 QuadTreeNode::Data quadTreeData(bounds, data); |
| 203 fRoot->insert(quadTreeData); |
| 204 ++fCount; |
| 205 } |
| 206 |
| 207 void SkQuadTree::search(const SkIRect& query, SkTDArray<void*>* results) { |
| 208 SkASSERT(NULL != results); |
| 209 fRoot->queryRange(query, results); |
| 210 } |
| 211 |
| 212 void SkQuadTree::clear() { |
| 213 fCount = 0; |
| 214 fRoot->clear(); |
| 215 } |
| 216 |
| 217 int SkQuadTree::getDepth() const { |
| 218 return fRoot->getDepth(); |
| 219 } |
| 220 |
| 221 void SkQuadTree::rewindInserts() { |
| 222 SkASSERT(fClient); |
| 223 fRoot->rewindInserts(fClient); |
| 224 } |
OLD | NEW |