Changeset 6171 in josm
- Timestamp:
- 2013-08-21T13:38:23+02:00 (11 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/data
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/coor/QuadTiling.java
r4319 r6171 9 9 public static final int TILES_PER_LEVEL_SHIFT = 2; // Has to be 2. Other parts of QuadBuckets code rely on it 10 10 public static final int TILES_PER_LEVEL = 1<<TILES_PER_LEVEL_SHIFT; 11 static public final int X_PARTS = 360;12 static public final int X_BIAS = -180;11 public static final int X_PARTS = 360; 12 public static final int X_BIAS = -180; 13 13 14 static public final int Y_PARTS = 180;15 static public final int Y_BIAS = -90;14 public static final int Y_PARTS = 180; 15 public static final int Y_BIAS = -90; 16 16 17 public static LatLon tile2LatLon(long quad) 18 { 17 public static LatLon tile2LatLon(long quad) { 19 18 // The world is divided up into X_PARTS,Y_PARTS. 20 19 // The question is how far we move for each bit … … 44 43 return new LatLon(y, x); 45 44 } 46 static long xy2tile(long x, long y)47 {45 46 static long xy2tile(long x, long y) { 48 47 long tile = 0; 49 48 int i; … … 58 57 return tile; 59 58 } 60 static long coorToTile(LatLon coor)61 {59 60 static long coorToTile(LatLon coor) { 62 61 return quadTile(coor); 63 62 } 64 static long lon2x(double lon)65 {63 64 static long lon2x(double lon) { 66 65 //return Math.round((lon + 180.0) * QuadBuckets.WORLD_PARTS / 360.0)-1; 67 66 long ret = (long)((lon + 180.0) * WORLD_PARTS / 360.0); … … 71 70 return ret; 72 71 } 73 static long lat2y(double lat)74 {72 73 static long lat2y(double lat) { 75 74 //return Math.round((lat + 90.0) * QuadBuckets.WORLD_PARTS / 180.0)-1; 76 75 long ret = (long)((lat + 90.0) * WORLD_PARTS / 180.0); … … 80 79 return ret; 81 80 } 82 static public long quadTile(LatLon coor) 83 { 84 return xy2tile(lon2x(coor.lon()), 85 lat2y(coor.lat())); 81 82 public static long quadTile(LatLon coor) { 83 return xy2tile(lon2x(coor.lon()), lat2y(coor.lat())); 86 84 } 87 static public int index(int level, long quad)88 {85 86 public static int index(int level, long quad) { 89 87 long mask = 0x00000003; 90 88 int total_shift = TILES_PER_LEVEL_SHIFT*(NR_LEVELS-level-1); 91 89 return (int)(mask & (quad >> total_shift)); 92 90 } 93 static public int index(LatLon coor, int level) { 94 // The nodes that don't return coordinates will all get 95 // stuck in a single tile. Hopefully there are not too 96 // many of them 91 92 /** 93 * Returns quad tiling index for given coordinates and level. 94 * 95 * @param coor coordinates 96 * @param level level 97 * 98 * @return quad tiling index for given coordinates and level. 99 * @since 2263 100 */ 101 public static int index(LatLon coor, int level) { 102 // The nodes that don't return coordinates will all get stuck in a single tile. 103 // Hopefully there are not too many of them 97 104 if (coor == null) 98 105 return 0; 99 106 100 long x = lon2x(coor.lon()); 101 long y = lat2y(coor.lat()); 107 return index(coor.lat(), coor.lon(), level); 108 } 109 110 /** 111 * Returns quad tiling index for given coordinates and level. 112 * 113 * @param lat latitude 114 * @param lon longitude 115 * @param level level 116 * 117 * @return quad tiling index for given coordinates and level. 118 * @since 6171 119 */ 120 public static int index(final double lat, final double lon, final int level) { 121 long x = lon2x(lon); 122 long y = lat2y(lat); 102 123 int shift = NR_LEVELS-level-1; 103 124 return (int)((x >> shift & 1) * 2 + (y >> shift & 1)); -
trunk/src/org/openstreetmap/josm/data/osm/BBox.java
r6069 r6171 8 8 import org.openstreetmap.josm.data.Bounds; 9 9 import org.openstreetmap.josm.data.coor.LatLon; 10 import org.openstreetmap.josm.data.coor.QuadTiling; 10 11 import org.openstreetmap.josm.tools.Utils; 11 12 … … 152 153 } 153 154 154 /**155 * Returns a list of all 4 corners of the bbox rectangle.156 */157 public List<LatLon> points() {158 LatLon p1 = new LatLon(ymin, xmin);159 LatLon p2 = new LatLon(ymin, xmax);160 LatLon p3 = new LatLon(ymax, xmin);161 LatLon p4 = new LatLon(ymax, xmax);162 List<LatLon> ret = new ArrayList<LatLon>(4);163 ret.add(p1);164 ret.add(p2);165 ret.add(p3);166 ret.add(p4);167 return ret;168 }169 170 155 public LatLon getTopLeft() { 171 156 return new LatLon(ymax, xmin); … … 178 163 public LatLon getCenter() { 179 164 return new LatLon(ymin + (ymax-ymin)/2.0, xmin + (xmax-xmin)/2.0); 165 } 166 167 int getIndex(final int level) { 168 169 int idx1 = QuadTiling.index(ymin, xmin, level); 170 171 final int idx2 = QuadTiling.index(ymin, xmax, level); 172 if (idx1 == -1) idx1 = idx2; 173 else if (idx1 != idx2) return -1; 174 175 final int idx3 = QuadTiling.index(ymax, xmin, level); 176 if (idx1 == -1) idx1 = idx3; 177 else if (idx1 != idx3) return -1; 178 179 final int idx4 = QuadTiling.index(ymax, xmax, level); 180 if (idx1 == -1) idx1 = idx4; 181 else if (idx1 != idx4) return -1; 182 183 return idx1; 180 184 } 181 185 -
trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java
r6113 r6171 9 9 import java.util.List; 10 10 11 import org.openstreetmap.josm.Main; 11 12 import org.openstreetmap.josm.data.coor.LatLon; 12 13 import org.openstreetmap.josm.data.coor.QuadTiling; … … 21 22 public class QuadBuckets<T extends OsmPrimitive> implements Collection<T> 22 23 { 23 //private static boolean debug = false;24 24 private static final boolean consistency_testing = false; 25 25 private static final int NW_INDEX = 1; … … 28 28 private static final int SW_INDEX = 0; 29 29 30 static void abort(String s) 31 { 30 static void abort(String s) { 32 31 throw new AssertionError(s); 33 32 } 34 static void out(String s)35 {36 System.out.println(s);37 }38 // periodic output39 long last_out = -1;40 void pout(String s)41 {42 long now = System.currentTimeMillis();43 if (now - last_out < 300)44 return;45 last_out = now;46 System.out.print(s + "\r");47 }48 void pout(String s, int i, int total)49 {50 long now = System.currentTimeMillis();51 if ((now - last_out < 300) &&52 ((i+1) < total))53 return;54 last_out = now;55 // cast to float to keep the output size down56 System.out.print(s + " " + (float)((i+1)*100.0/total) + "% done \r");57 }58 33 59 34 public static final int MAX_OBJECTS_PER_LEVEL = 16; 35 60 36 class QBLevel 61 37 { … … 115 91 return super.toString()+ "["+level+"]: " + bbox(); 116 92 } 93 117 94 /** 118 95 * Constructor for root node … … 130 107 int shift = (QuadTiling.NR_LEVELS - level) * 2; 131 108 long mult = 1; 132 // Java blows the big one. It seems to wrap when 133 // you shift by > 31 109 // Java blows the big one. It seems to wrap when you shift by > 31 134 110 if (shift >= 30) { 135 111 shift -= 30; … … 139 115 this.quad = parent.quad | this_quadpart; 140 116 this.bbox = calculateBBox(); // calculateBBox reference quad 141 /*if (debug) {142 out("new level["+this.level+"] bbox["+parent_index+"]: " + this.bbox()143 + " coor: " + this.coor()144 + " quadpart: " + Long.toHexString(this_quadpart)145 + " quad: " + Long.toHexString(this.quad));146 }*/147 117 } 148 118 … … 159 129 return this; 160 130 else { 161 int index = get_index(bbox,level);131 int index = bbox.getIndex(level); 162 132 if (index == -1) 163 133 return this; … … 166 136 } 167 137 168 boolean remove_content(T o) 169 { 138 boolean remove_content(T o) { 170 139 // If two threads try to remove item at the same time from different buckets of this QBLevel, 171 140 // it might happen that one thread removes bucket but don't remove parent because it still sees … … 184 153 return ret; 185 154 } 186 // Get the correct index for the given primitive 187 // at the given level. If the primitive can not 188 // fit into a single quad at this level, return -1 189 int get_index(BBox bbox, int level) { 190 int index = -1; 191 for (LatLon c : bbox.points()) { 192 /*if (debug) { 193 out("getting index for point: " + c); 194 }*/ 195 if (index == -1) { 196 index = QuadTiling.index(c, level); 197 /*if (debug) { 198 out("set initial index to: " + index); 199 }*/ 200 continue; 201 } 202 int another_index = QuadTiling.index(c, level); 203 /*if (debug) { 204 out("other point index: " + another_index); 205 }*/ 206 if (another_index != index) 207 return -1; 208 } 209 return index; 210 } 155 211 156 /* 212 157 * There is a race between this and qb.nextContentNode(). … … 216 161 */ 217 162 void __split() { 218 /*if (debug) {219 out("splitting "+this.bbox()+" level "+level+" with "220 + content.size() + " entries (my dimensions: "221 + this.bbox().width()+", "+this.bbox().height()+")");222 }*/223 163 List<T> tmpcontent = content; 224 164 content = null; 225 165 226 166 for (T o: tmpcontent) { 227 int index = get_index(o.getBBox(),level);167 int index = o.getBBox().getIndex(level); 228 168 if (index == -1) { 229 169 __add_content(o); … … 235 175 } 236 176 237 boolean __add_content(T o) 238 { 177 boolean __add_content(T o) { 239 178 boolean ret = false; 240 // The split_lock will keep two concurrent 241 // calls from overwriting content 179 // The split_lock will keep two concurrent calls from overwriting content 242 180 if (content == null) { 243 181 content = new ArrayList<T>(); 244 182 } 245 183 ret = content.add(o); 246 /*if (debug && !this.isLeaf()) {247 pout("added "+o.getClass().getName()+" to non-leaf with size: " + content.size());248 }*/249 184 return ret; 250 185 } 251 boolean matches(T o, BBox search_bbox)252 {186 187 boolean matches(T o, BBox search_bbox) { 253 188 // This can be optimized when o is a node 254 //return search_bbox.bounds(coor));255 189 return o.getBBox().intersects(search_bbox); 256 190 } 257 private void search_contents(BBox search_bbox, List<T> result) 258 { 259 /*if (debug) { 260 out("searching contents (size: " + content == null?"<null>":content.size() + ") for " + search_bbox); 261 }*/ 191 192 private void search_contents(BBox search_bbox, List<T> result) { 262 193 /* 263 194 * It is possible that this was created in a split … … 272 203 } 273 204 } 274 /*if (debug) { 275 out("done searching quad " + Long.toHexString(this.quad)); 276 }*/ 277 } 205 } 206 278 207 /* 279 * This is stupid. 280 * class decending from a QBLevel. 281 * as slow. 282 * is fast. 208 * This is stupid. I tried to have a QBLeaf and QBBranch 209 * class decending from a QBLevel. It's more than twice 210 * as slow. So, this throws OO out the window, but it 211 * is fast. Runtime type determination must be slow. 283 212 */ 284 213 boolean isLeaf() { 285 214 return isLeaf; 286 215 } 216 287 217 boolean hasChildren() { 288 218 return nw != null || ne != null || sw != null || se != null; 289 219 } 290 220 291 QBLevel next_sibling() 292 { 221 QBLevel next_sibling() { 293 222 boolean found_me = false; 294 223 if (parent == null) 295 224 return null; 296 int __nr = 0;297 225 for (QBLevel sibling : parent.getChildren()) { 298 __nr++;299 int nr = __nr-1;300 226 if (sibling == null) { 301 /*if (debug) {302 out("[" + this.level + "] null child nr: " + nr);303 }*/304 227 continue; 305 228 } 306 // We're looking for the *next* child 307 // after us. 229 // We're looking for the *next* child after us. 308 230 if (sibling == this) { 309 /*if (debug) {310 out("[" + this.level + "] I was child nr: " + nr);311 }*/312 231 found_me = true; 313 232 continue; 314 233 } 315 234 if (found_me) 316 /*if (debug) {317 out("[" + this.level + "] next sibling was child nr: " + nr);318 }*/319 235 return sibling; 320 236 } 321 237 return null; 322 238 } 323 boolean hasContent()324 {239 240 boolean hasContent() { 325 241 return content != null; 326 242 } 327 QBLevel nextSibling()328 {243 244 QBLevel nextSibling() { 329 245 QBLevel next = this; 330 246 QBLevel sibling = next.next_sibling(); … … 333 249 // a leaf or branch. 334 250 while (sibling == null) { 335 /*if (debug) {336 out("no siblings at level["+next.level+"], moving to parent");337 }*/338 251 next = next.parent; 339 252 if (next == null) { … … 345 258 return next; 346 259 } 347 QBLevel firstChild()348 {260 261 QBLevel firstChild() { 349 262 QBLevel ret = null; 350 263 for (QBLevel child : getChildren()) { … … 357 270 return ret; 358 271 } 359 QBLevel nextNode()360 {272 273 QBLevel nextNode() { 361 274 if (!this.hasChildren()) 362 275 return this.nextSibling(); 363 276 return this.firstChild(); 364 277 } 365 QBLevel nextContentNode()366 {278 279 QBLevel nextContentNode() { 367 280 QBLevel next = this.nextNode(); 368 281 if (next == null) … … 376 289 if (consistency_testing) { 377 290 if (!matches(o, this.bbox())) { 378 /*out("-----------------------------"); 379 debug = true;*/ 380 get_index(o.getBBox(), level); 381 get_index(o.getBBox(), level-1); 291 o.getBBox().getIndex(level); 292 o.getBBox().getIndex(level-1); 382 293 int nr = 0; 383 /*for (QBLevel sibling : parent.getChildren()) {384 out("sibling["+ (nr++) +"]: " + sibling.bbox() + " this: " + (this==sibling));385 }*/386 294 abort("\nobject " + o + " does not belong in node at level: " + level + " bbox: " + this.bbox()); 387 295 } … … 397 305 } 398 306 399 private void search(BBox search_bbox, List<T> result) 400 { 401 /*if (debug) { 402 System.out.print("[" + level + "] qb bbox: " + this.bbox() + " "); 403 }*/ 307 private void search(BBox search_bbox, List<T> result) { 404 308 if (!this.bbox().intersects(search_bbox)) 405 /*if (debug) {406 out("miss " + Long.toHexString(this.quad));407 //QuadTiling.tile2xy(this.quad);408 }*/409 309 return; 410 310 else if (bbox().bounds(search_bbox)) { … … 416 316 } 417 317 418 /*if (debug) {419 out("hit " + this.quads());420 out("[" + level + "] not leaf, moving down");421 }*/422 423 318 //TODO Coincidence vector should be calculated here and only buckets that match search_bbox should be checked 424 319 … … 436 331 } 437 332 } 438 public String quads()439 {333 334 public String quads() { 440 335 return Long.toHexString(quad); 441 336 } 442 int index_of(QBLevel find_this)443 {337 338 int index_of(QBLevel find_this) { 444 339 QBLevel[] children = getChildren(); 445 340 for (int i = 0; i < QuadTiling.TILES_PER_LEVEL; i++) { … … 449 344 return -1; 450 345 } 346 451 347 double width() { 452 348 return bbox.width(); … … 460 356 return bbox; 461 357 } 358 462 359 /* 463 360 * This gives the coordinate of the bottom-left 464 361 * corner of the box 465 362 */ 466 LatLon coor() 467 { 363 LatLon coor() { 468 364 return QuadTiling.tile2LatLon(this.quad); 469 365 } 470 void remove_from_parent()471 {366 367 void remove_from_parent() { 472 368 if (parent == null) 473 369 return; … … 491 387 } 492 388 } 493 boolean canRemove()494 {389 390 boolean canRemove() { 495 391 if (content != null && !content.isEmpty()) 496 392 return false; … … 505 401 private int size; 506 402 507 public QuadBuckets() 508 { 403 /** 404 * Constructs a new {@code QuadBuckets}. 405 */ 406 public QuadBuckets() { 509 407 clear(); 510 408 } 409 511 410 @Override 512 411 public void clear() { … … 514 413 search_cache = null; 515 414 size = 0; 516 /*if (debug) { 517 out("QuadBuckets() cleared: " + this); 518 out("root: " + root + " level: " + root.level + " bbox: " + root.bbox()); 519 }*/ 520 } 415 } 416 521 417 @Override 522 418 public boolean add(T n) { … … 527 423 528 424 @Override 529 public boolean retainAll(Collection<?> objects) 530 { 425 public boolean retainAll(Collection<?> objects) { 531 426 for (T o : this) { 532 427 if (objects.contains(o)) { … … 538 433 return true; 539 434 } 540 @Override541 public boolean removeAll(Collection<?> objects)542 {435 436 @Override 437 public boolean removeAll(Collection<?> objects) { 543 438 boolean changed = false; 544 439 for (Object o : objects) { … … 547 442 return changed; 548 443 } 549 @Override550 public boolean addAll(Collection<? extends T> objects)551 {444 445 @Override 446 public boolean addAll(Collection<? extends T> objects) { 552 447 boolean changed = false; 553 448 for (T o : objects) { … … 556 451 return changed; 557 452 } 558 @Override559 public boolean containsAll(Collection<?> objects)560 {453 454 @Override 455 public boolean containsAll(Collection<?> objects) { 561 456 for (Object o : objects) { 562 457 if (!this.contains(o)) … … 565 460 return true; 566 461 } 462 567 463 @Override 568 464 public boolean remove(Object o) { … … 576 472 return false; 577 473 } 474 578 475 @Override 579 476 public boolean contains(Object o) { … … 583 480 } 584 481 585 public ArrayList<T> toArrayList() 586 { 482 public ArrayList<T> toArrayList() { 587 483 ArrayList<T> a = new ArrayList<T>(); 588 484 for (T n : this) { 589 485 a.add(n); 590 486 } 591 /*if (debug) {592 out("returning array list with size: " + a.size());593 }*/594 487 return a; 595 488 } 596 @Override597 public Object[] toArray()598 {489 490 @Override 491 public Object[] toArray() { 599 492 return this.toArrayList().toArray(); 600 493 } 601 @Override602 public <A> A[] toArray(A[] template)603 {494 495 @Override 496 public <A> A[] toArray(A[] template) { 604 497 return this.toArrayList().toArray(template); 605 498 } 499 606 500 class QuadBucketIterator implements Iterator<T> 607 501 { … … 609 503 int content_index; 610 504 int iterated_over; 611 QBLevel next_content_node(QBLevel q) 612 { 505 QBLevel next_content_node(QBLevel q) { 613 506 if (q == null) 614 507 return null; … … 622 515 return next; 623 516 } 624 public QuadBucketIterator(QuadBuckets<T> qb) 625 { 626 /*if (debug) { 627 out(this + " is a new iterator qb: " + qb + " size: " + qb.size()); 628 }*/ 517 518 public QuadBucketIterator(QuadBuckets<T> qb) { 629 519 if (!qb.root.hasChildren() || qb.root.hasContent()) { 630 520 current_node = qb.root; … … 632 522 current_node = next_content_node(qb.root); 633 523 } 634 /*if (debug) {635 out("\titerator first leaf: " + current_node);636 }*/637 524 iterated_over = 0; 638 525 } 526 639 527 @Override 640 public boolean hasNext() 641 { 528 public boolean hasNext() { 642 529 if (this.peek() == null) 643 /*if (debug) {644 out(this + " no hasNext(), but iterated over so far: " + iterated_over);645 }*/646 530 return false; 647 531 return true; 648 532 } 649 T peek()650 {533 534 T peek() { 651 535 if (current_node == null) 652 /*if (debug) {653 out("null current leaf, nowhere to go");654 }*/655 536 return null; 656 537 while((current_node.content == null) || 657 538 (content_index >= current_node.content.size())) { 658 /*if (debug) {659 out("moving to next leaf");660 }*/661 539 content_index = 0; 662 540 current_node = next_content_node(current_node); … … 666 544 } 667 545 if (current_node == null || current_node.content == null) 668 /*if (debug) {669 out("late nowhere to go " + current_node);670 }*/671 546 return null; 672 547 return current_node.content.get(content_index); 673 548 } 549 674 550 @Override 675 public T next() 676 { 551 public T next() { 677 552 T ret = peek(); 678 553 content_index++; 679 /*if (debug) {680 out("iteration["+iterated_over+"] " + content_index + " leaf: " + current_node);681 }*/682 554 iterated_over++; 683 if (ret == null) {684 /*if (debug) {685 out(this + " no next node, but iterated over so far: " + iterated_over);686 }*/687 }688 555 return ret; 689 556 } 557 690 558 @Override 691 public void remove() 692 { 559 public void remove() { 693 560 // two uses 694 561 // 1. Back up to the thing we just returned … … 700 567 } 701 568 } 702 @Override703 public Iterator<T> iterator()704 {569 570 @Override 571 public Iterator<T> iterator() { 705 572 return new QuadBucketIterator(this); 706 573 } 574 707 575 @Override 708 576 public int size() { … … 711 579 712 580 @Override 713 public boolean isEmpty() 714 { 581 public boolean isEmpty() { 715 582 if (this.size() == 0) 716 583 return true; 717 584 return false; 718 585 } 586 719 587 public List<T> search(BBox search_bbox) { 720 /*if (debug) {721 out("qb root search at " + search_bbox);722 out("root bbox: " + root.bbox());723 }*/724 588 List<T> ret = new ArrayList<T>(); 725 // Doing this cuts down search cost on a real-life data 726 // set by about 25% 589 // Doing this cuts down search cost on a real-life data set by about 25% 727 590 boolean cache_searches = true; 728 591 if (cache_searches) { … … 730 593 search_cache = root; 731 594 } 732 // Walk back up the tree when the last 733 // search spot can not cover the current 734 // search 595 // Walk back up the tree when the last search spot can not cover the current search 735 596 while (search_cache != null && !search_cache.bbox().bounds(search_bbox)) { 736 /*if (debug) {737 out("bbox: " + search_bbox);738 out("search_cache: " + search_cache + " level: " + search_cache.level);739 out("search_cache.bbox(): " + search_cache.bbox());740 }*/741 597 search_cache = search_cache.parent; 742 /*if (debug) {743 out("new search_cache: " + search_cache);744 }*/745 598 } 746 599 747 600 if (search_cache == null) { 748 601 search_cache = root; 749 out("bbox: " + search_bbox + " is out of the world");602 Main.info("bbox: " + search_bbox + " is out of the world"); 750 603 } 751 604 } else { … … 764 617 tmp = tmp.parent; 765 618 } 766 /*if (debug) {767 out("search of QuadBuckets for " + search_bbox + " ret len: " + ret.size());768 }*/769 619 return ret; 770 620 }
Note:
See TracChangeset
for help on using the changeset viewer.