
com.conversantmedia.util.collection.spatial.Branch Maven / Gradle / Ivy
package com.conversantmedia.util.collection.spatial;
/*
* #%L
* Conversant RTree
* ~~
* Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, Inc.
* ~~
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.function.Consumer;
/**
* RTree node that contains leaf nodes
*
* Created by jcairns on 4/30/15.
*/
final class Branch implements Node {
private HyperRect mbr;
private final Node[] child;
private int size;
private final RectBuilder builder;
private final int mMax;
private final int mMin;
private final RTree.Split splitType;
Branch(final RectBuilder builder, final int mMin, final int mMax, final RTree.Split splitType) {
this.mMin = mMin;
this.mMax = mMax;
this.builder = builder;
this.mbr = null;
this.size = 0;
this.child = new Node[mMax];
this.splitType = splitType;
}
/**
* Add a new node to this branch's list of children
*
* @param n node to be added (can be leaf or branch)
* @return position of the added node
*/
protected int addChild(final Node n) {
if(size < mMax) {
child[size++] = n;
if(mbr != null) {
mbr = mbr.getMbr(n.getRect());
}
else {
mbr = n.getRect();
}
return size - 1;
}
else {
throw new RuntimeException("Too many children");
}
}
@Override
public boolean isLeaf() {
return false;
}
@Override
public HyperRect getRect() {
return mbr;
}
/**
* Adds a data entry to one of the child nodes of this branch
*
* @param t data entry to add
* @return Node that the entry was added to
*/
@Override
public Node add(final T t) {
final HyperRect tRect = builder.getBBox(t);
if(size < mMin) {
for(int i=0; i nextLeaf = Leaf.create(builder, mMin, mMax, splitType);
nextLeaf.add(t);
final int nextChild = addChild(nextLeaf);
mbr = mbr.getMbr(child[nextChild].getRect());
return this;
} else {
final int bestLeaf = chooseLeaf(t, tRect);
child[bestLeaf] = child[bestLeaf].add(t);
mbr = mbr.getMbr(child[bestLeaf].getRect());
// optimize on split to remove the extra created branch when there
// is space for the children here
if(child[bestLeaf].size() == 2 &&
size < mMax &&
child[bestLeaf] instanceof Branch) {
final Branch branch = (Branch)child[bestLeaf];
child[bestLeaf] = branch.child[0];
child[size++] = branch.child[1];
}
return this;
}
}
@Override
public Node remove(final T t) {
final HyperRect tRect = builder.getBBox(t);
Node returned = null;
for (int i = 0; i < size; i++) {
if (child[i].getRect().contains(tRect)) {
returned = child[i].remove(t);
// Replace a Branch Node with 1 child with it's child
// Will not work for a RTree with mMin > 2
if(returned != null) {
if (returned.size() == 0) {
child[i] = null;
if (i < (size - 1)) {
child[i] = child[size - 1];
child[size - 1] = null;
}
--size;
}
if (size == 1) {
return child[0];
}
if (child[i] != null) {
if (child[i].size() == 1 && returned.isLeaf()) {
child[i] = returned;
}
}
}
}
}
return returned;
}
@Override
public Node update(final T told, final T tnew) {
final HyperRect tRect = builder.getBBox(told);
for(int i = 0; i < size; i++){
if(child[i].getRect().contains(tRect)){
child[i] = child[i].update(told, tnew);
mbr = mbr.getMbr(child[i].getRect());
return child[i];
}
}
return this;
}
@Override
public int search(final HyperRect rect, final T[] t, int n) {
final int tLen = t.length;
final int n0 = n;
for(int i=0; i < size && n < tLen; i++) {
if (rect.intersects(child[i].getRect())) {
n += child[i].search(rect, t, n);
}
}
return n-n0;
}
/**
* @return number of child nodes
*/
@Override
public int size() {
return size;
}
private int chooseLeaf(final T t, final HyperRect tRect) {
if(size > 0) {
int bestNode = 0;
HyperRect childMbr = child[0].getRect().getMbr(tRect);
double leastEnlargement = childMbr.cost() - (child[0].getRect().cost() + tRect.cost());
double leastPerimeter = childMbr.perimeter();
for(int i = 1; i n = Leaf.create(builder, mMin, mMax, splitType);
n.add(t);
child[size++] = n;
if(mbr == null) {
mbr = n.getRect();
}
else {
mbr = mbr.getMbr(n.getRect());
}
return size-1;
}
}
/**
* Return child nodes of this branch.
*
* @return array of child nodes (leaves or branches)
*/
public Node[] getChildren() {
return child;
}
@Override
public void forEach(Consumer consumer) {
for(int i = 0; i < size; i++) {
child[i].forEach(consumer);
}
}
@Override
public void forEach(Consumer consumer, HyperRect rect) {
for(int i = 0; i < size; i++) {
if(rect.intersects(child[i].getRect())) {
child[i].forEach(consumer, rect);
}
}
}
@Override
public void collectStats(Stats stats, int depth) {
for(int i = 0; i < size; i++) {
child[i].collectStats(stats, depth + 1);
}
stats.countBranchAtDepth(depth);
}
@Override
public Node instrument() {
for(int i = 0; i < size; i++) {
child[i] = child[i].instrument();
}
return new CounterNode<>(this);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy