MP5
Photomosaic
|
KDTree class: implemented using Points in Dim dimensional space (given by the template parameter). More...
#include "kdtree.h"
Classes | |
struct | KDTreeNode |
Internal structure for a node of KDTree. More... | |
Public Member Functions | |
bool | smallerDimVal (const Point< Dim > &first, const Point< Dim > &second, int curDim) const |
Determines if Point a is smaller than Point b in a given dimension d. More... | |
bool | shouldReplace (const Point< Dim > &target, const Point< Dim > ¤tBest, const Point< Dim > &potential) const |
Determines if a Point is closer to the target Point than another reference Point. More... | |
KDTree (const vector< Point< Dim >> &newPoints) | |
Constructs a KDTree from a vector of Points, each having dimension Dim. More... | |
KDTree (const KDTree &other) | |
Copy constructor for KDTree. More... | |
KDTree const & | operator= (const KDTree &rhs) |
Assignment operator for KDTree. More... | |
~KDTree () | |
Destructor for KDTree. More... | |
Point< Dim > | findNearestNeighbor (const Point< Dim > &query) const |
Finds the closest point to the parameter point in the KDTree. More... | |
void | printTree (ostream &out=cout, colored_out::enable_t enable_bold=colored_out::COUT, int modWidth=-1) const |
You do not need to modify this function. More... | |
Private Member Functions | |
int | getPrintData (KDTreeNode *subroot) const |
Helper function for grading. More... | |
void | printTree (KDTreeNode *subroot, std::vector< std::string > &output, int left, int top, int width, int currd) const |
Helper function for grading. More... | |
Private Attributes | |
KDTreeNode * | root |
Internal representation, root and size. More... | |
KDTree class: implemented using Points in Dim dimensional space (given by the template parameter).
Constructs a KDTree from a vector of Points, each having dimension Dim.
You need to handle the case that the vector has no Point in it. It should build the tree using recursive helper functions.
Since we know the size of the KDTree at construction, we can represent the tree as a linear structure and building the tree nodes based off this structure efficiently. For testing, we require the following:
KD-trees are created recursively; at any stage of the construction, the median value in the current dimension is selected and a node is created based on it. Then, all the elements in the current subtree are divided up into elements which are less than the median, or greater than the median, and then the subtrees are created recursively. The children pick the median in the next dimension, and repeat until the entire set of inputs has been processed. Successive levels of the tree split on increasing dimensions, modulo the total number: a 3D tree will have levels split by dimension 0, 1, 2, 0, 1, 2, etc.
You will probably want to write a helper function which performs the median selection and partitioning. Maybe you can use a function you already wrote...
newPoints | The vector of points to build your KDTree off of. |
bool KDTree< Dim >::smallerDimVal | ( | const Point< Dim > & | first, |
const Point< Dim > & | second, | ||
int | curDim | ||
) | const |
Determines if Point a is smaller than Point b in a given dimension d.
If there is a tie, break it with Point::operator<().
For example:
Point<3> a(1, 2, 3); Point<3> b(3, 2, 1); cout << smallerDimVal(a, b, 0) << endl; // should print true cout << smallerDimVal(a, b, 2) << endl; // should print false cout << smallerDimVal(a, b, 1) << endl; // based on operator<, this should be true
first | Point to compare. |
second | Second point to compare. |
curDim | Dimension these points are being compared in. |
bool KDTree< Dim >::shouldReplace | ( | const Point< Dim > & | target, |
const Point< Dim > & | currentBest, | ||
const Point< Dim > & | potential | ||
) | const |
Determines if a Point is closer to the target Point than another reference Point.
Takes three points: target, currentBest, and potential, and returns whether or not potential is closer to target than currentBest.
We are using Euclidean distance to compare k-dimensional points: \(\sqrt{(p_1-q_1)^2+(p_2-q_2)^2+\ldots+(p_n-q_n)^2} = \sqrt{\sum_{i=1}^n (p_i-q_i)^2}\). Note, however, that minimizing distance is the same as minimizing squared distance, so you can avoid invoking the square root and just compare squared distances in your code.
For example:
Point<3> target(1, 3, 5); Point<3> currentBest1(1, 3, 2); Point<3> possibleBest1(2, 4, 4); Point<3> currentBest2(1, 3, 6); Point<3> possibleBest2(2, 4, 4); Point<3> currentBest3(0, 2, 4); Point<3> possibleBest3(2, 4, 6); cout << shouldReplace(target, currentBest1, possibleBest1) << endl; // true cout << shouldReplace(target, currentBest2, possibleBest2) << endl; // false cout << shouldReplace(target, currentBest3, possibleBest3) << endl; // based on operator<, this should be false
target | The Point we want to be close to. |
currentBest | The Point that is currently our closest Point to target. |
potential | Our Point that is a candidate to replace currentBest (that is, it may be closer to target than currentBest). |
Point< Dim > KDTree< Dim >::findNearestNeighbor | ( | const Point< Dim > & | query | ) | const |
Finds the closest point to the parameter point in the KDTree.
This function takes a reference to a template parameter Point and returns the Point closest to it in the tree. We are defining closest here to be the minimum Euclidean distance between elements. Again, if there are ties (this time in distance), they must be decided using Point::operator<(). Recall that an HSLAPixel is defined by three components: hue, saturation, and luminance.
The findNearestNeighbor() search is done in two steps: a search to find the smallest hyperrectangle that contains the target element, and then a back traversal to see if any other hyperrectangle could contain a closer point, which may be a point with smaller distance or a point with equal distance, but a "smaller" point (as defined by operator< in the point class). In the first step, you must recursively traverse down the tree, at each level choosing the subtree which represents the region containing the search element (another place to save some duplicate code?). When you reach the lowest bounding hyperrectangle, then the corresponding node is effectively the "current best" neighbor.
However, it may be the case that a better match exists outside of the containing hyperrectangle. At then end of first step of the search, we start traversing back up the kdtree to the parent node. The current best distance defines a radius which contains the nearest neighbor. During the back-traversal (i.e., stepping out of the recursive calls), you must first check if the distance to the parent node is less than the current radius. If so, then that distance now defines the radius, and we replace the "current best" match. Next, it is necessary to check to see if the current splitting plane's distance from search node is within the current radius. If so, then the opposite subtree could contain a closer node, and must also be searched recursively.
During the back-traversal, it is important to only check the subtrees that are within the current radius, or else the efficiency of the kdtree is lost. If the distance from the search node to the splitting plane is greater than the current radius, then there cannot possibly be a better nearest neighbor in the subtree, so the subtree can be skipped entirely.
You can assume that findNearestNeighbor will only be called on a valid kd-tree.
query | The point we wish to find the closest neighbor to in the tree. |
void KDTree< Dim >::printTree | ( | ostream & | out = cout , |
colored_out::enable_t | enable_bold = colored_out::COUT , |
||
int | modWidth = -1 |
||
) | const |
You do not need to modify this function.
Its implementation is in kdtree_extras.cpp. Prints the KDTree to the terminal in a pretty way.
|
private |
Helper function for grading.
|
private |
Helper function for grading.
|
private |
Internal representation, root and size.