- Timestamp:
- 2009-10-10T14:08:39+02:00 (15 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
r2165 r2263 98 98 return (int)(mask & (quad >> total_shift)); 99 99 } 100 static public int index( Node n, int level)100 static public int index(LatLon coor, int level) 101 101 { 102 LatLon coor = n.getCoor();103 102 // The nodes that don't return coordinates will all get 104 103 // stuck in a single tile. Hopefully there are not too … … 106 105 if (coor == null) 107 106 return 0; 108 long quad = coorToTile( n.getCoor());107 long quad = coorToTile(coor); 109 108 return index(level, quad); 110 109 } -
trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
r2181 r2263 1 1 // License: GPL. Copyright 2007 by Immanuel Scholz and others 2 2 package org.openstreetmap.josm.data.osm; 3 3 import org.openstreetmap.josm.tools.ReverseLookup; 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 … … 39 39 * conversion of the whole DataSet by iterating over this data structure. 40 40 */ 41 public Collection<Node> nodes = new QuadBuckets();41 public QuadBuckets<Node> nodes = new QuadBuckets<Node>(); 42 42 43 43 /** … … 46 46 * The way nodes are stored only in the way list. 47 47 */ 48 public Collection<Way> ways = new LinkedList<Way>();48 public QuadBuckets<Way> ways = new QuadBuckets<Way>(); 49 49 50 50 /** -
trunk/src/org/openstreetmap/josm/data/osm/QuadBuckets.java
r2197 r2263 1 1 package org.openstreetmap.josm.data.osm; 2 import java.lang.reflect.Array; 2 3 import java.util.ArrayList; 3 4 import java.util.Collection; … … 9 10 import org.openstreetmap.josm.data.coor.EastNorth; 10 11 import org.openstreetmap.josm.data.osm.Node; 12 import org.openstreetmap.josm.data.osm.Way; 13 import org.openstreetmap.josm.data.osm.OsmPrimitive; 11 14 import org.openstreetmap.josm.tools.Pair; 12 15 … … 35 38 36 39 37 public class QuadBuckets implements Collection<Node>40 public class QuadBuckets<T extends OsmPrimitive> implements Collection<T> 38 41 { 39 42 public static boolean debug = false; … … 80 83 public static int TILES_PER_LEVEL_SHIFT = 2; 81 84 public static int TILES_PER_LEVEL = 1<<TILES_PER_LEVEL_SHIFT; 85 // Maybe this should just be a Rectangle?? 82 86 class BBox 83 87 { 84 private double xmin ;85 private double xmax ;86 private double ymin ;87 private double ymax ;88 private double xmin = Double.POSITIVE_INFINITY; 89 private double xmax = Double.NEGATIVE_INFINITY; 90 private double ymin = Double.POSITIVE_INFINITY; 91 private double ymax = Double.NEGATIVE_INFINITY; 88 92 void sanity() 89 93 { … … 107 111 public String toString() 108 112 { 109 return "[ " + xmin + " -> " + xmax + ", "+110 113 return "[ x: " + xmin + " -> " + xmax + 114 ", y: " + ymin + " -> " + ymax + " ]"; 111 115 } 112 116 double min(double a, double b) … … 122 126 return b; 123 127 } 128 private void add(LatLon c) 129 { 130 xmin = min(xmin, c.lon()); 131 xmax = max(xmax, c.lon()); 132 ymin = min(ymin, c.lat()); 133 ymax = max(ymax, c.lat()); 134 } 124 135 public BBox(LatLon a, LatLon b) 125 136 { 126 xmin = min(a.lon(), b.lon()); 127 xmax = max(a.lon(), b.lon()); 128 ymin = min(a.lat(), b.lat()); 129 ymax = max(a.lat(), b.lat()); 137 add(a); 138 add(b); 130 139 sanity(); 131 140 } … … 137 146 ymax = max(a_y, b_y); 138 147 sanity(); 148 } 149 public BBox(Way w) 150 { 151 for (Node n : w.getNodes()) { 152 LatLon coor = n.getCoor(); 153 if (coor == null) 154 continue; 155 add(coor); 156 } 157 this.sanity(); 139 158 } 140 159 public double height() … … 180 199 return this.inside(b) || b.inside(this); 181 200 } 201 List<LatLon> points() 202 { 203 LatLon p1 = new LatLon(ymin, xmin); 204 LatLon p2 = new LatLon(ymin, xmax); 205 LatLon p3 = new LatLon(ymax, xmin); 206 LatLon p4 = new LatLon(ymax, xmax); 207 List<LatLon> ret = new ArrayList<LatLon>(); 208 ret.add(p1); 209 ret.add(p2); 210 ret.add(p3); 211 ret.add(p4); 212 return ret; 213 } 182 214 } 183 215 class QBLevel … … 187 219 QBLevel parent; 188 220 189 public List< Node> content;221 public List<T> content; 190 222 public QBLevel children[]; 223 public String toString() 224 { 225 return super.toString()+ "["+level+"]: " + bbox; 226 } 191 227 public QBLevel(QBLevel parent) 192 228 { 193 229 init(parent); 194 230 } 195 String quads(Node n) 196 { 197 return Long.toHexString(QuadTiling.quadTile(n.getCoor())); 231 String quads(T o) 232 { 233 if (o instanceof Node) { 234 LatLon coor = ((Node)o).getCoor(); 235 if (coor == null) 236 return "null node coordinates"; 237 return Long.toHexString(QuadTiling.quadTile(coor)); 238 } 239 return "Way??"; 240 } 241 boolean remove_content(T o) 242 { 243 boolean ret = this.content.remove(o); 244 if (this.content.size() == 0) 245 this.content = null; 246 return ret; 247 } 248 // Get the correct index for the given primitive 249 // at the given level. If the primitive can not 250 // fit into a single quad at this level, return -1 251 int get_index(T o, int level) 252 { 253 if (debug) 254 out("getting index for " + o + " at level: " + level); 255 if (o instanceof Node) { 256 Node n = (Node)o; 257 LatLon coor = ((Node)o).getCoor(); 258 if (coor == null) 259 return -1; 260 return QuadTiling.index(coor, level); 261 } 262 if (o instanceof Way) { 263 Way w = (Way)o; 264 int index = -1; 265 //for (Node n : w.getNodes()) { 266 for (LatLon c : way_bbox(w).points()) { 267 // LatLon c = n.getCoor(); 268 if (debug) 269 out("getting index for point: " + c); 270 if (index == -1) { 271 index = QuadTiling.index(c, level); 272 if (debug) 273 out("set initial way index to: " + index); 274 continue; 275 } 276 int node_index = QuadTiling.index(c, level); 277 if (debug) 278 out("other node way index: " + node_index); 279 if (node_index != index) { 280 // This happens at level 0 sometimes when a way has no 281 // nodes present. 282 if (debug) { 283 out("way ("+w.getId()+") would have gone across two quads " 284 + node_index + "/" + index + " at level: " + level + " "); 285 out("node count: " + w.getNodes().size()); 286 for (LatLon c2 : way_bbox(w).points()) 287 out("points: " + c2); 288 } 289 return -1; 290 } 291 } 292 return index; 293 } 294 abort("bad primitive: " + o); 295 return -1; 198 296 } 199 297 void split() … … 206 304 abort("overwrote children"); 207 305 } 208 children = new QBLevel[QuadTiling.TILES_PER_LEVEL]; 306 // This is ugly and hackish. But, it seems to work, 307 // and using an ArrayList here seems to cost us 308 // a significant performance penalty -- 50% in my 309 // testing. Child access is one of the single 310 // hottest code paths in this entire class. 311 children = (QBLevel[])Array.newInstance(this.getClass(), QuadTiling.TILES_PER_LEVEL); 209 312 // deferring allocation of children until use 210 313 // seems a bit faster 211 314 //for (int i = 0; i < TILES_PER_LEVEL; i++) 212 315 // children[i] = new QBLevel(this, i); 213 List< Node> tmpcontent = content;316 List<T> tmpcontent = content; 214 317 content = null; 215 for (Node n : tmpcontent) { 216 int new_index = QuadTiling.index(n, level); 318 for (T o : tmpcontent) { 319 int new_index = get_index(o, level); 320 if (new_index == -1) { 321 this.add_content(o); 322 //out("adding content to branch: " + this); 323 continue; 324 } 217 325 if (children[new_index] == null) 218 326 children[new_index] = new QBLevel(this, new_index); 219 327 QBLevel child = children[new_index]; 220 328 if (debug) 221 out("putting "+n+"(q:"+quads(n)+") into ["+new_index+"] " + child.bbox()); 222 child.add(n); 223 } 224 } 225 void add_leaf(Node n) 226 { 227 LatLon c = n.getCoor(); 329 out("putting "+o+"(q:"+quads(o)+") into ["+new_index+"] " + child.bbox()); 330 child.add(o); 331 } 332 } 333 boolean add_content(T o) 334 { 335 boolean ret = false; 336 if (content == null) 337 content = new LinkedList<T>(); 338 ret = content.add(o); 339 if (debug && !this.isLeaf()) 340 pout("added "+o.getClass().getName()+" to non-leaf with size: " + content.size()); 341 return ret; 342 } 343 void add_to_leaf(T o) 344 { 228 345 QBLevel ret = this; 229 if (content == null) { 230 if (debug) 231 out(" new content array"); 232 // I chose a LinkedList because we do not do 233 // any real random access to this. We generally 234 // just run through the whole thing all at once 235 content = new LinkedList<Node>(); 236 } 237 content.add(n); 346 add_content(o); 238 347 if (content.size() > MAX_OBJECTS_PER_LEVEL) { 239 348 if (debug) … … 255 364 return; 256 365 } 257 if (debug) { 258 out(" plain content put now have " + content.size()); 259 if (content.contains(c)) 260 out(" and I already have that one"); 261 } 262 } 263 264 List<Node> search(BBox bbox, LatLon point, double radius) 265 { 266 if (isLeaf()) 267 return search_leaf(bbox, point, radius); 268 return search_branch(bbox, point, radius); 269 } 270 private List<Node> search_leaf(BBox bbox, LatLon point, double radius) 271 { 272 if (debug) 273 out("searching contents in tile " + this.bbox() + " for " + bbox); 366 } 367 /* 368 * This is a quick hack. The problem is that we need the 369 * way's bounding box a *bunch* of times when it gets 370 * inserted. It gets expensive if we have to recreate 371 * them each time. 372 * 373 * An alternative would be to calculate it at .add() time 374 * and passing it down the call chain. 375 */ 376 HashMap<Way,BBox> way_bbox_cache = new HashMap<Way, BBox>(); 377 BBox way_bbox(Way w) 378 { 379 if (way_bbox_cache.size() > 100) 380 way_bbox_cache.clear(); 381 BBox b = way_bbox_cache.get(w); 382 if (b == null) { 383 b = new BBox(w); 384 way_bbox_cache.put(w, b); 385 } 386 return b; 387 //return new BBox(w); 388 } 389 390 boolean matches(T o, BBox search_bbox) 391 { 392 if (o instanceof Node) { 393 LatLon coor = ((Node)o).getCoor(); 394 if (coor == null) 395 return false; 396 return search_bbox.bounds(coor); 397 } 398 if (o instanceof Way) { 399 BBox bbox = way_bbox((Way)o); 400 return bbox.intersects(search_bbox); 401 } 402 abort("matches() bad primitive: " + o); 403 return false; 404 } 405 private List<T> search_contents(BBox search_bbox) 406 { 407 String size = "null"; 408 if (content != null) 409 size = ""+content.size(); 410 if (debug) 411 out("searching contents (size: "+size+") for " + search_bbox); 274 412 /* 275 413 * It is possible that this was created in a split … … 284 422 // the iterator's calls to ArrayList.size() were showing up in 285 423 // some profiles, so I'm trying a LinkedList instead 286 List<Node> ret = new LinkedList<Node>(); 287 for (Node n : content) { 288 // This supports two modes: one where the bbox is just 289 // an outline of the point/radius combo, and one where 290 // it is *just* the bbox. If it is *just* the bbox, 291 // don't consider the points below 292 if (point == null) { 293 ret.add(n); 294 continue; 295 } 296 LatLon c = n.getCoor(); 297 // is greatCircleDistance really necessary? 298 double d = c.greatCircleDistance(point); 299 if (debug) 300 out("[" + level + "] Checking coor: " + c + " dist: " + d + " vs. " + radius + " " + quads(n)); 301 if (d > radius) 302 continue; 303 if (debug) 304 out("hit in quad: "+Long.toHexString(this.quad)+"\n"); 305 //if (ret == null) 306 // ret = new LinkedList<Node>(); 307 ret.add(n); 424 List<T> ret = new LinkedList<T>(); 425 for (T o : content) { 426 if (matches(o, search_bbox)) 427 ret.add(o); 308 428 } 309 429 if (debug) … … 355 475 return null; 356 476 } 357 QBLevel nextLeaf() 477 boolean hasContent() 478 { 479 if (content == null) 480 return false; 481 return true; 482 } 483 QBLevel nextContentNode() 358 484 { 359 485 QBLevel next = this; … … 381 507 // and find the first leaf 382 508 while (!next.isLeaf()) { 383 if (debug) 384 out("["+next.level+"] next node is a branch, moving down..."); 509 if (next.hasContent() && next != this) 510 break; 511 if (debug) 512 out("["+next.level+"] next node ("+next+") is a branch (content: "+next.hasContent()+"), moving down..."); 385 513 for (QBLevel child : next.children) { 386 514 if (child == null) … … 417 545 ret += l.size(); 418 546 } 547 if (content != null) 548 ret += content.size(); 419 549 if (debug) 420 550 out("["+level+"] branch size: " + ret); 421 551 return ret; 422 552 } 423 boolean contains( Noden)553 boolean contains(T n) 424 554 { 425 555 QBLevel res = find_exact(n); … … 428 558 return true; 429 559 } 430 QBLevel find_exact( Noden)560 QBLevel find_exact(T n) 431 561 { 432 562 if (isLeaf()) … … 434 564 return find_exact_branch(n); 435 565 } 436 QBLevel find_exact_leaf( Noden)566 QBLevel find_exact_leaf(T n) 437 567 { 438 568 QBLevel ret = null; … … 441 571 return ret; 442 572 } 443 QBLevel find_exact_branch( Noden)573 QBLevel find_exact_branch(T n) 444 574 { 445 575 QBLevel ret = null; … … 453 583 return ret; 454 584 } 455 boolean add(Node n) 456 { 585 boolean add(T n) 586 { 587 if (consistency_testing) { 588 if (!matches(n, this.bbox())) { 589 out("-----------------------------"); 590 debug = true; 591 get_index(n, level); 592 abort("object " + n + " does not belong in node at level: " + level + " bbox: " + this.bbox()); 593 } 594 } 457 595 if (isLeaf()) 458 add_ leaf(n);596 add_to_leaf(n); 459 597 else 460 add_ branch(n);598 add_to_branch(n); 461 599 return true; 462 600 } 463 QBLevel add_branch(Node n) 464 { 465 LatLon c = n.getCoor(); 466 int index = QuadTiling.index(n, level); 467 if (debug) 601 QBLevel add_to_branch(T n) 602 { 603 int index = get_index(n, level); 604 if (index == -1) { 605 if (debug) 606 out("unable to get index for " + n + "at level: " + level + ", adding content to branch: " + this); 607 this.add_content(n); 608 return this; 609 } 610 if (debug) { 468 611 out("[" + level + "]: " + n + 469 612 " index " + index + " levelquad:" + this.quads() + " level bbox:" + this.bbox()); 470 if (debug)471 613 out(" put in child["+index+"]"); 614 } 472 615 if (children[index] == null) 473 616 children[index] = new QBLevel(this, index); 474 617 children[index].add(n); 475 /* this is broken at the moment because we need to handle the null n.getCoor()476 if (consistency_testing && !children[index].bbox().bounds(n.getCoor())) {477 out("target child["+index+"] does not bound " + children[index].bbox() + " " + c);478 for (int i = 0; i < children.length; i++) {479 QBLevel ch = children[i];480 if (ch == null)481 continue;482 out("child["+i+"] quad: " + ch.quads() + " bounds: " + ch.bbox.bounds(n.getCoor()));483 }484 out(" coor quad: " + quads(n));485 abort("");486 }*/487 488 if (consistency_testing) {489 for (int i = 0; i < children.length; i++) {490 QBLevel ch = children[i];491 if (ch == null)492 continue;493 if (ch.bbox().bounds(c) && i != index) {494 out("multible bounding?? expected: " + index + " but saw at " + i + " " + ch.quads());495 out("child["+i+"] bbox: " + ch.bbox());496 }497 }498 }499 618 return this; 500 619 } 501 private List< Node> search_branch(BBox bbox, LatLon point, double radius)502 { 503 List< Node> ret = null;620 private List<T> search(BBox search_bbox) 621 { 622 List<T> ret = null; 504 623 if (debug) 505 624 System.out.print("[" + level + "] qb bbox: " + this.bbox() + " "); 506 if (!this.bbox().intersects( bbox)) {625 if (!this.bbox().intersects(search_bbox)) { 507 626 if (debug) { 508 627 out("miss " + Long.toHexString(this.quad)); … … 511 630 return ret; 512 631 } 632 if (this.hasContent()) 633 ret = this.search_contents(search_bbox); 634 if (this.isLeaf()) { 635 return ret; 636 } 637 //if (this.hasContent()) 638 // abort("branch had stuff"); 513 639 if (debug) 514 640 out("hit " + this.quads()); … … 516 642 if (debug) 517 643 out("[" + level + "] not leaf, moving down"); 518 int child_nr = 0; 519 for (QBLevel q : children) { 644 for (int i = 0; i < children.length; i++) { 645 QBLevel q = children[i]; 646 if (debug) 647 out("child["+i+"]: " + q); 520 648 if (q == null) 521 649 continue; 522 child_nr++; 523 if (debug) 524 System.out.print(child_nr+": "); 525 List<Node> coors = q.search(bbox, point, radius); 650 if (debug) 651 System.out.print(i+": "); 652 List<T> coors = q.search(search_bbox); 526 653 if (coors == null) 527 654 continue; … … 530 657 else 531 658 ret.addAll(coors); 532 if (q.bbox().bounds( bbox)) {659 if (q.bbox().bounds(search_bbox)) { 533 660 search_cache = q; 534 661 // optimization: do not continue searching … … 551 678 { 552 679 this.parent = parent; 553 if (parent != null) 680 if (parent == null) 681 this.level = 0; 682 else 554 683 this.level = parent.level + 1; 555 684 this.quad = 0; … … 569 698 { 570 699 this.init(parent); 571 this.level = parent.level+1;572 this.parent = parent;573 700 int shift = (QuadBuckets.NR_LEVELS - level) * 2; 574 701 long mult = 1; … … 645 772 root = new QBLevel(null); 646 773 search_cache = null; 774 if (debug) { 775 out("QuadBuckets() cleared: " + this); 776 out("root: " + root + " level: " + root.level + " bbox: " + root.bbox()); 777 } 778 } 779 public boolean add(T n) 780 { 647 781 if (debug) 648 out("QuadBuckets() cleared: " + this); 649 } 650 public boolean add(Node n) 651 { 652 if (debug) 653 out(this + " QuadBuckets() add: " + n + " size now: " + this.size()); 782 out("QuadBuckets() add: " + n + " size now: " + this.size()); 654 783 int before_size = -1; 655 784 if (consistency_testing) 656 785 before_size = root.size(); 657 boolean ret = root.add(n); 786 boolean ret; 787 // A way with no nodes will have an infinitely large 788 // bounding box. Just stash it in the root node. 789 if (!n.isUsable()) 790 ret = root.add_content(n); 791 else 792 ret = root.add(n); 658 793 if (consistency_testing) { 659 794 int end_size = root.size(); … … 663 798 abort("size inconsistency before add: " + before_size + " after: " + end_size); 664 799 } 800 if (debug) 801 out("QuadBuckets() add: " + n + " size after: " + this.size()); 665 802 return ret; 803 } 804 public void reindex() 805 { 806 QBLevel newroot = new QBLevel(null); 807 Iterator<T> i = this.iterator(); 808 while (i.hasNext()) { 809 T o = i.next(); 810 newroot.add(o); 811 } 812 root = newroot; 666 813 } 667 814 public void unsupported() … … 670 817 throw new UnsupportedOperationException(); 671 818 } 672 public boolean retainAll(Collection nodes)673 { 674 for ( Node n: this) {675 if ( nodes.contains(n))819 public boolean retainAll(Collection objects) 820 { 821 for (T o : this) { 822 if (objects.contains(o)) 676 823 continue; 677 if (!this.remove( n))824 if (!this.remove(o)) 678 825 return false; 679 826 } 680 827 return true; 681 828 } 682 public boolean removeAll(Collection nodes) 683 { 684 for (Object o : nodes) { 685 if (!(o instanceof Node)) 686 return false; 687 Node n = (Node)o; 688 if (!this.remove(n)) 829 boolean canStore(Object o) 830 { 831 if (o instanceof Way) 832 return true; 833 if (o instanceof Node) 834 return true; 835 return false; 836 } 837 public boolean removeAll(Collection objects) 838 { 839 for (Object o : objects) { 840 if (!canStore(o)) 841 return false; 842 if (!this.remove(o)) 689 843 return false; 690 844 } 691 845 return true; 692 846 } 693 public boolean addAll(Collection nodes) 694 { 695 for (Object o : nodes) { 696 if (!(o instanceof Node)) 697 return false; 698 Node n = (Node)o; 699 if (!this.add(n)) 847 public boolean addAll(Collection objects) 848 { 849 for (Object o : objects) { 850 if (!canStore(o)) 851 return false; 852 if (!this.add(convert(o))) 700 853 return false; 701 854 } 702 855 return true; 703 856 } 704 public boolean containsAll(Collection nodes)857 public boolean containsAll(Collection objects) 705 858 { 706 859 boolean ret = true; 707 for (Object o : nodes) { 708 if (!(o instanceof Node)) 709 return false; 710 Node n = (Node)o; 711 if (!this.contains(n)) 860 for (Object o : objects) { 861 if (!canStore(o)) 862 return false; 863 if (!this.contains(o)) 712 864 return false; 713 865 } … … 716 868 private void check_type(Object o) 717 869 { 718 if ( o instanceof Node)870 if (canStore(o)) 719 871 return; 720 872 unsupported(); 721 873 } 874 // If anyone has suggestions for how to fix 875 // this properly, I'm listening :) 876 private T convert(Object raw) 877 { 878 //@SuppressWarnings("unchecked") 879 return (T)raw; 880 } 722 881 public boolean remove(Object o) 723 882 { 724 883 check_type(o); 725 return this.remove( (Node)o);726 } 727 public boolean remove( Noden)884 return this.remove(convert(o)); 885 } 886 public boolean remove(T n) 728 887 { 729 888 QBLevel bucket = root.find_exact(n); 730 889 if (!bucket.isLeaf()) 731 890 abort("found branch where leaf expected"); 732 return bucket.content.remove(n); 891 boolean ret = bucket.remove_content(n); 892 return ret; 733 893 } 734 894 public boolean contains(Object o) 735 895 { 736 if (! (o instanceof Node))896 if (!canStore(o)) 737 897 return false; 738 QBLevel bucket = root.find_exact( (Node)o);898 QBLevel bucket = root.find_exact(convert(o)); 739 899 if (bucket == null) 740 900 return false; 741 901 return true; 742 902 } 743 public ArrayList< Node> toArrayList()744 { 745 ArrayList< Node> a = new ArrayList<Node>();746 for ( Noden : this)903 public ArrayList<T> toArrayList() 904 { 905 ArrayList<T> a = new ArrayList<T>(); 906 for (T n : this) 747 907 a.add(n); 748 out("returning array list with size: " + a.size()); 908 if (debug) 909 out("returning array list with size: " + a.size()); 749 910 return a; 750 911 } … … 757 918 return this.toArrayList().toArray(template); 758 919 } 759 class QuadBucketIterator implements Iterator< Node>760 { 761 QBLevel current_ leaf;762 int index_in_leaf;920 class QuadBucketIterator implements Iterator<T> 921 { 922 QBLevel current_node; 923 int content_index; 763 924 int iterated_over; 764 QBLevel next_ leaf(QBLevel q)925 QBLevel next_content_node(QBLevel q) 765 926 { 766 927 if (q == null) 767 928 return null; 768 929 QBLevel orig = q; 769 QBLevel next = q.nextLeaf(); 770 if (consistency_testing && (orig == next)) 930 QBLevel next = q.nextContentNode(); 931 //if (consistency_testing && (orig == next)) 932 if (orig == next) 771 933 abort("got same leaf back leaf: " + q.isLeaf()); 772 934 return next; 773 935 } 774 public QuadBucketIterator(QuadBuckets qb)775 { 776 if (debug) 777 out(this + " is a new iterator qb .root: " + qb.root+ " size: " + qb.size());778 if (qb.root.isLeaf() )779 current_ leaf= qb.root;936 public QuadBucketIterator(QuadBuckets<T> qb) 937 { 938 if (debug) 939 out(this + " is a new iterator qb: " + qb + " size: " + qb.size()); 940 if (qb.root.isLeaf() || qb.root.hasContent()) 941 current_node = qb.root; 780 942 else 781 current_ leaf = next_leaf(qb.root);782 if (debug) 783 out("\titerator first leaf: " + current_ leaf);943 current_node = next_content_node(qb.root); 944 if (debug) 945 out("\titerator first leaf: " + current_node); 784 946 iterated_over = 0; 785 947 } … … 793 955 return true; 794 956 } 795 Nodepeek()796 { 797 if (current_ leaf== null) {957 T peek() 958 { 959 if (current_node == null) { 798 960 if (debug) 799 961 out("null current leaf, nowhere to go"); 800 962 return null; 801 963 } 802 while((current_ leaf.content == null) ||803 ( index_in_leaf >= current_leaf.content.size())) {964 while((current_node.content == null) || 965 (content_index >= current_node.content.size())) { 804 966 if (debug) 805 967 out("moving to next leaf"); 806 index_in_leaf= 0;807 current_ leaf = next_leaf(current_leaf);808 if (current_ leaf== null)968 content_index = 0; 969 current_node = next_content_node(current_node); 970 if (current_node == null) 809 971 break; 810 972 } 811 if (current_ leaf == null || current_leaf.content == null) {812 if (debug) 813 out("late nowhere to go " + current_ leaf);973 if (current_node == null || current_node.content == null) { 974 if (debug) 975 out("late nowhere to go " + current_node); 814 976 return null; 815 977 } 816 return current_ leaf.content.get(index_in_leaf);817 } 818 public Nodenext()819 { 820 Noderet = peek();821 index_in_leaf++;822 if (debug) 823 out("iteration["+iterated_over+"] " + index_in_leaf + " leaf: " + current_leaf);978 return current_node.content.get(content_index); 979 } 980 public T next() 981 { 982 T ret = peek(); 983 content_index++; 984 if (debug) 985 out("iteration["+iterated_over+"] " + content_index + " leaf: " + current_node); 824 986 iterated_over++; 825 987 if (ret == null) { … … 835 997 // 2. move the index back since we removed 836 998 // an element 837 index_in_leaf--; 838 current_leaf.content.remove(index_in_leaf); 839 } 840 } 841 public Iterator<Node> iterator() 999 content_index--; 1000 T object = peek(); 1001 current_node.content.remove(content_index); 1002 } 1003 } 1004 public Iterator<T> iterator() 842 1005 { 843 1006 return new QuadBucketIterator(this); … … 850 1013 out(this + " QuadBuckets size: " + ret); 851 1014 return ret; 1015 } 1016 public int size_iter() 1017 { 1018 int count = 0; 1019 Iterator<T> i = this.iterator(); 1020 while (i.hasNext()) { 1021 i.next(); 1022 count++; 1023 } 1024 return count; 852 1025 } 853 1026 public boolean isEmpty() … … 868 1041 return bbox; 869 1042 } 870 List<Node> search(LatLon point, double radius) 871 { 872 return this.search(search_to_bbox(point, radius), point, radius); 873 } 874 List<Node> search(BBox bbox) 875 { 876 return this.search(bbox, null, -1); 877 } 878 public List<Node> search(LatLon b1, LatLon b2) 1043 List<T> search(Way w) 1044 { 1045 BBox way_bbox = new BBox(w); 1046 return this.search(way_bbox); 1047 } 1048 public List<T> search(Node n, double radius) 1049 { 1050 return this.search(n.getCoor(), radius); 1051 } 1052 public List<T> search(LatLon point, double radius) 1053 { 1054 if (point == null) 1055 return Collections.emptyList(); 1056 return this.search(search_to_bbox(point, radius)); 1057 } 1058 public List<T> search(LatLon b1, LatLon b2) 879 1059 { 880 1060 BBox bbox = new BBox(b1.lon(), b1.lat(), b2.lon(), b2.lat()); … … 882 1062 return this.search(bbox); 883 1063 } 884 List< Node> search(BBox bbox, LatLon point, double radius)1064 List<T> search(BBox search_bbox) 885 1065 { 886 1066 if (debug) { 887 out("qb root search at " + point + " around: " + radius);1067 out("qb root search at " + search_bbox); 888 1068 out("root bbox: " + root.bbox()); 889 1069 } 890 List< Node> ret = null;1070 List<T> ret; 891 1071 // Doing this cuts down search cost on a real-life data 892 1072 // set by about 25% … … 898 1078 // search spot can not cover the current 899 1079 // search 900 while (!search_cache.bbox().bounds(bbox)) { 1080 while (!search_cache.bbox().bounds(search_bbox)) { 1081 out("bbox: " + search_bbox); 1082 if (debug) { 1083 out("search_cache: " + search_cache + " level: " + search_cache.level); 1084 out("search_cache.bbox(): " + search_cache.bbox()); 1085 } 901 1086 search_cache = search_cache.parent; 1087 if (debug) 1088 out("new search_cache: " + search_cache); 902 1089 } 903 1090 } else { 904 1091 search_cache = root; 905 1092 } 906 return search_cache.search(bbox, point, radius); 1093 ret = search_cache.search(search_bbox); 1094 if (ret == null) 1095 ret = new ArrayList<T>(); 1096 // A way that spans this bucket may be stored in one 1097 // of the nodes which is a parent of the search cache 1098 QBLevel tmp = search_cache.parent; 1099 while (tmp != null) { 1100 List<T> content_result = tmp.search_contents(search_bbox); 1101 if (content_result != null) 1102 ret.addAll(content_result); 1103 tmp = tmp.parent; 1104 } 1105 if (ret == null || ret.size() == 0) 1106 return Collections.emptyList(); 1107 if (debug) 1108 out("search of QuadBuckets for " + search_bbox + " ret len: " + ret.size()); 1109 return ret; 907 1110 } 908 1111 }
Note:
See TracChangeset
for help on using the changeset viewer.