Ticket #13933: improve_quadbuckets.patch
| File improve_quadbuckets.patch, 9.4 KB (added by , 9 years ago) |
|---|
-
src/org/openstreetmap/josm/data/osm/BBox.java
11 11 12 12 public class BBox { 13 13 14 pr ivatedouble xmin = Double.POSITIVE_INFINITY;15 pr ivatedouble xmax = Double.NEGATIVE_INFINITY;16 pr ivatedouble ymin = Double.POSITIVE_INFINITY;17 pr ivatedouble ymax = Double.NEGATIVE_INFINITY;14 protected double xmin = Double.POSITIVE_INFINITY; 15 protected double xmax = Double.NEGATIVE_INFINITY; 16 protected double ymin = Double.POSITIVE_INFINITY; 17 protected double ymax = Double.NEGATIVE_INFINITY; 18 18 19 19 /** 20 * Constructs a new (invalid) BBox 21 */ 22 protected BBox() { } 23 24 25 /** 20 26 * Constructs a new {@code BBox} defined by a single point. 21 27 * 22 28 * @param x X coordinate -
src/org/openstreetmap/josm/data/osm/QuadBuckets.java
14 14 15 15 /** 16 16 * Note: bbox of primitives added to QuadBuckets has to stay the same. In case of coordinate change, primitive must 17 * be removed and re added.17 * be removed and re-added. 18 18 * 19 19 * This class is (no longer) thread safe. 20 20 * @param <T> type of primitives … … 31 31 throw new AssertionError(s); 32 32 } 33 33 34 p ublic static final int MAX_OBJECTS_PER_LEVEL = 16;34 private static final int MAX_OBJECTS_PER_NODE = 48; 35 35 36 static class QBLevel<T extends OsmPrimitive> { 37 private final int level; 38 private final int index; 39 private final BBox bbox; 36 static class QBLevel<T extends OsmPrimitive> extends BBox { 37 private final byte level; 38 private final byte index; 40 39 private final long quad; 41 40 private final QBLevel<T> parent; 42 41 private boolean isLeaf = true; … … 45 44 // child order by index is sw, nw, se, ne 46 45 private QBLevel<T> nw, ne, sw, se; 47 46 48 private final QuadBuckets<T> buckets;49 50 47 private QBLevel<T> getChild(int index) { 51 48 switch (index) { 52 49 case NE_INDEX: 53 50 if (ne == null) { 54 ne = new QBLevel<>(this, index , buckets);51 ne = new QBLevel<>(this, index); 55 52 } 56 53 return ne; 57 54 case NW_INDEX: 58 55 if (nw == null) { 59 nw = new QBLevel<>(this, index , buckets);56 nw = new QBLevel<>(this, index); 60 57 } 61 58 return nw; 62 59 case SE_INDEX: 63 60 if (se == null) { 64 se = new QBLevel<>(this, index , buckets);61 se = new QBLevel<>(this, index); 65 62 } 66 63 return se; 67 64 case SW_INDEX: 68 65 if (sw == null) { 69 sw = new QBLevel<>(this, index , buckets);66 sw = new QBLevel<>(this, index); 70 67 } 71 68 return sw; 72 69 default: … … 81 78 82 79 @Override 83 80 public String toString() { 84 return super.toString() + '[' + level + "]: " + bbox();81 return super.toString() + '[' + level + "]: "; 85 82 } 86 83 87 84 /** 88 85 * Constructor for root node 89 * @param buckets quadbuckets90 86 */ 91 QBLevel(final QuadBuckets<T> buckets) { 87 QBLevel() { 88 super(-180, 90, 180, -90); 92 89 level = 0; 93 90 index = 0; 94 91 quad = 0; 95 92 parent = null; 96 bbox = new BBox(-180, 90, 180, -90);97 this.buckets = buckets;98 93 } 99 94 100 QBLevel(QBLevel<T> parent, int parentIndex , final QuadBuckets<T> buckets) {95 QBLevel(QBLevel<T> parent, int parentIndex) { 101 96 this.parent = parent; 102 this.level = parent.level + 1; 103 this.index = parentIndex; 104 this.buckets = buckets; 97 this.level = (byte) (parent.level + 1); 98 this.index = (byte) parentIndex; 105 99 106 100 int shift = (QuadTiling.NR_LEVELS - level) * 2; 107 long mult = 1; 108 // Java blows the big one. It seems to wrap when you shift by > 31 109 if (shift >= 30) { 110 shift -= 30; 111 mult = 1 << 30; 112 } 113 long quadpart = mult * (parentIndex << shift); 101 long quadpart = (long) parentIndex << shift; 114 102 this.quad = parent.quad | quadpart; 115 this.bbox = calculateBBox(); // calculateBBox reference quad 103 LatLon bottomLeft = QuadTiling.tile2LatLon(this.quad); 104 xmin = bottomLeft.lon(); 105 ymin = bottomLeft.lat(); 106 xmax = xmin + parent.width() / 2; 107 ymax = ymin + parent.height() / 2; 116 108 } 117 109 118 private BBox calculateBBox() {119 LatLon bottomLeft = this.coor();120 double lat = bottomLeft.lat() + parent.height() / 2;121 double lon = bottomLeft.lon() + parent.width() / 2;122 return new BBox(bottomLeft.lon(), bottomLeft.lat(), lon, lat);123 }124 125 110 QBLevel<T> findBucket(BBox bbox) { 126 111 if (!hasChildren()) 127 112 return this; … … 282 267 283 268 void doAdd(T o) { 284 269 if (consistency_testing) { 285 if ( !matches(o, this.bbox())) {270 if (o instanceof Node && !matches(o, this)) { 286 271 o.getBBox().getIndex(level); 287 272 o.getBBox().getIndex(level - 1); 288 abort("\nobject " + o + " does not belong in node at level: " + level + " bbox: " + this.bbox());273 abort("\nobject " + o + " does not belong in node at level: " + level + " bbox: " + super.toString()); 289 274 } 290 275 } 291 276 doAddContent(o); 292 if (isLeaf() && content.size() > MAX_OBJECTS_PER_ LEVEL&& level < QuadTiling.NR_LEVELS) {277 if (isLeaf() && content.size() > MAX_OBJECTS_PER_NODE && level < QuadTiling.NR_LEVELS) { 293 278 doSplit(); 294 279 } 295 280 } … … 298 283 findBucket(o.getBBox()).doAdd(o); 299 284 } 300 285 301 private void search( BBox searchBbox, List<T> result) {302 if (!this. bbox().intersects(searchBbox))286 private void search(QuadBuckets<T> buckets, BBox searchBbox, List<T> result) { 287 if (!this.intersects(searchBbox)) 303 288 return; 304 else if ( bbox().bounds(searchBbox)) {289 else if (this.bounds(searchBbox)) { 305 290 buckets.searchCache = this; 306 291 } 307 292 … … 312 297 //TODO Coincidence vector should be calculated here and only buckets that match search_bbox should be checked 313 298 314 299 if (nw != null) { 315 nw.search( searchBbox, result);300 nw.search(buckets, searchBbox, result); 316 301 } 317 302 if (ne != null) { 318 ne.search( searchBbox, result);303 ne.search(buckets, searchBbox, result); 319 304 } 320 305 if (se != null) { 321 se.search( searchBbox, result);306 se.search(buckets, searchBbox, result); 322 307 } 323 308 if (sw != null) { 324 sw.search( searchBbox, result);309 sw.search(buckets, searchBbox, result); 325 310 } 326 311 } 327 312 … … 338 323 return -1; 339 324 } 340 325 341 double width() {342 return bbox.width();343 }344 345 double height() {346 return bbox.height();347 }348 349 public BBox bbox() {350 return bbox;351 }352 353 /*354 * This gives the coordinate of the bottom-left355 * corner of the box356 */357 final LatLon coor() {358 return QuadTiling.tile2LatLon(this.quad);359 }360 361 326 void removeFromParent() { 362 327 if (parent == null) 363 328 return; … … 403 368 404 369 @Override 405 370 public final void clear() { 406 root = new QBLevel<>( this);371 root = new QBLevel<>(); 407 372 searchCache = null; 408 373 size = 0; 409 374 } … … 582 547 return size == 0; 583 548 } 584 549 550 /** 551 * Search the tree for objects in the bbox (or crossing the bbox if they are ways) 552 * @param searchBbox the bbox 553 * @return List of primitives within the bbox (or crossing the bbox if they are ways). Can be empty, but not null. 554 */ 585 555 public List<T> search(BBox searchBbox) { 586 556 List<T> ret = new ArrayList<>(); 587 557 // Doing this cuts down search cost on a real-life data set by about 25% … … 589 559 searchCache = root; 590 560 } 591 561 // Walk back up the tree when the last search spot can not cover the current search 592 while (searchCache != null && !searchCache.b box().bounds(searchBbox)) {562 while (searchCache != null && !searchCache.bounds(searchBbox)) { 593 563 searchCache = searchCache.parent; 594 564 } 595 565 … … 601 571 // Save parent because searchCache might change during search call 602 572 QBLevel<T> tmp = searchCache.parent; 603 573 604 searchCache.search( searchBbox, ret);574 searchCache.search(this, searchBbox, ret); 605 575 606 576 // A way that spans this bucket may be stored in one 607 577 // of the nodes which is a parent of the search cache
