8 #ifndef IMPMULTIFIT_GEOMETRIC_HASH_H
9 #define IMPMULTIFIT_GEOMETRIC_HASH_H
15 #include <boost/array.hpp>
16 #include <IMP/multifit/multifit_config.h>
19 IMPMULTIFIT_BEGIN_NAMESPACE
26 template <
typename T,
size_t D >
30 enum Distance { INF, EUCLIDEAN };
31 typedef algebra::VectorD<D> Point;
32 typedef boost::array<int, D> Bucket;
33 typedef std::pair< Point, T > ValueType;
34 typedef std::vector< ValueType > PointList;
35 typedef std::map<const Bucket, PointList> GeomMap;
36 typedef typename GeomMap::iterator iterator;
37 typedef typename GeomMap::const_iterator const_iterator;
38 typedef std::vector< const ValueType *> HashResult;
40 typedef std::vector<Bucket> BucketList;
44 GeometricHash(
double radius = 1)
46 for (
size_t i=0; i<D; ++i )
51 template <
typename X >
52 GeometricHash(
const X &radii)
54 for (
size_t i=0; i<D; ++i )
59 GeometricHash(
const algebra::VectorD<D> &radii)
61 for (
size_t i=0; i<D; ++i )
67 void add(
const Point &pt,
const T &data)
69 Bucket b = to_bucket(pt);
70 gmap_[b].push_back(std::make_pair(pt, data));
75 template <
typename X >
76 void add(
const X &coordinates,
const T &data)
79 for (
size_t i=0; i<D; ++i )
80 pt[i] = coordinates[i];
81 Bucket b = to_bucket(pt);
82 gmap_[b].push_back(std::make_pair(pt, data));
91 HashResult neighbors(Distance dt,
const Point ¢er,
94 if ( dt == EUCLIDEAN )
95 return points_in_sphere(inside_sphere(center, radius));
97 return points_in_sphere(inside_sphere_inf(center, radius));
101 HashResultT neighbors_data(Distance dt,
const Point ¢er,
104 HashResult r = neighbors(dt, center, radius);
106 tr.reserve(r.size());
107 for (
size_t i=0; i<r.size(); ++i )
108 tr.push_back(r[i]->second);
112 template <
typename X >
113 HashResult neighbors(Distance dt,
const X ¢er_coordinates,
117 for (
size_t i=0; i<D; ++i )
118 center[i] = center_coordinates[i];
119 if ( dt == EUCLIDEAN )
120 return points_in_sphere(inside_sphere(center, radius));
122 return points_in_sphere(inside_sphere_inf(center, radius));
125 void neighbors(Distance dt,
const Point ¢er,
126 double radius, HashResultT &values)
129 HashResult nb = neighbors(dt, center, radius);
130 values.reserve(nb.size());
131 for (
size_t i=0; i<nb.size(); ++i )
132 values.push_back(nb[i]->second);
138 template <
typename X >
139 HashResult neighbors(
const Point ¢er,
140 const X &radii)
const
142 return points_in_sphere(inside_cube(center, radii));
147 HashResult neighbors(
const Point ¢er)
149 return neighbors(center, radii_);
152 template <
typename X >
153 HashResult neighbors(
const X ¢er_coordinates)
156 for (
size_t i=0; i<D; ++i )
157 center[i] = center_coordinates[i];
158 return neighbors(center, radii_);
162 GeomMap
const &Map()
const
169 return gmap_.begin();
177 const_iterator begin()
const
179 return gmap_.begin();
182 const_iterator end()
const
188 BucketList get_buckets()
const
191 for (
typename GeomMap::const_iterator p = gmap_.begin();
192 p != gmap_.end(); ++p )
193 result.push_back(p->first);
203 PointList
const *bucket(
const Point &pt)
const
205 typename GeomMap::const_iterator p = gmap_.find(to_bucket(pt));
206 if ( p != gmap_.end() )
211 double resolution(
int axis = 0)
const
221 inside_sphere(
const Point ¢er,
double radius)
224 , sq_radius_(radius*radius)
227 bool operator()(
const Point &pt)
const
229 return get_squared_distance(center_, pt) <= sq_radius_;
232 double radius(
int)
const
237 const Point ¢er_;
242 struct inside_sphere_inf
244 inside_sphere_inf(
const Point ¢er,
double radius)
249 bool operator()(
const Point &pt)
const
251 return inf_distance(center_, pt) <= radius_;
254 double radius(
int)
const
259 const Point ¢er_;
265 template <
typename X >
266 inside_cube(
const Point ¢er,
const X &radii)
269 for (
size_t i=0; i<D; ++i )
270 radii_[i] = radii[i];
273 bool operator()(
const Point &pt)
const
275 for (
size_t i=0; i<D; ++i )
276 if ( std::fabs(pt[i] - center_[i]) > radii_[i] )
281 double radius(
size_t i)
const
286 const Point ¢er_;
290 template <
typename Dist >
291 HashResult points_in_sphere(Dist
const &dist)
const
294 for (
size_t i=0; i<D; ++i )
295 C[i] = dist.center_[i] - dist.radius(i);
296 Bucket l = to_bucket(C);
297 for (
size_t i=0; i<D; ++i )
298 C[i] = dist.center_[i] + dist.radius(i);
299 Bucket u = to_bucket(C);
302 points_in_sphere_rec(0, l, u, dist, tmp, result);
306 template <
typename Dist >
307 bool cube_inside_sphere(
const Dist &ins,
const Bucket &l)
const
309 Point p = from_bucket(l);
310 return cube_inside_sphere_rec(ins, p, 0);
313 template <
typename Dist >
314 bool cube_inside_sphere_rec(
const Dist &ins,
315 Point &p,
size_t idx)
const
319 if (! cube_inside_sphere_rec(ins, p, idx + 1) )
322 p[idx] += radii_[idx];
323 bool r = cube_inside_sphere_rec(ins, p, idx + 1);
328 template <
typename Dist >
329 void points_in_sphere_rec(
size_t idx,
const Bucket &l,
const Bucket &u,
330 const Dist &ins, Bucket &tmp,
331 HashResult &result)
const
335 typename GeomMap::const_iterator p = gmap_.find(tmp);
336 if ( p != gmap_.end() )
338 const PointList &v = p->second;
339 if ( v.size() > (1<<D) && cube_inside_sphere(ins, tmp) )
341 for (
typename PointList::const_iterator q = v.begin();
343 result.push_back(&(*q));
347 for (
typename PointList::const_iterator q = v.begin();
350 result.push_back(&(*q));
355 for (
int i=l[idx]; i<=u[idx]; ++i )
358 points_in_sphere_rec(idx + 1, l, u, ins, tmp, result);
363 Bucket to_bucket(
const Point &p)
const
366 for (
size_t i=0; i<D; ++i )
369 r[i] = int(p[i]/radii_[i]) - 1;
371 r[i] = int(p[i]/radii_[i]);
377 Point from_bucket(
const Bucket &b)
const
379 Point p(b.begin(), b.end());
380 for (
size_t i=0; i<D; ++i )
386 static double inf_distance(
const Point &p1,
const Point &p2)
388 double r = std::fabs(p1[0] - p2[0]);
389 for (
size_t i=1; i<D; ++i )
391 double d = std::fabs(p1[i] - p2[i]);
402 IMPMULTIFIT_END_NAMESPACE