Difference between revisions of "User:Chase-san/Kd-Tree"
Jump to navigation
Jump to search
(Changed distance to use distanceSq in comparator) |
(There, updated to my smaller version.) |
||
Line 2: | Line 2: | ||
Everyone and their brother has one of these now, me and Simonton started it, but I was to inexperienced to get anything written, I took an hour or two to rewrite it today, because I am no longer completely terrible at these things. So here is mine if you care to see it. | Everyone and their brother has one of these now, me and Simonton started it, but I was to inexperienced to get anything written, I took an hour or two to rewrite it today, because I am no longer completely terrible at these things. So here is mine if you care to see it. | ||
− | === | + | === KDTreeC === |
<pre> | <pre> | ||
− | package org.csdgn.util; | + | package org.csdgn.util.kd2; |
− | import java.util. | + | import java.util.Arrays; |
− | + | /** | |
− | + | * This is a KD Bucket Tree, for fast sorting and searching of K dimensional data. | |
− | + | * @author Chase | |
− | + | * | |
− | + | */ | |
− | + | public class KDTreeC { | |
− | |||
/** | /** | ||
− | * | + | * Item, for moving data around. |
− | + | * @author Chase | |
− | * @ | ||
*/ | */ | ||
− | public | + | public class Item { |
− | + | public double[] pnt; | |
+ | public Object obj; | ||
+ | public double distance; | ||
+ | private Item(double[] p, Object o) { | ||
+ | pnt = p; obj = o; | ||
+ | } | ||
} | } | ||
+ | private final int dimensions; | ||
+ | private final int bucket_size; | ||
+ | private NodeKD root; | ||
+ | |||
/** | /** | ||
− | * | + | * Constructor with value for dimensions. |
− | + | * @param dimensions - Number of dimensions | |
− | * @param dimensions | ||
− | |||
*/ | */ | ||
− | public | + | public KDTreeC(int dimensions) { |
this.dimensions = dimensions; | this.dimensions = dimensions; | ||
− | this.bucket_size = | + | this.bucket_size = 64; |
− | root = new | + | this.root = new NodeKD(this); |
} | } | ||
/** | /** | ||
− | * | + | * Constructor with value for dimensions and bucket size. |
− | * @param | + | * @param dimensions - Number of dimensions |
+ | * @param bucket - Size of the buckets. | ||
*/ | */ | ||
− | public | + | public KDTreeC(int dimensions, int bucket) { |
− | root | + | this.dimensions = dimensions; |
+ | this.bucket_size = bucket; | ||
+ | this.root = new NodeKD(this); | ||
} | } | ||
/** | /** | ||
− | * | + | * Add a key and its associated value to the tree. |
− | * @param | + | * @param key - Key to add |
− | * @ | + | * @param val - object to add |
*/ | */ | ||
− | public | + | public void add(double[] key, Object val) { |
− | + | root.add(new Item(key,val)); | |
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
/** | /** | ||
* Returns all PointKD within a certain range defined by an upper and lower PointKD. | * Returns all PointKD within a certain range defined by an upper and lower PointKD. | ||
Line 98: | Line 66: | ||
* @return - All PointKD between low and high. | * @return - All PointKD between low and high. | ||
*/ | */ | ||
− | public | + | public Item[] getRange(double[] low, double[] high) { |
− | + | return root.range(high, low); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
/** | /** | ||
− | * | + | * Gets the N nearest neighbors to the given key. |
+ | * @param key - Key | ||
+ | * @param num - Number of results | ||
+ | * @return Array of Item Objects | ||
*/ | */ | ||
− | public | + | public Item[] getNearestNeighbor(double[] key, int num) { |
− | return | + | ShiftArray arr = new ShiftArray(num); |
+ | root.nearestn(arr, key); | ||
+ | return arr.getArray(); | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
/** | /** | ||
* Compares arrays of double and returns the euclidean distance | * Compares arrays of double and returns the euclidean distance | ||
Line 434: | Line 95: | ||
return Math.sqrt(total); | return Math.sqrt(total); | ||
} | } | ||
− | |||
/** | /** | ||
* Compares arrays of double and returns the squared euclidean distance | * Compares arrays of double and returns the squared euclidean distance | ||
Line 448: | Line 108: | ||
total += (b[i] - a[i]) * (b[i] - a[i]); | total += (b[i] - a[i]) * (b[i] - a[i]); | ||
return total; | return total; | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | / | + | //Internal tree node |
− | + | private class NodeKD { | |
− | + | private KDTreeC owner; | |
− | + | private NodeKD left, right; | |
− | + | private double[] upper, lower; | |
− | + | private Item[] bucket; | |
− | + | private int current, dim; | |
− | + | private double slice; | |
− | + | ||
+ | //note: we always start as a bucket | ||
+ | private NodeKD(KDTreeC own) { | ||
+ | owner = own; | ||
+ | upper = lower = null; | ||
+ | left = right = null; | ||
+ | bucket = new Item[own.bucket_size]; | ||
+ | current = 0; | ||
+ | dim = 0; | ||
} | } | ||
− | + | //when we create non-root nodes within this class | |
− | + | //we use this one here | |
− | + | private NodeKD(NodeKD node) { | |
− | if( | + | owner = node.owner; |
− | + | dim = node.dim + 1; | |
+ | bucket = new Item[owner.bucket_size]; | ||
+ | if(dim + 1 > owner.dimensions) dim = 0; | ||
+ | left = right = null; | ||
+ | upper = lower = null; | ||
+ | current = 0; | ||
} | } | ||
− | + | //what it says on the tin | |
− | + | private void add(Item m) { | |
− | + | if(bucket == null) { | |
− | + | //Branch | |
− | + | if(m.pnt[dim] > slice) | |
− | + | right.add(m); | |
− | + | else left.add(m); | |
− | + | } else { | |
− | + | //Bucket | |
− | + | if(current+1>owner.bucket_size) { | |
− | + | split(m); | |
− | + | return; | |
− | + | } | |
+ | bucket[current++] = m; | ||
+ | } | ||
+ | expand(m.pnt); | ||
} | } | ||
− | + | //nearest neighbor thing | |
− | + | private void nearestn(ShiftArray arr, double[] data) { | |
− | + | if(bucket == null) { | |
− | + | //Branch | |
− | + | if(data[dim] > slice) { | |
− | + | right.nearestn(arr, data); | |
− | + | if(left.current != 0) { | |
− | + | if(KDTreeC.distanceSq(left.nearestRect(data),data) | |
− | + | < arr.getLongest()) { | |
− | + | left.nearestn(arr, data); | |
− | + | } | |
− | + | } | |
− | + | ||
+ | } else { | ||
+ | left.nearestn(arr, data); | ||
+ | if(right.current != 0) { | ||
+ | if(KDTreeC.distanceSq(right.nearestRect(data),data) | ||
+ | < arr.getLongest()) { | ||
+ | right.nearestn(arr, data); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } else { | ||
+ | //Bucket | ||
+ | for(int i = 0; i < current; i++) { | ||
+ | bucket[i].distance = KDTreeC.distanceSq(bucket[i].pnt, data); | ||
+ | arr.add(bucket[i]); | ||
+ | } | ||
+ | } | ||
} | } | ||
− | + | //gets all items from within a range | |
− | + | private Item[] range(double[] upper, double[] lower) { | |
− | + | //TODO: clean this up a bit | |
− | + | if(bucket == null) { | |
− | + | //Branch | |
− | + | Item[] tmp = new Item[0]; | |
− | + | if (intersects(upper,lower,left.upper,left.lower)) { | |
− | + | Item[] tmpl = left.range(upper,lower); | |
− | + | if(0 == tmp.length) | |
− | + | tmp = tmpl; | |
− | + | } | |
− | + | if (intersects(upper,lower,right.upper,right.lower)) { | |
− | + | Item[] tmpr = right.range(upper,lower); | |
− | + | if (0 == tmp.length) | |
− | + | tmp = tmpr; | |
− | + | else if (0 < tmpr.length) { | |
− | + | Item[] tmp2 = new Item[tmp.length + tmpr.length]; | |
+ | System.arraycopy(tmp, 0, tmp2, 0, tmp.length); | ||
+ | System.arraycopy(tmpr, 0, tmp2, tmp.length, tmpr.length); | ||
+ | tmp = tmp2; | ||
+ | } | ||
+ | } | ||
+ | return tmp; | ||
+ | } | ||
+ | //Bucket | ||
+ | Item[] tmp = new Item[current]; | ||
+ | int n = 0; | ||
+ | for (int i = 0; i < current; i++) { | ||
+ | if (contains(upper, lower, bucket[i].pnt)) { | ||
+ | tmp[n++] = bucket[i]; | ||
+ | } | ||
+ | } | ||
+ | Item[] tmp2 = new Item[n]; | ||
+ | System.arraycopy(tmp, 0, tmp2, 0, n); | ||
+ | return tmp2; | ||
} | } | ||
− | + | ||
− | + | //These are helper functions from here down | |
− | + | //check if this hyper rectangle contains a give hyper-point | |
− | + | public boolean contains(double[] upper, double[] lower, double[] point) { | |
− | + | if(current == 0) return false; | |
− | === | + | for(int i=0; i<point.length; ++i) { |
− | < | + | if(point[i] > upper[i] || |
− | + | point[i] < lower[i]) | |
− | + | return false; | |
− | + | } | |
− | + | return true; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | //checks if two hyper-rectangles intersect | |
− | + | public boolean intersects(double[] up0, double[] low0, | |
− | + | double[] up1, double[] low1) { | |
− | + | for(int i=0; i<up0.length; ++i) { | |
− | + | if(up1[i] < low0[i] || low1[i] > up0[i]) return false; | |
− | + | } | |
− | + | return true; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | //splits a bucket into a branch | |
− | + | private void split(Item m) { | |
− | + | //split based on our bound data | |
− | + | slice = (upper[dim]+lower[dim])/2.0; | |
− | + | left = new NodeKD(this); | |
− | + | right = new NodeKD(this); | |
− | + | for(int i=0; i<current; ++i) { | |
− | + | if(bucket[i].pnt[dim] > slice) | |
− | + | right.add(bucket[i]); | |
− | + | else left.add(bucket[i]); | |
} | } | ||
+ | bucket = null; | ||
+ | add(m); | ||
} | } | ||
− | + | //gets nearest point to data within this hyper rectangle | |
− | + | private double[] nearestRect(double[] data) { | |
− | + | double[] nearest = data.clone(); | |
− | + | for(int i = 0; i < data.length; ++i) { | |
− | + | if(nearest[i] > upper[i]) nearest[i] = upper[i]; | |
− | + | if(nearest[i] < lower[i]) nearest[i] = lower[i]; | |
− | |||
− | |||
− | |||
} | } | ||
− | return; | + | return nearest; |
} | } | ||
− | + | //expands this hyper rectangle | |
− | // | + | private void expand(double[] data) { |
− | + | if(upper == null) { | |
− | + | upper = Arrays.copyOf(data, owner.dimensions); | |
− | if( | + | lower = Arrays.copyOf(data, owner.dimensions); |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
return; | return; | ||
} | } | ||
− | + | for(int i=0; i<data.length; ++i) { | |
+ | if(upper[i] < data[i]) upper[i] = data[i]; | ||
+ | if(lower[i] > data[i]) lower[i] = data[i]; | ||
+ | } | ||
} | } | ||
− | + | } | |
− | + | //A simple shift array that sifts data up | |
− | + | //as we add new ones to lower in the array. | |
− | + | private class ShiftArray { | |
− | + | private Item[] items; | |
− | + | private final int max; | |
− | + | private int current; | |
− | + | private ShiftArray(int maximum) { | |
+ | max = maximum; | ||
+ | current = 0; | ||
+ | items = new Item[max]; | ||
} | } | ||
− | + | private void add(Item m) { | |
− | + | int i; | |
− | + | for(i=current;i>0&&items[i-1].distance > m.distance; --i); | |
− | + | if(i >= max) return; | |
− | + | if(current < max) ++current; | |
− | + | System.arraycopy(items, i, items, i+1, current-(i+1)); | |
− | + | items[i] = m; | |
− | |||
− | |||
− | |||
− | if( | ||
− | |||
− | |||
} | } | ||
− | + | private double getLongest() { | |
− | + | if (current < max) return Double.POSITIVE_INFINITY; | |
− | + | return items[max-1].distance; | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | private Item[] getArray() { | |
− | + | return items.clone(); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
} | } | ||
− | |||
</pre> | </pre> |
Revision as of 05:09, 2 March 2010
Everyone and their brother has one of these now, me and Simonton started it, but I was to inexperienced to get anything written, I took an hour or two to rewrite it today, because I am no longer completely terrible at these things. So here is mine if you care to see it.
KDTreeC
package org.csdgn.util.kd2; import java.util.Arrays; /** * This is a KD Bucket Tree, for fast sorting and searching of K dimensional data. * @author Chase * */ public class KDTreeC { /** * Item, for moving data around. * @author Chase */ public class Item { public double[] pnt; public Object obj; public double distance; private Item(double[] p, Object o) { pnt = p; obj = o; } } private final int dimensions; private final int bucket_size; private NodeKD root; /** * Constructor with value for dimensions. * @param dimensions - Number of dimensions */ public KDTreeC(int dimensions) { this.dimensions = dimensions; this.bucket_size = 64; this.root = new NodeKD(this); } /** * Constructor with value for dimensions and bucket size. * @param dimensions - Number of dimensions * @param bucket - Size of the buckets. */ public KDTreeC(int dimensions, int bucket) { this.dimensions = dimensions; this.bucket_size = bucket; this.root = new NodeKD(this); } /** * Add a key and its associated value to the tree. * @param key - Key to add * @param val - object to add */ public void add(double[] key, Object val) { root.add(new Item(key,val)); } /** * Returns all PointKD within a certain range defined by an upper and lower PointKD. * @param low - lower bounds of area * @param high - upper bounds of area * @return - All PointKD between low and high. */ public Item[] getRange(double[] low, double[] high) { return root.range(high, low); } /** * Gets the N nearest neighbors to the given key. * @param key - Key * @param num - Number of results * @return Array of Item Objects */ public Item[] getNearestNeighbor(double[] key, int num) { ShiftArray arr = new ShiftArray(num); root.nearestn(arr, key); return arr.getArray(); } /** * Compares arrays of double and returns the euclidean distance * between them. * * @param a - The first set of numbers * @param b - The second set of numbers * @return The distance squared between <b>a</b> and <b>b</b>. */ public static final double distance(double[] a, double[] b) { double total = 0; for (int i = 0; i < a.length; ++i) total += (b[i] - a[i]) * (b[i] - a[i]); return Math.sqrt(total); } /** * Compares arrays of double and returns the squared euclidean distance * between them. * * @param a - The first set of numbers * @param b - The second set of numbers * @return The distance squared between <b>a</b> and <b>b</b>. */ public static final double distanceSq(double[] a, double[] b) { double total = 0; for (int i = 0; i < a.length; ++i) total += (b[i] - a[i]) * (b[i] - a[i]); return total; } //Internal tree node private class NodeKD { private KDTreeC owner; private NodeKD left, right; private double[] upper, lower; private Item[] bucket; private int current, dim; private double slice; //note: we always start as a bucket private NodeKD(KDTreeC own) { owner = own; upper = lower = null; left = right = null; bucket = new Item[own.bucket_size]; current = 0; dim = 0; } //when we create non-root nodes within this class //we use this one here private NodeKD(NodeKD node) { owner = node.owner; dim = node.dim + 1; bucket = new Item[owner.bucket_size]; if(dim + 1 > owner.dimensions) dim = 0; left = right = null; upper = lower = null; current = 0; } //what it says on the tin private void add(Item m) { if(bucket == null) { //Branch if(m.pnt[dim] > slice) right.add(m); else left.add(m); } else { //Bucket if(current+1>owner.bucket_size) { split(m); return; } bucket[current++] = m; } expand(m.pnt); } //nearest neighbor thing private void nearestn(ShiftArray arr, double[] data) { if(bucket == null) { //Branch if(data[dim] > slice) { right.nearestn(arr, data); if(left.current != 0) { if(KDTreeC.distanceSq(left.nearestRect(data),data) < arr.getLongest()) { left.nearestn(arr, data); } } } else { left.nearestn(arr, data); if(right.current != 0) { if(KDTreeC.distanceSq(right.nearestRect(data),data) < arr.getLongest()) { right.nearestn(arr, data); } } } } else { //Bucket for(int i = 0; i < current; i++) { bucket[i].distance = KDTreeC.distanceSq(bucket[i].pnt, data); arr.add(bucket[i]); } } } //gets all items from within a range private Item[] range(double[] upper, double[] lower) { //TODO: clean this up a bit if(bucket == null) { //Branch Item[] tmp = new Item[0]; if (intersects(upper,lower,left.upper,left.lower)) { Item[] tmpl = left.range(upper,lower); if(0 == tmp.length) tmp = tmpl; } if (intersects(upper,lower,right.upper,right.lower)) { Item[] tmpr = right.range(upper,lower); if (0 == tmp.length) tmp = tmpr; else if (0 < tmpr.length) { Item[] tmp2 = new Item[tmp.length + tmpr.length]; System.arraycopy(tmp, 0, tmp2, 0, tmp.length); System.arraycopy(tmpr, 0, tmp2, tmp.length, tmpr.length); tmp = tmp2; } } return tmp; } //Bucket Item[] tmp = new Item[current]; int n = 0; for (int i = 0; i < current; i++) { if (contains(upper, lower, bucket[i].pnt)) { tmp[n++] = bucket[i]; } } Item[] tmp2 = new Item[n]; System.arraycopy(tmp, 0, tmp2, 0, n); return tmp2; } //These are helper functions from here down //check if this hyper rectangle contains a give hyper-point public boolean contains(double[] upper, double[] lower, double[] point) { if(current == 0) return false; for(int i=0; i<point.length; ++i) { if(point[i] > upper[i] || point[i] < lower[i]) return false; } return true; } //checks if two hyper-rectangles intersect public boolean intersects(double[] up0, double[] low0, double[] up1, double[] low1) { for(int i=0; i<up0.length; ++i) { if(up1[i] < low0[i] || low1[i] > up0[i]) return false; } return true; } //splits a bucket into a branch private void split(Item m) { //split based on our bound data slice = (upper[dim]+lower[dim])/2.0; left = new NodeKD(this); right = new NodeKD(this); for(int i=0; i<current; ++i) { if(bucket[i].pnt[dim] > slice) right.add(bucket[i]); else left.add(bucket[i]); } bucket = null; add(m); } //gets nearest point to data within this hyper rectangle private double[] nearestRect(double[] data) { double[] nearest = data.clone(); for(int i = 0; i < data.length; ++i) { if(nearest[i] > upper[i]) nearest[i] = upper[i]; if(nearest[i] < lower[i]) nearest[i] = lower[i]; } return nearest; } //expands this hyper rectangle private void expand(double[] data) { if(upper == null) { upper = Arrays.copyOf(data, owner.dimensions); lower = Arrays.copyOf(data, owner.dimensions); return; } for(int i=0; i<data.length; ++i) { if(upper[i] < data[i]) upper[i] = data[i]; if(lower[i] > data[i]) lower[i] = data[i]; } } } //A simple shift array that sifts data up //as we add new ones to lower in the array. private class ShiftArray { private Item[] items; private final int max; private int current; private ShiftArray(int maximum) { max = maximum; current = 0; items = new Item[max]; } private void add(Item m) { int i; for(i=current;i>0&&items[i-1].distance > m.distance; --i); if(i >= max) return; if(current < max) ++current; System.arraycopy(items, i, items, i+1, current-(i+1)); items[i] = m; } private double getLongest() { if (current < max) return Double.POSITIVE_INFINITY; return items[max-1].distance; } private Item[] getArray() { return items.clone(); } } }