MATSIM
QuadTree.java
Go to the documentation of this file.
1 /* *********************************************************************** *
2  * project: org.matsim.*
3  * QuadTree.java
4  * *
5  * *********************************************************************** *
6  * *
7  * copyright : (C) 2007 by the members listed in the COPYING, *
8  * LICENSE and WARRANTY file. *
9  * email : info at matsim dot org *
10  * *
11  * *********************************************************************** *
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * See also COPYING, LICENSE and WARRANTY file *
18  * *
19  * *********************************************************************** */
20 
21 package org.matsim.core.utils.collections;
22 
23 import java.io.Serializable;
24 import java.util.*;
25 
38 public class QuadTree<T> implements Serializable {
39 
40  private static final long serialVersionUID = 1L;
41 
43  protected Node<T> top = null;
44 
46  private int size = 0;
47 
49  private transient int modCount = 0;
50 
56  transient volatile Collection<T> values = null;
57 
58  private void incrementSize() { this.modCount++; this.size++; this.values = null; }
59  private void decrementSize() { this.modCount++; this.size--; this.values = null; }
60 
71  public QuadTree(final double minX, final double minY, final double maxX, final double maxY) {
72  this.top = new Node<>(minX, minY, maxX, maxY);
73  }
74 
86  public boolean put(final double x, final double y, final T value) {
87  if (!this.top.bounds.containsOrEquals(x, y)) {
88  throw new IllegalArgumentException("cannot add a point at x=" + x + ", y=" + y + " with bounds " + this.top.bounds);
89  }
90  if (this.top.put(x, y, value)) {
91  incrementSize();
92  return true;
93  }
94  return false;
95  }
96 
108  public boolean remove(final double x, final double y, final T value) {
109  if (this.top.remove(x, y, value)) {
110  decrementSize();
111  return true;
112  }
113  return false;
114  }
115 
117  public void clear() {
118  this.top.clear();
119  this.size = 0;
120  this.modCount++;
121  }
122 
130  public T getClosest(final double x, final double y) {
131  return this.top.get(x, y, new MutableDouble(Double.POSITIVE_INFINITY));
132  }
133 
142  public Collection<T> getDisk(final double x, final double y, final double distance) {
143  return this.top.get(x, y, distance * distance, new ArrayList<>());
144  }
145 
159  public Collection<T> getRing(final double x, final double y, final double rMin, final double rMax) {
160  return this.top.get(x, y, rMin * rMin, rMax * rMax, new ArrayList<>());
161  }
162 
174  public Collection<T> getElliptical(
175  final double x1,
176  final double y1,
177  final double x2,
178  final double y2,
179  final double distance) {
180  if ( Math.pow( distance , 2 ) < Math.pow( (x1 - x2), 2 ) + Math.pow( (y1 - y2) , 2 ) ) {
181  throw new IllegalArgumentException( "wrong ellipse specification: distance must be greater than distance between foci."
182  +" x1="+x1
183  +" y1="+y1
184  +" x2="+x2
185  +" y2="+y2
186  +" distance="+distance );
187  }
188  return this.top.getElliptical(x1, y1, x2, y2, distance, new ArrayList<>());
189  }
190 
191 
200  public Collection<T> getRectangle(final Rect bounds, final Collection<T> values1) {
201  return this.top.get(bounds, values1);
202  }
203 
215  public Collection<T> getRectangle(final double minX, final double minY, final double maxX, final double maxY, final Collection<T> values1) {
216  return getRectangle(new Rect(minX, minY, maxX, maxY), values1);
217  }
218 
226  public int execute(final Rect bounds, final Executor<T> executor) {
227  if (bounds == null) {
228  return this.top.execute(this.top.getBounds(), executor);
229  }
230  return this.top.execute(bounds, executor);
231  }
232 
243  public int execute(final double minX, final double minY, final double maxX, final double maxY, final Executor<T> executor) {
244  return execute(new Rect(minX, minY, maxX, maxY), executor);
245  }
246 
252  public int size() {
253  return this.size;
254  }
255 
257  public double getMinEasting() {
258  return this.top.getBounds().minX;
259  }
260 
262  public double getMaxEasting() {
263  return this.top.getBounds().maxX;
264  }
265 
267  public double getMinNorthing() {
268  return this.top.getBounds().minY;
269  }
270 
272  public double getMaxNorthing() {
273  return this.top.getBounds().maxY;
274  }
275 
285  public Collection<T> values() {
286  if (this.values == null) {
287  this.values = new AbstractCollection<>() {
288  @Override
289  public Iterator<T> iterator() {
290  return new Iterator<>() {
291  private final int expectedModCount = QuadTree.this.modCount;
292  private Leaf<T> currentLeaf = firstLeaf();
293  private int nextIndex = 0;
294  private T next = first();
295 
296  private T first() {
297  if (this.currentLeaf == null) {
298  return null;
299  }
300  this.nextIndex = 0;
301  loadNext();
302  return this.next;
303  }
304 
305  @Override
306  public boolean hasNext() {
307  return this.next != null;
308  }
309 
310  @Override
311  public T next() {
312  if (this.next == null) {
313  return null;
314  }
315  if (QuadTree.this.modCount != this.expectedModCount) {
316  throw new ConcurrentModificationException();
317  }
318  T current = this.next;
319  loadNext();
320  return current;
321  }
322 
323  private void loadNext() {
324  boolean searching = true;
325  while (searching) {
326  int size = this.currentLeaf.value != null ? 1 : this.currentLeaf.values.size();
327  if (this.nextIndex < size) {
328  this.nextIndex++;
329  this.next = this.currentLeaf.value != null ? this.currentLeaf.value : this.currentLeaf.values.get(this.nextIndex - 1);
330  searching = false;
331  } else {
332  this.currentLeaf = nextLeaf(this.currentLeaf);
333  if (this.currentLeaf == null) {
334  this.next = null;
335  searching = false;
336  } else {
337  this.nextIndex = 0;
338  }
339  }
340  }
341  }
342 
343  @Override
344  public void remove() {
345  throw new UnsupportedOperationException();
346  }
347 
348  };
349  }
350 
351  @Override
352  public int size() {
353  return QuadTree.this.size;
354  }
355  };
356  }
357  return this.values;
358  }
359 
360  private Leaf<T> firstLeaf() {
361  return this.top.firstLeaf();
362  }
363 
364  private Leaf<T> nextLeaf(final Leaf<T> currentLeaf) {
365  return this.top.nextLeaf(currentLeaf);
366  }
367 
373  private static class MutableDouble {
374  public double value;
375 
376  public MutableDouble(final double value) {
377  this.value = value;
378  }
379  }
380 
388  private static class MutableLeaf<T> {
389  public Leaf<T> value;
390 
391  public MutableLeaf(final Leaf<T> value) {
392  this.value = value;
393  }
394  }
395 
396  public static class Rect implements Serializable {
397  private static final long serialVersionUID = -837712701959689133L;
398  public final double minX;
399  public final double minY;
400  public final double maxX;
401  public final double maxY;
402  public final double centerX;
403  public final double centerY;
404 
405  public Rect(final double minX, final double minY, final double maxX, final double maxY) {
406  this.minX = Math.min(minX, maxX);
407  this.minY = Math.min(minY, maxY);
408  this.maxX = Math.max(minX, maxX);
409  this.maxY = Math.max(minY, maxY);
410  this.centerX = (minX + maxX) / 2;
411  this.centerY = (minY + maxY) / 2;
412  }
413 
423  public double calcDistance(final double x, final double y) {
424  double distanceX;
425  double distanceY;
426 
427  if (this.minX <= x && x <= this.maxX) {
428  distanceX = 0;
429  } else {
430  distanceX = Math.min(Math.abs(this.minX - x), Math.abs(this.maxX - x));
431  }
432  if (this.minY <= y && y <= this.maxY) {
433  distanceY = 0;
434  } else {
435  distanceY = Math.min(Math.abs(this.minY - y), Math.abs(this.maxY - y));
436  }
437 
438  return Math.sqrt(distanceX * distanceX + distanceY * distanceY);
439  }
440 
450  public double calcDistanceSqr(final double x, final double y) {
451  double distanceX;
452  double distanceY;
453 
454  if (this.minX <= x && x <= this.maxX) {
455  distanceX = 0;
456  } else {
457  distanceX = Math.min(Math.abs(this.minX - x), Math.abs(this.maxX - x));
458  }
459  if (this.minY <= y && y <= this.maxY) {
460  distanceY = 0;
461  } else {
462  distanceY = Math.min(Math.abs(this.minY - y), Math.abs(this.maxY - y));
463  }
464 
465  return distanceX * distanceX + distanceY * distanceY;
466  }
467 
475  public double calcMaxDistanceSqr(final double x, final double y) {
476  double distanceX = Math.max(Math.abs(this.minX - x), Math.abs(this.maxX - x));
477  double distanceY = Math.max(Math.abs(this.minY - y), Math.abs(this.maxY - y));
478 
479  return distanceX * distanceX + distanceY * distanceY;
480  }
481 
482 
491  public boolean contains(final double x, final double y) {
492  return (x >= this.minX &&
493  y >= this.minY &&
494  x < this.maxX &&
495  y < this.maxY);
496  }
497 
498  public boolean containsOrEquals(final double x, final double y) {
499  return (x >= this.minX &&
500  y >= this.minY &&
501  x <= this.maxX &&
502  y <= this.maxY);
503  }
504 
512  public boolean containsOrEquals(final Rect rect) {
513  return (rect.minX >= this.minX &&
514  rect.minY >= this.minY &&
515  rect.maxX <= this.maxX &&
516  rect.maxY <= this.maxY);
517  }
518 
526  public boolean intersects(final Rect other) {
527  if ((this.maxX-this.minX) < 0 || (this.maxY-this.minY) < 0) {
528  return false;
529  }
530  return (other.maxX >= this.minX &&
531  other.maxY >= this.minY &&
532  other.minX <= this.maxX &&
533  other.minY <= this.maxY);
534  }
535 
549  public Rect intersection(final Rect r) {
550  double tx1 = this.minX;
551  double ty1 = this.minY;
552  double tx2 = this.maxX;
553  double ty2 = this.maxY;
554  if (this.minX < r.minX) tx1 = r.minX;
555  if (this.minY < r.minY) ty1 = r.minY;
556  if (tx2 > r.maxX) tx2 = r.maxX;
557  if (ty2 > r.maxY) ty2 = r.maxY;
558  // did they intersect at all?
559  if(tx2-tx1 <=0.f || ty2-ty1 <= 0.f) return null;
560 
561  return new Rect(tx1, ty1, tx2, ty2);
562  }
563 
570  public Rect union(final Rect r) {
571  return new Rect( Math.min(this.minX, r.minX),
572  Math.min(this.minY, r.minY),
573  Math.max(this.maxX, r.maxX),
574  Math.max(this.maxY, r.maxY));
575  }
576 
587  public Rect scale(double scaleX, double scaleY) {
588  scaleY *= this.centerY - this.minY;
589  scaleX *= this.centerX - this.minX;
590  return new Rect(this.minX - scaleX, this.minY-scaleY, this.maxX + scaleX, this.maxY + scaleY);
591  }
592 
593  @Override
594  public String toString() {
595  return "topLeft: ("+minX+","+minY+") bottomRight: ("+maxX+","+maxY+")";
596  }
597 
598  }
599 
600  protected static class Leaf<T> implements Serializable {
601  private static final long serialVersionUID = -6527830222532634476L;
602  final public double x;
603  final public double y;
604  /* a leaf can contain one more multiple objects at the same coordinate.
605  * in many cases it will be only one, so to save memory, we'll store it in "value".
606  * only if actually multiple objects at the same coordinate need to be stored,
607  * we create the values-list and add all objects there.
608  * So either value or values is non-null. it should never be the case that both are null
609  * or both are non-null. mrieser/oct2018
610  */
611  public T value;
612  public ArrayList<T> values;
613 
614  public Leaf(final double x, final double y, final T value) {
615  this.x = x;
616  this.y = y;
617  this.value = value;
618  this.values = null;
619  }
620  }
621 
622  protected static class Node<T> implements Serializable {
623  private static final long serialVersionUID = 8151154226742383421L;
624 
625  private static final int MAX_CHILDS = 128;
626 
627  private ArrayList<Leaf<T>> leaves = null;
628 
629  private boolean hasChilds = false;
630  private Node<T> northwest = null;
631  private Node<T> northeast = null;
632  private Node<T> southeast = null;
633  private Node<T> southwest = null;
634  private final Rect bounds;
635 
636  public Node(final double minX, final double minY, final double maxX, final double maxY) {
637  this.bounds = new Rect(minX, minY, maxX, maxY);
638  }
639 
640  public boolean put(final Leaf<T> leaf) {
641  if (this.hasChilds) return getChild(leaf.x, leaf.y).put(leaf);
642  if (this.leaves == null) {
643  this.leaves = new ArrayList<>();
644  this.leaves.add(leaf);
645  return true;
646  }
647  for (Leaf<T> l : this.leaves) {
648  if (l.x == leaf.x && l.y == leaf.y) {
649  if (leaf.value == l.value) {
650  return false;
651  }
652  if (l.values != null) {
653  if (l.values.contains(leaf.value)) {
654  return false;
655  }
656  l.values.add(leaf.value);
657  return true;
658  }
659  if (l.value == null) {
660  l.value = leaf.value;
661  return true;
662  } else {
663  l.values = new ArrayList<>(3);
664  l.values.add(l.value);
665  l.value = null;
666  l.values.add(leaf.value);
667  return true;
668  }
669  }
670 
671  }
672  if (this.leaves.size() < MAX_CHILDS) {
673  this.leaves.add(leaf);
674  return true;
675  }
676  this.split();
677  return getChild(leaf.x, leaf.y).put(leaf);
678  }
679 
680  public boolean put(final double x, final double y, final T value) {
681  return put(new Leaf<>(x, y, value));
682  }
683 
684  public boolean remove(final double x, final double y, final T value) {
685  if (this.hasChilds) return getChild(x, y).remove(x, y, value);
686  if (this.leaves != null) {
687  for (Leaf<T> leaf : this.leaves) {
688  if (leaf.x == x && leaf.y == y) {
689  if (leaf.value == value) {
690  leaf.value = null;
691  this.leaves.remove(leaf);
692  return true;
693  }
694  if (leaf.values != null) {
695  if (leaf.values.remove(value)) {
696  if (leaf.values.isEmpty()) {
697  this.leaves.remove(leaf);
698  }
699  return true;
700  }
701  }
702  }
703  }
704  }
705  return false;
706  }
707 
708  public void clear() {
709  // we could as well just set everything to null and let the
710  // garbage collection do its job.
711  if (this.hasChilds) {
712  this.northwest.clear();
713  this.northeast.clear();
714  this.southeast.clear();
715  this.southwest.clear();
716  this.northwest = null;
717  this.northeast = null;
718  this.southeast = null;
719  this.southwest = null;
720  this.hasChilds = false;
721  } else {
722  if (this.leaves != null) {
723  this.leaves = null;
724  }
725  }
726  }
727 
728  /* default */ T get(final double x, final double y, final MutableDouble bestDistanceSqr) {
729  if (this.hasChilds) {
730  T closest = null;
731  Node<T> bestChild = this.getChild(x, y);
732  if (bestChild != null) {
733  closest = bestChild.get(x, y, bestDistanceSqr);
734  }
735  if (bestChild != this.northwest && this.northwest.bounds.calcDistanceSqr(x, y) < bestDistanceSqr.value) {
736  T value = this.northwest.get(x, y, bestDistanceSqr);
737  if (value != null) { closest = value; }
738  }
739  if (bestChild != this.northeast && this.northeast.bounds.calcDistanceSqr(x, y) < bestDistanceSqr.value) {
740  T value = this.northeast.get(x, y, bestDistanceSqr);
741  if (value != null) { closest = value; }
742  }
743  if (bestChild != this.southeast && this.southeast.bounds.calcDistanceSqr(x, y) < bestDistanceSqr.value) {
744  T value = this.southeast.get(x, y, bestDistanceSqr);
745  if (value != null) { closest = value; }
746  }
747  if (bestChild != this.southwest && this.southwest.bounds.calcDistanceSqr(x, y) < bestDistanceSqr.value) {
748  T value = this.southwest.get(x, y, bestDistanceSqr);
749  if (value != null) { closest = value; }
750  }
751  return closest;
752  }
753  // no more childs, so we must contain the closest object
754  T closest = null;
755  if (this.leaves != null) {
756  for (Leaf<T> leaf : this.leaves) {
757  double deltaX = leaf.x - x;
758  double deltaY = leaf.y - y;
759  double distanceSqr = deltaX * deltaX + deltaY * deltaY;
760  if (distanceSqr < bestDistanceSqr.value) {
761  bestDistanceSqr.value = distanceSqr;
762  closest = leaf.value != null ? leaf.value : leaf.values.get(0);
763  }
764  }
765  }
766  return closest;
767  }
768 
769  /* default */ Collection<T> getElliptical(
770  final double x1,
771  final double y1,
772  final double x2,
773  final double y2,
774  final double maxDistance,
775  final Collection<T> values) {
776  assert Math.pow( maxDistance , 2 ) >= Math.pow( (x1 - x2), 2 ) + Math.pow( (y1 - y2) , 2 );
777  if (this.hasChilds) {
778  // note: this could probably be improved. The idea here
779  // is NOT to dive in quadrants which we know do not contain points
780  // in the ellipse.
781  // This is done, but we will also dive in some quadrants not intersecting
782  // the ellipse, which is just a loss of time (the sum of the minimum distances
783  // to an area is always lower than the munimum of the sum of the distances,
784  // and the difference can be substantial. Just not sure how efficiently
785  // one can estimate the minimum of the sum of the distances).
786 
787  // this is a trick to avoid computing distance of quadrant to second focus
788  // if the quandrant is already too far from first focus.
789  // Some tests showed a huge improvement with this, when a large part
790  // of the space has to be pruned (which is typically the case in
791  // real applications). By "huge improvement", I mean several times
792  // faster (how much depends on the particular instance).
793  final double nw1 = this.northwest.bounds.calcDistance(x1, y1);
794  if ( nw1 <= maxDistance && nw1 + this.northwest.bounds.calcDistance(x2, y2) <= maxDistance) {
795  this.northwest.getElliptical(x1, y1, x2, y2, maxDistance, values);
796  }
797  final double ne1 = this.northeast.bounds.calcDistance(x1, y1);
798  if (ne1 <= maxDistance && ne1 + this.northeast.bounds.calcDistance(x2, y2) <= maxDistance) {
799  this.northeast.getElliptical(x1, y1, x2, y2, maxDistance, values);
800  }
801  final double se1 = this.southeast.bounds.calcDistance(x1, y1);
802  if (se1 <= maxDistance && se1 + this.southeast.bounds.calcDistance(x2, y2) <= maxDistance) {
803  this.southeast.getElliptical(x1, y1, x2, y2, maxDistance, values);
804  }
805  final double sw1 = this.southwest.bounds.calcDistance(x1, y1);
806  if (sw1 <= maxDistance && sw1 + this.southwest.bounds.calcDistance(x2, y2) <= maxDistance) {
807  this.southwest.getElliptical(x1, y1, x2, y2, maxDistance, values);
808  }
809  return values;
810  }
811  // no more childs, so we must contain the closest object
812  if (this.leaves != null) {
813  for (Leaf<T> leaf : this.leaves) {
814  final double distance1 = Math.sqrt(
815  (leaf.x - x1) * (leaf.x - x1)
816  + (leaf.y - y1) * (leaf.y - y1));
817  // same trick as above, though it should not be useul in the vast
818  // majority of cases
819  if (distance1 <= maxDistance) {
820  final double distance2 = Math.sqrt(
821  (leaf.x - x2) * (leaf.x - x2)
822  + (leaf.y - y2) * (leaf.y - y2));
823  if (distance1 + distance2 <= maxDistance) {
824  if (leaf.value != null) {
825  values.add(leaf.value);
826  } else {
827  values.addAll(leaf.values);
828  }
829  }
830  }
831  }
832  }
833  return values;
834  }
835 
836  /* default */ Collection<T> get(final double x, final double y, final double maxDistanceSqr, final Collection<T> values) {
837  if (this.hasChilds) {
838  if (this.northwest.bounds.calcDistanceSqr(x, y) <= maxDistanceSqr) {
839  this.northwest.get(x, y, maxDistanceSqr, values);
840  }
841  if (this.northeast.bounds.calcDistanceSqr(x, y) <= maxDistanceSqr) {
842  this.northeast.get(x, y, maxDistanceSqr, values);
843  }
844  if (this.southeast.bounds.calcDistanceSqr(x, y) <= maxDistanceSqr) {
845  this.southeast.get(x, y, maxDistanceSqr, values);
846  }
847  if (this.southwest.bounds.calcDistanceSqr(x, y) <= maxDistanceSqr) {
848  this.southwest.get(x, y, maxDistanceSqr, values);
849  }
850  return values;
851  }
852  // no more childs, so we must contain the closest object
853  if (this.leaves != null) {
854  for (Leaf<T> leaf : this.leaves) {
855  double distanceSqr = (leaf.x - x) * (leaf.x - x) + (leaf.y - y) * (leaf.y - y);
856  if (distanceSqr <= maxDistanceSqr) {
857  if (leaf.value != null) {
858  values.add(leaf.value);
859  } else {
860  values.addAll(leaf.values);
861  }
862  }
863  }
864  }
865  return values;
866  }
867 
868  /* default */ Collection<T> get(final double x, final double y, final double rMinSqr, final double rMaxSqr,
869  Collection<T> values) {
870  if (this.hasChilds) {
871  stepIntoSqr(this.northwest, x, y, rMinSqr, rMaxSqr, values);
872  stepIntoSqr(this.northeast, x, y, rMinSqr, rMaxSqr, values);
873  stepIntoSqr(this.southeast, x, y, rMinSqr, rMaxSqr, values);
874  stepIntoSqr(this.southwest, x, y, rMinSqr, rMaxSqr, values);
875  return values;
876  }
877  // no more childs, so we must contain the closest object
878  if (this.leaves != null) {
879  for (Leaf<T> leaf : this.leaves) {
880  double distanceSqr = (leaf.x - x) * (leaf.x - x) + (leaf.y - y) * (leaf.y - y);
881  if (distanceSqr <= rMaxSqr && distanceSqr >= rMinSqr) {
882  if (leaf.value != null) {
883  values.add(leaf.value);
884  } else {
885  values.addAll(leaf.values);
886  }
887  }
888  }
889  }
890  return values;
891  }
892 
893  private void stepIntoSqr(Node<T> node, double x, double y, double rMinSqr, double rMaxSqr, Collection<T> values) {
894  double minDistanceSqr = node.bounds.calcDistanceSqr(x, y);
895  double maxDistanceSqr = node.bounds.calcMaxDistanceSqr(x, y);
896 
897  if (minDistanceSqr <= rMaxSqr && maxDistanceSqr >= rMinSqr) {
898  node.get(x, y, rMinSqr, rMaxSqr, values);
899  }
900  }
901 
902  /* default */ Collection<T> get(final Rect bounds, final Collection<T> values) {
903  if (this.hasChilds) {
904  if (this.northwest.bounds.intersects(bounds)) {
905  this.northwest.get(bounds, values);
906  }
907  if (this.northeast.bounds.intersects(bounds)) {
908  this.northeast.get(bounds, values);
909  }
910  if (this.southeast.bounds.intersects(bounds)) {
911  this.southeast.get(bounds, values);
912  }
913  if (this.southwest.bounds.intersects(bounds)) {
914  this.southwest.get(bounds, values);
915  }
916  return values;
917  }
918  // no more childs, so we must contain the closest object
919  if (this.leaves != null) {
920  for (Leaf<T> leaf : this.leaves) {
921  if (bounds.containsOrEquals(leaf.x, leaf.y)) {
922  if (leaf.value != null) {
923  values.add(leaf.value);
924  } else {
925  values.addAll(leaf.values);
926  }
927  }
928  }
929  }
930  return values;
931  }
932 
933  /* default */ int execute(final Rect globalBounds, final Executor<T> executor) {
934  int count = 0;
935  if (this.hasChilds) {
936  if (this.northwest.bounds.intersects(globalBounds)) {
937  count += this.northwest.execute(globalBounds, executor);
938  }
939  if (this.northeast.bounds.intersects(globalBounds)) {
940  count += this.northeast.execute(globalBounds, executor);
941  }
942  if (this.southeast.bounds.intersects(globalBounds)) {
943  count += this.southeast.execute(globalBounds, executor);
944  }
945  if (this.southwest.bounds.intersects(globalBounds)) {
946  count += this.southwest.execute(globalBounds, executor);
947  }
948  return count;
949  }
950  // no more childs, so we must contain the closest object
951  if (this.leaves != null) {
952  for (Leaf<T> leaf : this.leaves) {
953  if (globalBounds.contains(leaf.x, leaf.y)) {
954  if (leaf.value != null) {
955  count++;
956  executor.execute(leaf.x, leaf.y, leaf.value);
957  } else {
958  count += leaf.values.size();
959  for (T object : leaf.values) executor.execute(leaf.x, leaf.y, object);
960  }
961  }
962  }
963  }
964  return count;
965  }
966 
967  private void split() {
968  this.northwest = new Node<>(this.bounds.minX, this.bounds.centerY, this.bounds.centerX, this.bounds.maxY);
969  this.northeast = new Node<>(this.bounds.centerX, this.bounds.centerY, this.bounds.maxX, this.bounds.maxY);
970  this.southeast = new Node<>(this.bounds.centerX, this.bounds.minY, this.bounds.maxX, this.bounds.centerY);
971  this.southwest = new Node<>(this.bounds.minX, this.bounds.minY, this.bounds.centerX, this.bounds.centerY);
972  this.hasChilds = true;
973  if (this.leaves != null) {
974  for (Leaf<T> leaf : this.leaves) {
975  getChild(leaf.x, leaf.y).put(leaf);
976  }
977  this.leaves= null;
978  }
979  }
980 
981  private Node<T> getChild(final double x, final double y) {
982  if (this.hasChilds) {
983  if (x < this.bounds.centerX) {
984  if (y < this.bounds.centerY)
985  return this.southwest;
986  return this.northwest;
987  }
988  if (y < this.bounds.centerY)
989  return this.southeast;
990  return this.northeast;
991  }
992  return null;
993  }
994 
995  /* default */ Leaf<T> firstLeaf() {
996  if (this.hasChilds) {
997  Leaf<T> leaf = this.southwest.firstLeaf();
998  if (leaf == null) { leaf = this.northwest.firstLeaf(); }
999  if (leaf == null) { leaf = this.southeast.firstLeaf(); }
1000  if (leaf == null) { leaf = this.northeast.firstLeaf(); }
1001  return leaf;
1002  }
1003  return (this.leaves == null || this.leaves.isEmpty()) ? null : this.leaves.get(0);
1004  }
1005 
1006  /* default */ boolean nextLeaf(final Leaf<T> currentLeaf, final MutableLeaf<T> nextLeaf) {
1007  if (this.hasChilds) {
1008  if (currentLeaf.x <= this.bounds.centerX && currentLeaf.y <= this.bounds.centerY) {
1009  boolean found = this.southwest.nextLeaf(currentLeaf, nextLeaf);
1010  if (found) {
1011  if (nextLeaf.value == null) { nextLeaf.value = this.northwest.firstLeaf(); }
1012  if (nextLeaf.value == null) { nextLeaf.value = this.southeast.firstLeaf(); }
1013  if (nextLeaf.value == null) { nextLeaf.value = this.northeast.firstLeaf(); }
1014  return true;
1015  }
1016  }
1017  if (currentLeaf.x <= this.bounds.centerX && currentLeaf.y >= this.bounds.centerY) {
1018  boolean found = this.northwest.nextLeaf(currentLeaf, nextLeaf);
1019  if (found) {
1020  if (nextLeaf.value == null) { nextLeaf.value = this.southeast.firstLeaf(); }
1021  if (nextLeaf.value == null) { nextLeaf.value = this.northeast.firstLeaf(); }
1022  return true;
1023  }
1024  }
1025  if (currentLeaf.x >= this.bounds.centerX && currentLeaf.y <= this.bounds.centerY) {
1026  boolean found = this.southeast.nextLeaf(currentLeaf, nextLeaf);
1027  if (found) {
1028  if (nextLeaf.value == null) { nextLeaf.value = this.northeast.firstLeaf(); }
1029  return true;
1030  }
1031  }
1032  if (currentLeaf.x >= this.bounds.centerX && currentLeaf.y >= this.bounds.centerY) {
1033  return this.northeast.nextLeaf(currentLeaf, nextLeaf);
1034  }
1035  return false;
1036  }
1037  if (this.leaves != null) {
1038  int idx = this.leaves.indexOf(currentLeaf);
1039  if (idx >= 0) {
1040  if (idx + 1 < this.leaves.size()) {
1041  nextLeaf.value = this.leaves.get(idx + 1);
1042  }
1043  return true;
1044  }
1045  }
1046  return false;
1047  }
1048 
1049  public Leaf<T> nextLeaf(final Leaf<T> currentLeaf) {
1050  MutableLeaf<T> nextLeaf = new MutableLeaf<>(null);
1051  nextLeaf(currentLeaf, nextLeaf);
1052  return nextLeaf.value;
1053  }
1054 
1055  public Rect getBounds() {
1056  return this.bounds;
1057  }
1058 
1059  }
1060 
1061  public interface Executor<T> {
1062  void execute(double x, double y, T object);
1063  }
1064 }
void stepIntoSqr(Node< T > node, double x, double y, double rMinSqr, double rMaxSqr, Collection< T > values)
Definition: QuadTree.java:893
Rect scale(double scaleX, double scaleY)
Definition: QuadTree.java:587
void execute(double x, double y, T object)
Collection< T > getRing(final double x, final double y, final double rMin, final double rMax)
Definition: QuadTree.java:159
Leaf< T > nextLeaf(final Leaf< T > currentLeaf)
Definition: QuadTree.java:1049
boolean contains(final double x, final double y)
Definition: QuadTree.java:491
Collection< T > getRectangle(final Rect bounds, final Collection< T > values1)
Definition: QuadTree.java:200
double calcMaxDistanceSqr(final double x, final double y)
Definition: QuadTree.java:475
int execute(final double minX, final double minY, final double maxX, final double maxY, final Executor< T > executor)
Definition: QuadTree.java:243
Node< T > getChild(final double x, final double y)
Definition: QuadTree.java:981
boolean containsOrEquals(final double x, final double y)
Definition: QuadTree.java:498
boolean put(final double x, final double y, final T value)
Definition: QuadTree.java:86
Collection< T > getRectangle(final double minX, final double minY, final double maxX, final double maxY, final Collection< T > values1)
Definition: QuadTree.java:215
Leaf< T > nextLeaf(final Leaf< T > currentLeaf)
Definition: QuadTree.java:364
T getClosest(final double x, final double y)
Definition: QuadTree.java:130
int execute(final Rect bounds, final Executor< T > executor)
Definition: QuadTree.java:226
boolean put(final double x, final double y, final T value)
Definition: QuadTree.java:680
QuadTree(final double minX, final double minY, final double maxX, final double maxY)
Definition: QuadTree.java:71
Leaf(final double x, final double y, final T value)
Definition: QuadTree.java:614
Node(final double minX, final double minY, final double maxX, final double maxY)
Definition: QuadTree.java:636
Collection< T > getElliptical(final double x1, final double y1, final double x2, final double y2, final double distance)
Definition: QuadTree.java:174
Collection< T > getDisk(final double x, final double y, final double distance)
Definition: QuadTree.java:142
Rect(final double minX, final double minY, final double maxX, final double maxY)
Definition: QuadTree.java:405
double calcDistanceSqr(final double x, final double y)
Definition: QuadTree.java:450
double calcDistance(final double x, final double y)
Definition: QuadTree.java:423