package com.revolsys.geometry.index.rtree;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import com.revolsys.geometry.index.SpatialIndex;
import com.revolsys.geometry.model.BoundingBox;
import com.revolsys.util.ExitLoopException;
public class RTree<T> implements SpatialIndex<T> {
private int maxEntries;
private RTreeNode<T> root = new RTreeLeaf<>(this.maxEntries);
private int size;
public RTree() {
this(12, 32);
}
public RTree(final int minEntries, final int maxEntries) {
this.maxEntries = maxEntries;
this.root = new RTreeLeaf<>(maxEntries);
}
@Override
public void forEach(final Consumer<? super T> action) {
try {
this.root.forEachValue(action);
} catch (final ExitLoopException e) {
}
}
@Override
public void forEach(final double x, final double y, final Consumer<? super T> action) {
try {
this.root.forEach(x, y, action);
} catch (final ExitLoopException e) {
}
}
@Override
public void forEach(final double minX, final double minY, final double maxX, final double maxY,
final Consumer<? super T> action) {
try {
this.root.forEach(minX, minY, maxX, maxY, action);
} catch (final ExitLoopException e) {
}
}
@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) {
try {
this.root.forEach(minX, minY, maxX, maxY, filter, action);
} catch (final ExitLoopException e) {
}
}
@Override
public void forEach(final Predicate<? super T> filter, final Consumer<? super T> action) {
try {
this.root.forEachValue(filter, action);
} catch (final ExitLoopException e) {
}
}
@Override
public int getSize() {
return this.size;
}
@Override
public void insertItem(final BoundingBox boundingBox, final T object) {
final LinkedList<RTreeBranch<T>> path = new LinkedList<>();
final RTreeLeaf<T> leaf = this.root.chooseLeaf(path, boundingBox);
if (leaf.getSize() == this.maxEntries) {
final List<RTreeNode<T>> newNodes = leaf.split(object, boundingBox);
replace(path, leaf, newNodes);
} else {
leaf.add(boundingBox, object);
}
this.size++;
}
@Override
public boolean removeItem(final BoundingBox boundingBox, final T object) {
final double minX = boundingBox.getMinX();
final double minY = boundingBox.getMinY();
final double maxX = boundingBox.getMaxX();
final double maxY = boundingBox.getMaxY();
if (this.root.remove(null, minX, minY, maxX, maxY, object)) {
this.size--;
return true;
} else {
return false;
}
}
private void replace(final LinkedList<RTreeBranch<T>> path, final RTreeNode<T> oldNode,
final List<RTreeNode<T>> newNodes) {
if (path.isEmpty()) {
this.root = new RTreeBranch<>(this.maxEntries, newNodes);
} else {
final RTreeBranch<T> parentNode = path.removeLast();
if (parentNode.getSize() + newNodes.size() - 1 >= this.maxEntries) {
final List<RTreeNode<T>> newParentNodes = parentNode.split(oldNode, newNodes);
replace(path, parentNode, newParentNodes);
} else {
parentNode.replace(oldNode, newNodes);
}
}
}
}