package spimedb.util.geom;
import spimedb.util.math.MathUtils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class SpatialBins<T> implements SpatialIndex<T> {
private final float invBinWidth;
private final float minOffset;
private final int numBins;
private int numItems;
private final List<HashSet<T>> bins;
private final CoordinateExtractor<T> extractor;
public SpatialBins(float min, float max, int numBins,
CoordinateExtractor<T> extractor) {
this.extractor = extractor;
this.bins = new ArrayList<>();
for (int i = 0; i < numBins; i++) {
bins.add(new HashSet<>());
}
this.minOffset = min;
this.numBins = numBins;
this.invBinWidth = numBins / (max - min);
}
/*
* (non-Javadoc)
*
* @see toxi.geom.SpatialIndex#clear()
*/
public void clear() {
for (HashSet<T> bin : bins) {
bin.clear();
}
numItems = 0;
}
/*
* (non-Javadoc)
*
* @see toxi.geom.SpatialIndex#index(T)
*/
public boolean index(T p) {
int id = (int) MathUtils.clip((extractor.coordinate(p) - minOffset)
* invBinWidth, 0, numBins - 1);
if (bins.get(id).add(p)) {
numItems++;
return true;
}
return false;
}
/*
* (non-Javadoc)
*
* @see toxi.geom.SpatialIndex#isIndexed(T)
*/
public boolean isIndexed(T item) {
// TODO Auto-generated method stub
return false;
}
public List<T> itemsWithinRadius(T p, float radius, List<T> results) {
int id = (int) MathUtils.clip((extractor.coordinate(p) - minOffset)
* invBinWidth, 0, numBins);
int tol = (int) Math.ceil(radius * invBinWidth);
for (int i = Math.max(id - tol, 0), n = Math.min(
Math.min(id + tol, numBins), numBins - 1); i <= n; i++) {
if (results == null) {
results = new ArrayList<>();
}
results.addAll(bins.get(i));
}
return results;
}
/*
* (non-Javadoc)
*
* @see toxi.geom.SpatialIndex#reindex(float, T)
*/
public boolean reindex(T p, T q) {
int id1 = (int) MathUtils.clip((extractor.coordinate(p) - minOffset)
* invBinWidth, 0, numBins);
int id2 = (int) MathUtils.clip((extractor.coordinate(q) - minOffset)
* invBinWidth, 0, numBins);
if (id1 != id2) {
if (bins.get(id1).remove(p)) {
numItems--;
}
if (bins.get(id2).add(q)) {
numItems++;
}
return true;
}
return false;
}
/*
* (non-Javadoc)
*
* @see toxi.geom.SpatialIndex#size()
*/
public int size() {
return numItems;
}
/*
* (non-Javadoc)
*
* @see toxi.geom.SpatialIndex#unindex(T)
*/
public boolean unindex(T p) {
int id = (int) MathUtils.clip((extractor.coordinate(p) - minOffset)
* invBinWidth, 0, numBins);
return bins.get(id).remove(p);
}
}