00001
00002
00003
00004
00005
00006
00007
00008 #ifndef IMPALGEBRA_VECTOR_SEARCH_H
00009 #define IMPALGEBRA_VECTOR_SEARCH_H
00010
00011 #include "VectorD.h"
00012
00013
00014 #ifdef IMP_USE_CGAL
00015 #include <CGAL/basic.h>
00016 #include <CGAL/Search_traits.h>
00017 #include <CGAL/Orthogonal_k_neighbor_search.h>
00018 #include <CGAL/K_neighbor_search.h>
00019 #include <boost/static_assert.hpp>
00020 #endif
00021
00022 IMPALGEBRA_BEGIN_NAMESPACE
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 template <unsigned int D>
00037 class NearestNeighborD {
00038
00039 template <bool SKIP>
00040 Ints linear_nearest_neighbor(const VectorD<D> &q, int skip,
00041 unsigned int k) const {
00042 Ints ret;
00043 std::vector<double> retds;
00044 for (unsigned int i=0; i< data_.size(); ++i) {
00045 if (SKIP && i==static_cast<unsigned int>(skip)) continue;
00046 double cd=(data_[i]-q).get_squared_magnitude();
00047 if (ret.size() < k || cd < retds.back()) {
00048 std::vector<double>::iterator it= std::lower_bound(retds.begin(),
00049 retds.end(), cd);
00050 ret.insert(ret.begin()+(it-retds.begin()), i);
00051 retds.insert(it, cd);
00052 if (ret.size() > k) {
00053 ret.pop_back();
00054 retds.pop_back();
00055 }
00056 }
00057 }
00058 return ret;
00059 }
00060
00061 #ifdef IMP_USE_CGAL
00062 struct VectorWithIndex: public VectorD<D> {
00063 int index;
00064 VectorWithIndex(unsigned int i, const VectorD<D>& p): VectorD<D>(p),
00065 index(i){}
00066 VectorWithIndex(): index(-1){}
00067 };
00068 struct Construct_coord_iterator {
00069 const double* operator()(const VectorD<D>& p) const
00070 { return p.get_data(); }
00071 const double* operator()(const VectorD<D>& p, int) const
00072 { return p.get_data()+D; }
00073 };
00074 struct Distance {
00075 typedef VectorD<D> Query_item;
00076
00077 double transformed_distance(const VectorD<D>& p1,
00078 const VectorD<D>& p2) const {
00079 return (p1-p2).get_squared_magnitude();
00080 }
00081
00082 template <class TreeTraits>
00083 double min_distance_to_rectangle(const VectorD<D>& p,
00084 const CGAL::Kd_tree_rectangle<TreeTraits>& b) const {
00085 double distance(0.0);
00086 for (unsigned int i=0; i< D; ++i) {
00087 double h = p[i];
00088 if (h < b.min_coord(i)) distance += square(b.min_coord(i)-h);
00089 if (h > b.max_coord(i)) distance += square(h-b.max_coord(i));
00090 }
00091 return distance;
00092 }
00093
00094 template <class TreeTraits>
00095 double max_distance_to_rectangle(const VectorD<D>& p,
00096 const CGAL::Kd_tree_rectangle<TreeTraits>& b) const {
00097 double d=0.0;
00098 for (unsigned int i=0; i< D; ++i) {
00099 double h = p[i];
00100 double di = (h >= (b.min_coord(i)+b.max_coord(i))/2.0) ?
00101 square(h-b.min_coord(i)) : square(b.max_coord(i)-h);
00102 d+=di;
00103 }
00104 return d;
00105 }
00106 double new_distance(double dist, double old_off, double new_off,
00107 int ) const {
00108 return dist + new_off*new_off - old_off*old_off;
00109 }
00110 double transformed_distance(double d) const { return d*d; }
00111 double inverse_of_transformed_distance(double d) { return std::sqrt(d); }
00112 };
00113
00114 typedef typename CGAL::Search_traits<double, VectorWithIndex,
00115 const double*, Construct_coord_iterator> Traits;
00116 typedef typename CGAL::K_neighbor_search<Traits,
00117 Distance> K_neighbor_search;
00118 typedef typename K_neighbor_search::Tree Tree;
00119
00120 struct RCTree: public Tree, public RefCounted {
00121 template <class It>
00122 RCTree(It b, It e): Tree(b,e){}
00123 virtual ~RCTree(){}
00124 };
00125 mutable Pointer<RCTree> tree_;
00126 #endif
00127 std::vector<VectorD<D> > data_;
00128 double eps_;
00129 public:
00130 NearestNeighborD(const std::vector<VectorD<D> > &vs,
00131 double epsilon=0):
00132 data_(vs),
00133 eps_(epsilon)
00134 {
00135 #ifdef IMP_USE_CGAL
00136 std::vector<VectorWithIndex> vsi(vs.size());
00137 for (unsigned int i=0; i< vs.size(); ++i) {
00138 vsi[i]= VectorWithIndex(i, vs[i]);
00139 }
00140 tree_= new RCTree(vsi.begin(), vsi.end());
00141 #endif
00142 }
00143
00144 unsigned int get_nearest_neighbor(const VectorD<D> &q) const {
00145 #ifdef IMP_USE_CGAL
00146 K_neighbor_search search(*tree_, VectorWithIndex(-1, q), 1, eps_);
00147 return search.begin()->first.index;
00148 #else
00149 return linear_nearest_neighbor<false>(q, -1, 1)[0];
00150 #endif
00151 }
00152
00153 unsigned int get_nearest_neighbor(unsigned int i) const {
00154 #ifdef IMP_USE_CGAL
00155 K_neighbor_search search(*tree_, data_[i], 2, eps_);
00156 IMP_INTERNAL_CHECK(std::distance(search.begin(), search.end()) >=2,
00157 "Wrong number of points returned "
00158 << std::distance(search.begin(), search.end()));
00159 if (search.begin()->first.index != i) return search.begin()->first.index;
00160 else return (++search.begin())->first.index;
00161 #else
00162 return linear_nearest_neighbor<true>(data_[i], i, 1)[0];
00163 #endif
00164 }
00165
00166
00167 Ints get_nearest_neighbors(unsigned int i, unsigned int k) const {
00168 Ints ret(std::min(k, static_cast<unsigned int>(data_.size())));
00169 #ifdef IMP_USE_CGAL
00170 K_neighbor_search search(*tree_, data_[i], k+1, eps_);
00171 typename K_neighbor_search::iterator it =search.begin();
00172 IMP_INTERNAL_CHECK(std::distance(search.begin(), search.end())
00173 == static_cast<int>(ret.size()+1),
00174 "Got the wrong number of points out from CGAL neighbor"
00175 << " search. Expected " << ret.size()+1
00176 << " got "
00177 << std::distance(search.begin(), search.end()));
00178 ++it;
00179 for (unsigned int j=0; j< k; ++j) {
00180 ret[j]=it->first.index;
00181 ++it;
00182 }
00183 #else
00184 ret= linear_nearest_neighbor<true>(data_[i], i, k);
00185 #endif
00186 return ret;
00187 }
00188 };
00189
00190
00191
00192 IMPALGEBRA_END_NAMESPACE
00193
00194 #endif