package com.revolsys.geometry.index.rtree; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; import com.revolsys.geometry.model.BoundingBox; public class RTreeLeaf<T> extends RTreeNode<T> { private BoundingBox[] objectBoundingBoxes; private T[] objects; private int size = 0; public RTreeLeaf() { } @SuppressWarnings("unchecked") public RTreeLeaf(final int size) { this.objects = (T[])new Object[size]; this.objectBoundingBoxes = new BoundingBox[size]; } public void add(final BoundingBox objectBoundingBox, final T object) { this.objectBoundingBoxes[this.size] = objectBoundingBox; this.objects[this.size] = object; this.size++; expandBoundingBox(objectBoundingBox); } @Override protected RTreeLeaf<T> chooseLeaf(final List<RTreeBranch<T>> path, final BoundingBox boundingBox) { return this; } @Override public void forEach(final double x, final double y, final Consumer<? super T> action) { for (int i = 0; i < this.size; i++) { final BoundingBox objectBounds = this.objectBoundingBoxes[i]; if (objectBounds.intersects(x, y)) { final T object = this.objects[i]; action.accept(object); } } } @Override public void forEach(final double minX, final double minY, final double maxX, final double maxY, final Consumer<? super T> action) { for (int i = 0; i < this.size; i++) { final BoundingBox objectBounds = this.objectBoundingBoxes[i]; if (objectBounds.intersects(minX, minY, maxX, maxY)) { final T object = this.objects[i]; action.accept(object); } } } @Override public void forEach(final double minX, final double minY, final double maxX, final double maxY, final Predicate<? super T> filter, final Consumer<? super T> action) { for (int i = 0; i < this.size; i++) { final BoundingBox objectBounds = this.objectBoundingBoxes[i]; if (objectBounds.intersects(minX, minY, maxX, maxY)) { final T object = this.objects[i]; if (filter.test(object)) { action.accept(object); } } } } @Override public void forEachValue(final Consumer<? super T> action) { for (int i = 0; i < this.size; i++) { final T object = this.objects[i]; action.accept(object); } } @Override public void forEachValue(final Predicate<? super T> filter, final Consumer<? super T> action) { for (int i = 0; i < this.size; i++) { final T object = this.objects[i]; if (filter.test(object)) { action.accept(object); } } } public int getSize() { return this.size; } @Override public boolean remove(final LinkedList<RTreeNode<T>> path, final double minX, final double minY, final double maxX, final double maxY, final T object) { for (int i = 0; i < this.size; i++) { final BoundingBox objectBounds = this.objectBoundingBoxes[i]; final T object1 = this.objects[i]; if (object1 == object) { if (objectBounds.getMinX() == minX && objectBounds.getMinY() == minY && objectBounds.getMaxX() == maxX && objectBounds.getMaxY() == maxY) { System.arraycopy(this.objectBoundingBoxes, i + 1, this.objectBoundingBoxes, i, this.size - i - 1); this.objectBoundingBoxes[this.size - 1] = null; System.arraycopy(this.objects, i + 1, this.objects, i, this.size - i - 1); this.objects[this.size - 1] = null; this.size--; if (path != null) { path.add(this); } updateEnvelope(); return true; } else { // ERROR } } } return false; } public List<RTreeNode<T>> split(final T object, final BoundingBox objectBoundingBox) { final RTreeLeaf<T> leaf1 = new RTreeLeaf<>(this.objects.length); final RTreeLeaf<T> leaf2 = new RTreeLeaf<>(this.objects.length); // TODO Add some ordering to the results final int midPoint = (int)Math.ceil(this.size / 2.0); for (int i = 0; i <= midPoint; i++) { final BoundingBox objectBounds = this.objectBoundingBoxes[i]; final T object1 = this.objects[i]; leaf1.add(objectBounds, object1); } for (int i = midPoint + 1; i < this.size; i++) { final BoundingBox objectBounds = this.objectBoundingBoxes[i]; final T object1 = this.objects[i]; leaf2.add(objectBounds, object1); } leaf2.add(objectBoundingBox, object); return Arrays.<RTreeNode<T>> asList(leaf1, leaf2); } @Override protected void updateEnvelope() { double minX = Double.MAX_VALUE; double maxX = -Double.MAX_VALUE; double minY = Double.MAX_VALUE; double maxY = -Double.MAX_VALUE; for (int i = 0; i < this.size; i++) { final BoundingBox objectBounds = this.objectBoundingBoxes[i]; final double nodeMinX = objectBounds.getMinX(); if (nodeMinX < minX) { minX = nodeMinX; } final double nodeMinY = objectBounds.getMinY(); if (nodeMinY < minY) { minY = nodeMinY; } final double nodeMaxX = objectBounds.getMaxX(); if (nodeMaxX > maxX) { maxX = nodeMaxX; } final double nodeMaxY = objectBounds.getMaxY(); if (nodeMaxY > maxY) { maxY = nodeMaxY; } } setBoundingBox(minX, minY, maxX, maxY); } }