Point<Dim> KDTree<Dim>::findNearestNeighbor(const Point<Dim> & query, int lo, int hi, int dim) const{ if(lo >= hi ) return points[lo]; //base case int mid = (hi+lo)/2; //calculate the minPoint index Point<Dim> temp; Point<Dim> curr = points[mid]; dim = dim%Dim; int direction=0; if(smallerDimVal(query, points[mid], dim)){ direction = 0; temp = findNearestNeighbor(query, lo, mid-1, dim+1); //left half } else{ direction =1; temp = findNearestNeighbor(query, mid+1, hi, dim+1); //recusively call the function on the left half } Point<Dim> best; if(shouldReplace(query, temp, curr) ) best= curr; else best = temp; int dimD = (curr[dim] - query[dim])*(curr[dim] - query[dim]); int bestCurr = squareDistance(best, query); if(dimD > bestCurr) return best; else{ Point<Dim> t; if(direction == 0) t = findNearestNeighbor(query, mid+1, hi, dim+1); else t = findNearestNeighbor(query, lo, mid-1,dim+1); if(shouldReplace(query,t, best)) return best; else return t; } }
Point<Dim> KDTree<Dim>::find(const Point<Dim> & query, int cur, int curDim, int a, int b) const { if(a == b) return points[a]; else { Point<Dim> temp; double childdist = 0; double parentdist2 = ((points[cur])[curDim] - query[curDim])*((points[cur])[curDim] - query[curDim]); double parentdist = 0; if(smallerDimVal(query, points[cur], curDim)) { if (cur-1 < a) return points[cur]; else { temp = find(query, (a+cur-1)/2, (curDim+1)%Dim, a, cur-1); for (int i = 0; i < Dim; i++) { childdist += ((temp[i]-query[i])*(temp[i]-query[i])); parentdist += (((points[cur])[i]-query[i])*((points[cur])[i]-query[i])); } if (parentdist2 <= childdist) { Point<Dim> temp2; if (cur+1 > b) temp2 = points[cur]; else temp2 = find(query, (cur+1+b)/2, (curDim+1)%Dim, cur+1, b); if ((parentdist < childdist)||((parentdist == childdist)&&(points[cur] < temp))) temp = points[cur]; if (shouldReplace(query, temp, temp2)) return temp2; else return temp; } else return temp; } } else { if (cur+1 > b) return points[cur]; else { temp = find(query, (cur+1+b)/2, (curDim+1)%Dim, cur+1, b); for (int i = 0; i < Dim; i++) { childdist += ((temp[i]-query[i])*(temp[i]-query[i])); parentdist += (((points[cur])[i]-query[i])*((points[cur])[i]-query[i])); } if (parentdist2 <= childdist) { Point<Dim> temp2; if (cur-1 < a) temp2 = points[cur]; else temp2 = find(query, (a+cur-1)/2, (curDim+1)%Dim, a, cur-1); if ((parentdist < childdist)||((parentdist == childdist)&&(points[cur] < temp))) temp = points[cur]; if (shouldReplace(query, temp, temp2)) return temp2; else return temp; } else return temp; } } } }
Point<Dim> KDTree<Dim>::walkThrough(const Point<Dim> &target, const Point<Dim> &ret, int lower, int upper, int curDim) const { //base case if (lower == upper) { if (shouldReplace(target, ret, points[lower])) { return points[lower]; } return ret; } // other int median = (lower + upper)/2; Point<Dim> ret2 = ret; //a recording for which side are we going int side = 0;//0:left, 1:right if (smallerDimVal(points[median], target, curDim)&&upper>median) //why do we have to check upper>median? { int dim2 = curDim+1; if(dim2>=Dim) dim2=dim2-Dim; ret2 = walkThrough(target, ret, median+1, upper, dim2); side=1; } if (smallerDimVal(target, points[median], curDim)&&lower<median) { int dim2 = curDim+1; if(dim2>=Dim) dim2=dim2-Dim; ret2 = walkThrough(target, ret, lower, median-1, dim2); side=0; } //Check if current node is closer than obtained above if (shouldReplace(target, ret2, points[median])) ret2 = points[median]; //prepare to check the other side Point<Dim> m = points[median];//don't understand why can't point[median][Dim] int distance=0;//distance we have now for(int i=0; i< Dim; i++) distance+= pow(target[i]-ret2[i],2); if(pow(m[curDim]-target[curDim],2)<=distance) { int dim2 = curDim+1; if(dim2>=Dim) dim2=dim2-Dim; if(side==0&&upper>median)//left has been checked, goto right ret2 = walkThrough(target, ret2, median+1, upper, dim2 ); if(side==1&&lower<median)//goto left ret2 = walkThrough(target, ret2, lower, median-1, dim2 ); } return ret2; }
Point<Dim> KDTree<Dim>::NearestNeighbor_helper(int curDim, const Point<Dim> &query, int bottom, int top, const Point<Dim> ¤tBest) const { Point<Dim> retVal = currentBest;//set a holder (call it return value) equal to currentBest to start bool target = true; //initialize our target bool to true if(bottom==top) { //this means were at a leaf //we need to check if were wcloser than current best and return the appropriate currnent best if(shouldReplace(query, currentBest, points[bottom])==true) { retVal = points[bottom];//set the return value return retVal; //send that thing up! } retVal = currentBest; //otherwise return the currentBest return retVal; } //declare the middle point int middle = (bottom+top)/2; //now lets get to work on tricky stuff if(smallerDimVal(points[middle], query, curDim) && top > middle) { //recursive call to set retVal retVal = NearestNeighbor_helper((curDim+1)%Dim, query, middle+1, top, currentBest); target = false; } if (smallerDimVal(query, points[middle], curDim) && bottom <middle) { //recursive call to set retVal retVal = NearestNeighbor_helper((curDim+1)%Dim, query, bottom, middle-1, currentBest); target = true; } //look to see if the node were on is closer than what was obtained earlier if(shouldReplace(query, retVal, points[middle])) { retVal = points[middle];//set retVal appropriately } //lots of TA guidance here this is still a little foggy Point <Dim> holder = points[middle]; if(pow(holder[curDim] - query[curDim], 2) <= distance(query, retVal)) { if(!target && bottom < middle) { retVal = NearestNeighbor_helper((curDim+1)%Dim, query, bottom, middle-1, retVal);//same as above but replace currentBest with retVal! } if(target && top > middle) { //recurisve call retVal = NearestNeighbor_helper((curDim+1)%Dim, query, middle+1, top, retVal);//same as above but replace currentBest with retVal! } } //AND FINALLY return retVal; }