aimstil  5.0.5
kdtree.tpp
Go to the documentation of this file.
1 #ifndef TIL_KDTREE_TPP_
2 #define TIL_KDTREE_TPP_
3 
4 namespace til
5 {
6 
7  //----------------------------------------------------------------------------------
8 
9  //-----------------//
10  // KDTreeFactory //
11  //-----------------//
12 
13  template < typename TKDTree >
14  void KDTreeFactory<TKDTree>::build(TKDTree & res)
15  {
16  // Create a vector containing the indices of the collection elements
17  makeIndexVector(m_v, m_vIndex);
18 
19  // Set kdtree as a global variable inside the class
20  m_pKdt = &res;
21 
22  // Start kdtree building iterations
23  typename std::vector<index_type>::iterator left = m_vIndex.begin();
24  typename std::vector<index_type>::iterator right = m_vIndex.end()-1;
25  genKDIter(left, right, m_pKdt->addChild(0, 0u), 0);
26  }
27 
28 
29  template < typename TKDTree >
30  void KDTreeFactory<TKDTree>::genKDIter
31  (
32  typename std::vector<index_type>::iterator left,
33  typename std::vector<index_type>::iterator right,
34  typename TKDTree::iterator iRes,
35  int dim
36  )
37  {
38  // We want the median to have a mean index.
39  typename std::vector<index_type>::iterator median = left+(right-left)/2;
40 
41  // sort and iterate
42  // NB: The right+1 is because STL algorithms expect to have an element out
43  // of range as the "end" element.
44  m_dim = dim;
45  std::nth_element(left, median, right+1, m_compare);
46  iRes->value() = *median;
47  iRes->dim() = dim;
48 
49  // Iterate right and left, if range permits it
50  if (left < median)
51  {
52  genKDIter(left, median-1, m_pKdt->addChild(iRes, TKDTree::LEFT), (dim+1)%3);
53  }
54  if (median < right)
55  {
56  genKDIter(median+1, right, m_pKdt->addChild(iRes, TKDTree::RIGHT), (dim+1)%3);
57  }
58  }
59 
60  template < typename TKDTree >
61  void KDTreeFactory<TKDTree>::makeIndexVector(const Collection & v, std::vector<index_type> & vIndex)
62  {
63  vIndex.resize(size(v));
64  typename std::vector<indexed_type>::const_iterator iV = v.begin();
65  typename std::vector<index_type>::iterator iVIndex = vIndex.begin();
66  for (; iV != v.end(); ++iV, ++iVIndex)
67  {
68  getIndex(iV, *iVIndex);
69  //*iVIndex = til::getIndex<index_type>(v, iV);
70  }
71  }
72 
73 
74  //----------------------------------------------------------------------------------
75 
76  //----------------//
77  // Find_closest //
78  //----------------//
79 
80 
81  template < typename TPrecision, typename TKDTree >
82  typename Find_closest<TPrecision,TKDTree>::index_type
83  Find_closest<TPrecision,TKDTree>::operator()(const indexed_type & vec)
84  {
85  this->init();
86  m_vec = vec;
87  lookMax(m_pKdt->root());
88  return m_minIndex;
89  }
90 
91  template < typename TPrecision, typename TKDTree >
92  void Find_closest<TPrecision,TKDTree>::init()
93  {
94  m_min = std::numeric_limits<TPrecision>::max();
95  m_minIndex = 0;
96  m_niter = 0;
97  }
98 
99  template < typename TPrecision, typename TKDTree >
100  void Find_closest<TPrecision,TKDTree>::lookMax(typename TKDTree::const_iterator iNode)
101  {
102  ++m_niter;
103  // Stop here if we reached end of tree
104  // TODO: this test might be put below, to avoid an extra function call
105  // everytime we reach an end point.
106  if (iNode == 0) return;
107  index_type node = *iNode;
108  //NB: this was used when node is a pointer. Dunno if its removal changes something. hope not.
109  //if (node == 0) return;
110 
111  // Compute the distance to the current node point
112  TPrecision dist2point = dist2(m_pKdt->get(node), m_vec, prec<TPrecision>());
113  //std::cout << dist2point << "*" << std::flush;
114  if (dist2point < m_min)
115  {
116  m_min = dist2point;
117  m_minIndex = node;
118  }
119 
120  // Continue looking downwards, starting from the lower half or the higher
121  // half, depending on which the vector belongs to.
122  TPrecision diffWall = m_vec[iNode->dim()] - m_pKdt->get(node)[iNode->dim()];
123 
124  if (diffWall < 0)
125  {
126  // Point belong to lower half: process this half first
127  lookMax(iNode.child(TKDTree::LEFT));
128  // We process the other half only if the min distance found so far
129  // is larger than the distance to the halfplane border
130  if (m_min > square(diffWall))
131  {
132  lookMax(iNode.child(TKDTree::RIGHT));
133  }
134  }
135  else
136  {
137  // Point belong to higher half: process this half first
138  lookMax(iNode.child(TKDTree::RIGHT));
139  // We process the other half only if the min distance found so far
140  // is larger than the distance to the halfplane border
141  if (m_min > square(diffWall))
142  {
143  lookMax(iNode.child(TKDTree::LEFT));
144  }
145  }
146  }
147 
148 
149 } // namespace til
150 
151 #endif /*KDTREE_TPP_*/