![JAR search and dependency download from the Maven repository](/logo.png)
de.biomedical_imaging.edu.wlu.cs.levy.CG.KDNode Maven / Gradle / Ivy
// KDNode.java : K-D Tree node class
//
// Copyright (C) Simon D. Levy 2014
//
// This code is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this code. If not, see .
// You should also have received a copy of the Parrot Parrot AR.Drone
// Development License and Parrot AR.Drone copyright notice and disclaimer
// and If not, see
//
// and
// .
package de.biomedical_imaging.edu.wlu.cs.levy.CG;
import java.io.Serializable;
import java.util.List;
class KDNode implements Serializable{
// these are seen by KDTree
protected HPoint k;
T v;
protected KDNode left, right;
protected boolean deleted;
// Method ins translated from 352.ins.c of Gonnet & Baeza-Yates
protected static int edit(HPoint key, Editor editor, KDNode t, int lev, int K)
throws KeyDuplicateException {
KDNode next_node = null;
int next_lev = (lev+1) % K;
synchronized (t) {
if (key.equals(t.k)) {
boolean was_deleted = t.deleted;
t.v = editor.edit(t.deleted ? null : t.v );
t.deleted = (t.v == null);
if (t.deleted == was_deleted) {
// if I was and still am deleted or was and still am alive
return 0;
} else if (was_deleted) {
// if I was deleted => I am now undeleted
return 1;
}
// I was not deleted, but I am now deleted
return -1;
} else if (key.coord[lev] > t.k.coord[lev]) {
next_node = t.right;
if (next_node == null) {
t.right = create(key, editor);
return t.right.deleted ? 0 : 1;
}
}
else {
next_node = t.left;
if (next_node == null) {
t.left = create(key, editor);
return t.left.deleted ? 0 : 1;
}
}
}
return edit(key, editor, next_node, next_lev, K);
}
protected static KDNode create(HPoint key, Editor editor)
throws KeyDuplicateException {
KDNode t = new KDNode(key, editor.edit(null));
if (t.v == null) {
t.deleted = true;
}
return t;
}
protected static boolean del(KDNode t) {
synchronized (t) {
if (!t.deleted) {
t.deleted = true;
return true;
}
}
return false;
}
// Method srch translated from 352.srch.c of Gonnet & Baeza-Yates
protected static KDNode srch(HPoint key, KDNode t, int K) {
for (int lev=0; t!=null; lev=(lev+1)%K) {
if (!t.deleted && key.equals(t.k)) {
return t;
}
else if (key.coord[lev] > t.k.coord[lev]) {
t = t.right;
}
else {
t = t.left;
}
}
return null;
}
// Method rsearch translated from 352.range.c of Gonnet & Baeza-Yates
protected static void rsearch(HPoint lowk, HPoint uppk, KDNode t, int lev,
int K, List> v) {
if (t == null) return;
if (lowk.coord[lev] <= t.k.coord[lev]) {
rsearch(lowk, uppk, t.left, (lev+1)%K, K, v);
}
if (!t.deleted) {
int j = 0;
while (j=t.k.coord[j]) {
j++;
}
if (j==K) v.add(t);
}
if (uppk.coord[lev] > t.k.coord[lev]) {
rsearch(lowk, uppk, t.right, (lev+1)%K, K, v);
}
}
// Method Nearest Neighbor from Andrew Moore's thesis. Numbered
// comments are direct quotes from there. NearestNeighborList solution
// courtesy of Bjoern Heckel.
protected static void nnbr(KDNode kd, HPoint target, HRect hr,
double max_dist_sqd, int lev, int K,
NearestNeighborList> nnl,
Checker checker,
long timeout) {
// 1. if kd is empty then set dist-sqd to infinity and exit.
if (kd == null) {
return;
}
if ((timeout > 0) && (timeout < System.currentTimeMillis())) {
return;
}
// 2. s := split field of kd
int s = lev % K;
// 3. pivot := dom-elt field of kd
HPoint pivot = kd.k;
double pivot_to_target = HPoint.sqrdist(pivot, target);
// 4. Cut hr into to sub-hyperrectangles left-hr and right-hr.
// The cut plane is through pivot and perpendicular to the s
// dimension.
HRect left_hr = hr; // optimize by not cloning
HRect right_hr = (HRect) hr.clone();
left_hr.max.coord[s] = pivot.coord[s];
right_hr.min.coord[s] = pivot.coord[s];
// 5. target-in-left := target_s <= pivot_s
boolean target_in_left = target.coord[s] < pivot.coord[s];
KDNode nearer_kd;
HRect nearer_hr;
KDNode further_kd;
HRect further_hr;
// 6. if target-in-left then
// 6.1. nearer-kd := left field of kd and nearer-hr := left-hr
// 6.2. further-kd := right field of kd and further-hr := right-hr
if (target_in_left) {
nearer_kd = kd.left;
nearer_hr = left_hr;
further_kd = kd.right;
further_hr = right_hr;
}
//
// 7. if not target-in-left then
// 7.1. nearer-kd := right field of kd and nearer-hr := right-hr
// 7.2. further-kd := left field of kd and further-hr := left-hr
else {
nearer_kd = kd.right;
nearer_hr = right_hr;
further_kd = kd.left;
further_hr = left_hr;
}
// 8. Recursively call Nearest Neighbor with paramters
// (nearer-kd, target, nearer-hr, max-dist-sqd), storing the
// results in nearest and dist-sqd
nnbr(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl, checker, timeout);
KDNode nearest = nnl.getHighest();
double dist_sqd;
if (!nnl.isCapacityReached()) {
dist_sqd = Double.MAX_VALUE;
}
else {
dist_sqd = nnl.getMaxPriority();
}
// 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd
max_dist_sqd = Math.min(max_dist_sqd, dist_sqd);
// 10. A nearer point could only lie in further-kd if there were some
// part of further-hr within distance max-dist-sqd of
// target.
HPoint closest = further_hr.closest(target);
if (HPoint.sqrdist(closest, target) < max_dist_sqd) {
// 10.1 if (pivot-target)^2 < dist-sqd then
if (pivot_to_target < dist_sqd) {
// 10.1.1 nearest := (pivot, range-elt field of kd)
nearest = kd;
// 10.1.2 dist-sqd = (pivot-target)^2
dist_sqd = pivot_to_target;
// add to nnl
if (!kd.deleted && ((checker == null) || checker.usable(kd.v))) {
nnl.insert(kd, dist_sqd);
}
// 10.1.3 max-dist-sqd = dist-sqd
// max_dist_sqd = dist_sqd;
if (nnl.isCapacityReached()) {
max_dist_sqd = nnl.getMaxPriority();
}
else {
max_dist_sqd = Double.MAX_VALUE;
}
}
// 10.2 Recursively call Nearest Neighbor with parameters
// (further-kd, target, further-hr, max-dist_sqd),
// storing results in temp-nearest and temp-dist-sqd
nnbr(further_kd, target, further_hr, max_dist_sqd, lev + 1, K, nnl, checker, timeout);
}
}
// constructor is used only by class; other methods are static
private KDNode(HPoint key, T val) {
k = key;
v = val;
left = null;
right = null;
deleted = false;
}
protected String toString(int depth) {
String s = k + " " + v + (deleted ? "*" : "");
if (left != null) {
s = s + "\n" + pad(depth) + "L " + left.toString(depth+1);
}
if (right != null) {
s = s + "\n" + pad(depth) + "R " + right.toString(depth+1);
}
return s;
}
private static String pad(int n) {
String s = "";
for (int i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy