contrib/rpl/rsdl/rsdl_bins.txx

Go to the documentation of this file.
00001 #ifndef rsdl_bins_txx_
00002 #define rsdl_bins_txx_
00003 //:
00004 // \file
00005 // \author Amitha Perera
00006 // \date   Feb 2003
00007 
00008 #include "rsdl_bins.h"
00009 
00010 #include <vcl_cassert.h>
00011 #include <vcl_iostream.h>
00012 #include <vcl_cmath.h>
00013 #include <vcl_vector.h>
00014 #include <vcl_algorithm.h>
00015 #include <vcl_cstddef.h> // for std::size_t
00016 
00017 //:
00018 // This class is used in n_nearest_impl. It stores a pointer to an
00019 // entry (= (location,value) pair), and a distance to that entry from
00020 // the query point. It supports ordering by ascending distance.
00021 //
00022 template<unsigned N, typename CoordType, typename ValueType>
00023 struct rsdl_bins_point_dist_entry
00024 {
00025   typedef rsdl_bins<N,CoordType,ValueType>                 bin_class;
00026   typedef rsdl_bins_bin_entry_type<N,CoordType,ValueType>  bin_entry_type;
00027   typedef typename bin_class::coord_type                   coord_type;
00028   typedef typename bin_class::point_type                   point_type;
00029 
00030   rsdl_bins_point_dist_entry( point_type const& query_pt,
00031                               bin_entry_type const* entry );
00032 
00033   inline bool operator<( rsdl_bins_point_dist_entry const& other ) const;
00034 
00035   bin_entry_type const* entry_;
00036   coord_type            sqr_dist_;
00037 };
00038 
00039 
00040 // ---------------------------------------------------------------------------
00041 //                                                                   rsdl bins
00042 
00043 template<unsigned N, typename C, typename V>
00044 rsdl_bins<N,C,V>::
00045 rsdl_bins( point_type const& min_coord,
00046            point_type const& max_coord,
00047            point_type const& bin_sizes )
00048 {
00049   dist_tol_ = 0.0;
00050 
00051   int total_size = 1;
00052   for ( unsigned i=0; i < N; ++i ) {
00053     bin_size_[i] = bin_sizes[i];
00054     min_pt_[i] = min_coord[i];
00055     size_[i] = coord_to_bin( max_coord[i], i ) + 1;
00056     assert( size_[i] > 0 );
00057     total_size *= size_[i];
00058   }
00059 
00060   bins_.resize( total_size );
00061 }
00062 
00063 
00064 template<unsigned N, typename C, typename V>
00065 void
00066 rsdl_bins<N,C,V>::
00067 set_distance_tolerance( coord_type const& tol )
00068 {
00069   dist_tol_ = tol;
00070 }
00071 
00072 
00073 template<unsigned N, typename C, typename V>
00074 void
00075 rsdl_bins<N,C,V>::
00076 clear()
00077 {
00078   typedef typename vcl_vector< bin_type >::iterator vec_iter;
00079 
00080   for ( vec_iter i = bins_.begin(); i != bins_.end(); ++i ) {
00081     i->clear();
00082   }
00083 }
00084 
00085 
00086 template<unsigned N, typename C, typename V>
00087 void
00088 rsdl_bins<N,C,V>::
00089 add_point( point_type const& pt, value_type const& val )
00090 {
00091   bins_[ bin_index( pt ) ].push_back( bin_entry_type( pt, val ) );
00092 }
00093 
00094 
00095 template<unsigned N, typename C, typename V>
00096 bool
00097 rsdl_bins<N,C,V>::
00098 get_value( point_type const& pt, value_type& val ) const
00099 {
00100   typedef typename bin_index_vector::iterator ind_iter;
00101   typedef typename bin_type::const_iterator entry_iter;
00102 
00103   coord_type dist_tol_sqr = dist_tol_*dist_tol_;
00104 
00105   // Look through each entry in each possible bin and return the first
00106   // entry found.
00107   //
00108   bin_index_vector indices = bin_indices( pt );
00109   for ( ind_iter bi = indices.begin(); bi != indices.end(); ++bi ) {
00110     bin_type const& bin = bins_[*bi];
00111     for ( entry_iter ei = bin.begin(); ei != bin.end(); ++ei ) {
00112       if ( ei->equal( pt, dist_tol_sqr ) ) {
00113         val = ei->value_;
00114         return true;
00115       }
00116     }
00117   }
00118 
00119   // Point not found.
00120   //
00121   return false;
00122 }
00123 
00124 
00125 template<unsigned N, typename C, typename V>
00126 void
00127 rsdl_bins<N,C,V>::
00128 n_nearest( point_type const& pt,
00129            unsigned n,
00130            vcl_vector< value_type >& values ) const
00131 {
00132   n_nearest_impl( pt, n, values, 0 );
00133 }
00134 
00135 
00136 template<unsigned N, typename C, typename V>
00137 void
00138 rsdl_bins<N,C,V>::
00139 n_nearest( point_type const& pt,
00140            unsigned n,
00141            vcl_vector< point_type >& points,
00142            vcl_vector< value_type >& values  ) const
00143 {
00144   n_nearest_impl( pt, n, values, &points );
00145 }
00146 
00147 
00148 template<unsigned N, typename C, typename V>
00149 void
00150 rsdl_bins<N,C,V>::
00151 n_nearest_exhaustive( point_type const& pt,
00152                       unsigned n,
00153                       vcl_vector< value_type >& values ) const
00154 {
00155   n_nearest_exhaustive_impl( pt, n, values, 0 );
00156 }
00157 
00158 
00159 template<unsigned N, typename C, typename V>
00160 void
00161 rsdl_bins<N,C,V>::
00162 n_nearest_exhaustive( point_type const& pt,
00163                       unsigned n,
00164                       vcl_vector< point_type >& points,
00165                       vcl_vector< value_type >& values  ) const
00166 {
00167   n_nearest_exhaustive_impl( pt, n, values, &points );
00168 }
00169 
00170 
00171 template<unsigned N, typename C, typename V>
00172 bool
00173 rsdl_bins<N,C,V>::
00174 is_any_point_within_radius( point_type const& pt,
00175                             coord_type const& radius ) const
00176 {
00177   // FIXME: re-implement points_within_radius_impl here, without the
00178   // push_backs...
00179 
00180   vcl_vector< value_type > values;
00181   points_within_radius( pt, radius, values );
00182 
00183   return ! values.empty();
00184 }
00185 
00186 
00187 template<unsigned N, typename C, typename V>
00188 void
00189 rsdl_bins<N,C,V>::
00190 points_within_radius( point_type const& pt,
00191                       coord_type const& radius,
00192                       vcl_vector< value_type >& values ) const
00193 {
00194   points_within_radius_impl( pt, radius, values, 0 );
00195 }
00196 
00197 
00198 template<unsigned N, typename C, typename V>
00199 void
00200 rsdl_bins<N,C,V>::
00201 points_within_radius( point_type const& pt,
00202                       coord_type const& radius,
00203                       vcl_vector< point_type >& points,
00204                       vcl_vector< value_type >& values  ) const
00205 {
00206   points_within_radius_impl( pt, radius, values, &points );
00207 }
00208 
00209 
00210 template<unsigned N, typename C, typename V>
00211 void
00212 rsdl_bins<N,C,V>::
00213 points_in_bounding_box( point_type const& min_pt,
00214                         point_type const& max_pt,
00215                         vcl_vector< value_type >& values ) const
00216 {
00217   points_in_bounding_box_impl( min_pt, max_pt, values, 0 );
00218 }
00219 
00220 
00221 template<unsigned N, typename C, typename V>
00222 void
00223 rsdl_bins<N,C,V>::
00224 points_in_bounding_box( point_type const& min_pt,
00225                         point_type const& max_pt,
00226                         vcl_vector< point_type >& points,
00227                         vcl_vector< value_type >& values  ) const
00228 {
00229   points_in_bounding_box_impl( min_pt, max_pt, values, &points );
00230 }
00231 
00232 
00233 // ---------------------------------------------------------------------------
00234 //                                                rsdl bins internal functions
00235 
00236 template<unsigned N, typename C, typename V>
00237 int
00238 rsdl_bins<N,C,V>::
00239 coord_to_bin( coord_type x, unsigned d ) const
00240 {
00241   return int( vcl_floor( ( x - min_pt_[d] ) / bin_size_[d] ) );
00242 }
00243 
00244 
00245 template<unsigned N, typename C, typename V>
00246 void
00247 rsdl_bins<N,C,V>::
00248 point_to_bin( point_type const& pt, int ind[N] ) const
00249 {
00250   for ( unsigned d=0; d < N; ++d ) {
00251     ind[d] = coord_to_bin( pt[d], d );
00252     if ( ind[d] < 0 ) {
00253       ind[d] = 0;
00254     } else if ( ind[d] >= size_[d] ) {
00255       ind[d] = size_[d] - 1;
00256     }
00257   }
00258 }
00259 
00260 
00261 template<unsigned N, typename C, typename V>
00262 typename rsdl_bins<N,C,V>::bin_index_type
00263 rsdl_bins<N,C,V>::
00264 bin_index( point_type const& pt ) const
00265 {
00266   bin_index_type index = 0;
00267   bin_index_type skip = 1;
00268 
00269   for ( unsigned d=0; d < N; ++d ) {
00270     int i = coord_to_bin( pt[d], d );
00271     if ( i < 0 ) {
00272       i = 0;
00273     } else if ( i >= size_[d] ) {
00274       i = size_[d] - 1;
00275     }
00276     index += i*skip;
00277     skip *= size_[d];
00278   }
00279 
00280   return index;
00281 }
00282 
00283 
00284 template<unsigned N, typename C, typename V>
00285 typename rsdl_bins<N,C,V>::bin_index_type
00286 rsdl_bins<N,C,V>::
00287 bin_index( int bin[N] ) const
00288 {
00289   bin_index_type index = 0;
00290   bin_index_type skip = 1;
00291 
00292   for ( unsigned d=0; d < N; ++d ) {
00293     assert( 0 <= bin[d] && bin[d] < size_[d] );
00294     index += bin[d]*skip;
00295     skip *= size_[d];
00296   }
00297 
00298   return index;
00299 }
00300 
00301 
00302 template<unsigned N, typename C, typename V>
00303 typename rsdl_bins<N,C,V>::bin_index_vector
00304 rsdl_bins<N,C,V>::
00305 bin_indices( point_type const& pt ) const
00306 {
00307   bin_index_vector indices;
00308 
00309   int bin_lo[N], bin_hi[N];
00310   point_to_bin( pt-dist_tol_, bin_lo );
00311   point_to_bin( pt+dist_tol_, bin_hi );
00312 
00313   if ( bin_lo == bin_hi ) {
00314     indices.push_back( bin_index( bin_lo ) );
00315   } else {
00316     int cur[N];
00317     scan_region( bin_lo, bin_hi, cur, 0, indices );
00318   }
00319 
00320   return indices;
00321 }
00322 
00323 template<unsigned N, typename C, typename V>
00324 void
00325 rsdl_bins<N,C,V>::
00326 closest_face ( point_type const& pt,
00327                int bin_lo[N],
00328                int bin_hi[N],
00329                unsigned * face_dim,
00330                unsigned * face_dir,
00331                coord_type * face_dist,
00332                bool & face_inf_dist) const
00333 {
00334   face_inf_dist = true;         // init dist to closest face as infinity
00335   coord_type best_dist=0;       // need local copy of best distance since face_dist might be NULL
00336 
00337   // for each dimension
00338   for ( unsigned dim=0; dim<N; ++dim )
00339   {
00340     // for each direction
00341     for ( unsigned dir=0; dir<2; ++dir )
00342     {
00343       // faces at the extremes are treated as faces with infinite distance
00344       // since they cannot be closer than infinity, we just skip them
00345       if ( dir == 0 )
00346         if ( bin_lo[dim] == 0 )
00347           continue;
00348       if ( dir == 1 )
00349         if ( bin_hi[dim] == ( size_[dim] - 1 ) )
00350           continue;
00351 
00352       coord_type face_x;  // coordinate of the this face in this dimension
00353 
00354       if ( dir == 0 )
00355         face_x = bin_lo[dim] * bin_size_[dim] + min_pt_[dim];
00356       else
00357         face_x = ( bin_hi[dim] + 1 ) * bin_size_[dim] + min_pt_[dim];
00358 
00359       coord_type dist = vcl_fabs ( pt[dim] - face_x );
00360       if ( face_inf_dist || dist < best_dist ) {
00361         if (face_dim) *face_dim = dim;
00362         if (face_dir) *face_dir = dir;
00363         if (face_dist) *face_dist = dist;
00364         face_inf_dist = false;
00365         best_dist = dist;
00366       }
00367     }
00368   }
00369 }
00370 
00371 
00372 template<unsigned N, typename C, typename V>
00373 void
00374 rsdl_bins<N,C,V>::
00375 n_nearest_impl( point_type const& pt,
00376                 unsigned n,
00377                 vcl_vector< value_type >& values,
00378                 vcl_vector< point_type >* points ) const
00379 {
00380   // The rectangular region of bins defined here starts out empty and
00381   // is iteratively expanded in the loop below.  This region is the
00382   // bins which have been searched for nearest points.  Each expansion
00383   // extends one face of the rectangular region.  We will choose the
00384   // face that is closest to the point pt, skipping those that are
00385   // already at the limit of the bins.  The region is expanded until
00386   // we have found enough points and it is not possible for a point
00387   // closer than the current nth closest point to be in an unsearched
00388   // bin.
00389 
00390   // is the set of bins searched empty?
00391   bool bin_rng_empty = true;
00392   // range of bins searched
00393   int bin_rng_lo[N], bin_rng_hi[N];
00394   // new portion of the search range
00395   int bin_new_lo[N], bin_new_hi[N];
00396 
00397   // squared distance to nth closest point found
00398   coord_type nth_dist_sqr = 0;
00399 
00400   // the n closest points, with their distances to the test point
00401   vcl_vector< point_dist_entry > distances;
00402 
00403   bool done = false;
00404   while ( ! done )
00405   {
00406     // STEP 1: Determine whether we need to search more bins, either
00407     // because we have not yet found enough points or there are still
00408     // bins that may contain points closer than the nth closest point
00409     // found so far.
00410 
00411     bool add_new_bins = false;
00412 
00413     if ( distances.size() < n ) {
00414       add_new_bins = true;
00415     }
00416     else {
00417       // sort the points we have found so far
00418       // we only need the closest n points
00419       vcl_nth_element( distances.begin(),
00420                        distances.begin() + (n-1),
00421                        distances.end() );
00422 
00423       // remove all points that are further away than the nth closest point
00424       if ( distances.size() > n )
00425         distances.erase( distances.begin() + n, distances.end() );
00426       assert ( distances.size() == n );
00427 
00428       // squared distance to the nth closest point
00429       nth_dist_sqr = distances[n-1].sqr_dist_;
00430 
00431       coord_type face_dist = 0; // not-squared distance to closest side of rectangular region of bins searched
00432       bool face_inf_dist;       // is this distance infinite?
00433       closest_face (pt, bin_rng_lo, bin_rng_hi,
00434                     0, 0, &face_dist, face_inf_dist);
00435 
00436       if ( face_inf_dist || nth_dist_sqr <= face_dist*face_dist )
00437         done = true;
00438       else
00439         add_new_bins = true;
00440     }
00441 
00442     // STEP 2: Add new bins.  If the search range is empty add a
00443     // single bin.  Otherwise, expand one side of the rectangular
00444     // search range, choosing whichever side is closest to the point.
00445 
00446     bool found_new_bins = false; // were we able to add new bins to the search region?
00447 
00448     if ( add_new_bins )
00449     {
00450       if ( bin_rng_empty )
00451       {
00452         // the bin search range is empty, so initialize to single bin
00453         point_to_bin( pt, bin_rng_lo );
00454         for (unsigned i=0; i<N; ++i) bin_rng_hi[i] = bin_rng_lo[i];
00455         bin_rng_empty = false;
00456 
00457         // the entire bin search range is newly added
00458         for (unsigned i=0; i<N; ++i) bin_new_lo[i] = bin_rng_lo[i];
00459         for (unsigned i=0; i<N; ++i) bin_new_hi[i] = bin_rng_hi[i];
00460         found_new_bins = true;
00461       }
00462       else
00463       {
00464         // add bins to search region by extending the closest face
00465 
00466         unsigned face_dim = 0;
00467         unsigned face_dir = 0;
00468         bool face_inf_dist;
00469 
00470         closest_face (pt, bin_rng_lo, bin_rng_hi,
00471                       &face_dim, &face_dir, 0, face_inf_dist);
00472 
00473         if ( ! face_inf_dist )
00474         {
00475           // We have found the closest face.  Expand the bin search
00476           // range and keep tabs on what is the newly added part of
00477           // the search range.
00478 
00479           for (unsigned i=0; i<N; ++i) bin_new_lo[i] = bin_rng_lo[i];
00480           for (unsigned i=0; i<N; ++i) bin_new_hi[i] = bin_rng_hi[i];
00481 
00482           assert( face_dim < N );
00483 
00484           if ( face_dir == 0 ) {
00485             bin_rng_lo[face_dim] -= 1;
00486             bin_new_lo[face_dim] = bin_rng_lo[face_dim];
00487             bin_new_hi[face_dim] = bin_rng_lo[face_dim];
00488           }
00489           else {
00490             bin_rng_hi[face_dim] += 1;
00491             bin_new_lo[face_dim] = bin_rng_hi[face_dim];
00492             bin_new_hi[face_dim] = bin_rng_hi[face_dim];
00493           }
00494 
00495           found_new_bins = true;
00496         }
00497       }
00498     }
00499 
00500     // STEP 3: Add new points if we added new bins.
00501 
00502     if ( found_new_bins )
00503     {
00504       // Get the list of points in the new candidate bins and
00505       // compute their distance from the query point.
00506 
00507       // stores the indices of the new candidate bins.
00508       bin_index_vector indices;
00509 
00510       int cur[N];   // bin index, used by recursive iterator, needs no initializtion
00511       scan_region( bin_new_lo, bin_new_hi, cur, 0, indices );
00512 
00513       typedef typename bin_index_vector::iterator ind_iter;
00514       typedef typename bin_type::const_iterator entry_iter;
00515 
00516       for ( ind_iter bi = indices.begin(); bi != indices.end(); ++bi ) {
00517         bin_type const& bin = bins_[*bi];
00518         for ( entry_iter ei = bin.begin(); ei != bin.end(); ++ei ) {
00519           distances.push_back( point_dist_entry( pt, &(*ei) ) );
00520         }
00521       }
00522     }
00523 
00524     // STEP 4: If we wanted to add new bins to the search range, but
00525     // we did not find any bins to add, then we are done.  This will
00526     // always happen if there are fewer than n points in the data
00527     // structure.  (It could also happen when there are n or more
00528     // points, depending on the point distribution.)
00529 
00530     if ( add_new_bins && ! found_new_bins ) {
00531       done = true;
00532     }
00533   }
00534 
00535   // sort the points by distance
00536   // if ( distances.size() < n )
00537   //   vcl_sort( distances.begin(), distances.end() );
00538 
00539   // Copy into the output structures.
00540 
00541   typedef typename vcl_vector< point_dist_entry >::iterator point_dist_iter;
00542 
00543   assert( distances.size() <= n );
00544 
00545   for ( point_dist_iter i = distances.begin(); i != distances.end(); ++i ) {
00546     values.push_back( i->entry_->value_ );
00547     if ( points ) {
00548       points->push_back( i->entry_->point_ );
00549     }
00550   }
00551 }
00552 
00553 #if 0
00554 
00555 // previous implementation of n_nearest_impl - has some subtle bugs
00556 // and will be removed
00557 
00558 template<unsigned N, typename C, typename V>
00559 void
00560 rsdl_bins<N,C,V>::
00561 n_nearest_impl( point_type const& pt,
00562                 unsigned n,
00563                 vcl_vector< value_type >& values,
00564                 vcl_vector< point_type >* points ) const
00565 {
00566   // !!!!!!!!! BUG Notice !!!!!!!!!!
00567   //
00568   // The following implementation of N nearest neighbors did
00569   // not consider the situation where after found >=n candidates,
00570   // there can still exist a bin further away, but contains points
00571   // close than some of these candidates.
00572   //
00573   // !!!!!!! FIX Notice !!!!!!!
00574   //
00575 
00576   // Let N be the dimension of the space, and s be the bin size
00577   // (length of one side).  Then the length of the diagonal of a bin
00578   // is
00579   //   d = sqrt(N*s*s) = s*sqrt(N)
00580   // Now, if we grow an N-dimensional region in all directions by k
00581   // bins, the farthest possible distance between the given point and
00582   // its nearest neighbor in this region will be d' = (k+1) * d.  To
00583   // make sure we include all bins that may contain a point closer
00584   // than this, we will additionally increase our region by f
00585   // number of bins in all dimensions, where
00586   //  f = ceil ((d' - (k * s)) / s)
00587   // There might be more optimal solution to this fix.
00588 
00589   static bool rsdl_bins_bug_warning_s = false;
00590   if ( rsdl_bins_bug_warning_s ) {
00591     vcl_cerr << "Warning: results from current rsdl_bins<N,C,V>::n_nearest_impl "
00592              << "may be inaccurate.  Please contact developers for details.\n";
00593     rsdl_bins_bug_warning_s = false;
00594   }
00595 
00596   // 1. Find the list of bins with candidate points. The candidate
00597   // bins will collectively hold at least n points to test. Points in
00598   // non-candidate bins will be further away that all points in the
00599   // candidate bins.
00600   //
00601   // The idea is to repeatedly bins from an ever growning
00602   // (square) "circle" until we have enough bins.
00603 
00604   // stores the indices of the candidate bins.
00605   bin_index_vector indices;
00606 
00607   // dimensions of the box currently being examined.
00608   int bin_lo[N], bin_hi[N], cur[N];
00609 
00610   point_to_bin( pt, bin_lo );
00611   for (unsigned int i=0; i<N; ++i) bin_hi[i] = bin_lo[i];
00612 
00613   bool still_looking = true;
00614   unsigned found = 0;
00615   do {
00616     found += scan_bdy( bin_lo, bin_hi, cur, 0, indices );
00617     if ( found >= n ) {
00618       // We found the requested number of points, now make sure to
00619       // include all bins that might contain points that are closer
00620       // than the ones we found so far as described in the FIX notes
00621       // above.
00622       unsigned k = (bin_hi[0] - bin_lo[0]) / 2;
00623       // find number of bins needed to expand the region
00624       unsigned f = unsigned( vcl_ceil( double(k+1) * vcl_sqrt(double(N)) - double(k) ) );
00625       for (unsigned j=0; j<f; ++j) {
00626         for (unsigned i=0; i<N; ++i) {
00627           // increase the region one bin at a time
00628           --bin_lo[i];
00629           ++bin_hi[i];
00630         }
00631         found += scan_bdy( bin_lo, bin_hi, cur, 0, indices );
00632       }
00633       still_looking = false;
00634     } else {
00635       bool some_dimension_in_bounds = false;
00636       for ( unsigned i=0; i < N; ++i ) {
00637         --bin_lo[i];
00638         ++bin_hi[i];
00639         if ( bin_lo[i] >= 0 || bin_hi[i] < size_[i] )
00640           some_dimension_in_bounds = true;
00641       }
00642       // we've searched the whole space, and didn't find anything.
00643       if ( !some_dimension_in_bounds ) {
00644         still_looking = false;
00645       }
00646     }
00647   } while ( still_looking );
00648 
00649   // 2. Get the list of points in the candidate bins and compute their
00650   // distance from the query point.
00651   //
00652   typedef typename bin_index_vector::iterator ind_iter;
00653   typedef typename bin_type::const_iterator entry_iter;
00654 
00655   vcl_vector< point_dist_entry > distances;
00656 
00657   for ( ind_iter bi = indices.begin(); bi != indices.end(); ++bi ) {
00658     bin_type const& bin = bins_[*bi];
00659     for ( entry_iter ei = bin.begin(); ei != bin.end(); ++ei ) {
00660       distances.push_back( point_dist_entry( pt, &(*ei) ) );
00661     }
00662   }
00663 
00664   // 3. Extract the n-closest points and copy into the output
00665   // structures.
00666   //
00667   typedef typename vcl_vector< point_dist_entry >::iterator point_dist_iter;
00668 
00669   point_dist_iter mid;
00670   if ( distances.size() > n ) {
00671     mid = distances.begin() + n;
00672     vcl_partial_sort( distances.begin(), mid, distances.end() );
00673   } else {
00674     mid = distances.end();
00675   }
00676 
00677 #define support_points_outside_boundaries 0
00678 #if support_points_outside_boundaries
00679 
00680   // Check if any of the distances are greater than the dimensions of
00681   // the region that was searched.  This would cover points that are
00682   // located ouside min-max boundaries.  If a point is located outside
00683   // bin region, it would be placed into a bin on the boundary of the
00684   // region. As a result of this projection the distance information
00685   // would be lost and we have to search area that includes the
00686   // point's real location.
00687 
00688   // get the longest distance between a given point and points that were found
00689   double longest_distance = vcl_sqrt(double((mid-1)->sqr_dist_));
00690 
00691   // find dimension of the region that has been searched
00692   double r = ((bin_hi[0] - bin_lo[0]) / 2) * bin_size_[0];
00693 
00694   // check if we have a point outside this searched region
00695   if (longest_distance > r) {
00696     unsigned reg_incr = unsigned(vcl_ceil(longest_distance / bin_size_[0] - (bin_hi[0] - bin_lo[0])/2));
00697     for (unsigned j=0; j<reg_incr; ++j) {
00698       for (unsigned i=0; i<N; ++i) {
00699         // increase the region one bin at a time
00700         --bin_lo[i];
00701         ++bin_hi[i];
00702       }
00703       found += scan_bdy( bin_lo, bin_hi, cur, 0, indices );
00704     }
00705     // repeat above steps 2 and 3 here to compute distances again
00706     distances.clear();
00707     for ( ind_iter bi = indices.begin(); bi != indices.end(); ++bi ) {
00708       bin_type const& bin = bins_[*bi];
00709       for ( entry_iter ei = bin.begin(); ei != bin.end(); ++ei ) {
00710         distances.push_back( point_dist_entry( pt, &(*ei) ) );
00711       }
00712     }
00713     // sort points by their distance
00714     if ( distances.size() > n ) {
00715       mid = distances.begin() + n;
00716       vcl_partial_sort( distances.begin(), mid, distances.end() );
00717     }
00718     else {
00719       mid = distances.end();
00720     }
00721   }
00722 
00723 #endif  // end of support points outside region boundaries logic
00724 
00725   for ( point_dist_iter i = distances.begin(); i != mid; ++i ) {
00726     values.push_back( i->entry_->value_ );
00727     if ( points ) {
00728       points->push_back( i->entry_->point_ );
00729     }
00730   }
00731 }
00732 
00733 #endif
00734 
00735 template<unsigned N, typename C, typename V>
00736 void
00737 rsdl_bins<N,C,V>::
00738 n_nearest_exhaustive_impl( point_type const& pt,
00739                            unsigned n,
00740                            vcl_vector< value_type >& values,
00741                            vcl_vector< point_type >* points ) const
00742 {
00743   typedef typename vcl_vector< bin_type >::const_iterator vec_iter;
00744   typedef typename bin_type::const_iterator entry_iter;
00745   typedef typename vcl_vector< point_dist_entry >::iterator point_dist_iter;
00746 
00747   vcl_vector< point_dist_entry > distances;
00748   coord_type nth_dist_sqr = 0;
00749 
00750   // for every bin
00751   for ( vec_iter bi = bins_.begin(); bi != bins_.end(); ++bi ) {
00752     bin_type const & bin = *bi;
00753     // for every entry in the bin
00754     for ( entry_iter ei = bin.begin(); ei != bin.end(); ++ei ) {
00755       bin_entry_type const & entry = *ei;
00756 
00757       // if we don't yet have the requested n points, or this point is
00758       // closer than the nth closest point found so far
00759       if ( distances.size() < n
00760            || vnl_vector_ssd( pt, entry.point_ ) < nth_dist_sqr )
00761       {
00762         distances.push_back( point_dist_entry( pt, &entry ) );
00763 
00764         if ( distances.size() >= n )
00765           vcl_nth_element ( distances.begin(),
00766                             distances.begin() + (n-1),
00767                             distances.end() );
00768 
00769         // if we now have more than n points, get rid of the extra
00770         // there could only be 1 extra point here
00771         if ( distances.size() > n ) {
00772           distances.pop_back();
00773           // is size was >n then it must have been n+1
00774           assert ( distances.size() == n );
00775         }
00776 
00777         // if we have found n points, find the distance to the nth
00778         // point because that will be the new criteria for adding new
00779         // points
00780         if ( distances.size() == n )
00781           nth_dist_sqr = distances[n-1].sqr_dist_;
00782       }
00783     }
00784   }
00785 
00786   // sort the points by distance
00787   // if ( distances.size() < n )
00788   //   vcl_sort( distances.begin(), distances.end() );
00789 
00790   // copy points to the output structures
00791   for ( point_dist_iter i = distances.begin(); i != distances.end(); ++i ) {
00792     values.push_back( i->entry_->value_ );
00793     if ( points ) {
00794       points->push_back( i->entry_->point_ );
00795     }
00796   }
00797 }
00798 
00799 template<unsigned N, typename C, typename V>
00800 void
00801 rsdl_bins<N,C,V>::
00802 points_within_radius_impl( point_type const& pt,
00803                            coord_type const& radius,
00804                            vcl_vector< value_type >& values,
00805                            vcl_vector< point_type >* points ) const
00806 {
00807   // 1. Find the list of bins that may contain the points we
00808   // want. These are the bins overlapping
00809   // [pt-radius*vec(1), pt+radius*vec(1)].
00810   //
00811 
00812   // stores the indices of the candidate bins.
00813   bin_index_vector indices;
00814 
00815   // dimensions of the box currently being examined.
00816   int bin_lo[N], bin_hi[N], cur[N];
00817 
00818   point_to_bin( pt-radius, bin_lo );
00819   point_to_bin( pt+radius, bin_hi );
00820 
00821   scan_region( bin_lo, bin_hi, cur, 0, indices );
00822 
00823   // 2. Iterate over the list of points in the candidate bins and
00824   // output those in range.
00825   //
00826   typedef typename bin_index_vector::iterator ind_iter;
00827   typedef typename bin_type::const_iterator entry_iter;
00828 
00829   coord_type rad_sqr = radius * radius;
00830   for ( ind_iter bi = indices.begin(); bi != indices.end(); ++bi ) {
00831     bin_type const& bin = bins_[*bi];
00832     for ( entry_iter ei = bin.begin(); ei != bin.end(); ++ei ) {
00833       coord_type dist_sqr = vnl_vector_ssd( pt, ei->point_ );
00834       if ( dist_sqr < rad_sqr ) {
00835         values.push_back( ei->value_ );
00836         if ( points ) {
00837           points->push_back( ei->point_ );
00838         }
00839       }
00840     }
00841   }
00842 }
00843 
00844 
00845 template<unsigned N, typename C, typename V>
00846 void
00847 rsdl_bins<N,C,V>::
00848 points_in_bounding_box_impl( point_type const& min_pt,
00849                              point_type const& max_pt,
00850                              vcl_vector< value_type >& values,
00851                              vcl_vector< point_type >* points ) const
00852 {
00853   // 1. Find the list of bins that may contain the points we
00854   // want.
00855   //
00856 
00857   // stores the indices of the candidate bins.
00858   bin_index_vector indices;
00859 
00860   // dimensions of the box currently being examined.
00861   int bin_lo[N], bin_hi[N], cur[N];
00862 
00863   point_to_bin( min_pt, bin_lo );
00864   point_to_bin( max_pt, bin_hi );
00865 
00866   scan_region( bin_lo, bin_hi, cur, 0, indices );
00867 
00868   // 2. Iterate over the list of points in the candidate bins and
00869   // output those in range.
00870   //
00871   typedef typename bin_index_vector::iterator ind_iter;
00872   typedef typename bin_type::const_iterator entry_iter;
00873 
00874   for ( ind_iter bi = indices.begin(); bi != indices.end(); ++bi ) {
00875     bin_type const& bin = bins_[*bi];
00876     for ( entry_iter ei = bin.begin(); ei != bin.end(); ++ei ) {
00877       bool in_range = true;
00878       for ( unsigned d=0; d < N; ++d ) {
00879         if ( ei->point_[d] < min_pt[d] || ei->point_[d] > max_pt[d] ) {
00880           in_range = false;
00881           break;
00882         }
00883       }
00884       if ( in_range ) {
00885         values.push_back( ei->value_ );
00886         if ( points ) {
00887           points->push_back( ei->point_ );
00888         }
00889       }
00890     }
00891   }
00892 }
00893 
00894 
00895 //:
00896 //
00897 // This will scan the \a dim dimensional region bounded by
00898 // lo[dim..N-1] and hi[dim..N-1], boundary points inclusive. It
00899 // will return the indices of the bins that fall within the scanned
00900 // region. The coordinates for the first dim-1 dimensions are given in
00901 // \a cur.
00902 //
00903 // It will add the append the bins to \a indices. The return value is
00904 // the total number of points in the bins that were appended.
00905 //
00906 // The routine will scan the \a dim dimensional equivalent of
00907 // \verbatim
00908 //    +-----------+
00909 //    |           |
00910 //    |           |
00911 //    |           |
00912 //    |           |
00913 //    |           |
00914 //    |           |
00915 //    +-----------+
00916 // \endverbatim
00917 //
00918 template<unsigned N, typename C, typename V>
00919 vcl_size_t
00920 rsdl_bins<N,C,V>::
00921 scan_region( int lo[N], int hi[N], int cur[N], unsigned dim,
00922              bin_index_vector& indices ) const
00923 {
00924   vcl_size_t found = 0;
00925 
00926   if ( dim==N ) {
00927     // 0d region is a point, so just check this point.
00928     bin_index_type ind = bin_index( cur );
00929     indices.push_back( ind );
00930     found = bins_[ind].size();
00931   } else {
00932     int bx = vcl_max( lo[dim], 0 );
00933     int ex = vcl_min( hi[dim]+1, size_[dim] );
00934     for ( int x=bx; x < ex; ++x ) {
00935       cur[dim] = x;
00936       found += scan_region( lo, hi, cur, dim+1, indices );
00937     }
00938   }
00939 
00940   return found;
00941 }
00942 
00943 #if 0
00944 
00945 //:
00946 //
00947 // Similar to scan_region, but will only scan the boundary of the
00948 // region, not the interior. That is, it will scan the dim dimensional
00949 // equivalent of
00950 // \verbatim
00951 //    +-----------+
00952 //    |           |
00953 //    |  +-----+  |
00954 //    |  |     |  |
00955 //    |  |     |  |
00956 //    |  +-----+  |
00957 //    |           |
00958 //    +-----------+
00959 // \endverbatim
00960 //
00961 template<unsigned N, typename C, typename V>
00962 unsigned
00963 rsdl_bins<N,C,V>::
00964 scan_bdy( int lo[N], int hi[N], int cur[N], unsigned dim,
00965           bin_index_vector& indices ) const
00966 {
00967   unsigned found = 0;
00968 
00969   // There is no boundary in 0d, so we only need to do work for
00970   // dim < N
00971   //
00972   if ( dim < N ) {
00973     int bx = vcl_max( lo[dim], 0 );
00974     int ex = vcl_min( hi[dim]+1, size_[dim] );
00975     int x = bx;
00976     if ( x==lo[dim] ) {
00977       cur[dim] = x;
00978       found += scan_region( lo, hi, cur, dim+1, indices );
00979       ++x;
00980     }
00981     for ( ; x < ex-1; ++x ) {
00982       cur[dim] = x;
00983       found += scan_bdy( lo, hi, cur, dim+1, indices );
00984     }
00985     if ( x==hi[dim] ) {
00986       cur[dim] = x;
00987       found += scan_region( lo, hi, cur, dim+1, indices );
00988     }
00989   }
00990 
00991   return found;
00992 }
00993 
00994 #endif
00995 
00996 // ---------------------------------------------------------------------------
00997 //                                                              bin entry type
00998 //
00999 
01000 
01001 template<unsigned N, typename C, typename V>
01002 rsdl_bins_bin_entry_type<N,C,V>::
01003 rsdl_bins_bin_entry_type( point_type const& pt, const value_type val )
01004   : point_( pt ),
01005     value_( val )
01006 {
01007 }
01008 
01009 template<unsigned N, typename C, typename V>
01010 bool
01011 rsdl_bins_bin_entry_type<N,C,V>::
01012 equal( point_type const& pt, double tol_sqr ) const
01013 {
01014   return vnl_vector_ssd( pt, point_ ) < tol_sqr;
01015 }
01016 
01017 
01018 // ---------------------------------------------------------------------------
01019 //                                                            point dist entry
01020 //
01021 
01022 template<unsigned N, typename C, typename V>
01023 rsdl_bins_point_dist_entry<N,C,V>::
01024 rsdl_bins_point_dist_entry( point_type const& query_pt,
01025                             bin_entry_type const* entry )
01026  : entry_( entry ),
01027    sqr_dist_( vnl_vector_ssd( query_pt, entry->point_ ) )
01028 {
01029 }
01030 
01031 
01032 template<unsigned N, typename C, typename V>
01033 bool
01034 rsdl_bins_point_dist_entry<N,C,V>::
01035 operator<( rsdl_bins_point_dist_entry const& other ) const
01036 {
01037   return this->sqr_dist_ < other.sqr_dist_;
01038 }
01039 
01040 #define INSTANTIATE_RSDL_BINS( n, V, C ) \
01041   template class rsdl_bins< n, V, C >; \
01042   template struct rsdl_bins_bin_entry_type< n, V, C >; \
01043   template struct rsdl_bins_point_dist_entry< n, V, C >
01044 
01045 #endif // rsdl_bins_txx_

Generated on Mon Mar 8 05:26:57 2010 for contrib/rpl/rsdl by  doxygen 1.5.1