00001 #ifndef ConcentricShells_HEADER
00002 #define ConcentricShells_HEADER
00003
00004 #ifdef HAVE_CONFIG_H
00005 # include <config.h>
00006 #endif
00007
00008 #include <boost/utility.hpp>
00009 #include <utilities/SmallList.h>
00010 #include <math.h>
00011 #include <utilities/foreach.h>
00012 #include <utilities/bit-hacks.h>
00013
00014 #if 0
00015 #define dprintf(...) printf(__VA_ARGS__)
00016 #else
00017 #define dprintf(...)
00018 #endif
00019
00033 template <class Item, class Point>
00034 class ConcentricShells : public boost::noncopyable {
00035 typedef hudson::SmallList<Item*> ItemList;
00036
00037 struct Annulus {
00038 const int log_radius2;
00039 ItemList items;
00040 Annulus(int log_r2): log_radius2(log_r2) { }
00041 void add(Item *item) {
00042 items.push_front(item);
00043 }
00044 };
00045
00046 typedef hudson::SmallList<Annulus> Annuli;
00047
00048 Annuli annuli_;
00049
00050 void newAnnulus(const typename Annuli::iterator& next, int log_r2, Item *item) {
00051 typename Annuli::iterator it = annuli_.insert(next, Annulus(log_r2));
00052 (*it).add(item);
00053
00054 dprintf("Inserted annulus with radius %d; next has radius %d\n",
00055 log_r2,
00056 (++it) == annuli_.end()
00057 ? std::numeric_limits<int>::min()
00058 : (*it).log_radius2
00059 );
00060 }
00061
00062 public:
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 void add(const Point& center, Item *item) {
00078
00079 double dist2 = item->toPoint().dist2(center);
00080 if (dist2 == 0.0) { return; }
00081 int log_d2 = bithacks::log2_norm(dist2);
00082
00083 dprintf("Adding to center %s, item %s, annulus %d\n",
00084 center.toString().c_str(),
00085 item->toString().c_str(), log_d2);
00086
00087 if (annuli_.empty()) {
00088
00089 dprintf("Annuli empty\n");
00090 newAnnulus(annuli_.begin(), log_d2, item);
00091 }
00092 else if ( annuli_.front().log_radius2 < log_d2 ) {
00093
00094 dprintf("Annuli all small: %d\n", annuli_.front().log_radius2);
00095 newAnnulus(annuli_.begin(), log_d2, item);
00096 }
00097 else {
00098
00099 typename Annuli::iterator it = annuli_.begin();
00100 typename Annuli::iterator end = annuli_.end();
00101 while (it != end && (*it).log_radius2 > log_d2) { ++it; }
00102 if (it != end && (*it).log_radius2 == log_d2) {
00103
00104 dprintf("Found correct annulus\n");
00105 (*it).add(item);
00106 } else {
00107
00108 dprintf("No proper annulus\n");
00109 newAnnulus(it, log_d2, item);
00110 }
00111 }
00112 }
00113
00114
00115
00116
00117
00118
00119 void reassignTo(const Point& center, ConcentricShells& other, const Point& othercenter) {
00120
00121 double pq2 = center.dist2(othercenter);
00122 assert(pq2 > 0.0);
00123 double half2 = pq2 / 4.0;
00124 int last_annulus = bithacks::log2_norm(half2);
00125
00126
00127 typename Annuli::iterator annulus_it = annuli_.begin();
00128
00129
00130
00131 while (annulus_it != annuli_.end()
00132 && (*annulus_it).log_radius2 >= last_annulus) {
00133 ItemList& l = (*annulus_it).items;
00134 typename ItemList::iterator item_it = l.begin();
00135 while (item_it != l.end() ) {
00136
00137 Item *item = *item_it;
00138 double up2 = center.dist2(item->toPoint());
00139 double uq2 = othercenter.dist2(item->toPoint());
00140 if (uq2 < up2) {
00141 item_it = l.erase(item_it);
00142 other.add(othercenter, item);
00143 } else {
00144 ++item_it;
00145 }
00146 }
00147
00148
00149 if (l.empty()) {
00150 annulus_it = annuli_.erase(annulus_it);
00151 } else {
00152 ++annulus_it;
00153 }
00154 }
00155 }
00156
00157 private:
00173 static int computeSmallestAnnulus(double pq2, double r2) {
00174 if (pq2 <= r2) {
00175
00176 return std::numeric_limits<int>::min();
00177 } else {
00178 double pB2 = pq2 + r2 - 2.0 * sqrt(pq2 * r2);
00179 return bithacks::log2_norm(pB2);
00180 }
00181 }
00182
00183
00184
00185
00186
00187
00188
00189 public:
00190 std::pair<Item*, double> findClosest(const Point& center, const Point& q, double r2) const {
00191 double pq2 = center.dist2(q);
00192 int smallest_annulus = computeSmallestAnnulus(pq2, r2);
00193
00194 Item *best = NULL;
00195
00196
00197
00198 BOOST_FOREACH(const Annulus& annulus, annuli_) {
00199
00200 if (annulus.log_radius2 < smallest_annulus) { break; }
00201
00202
00203
00204 BOOST_FOREACH(Item *item, annulus.items) {
00205 double iq2 = item->toPoint().dist2(q);
00206 if (iq2 < r2) {
00207 best = item;
00208 r2 = iq2;
00209 smallest_annulus = computeSmallestAnnulus(pq2, r2);
00210 }
00211 }
00212 }
00213 return make_pair(best, r2);
00214 }
00215
00216
00217
00218
00219
00220
00221 public:
00222 std::pair<Item*, double> findPoint(const Point& center, const Point& q, double r2) const {
00223 double pq2 = center.dist2(q);
00224 int smallest_annulus = computeSmallestAnnulus(pq2, r2);
00225
00226
00227 BOOST_FOREACH(const Annulus& annulus, annuli_) {
00228
00229 if (annulus.log_radius2 < smallest_annulus) { break; }
00230
00231
00232 const ItemList& l = annulus.items;
00233 BOOST_FOREACH(Item *item, l) {
00234 double d2 = item->toPoint().dist2(q);
00235 if (d2 < r2) {
00236 return std::make_pair(item, d2);
00237 }
00238 }
00239 }
00240 return std::make_pair((Item*)0, r2);
00241 }
00242
00243
00244
00245
00246
00247
00248 bool empty() const {
00249
00250
00251
00252 return annuli_.empty();
00253 }
00254
00255
00256
00257
00258
00259
00260
00261 Item *getFarItem() const {
00262 assert(!empty());
00263 return annuli_.front().items.front();
00264 }
00265 };
00266
00267 #undef dprintf
00268
00269 #endif