Changeset 3476 in josm
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java
r3453 r3476 20 20 private static boolean debug = false; 21 21 private static final boolean consistency_testing = false; 22 private static final int NW_INDEX = 1; 23 private static final int NE_INDEX = 3; 24 private static final int SE_INDEX = 2; 25 private static final int SW_INDEX = 0; 22 26 /* 23 27 * Functions prefixed with __ need locking before … … 62 66 final long quad; 63 67 final QBLevel parent; 68 private boolean isLeaf = true; 64 69 65 70 public List<T> content; 66 public QBLevel children[]; 71 public QBLevel nw, ne, sw, se; 72 73 private QBLevel getChild(int index) { 74 switch (index) { 75 case NE_INDEX: 76 if (ne == null) { 77 ne = new QBLevel(this, index); 78 } 79 return ne; 80 case NW_INDEX: 81 if (nw == null) { 82 nw = new QBLevel(this, index); 83 } 84 return nw; 85 case SE_INDEX: 86 if (se == null) { 87 se = new QBLevel(this, index); 88 } 89 return se; 90 case SW_INDEX: 91 if (sw == null) { 92 sw = new QBLevel(this, index); 93 } 94 return sw; 95 default: 96 return null; 97 } 98 } 99 100 private QBLevel[] getChildren() { 101 // This is ugly and hackish. But, it seems to work, 102 // and using an ArrayList here seems to cost us 103 // a significant performance penalty -- 50% in my 104 // testing. Child access is one of the single 105 // hottest code paths in this entire class. 106 QBLevel[] result = (QBLevel[]) Array.newInstance(this.getClass(), QuadTiling.TILES_PER_LEVEL); 107 result[NW_INDEX] = nw; 108 result[NE_INDEX] = ne; 109 result[SW_INDEX] = sw; 110 result[SE_INDEX] = se; 111 return result; 112 } 113 67 114 @Override 68 public String toString() 69 { 115 public String toString() { 70 116 return super.toString()+ "["+level+"]: " + bbox(); 71 117 } … … 117 163 if (index == -1) 118 164 return this; 119 if (children[index] == null) { 120 children[index] = new QBLevel(this, index); 121 } 122 return children[index].findBucket(bbox); 165 return getChild(index).findBucket(bbox); 123 166 } 124 167 } … … 144 187 } 145 188 } 146 QBLevel[] newChildren()147 {148 // This is ugly and hackish. But, it seems to work,149 // and using an ArrayList here seems to cost us150 // a significant performance penalty -- 50% in my151 // testing. Child access is one of the single152 // hottest code paths in this entire class.153 return (QBLevel[])Array.newInstance(this.getClass(), QuadTiling.TILES_PER_LEVEL);154 }155 189 // Get the correct index for the given primitive 156 190 // at the given level. If the primitive can not … … 190 224 + this.bbox().width()+", "+this.bbox().height()+")"); 191 225 } 192 // deferring allocation of children until use193 // seems a bit faster194 //for (int i = 0; i < TILES_PER_LEVEL; i++)195 // children[i] = new QBLevel(this, i);196 226 List<T> tmpcontent = content; 197 227 content = null; 198 children = newChildren(); 228 199 229 for (T o: tmpcontent) { 200 add(o); 201 } 202 if (!hasChildren()) { 203 // All items stay at this level (get_index == -1). Create at least first child to keep the contract 204 // that at least one child always exists 205 children[0] = new QBLevel(this, 0); 206 } 230 int index = get_index(o.getBBox(), level); 231 if (index == -1) { 232 __add_content(o); 233 } else { 234 getChild(index).doAdd(o); 235 } 236 } 237 isLeaf = false; // It's not enough to check children because all items could end up in this level (index == -1) 207 238 } 208 239 … … 254 285 * is fast. Runtime type determination must be slow. 255 286 */ 256 boolean isLeaf() 257 { 258 if (children == null) 259 return true; 260 return false; 261 } 287 boolean isLeaf() { 288 return isLeaf; 289 } 290 boolean hasChildren() { 291 return nw != null || ne != null || sw != null || se != null; 292 } 293 262 294 QBLevel next_sibling() 263 295 { … … 265 297 if (parent == null) 266 298 return null; 267 if (parent.children == null)268 return null;269 299 int __nr = 0; 270 for (QBLevel sibling : parent. children) {300 for (QBLevel sibling : parent.getChildren()) { 271 301 __nr++; 272 302 int nr = __nr-1; … … 325 355 { 326 356 QBLevel ret = null; 327 for (QBLevel child : this.children) {357 for (QBLevel child : getChildren()) { 328 358 if (child == null) { 329 359 continue; … … 358 388 get_index(o.getBBox(), level-1); 359 389 int nr = 0; 360 for (QBLevel sibling : parent. children) {390 for (QBLevel sibling : parent.getChildren()) { 361 391 out("sibling["+ (nr++) +"]: " + sibling.bbox() + " this: " + (this==sibling)); 362 392 } … … 389 419 } 390 420 return; 391 } 421 } else if (bbox().bounds(search_bbox)) { 422 search_cache = this; 423 } 424 392 425 if (this.hasContent()) { 393 426 search_contents(search_bbox, result); … … 403 436 out("[" + level + "] not leaf, moving down"); 404 437 } 405 for (int i = 0; i < children.length; i++) { 406 QBLevel q = children[i]; 407 if (debug) { 408 out("child["+i+"]: " + q); 409 } 410 if (q == null) { 411 continue; 412 } 413 if (debug) { 414 System.out.print(i+": "); 415 } 416 q.search(search_bbox, result); 417 if (q.bbox().bounds(search_bbox)) { 418 search_cache = q; 419 // optimization: do not continue searching 420 // other tiles if this one wholly contained 421 // what we were looking for. 422 if (debug) { 423 out("break early"); 424 } 425 break; 426 } 438 439 //TODO Coincidence vector should be calculated here and only buckets that match search_bbox should be checked 440 441 if (nw != null) { 442 nw.search(search_bbox, result); 443 } 444 if (ne != null) { 445 ne.search(search_bbox, result); 446 } 447 if (se != null) { 448 se.search(search_bbox, result); 449 } 450 if (sw != null) { 451 sw.search(search_bbox, result); 427 452 } 428 453 } … … 436 461 return -1; 437 462 463 QBLevel[] children = getChildren(); 438 464 for (int i = 0; i < QuadTiling.TILES_PER_LEVEL; i++) { 439 465 if (children[i] == find_this) … … 461 487 return QuadTiling.tile2LatLon(this.quad); 462 488 } 463 boolean hasChildren()464 {465 if (children == null)466 return false;467 468 for (QBLevel child : children) {469 if (child != null)470 return true;471 }472 return false;473 }474 489 void remove_from_parent() 475 490 { … … 477 492 return; 478 493 479 int nr_siblings = 0; 480 for (int i = 0; i < parent.children.length; i++) { 481 QBLevel sibling = parent.children[i]; 482 if (sibling != null) { 483 nr_siblings++; 484 } 485 if (sibling != this) { 486 continue; 487 } 488 if (!canRemove()) { 489 abort("attempt to remove non-empty child: " + this.content + " " + Arrays.toString(this.children)); 490 } 491 parent.children[i] = null; 492 nr_siblings--; 493 } 494 if (nr_siblings == 0) { 495 parent.children = null; 496 } 494 if (!canRemove()) { 495 abort("attempt to remove non-empty child: " + this.content + " " + Arrays.toString(this.getChildren())); 496 } 497 498 if (parent.nw == this) { 499 parent.nw = null; 500 } else if (parent.ne == this) { 501 parent.ne = null; 502 } else if (parent.sw == this) { 503 parent.sw = null; 504 } else if (parent.se == this) { 505 parent.se = null; 506 } 507 497 508 if (parent.canRemove()) { 498 509 parent.remove_from_parent(); … … 791 802 } 792 803 } 793 if (level.children != null) { 794 for (QBLevel child:level.children) { 795 printTreeRecursive(child, indent + 2); 796 } 804 for (QBLevel child:level.getChildren()) { 805 printTreeRecursive(child, indent + 2); 797 806 } 798 807 } -
trunk/test/unit/org/openstreetmap/josm/data/osm/QuadBucketsTest.java
r3166 r3476 4 4 import java.io.FileInputStream; 5 5 import java.util.ArrayList; 6 import java.util.Collection; 7 import java.util.Iterator; 6 8 import java.util.List; 7 9 10 import org.fest.reflect.core.Reflection; 11 import org.fest.reflect.reference.TypeRef; 8 12 import org.junit.Assert; 9 13 import org.junit.Test; … … 20 24 List<Way> allWays = new ArrayList<Way>(ds.getWays()); 21 25 List<Relation> allRelations = new ArrayList<Relation>(ds.getRelations()); 26 27 QuadBuckets<Node> nodes = Reflection.field("nodes").ofType(new TypeRef<QuadBuckets<Node>>() {}).in(ds).get(); 28 QuadBuckets<Way> ways = Reflection.field("ways").ofType(new TypeRef<QuadBuckets<Way>>() {}).in(ds).get(); 29 Collection<Relation> relations = Reflection.field("relations").ofType(new TypeRef<Collection<Relation>>() {}).in(ds).get(); 30 31 int expectedCount = allNodes.size(); 22 32 for (OsmPrimitive o: allNodes) { 23 33 ds.removePrimitive(o); 34 checkIterator(nodes, --expectedCount); 24 35 } 36 expectedCount = allWays.size(); 25 37 for (OsmPrimitive o: allWays) { 26 38 ds.removePrimitive(o); 39 checkIterator(ways, --expectedCount); 27 40 } 28 41 for (OsmPrimitive o: allRelations) { 29 42 ds.removePrimitive(o); 30 43 } 44 Assert.assertTrue(nodes.isEmpty()); 45 Assert.assertTrue(ways.isEmpty()); 46 Assert.assertTrue(relations.isEmpty()); 47 } 31 48 32 Assert.assertTrue(ds.getNodes().isEmpty()); 33 Assert.assertTrue(ds.getWays().isEmpty()); 34 Assert.assertTrue(ds.getRelations().isEmpty()); 49 private void checkIterator(Collection<? extends OsmPrimitive> col, int expectedCount) { 50 int count = 0; 51 Iterator<? extends OsmPrimitive> it = col.iterator(); 52 while (it.hasNext()) { 53 count++; 54 it.next(); 55 } 56 Assert.assertEquals(expectedCount, count); 35 57 } 36 58
Note:
See TracChangeset
for help on using the changeset viewer.