00001
00002 #include "imesh_kd_tree.h"
00003 #include "imesh_kd_tree.txx"
00004
00005
00006
00007 #include <vgl/vgl_box_3d.h>
00008 #include <vgl/vgl_point_3d.h>
00009 #include <imesh/algo/imesh_intersect.h>
00010 #include <vcl_algorithm.h>
00011 #include <vcl_limits.h>
00012 #include <vcl_cmath.h>
00013
00014
00015
00016 double imesh_min_sq_dist(const vgl_point_3d<double>& p,
00017 const vgl_box_3d<double>& b)
00018 {
00019 double sum_sq = 0;
00020
00021 if (p.x() < b.min_x()) {
00022 double dist = b.min_x() - p.x();
00023 sum_sq += dist * dist;
00024 }
00025 else if (p.x() > b.max_x()) {
00026 double dist = b.max_x() - p.x();
00027 sum_sq += dist*dist;
00028 }
00029
00030 if (p.y() < b.min_y()) {
00031 double dist = b.min_y() - p.y();
00032 sum_sq += dist * dist;
00033 }
00034 else if (p.y() > b.max_y()) {
00035 double dist = b.max_y() - p.y();
00036 sum_sq += dist*dist;
00037 }
00038
00039 if (p.z() < b.min_z()) {
00040 double dist = b.min_z() - p.z();
00041 sum_sq += dist * dist;
00042 }
00043 else if (p.z() > b.max_z()) {
00044 double dist = b.max_z() - p.z();
00045 sum_sq += dist*dist;
00046 }
00047
00048 return sum_sq;
00049 }
00050
00051
00052
00053 double imesh_max_sq_dist(const vgl_point_3d<double>& p,
00054 const vgl_box_3d<double>& b)
00055 {
00056 vgl_point_3d<double> mp( (p.x() > b.centroid_x()) ? b.min_x() : b.max_x(),
00057 (p.y() > b.centroid_y()) ? b.min_y() : b.max_y(),
00058 (p.z() > b.centroid_z()) ? b.min_z() : b.max_z() );
00059 return (mp - p).sqr_length();
00060 }
00061
00062
00063 namespace {
00064
00065
00066 class less_box_centroid_x
00067 {
00068 vcl_vector<vgl_box_3d<double> > boxes;
00069 public:
00070 less_box_centroid_x(const vcl_vector<vgl_box_3d<double> >& b) : boxes(b) {}
00071 bool operator () (unsigned int i1, unsigned int i2) const
00072 {
00073 return boxes[i1].centroid_x() < boxes[i2].centroid_x();
00074 }
00075 };
00076
00077
00078 class less_box_centroid_y
00079 {
00080 vcl_vector<vgl_box_3d<double> > boxes;
00081 public:
00082 less_box_centroid_y(const vcl_vector<vgl_box_3d<double> >& b) : boxes(b) {}
00083 bool operator () (unsigned int i1, unsigned int i2) const
00084 {
00085 return boxes[i1].centroid_y() < boxes[i2].centroid_y();
00086 }
00087 };
00088
00089
00090 class less_box_centroid_z
00091 {
00092 vcl_vector<vgl_box_3d<double> > boxes;
00093 public:
00094 less_box_centroid_z(const vcl_vector<vgl_box_3d<double> >& b) : boxes(b) {}
00095 bool operator () (unsigned int i1, unsigned int i2) const
00096 {
00097 return boxes[i1].centroid_z() < boxes[i2].centroid_z();
00098 }
00099 };
00100
00101 bool
00102 best_split(const vcl_vector<vgl_box_3d<double> >& boxes,
00103 const vcl_vector<unsigned int>& indices,
00104 double& min_volume, unsigned int& split_ind)
00105 {
00106 const unsigned int ind_size = indices.size();
00107 vcl_vector<double> volume_seq;
00108 vgl_box_3d<double> box(boxes[indices[0]]);
00109 for (unsigned int i=1; i<ind_size; ++i)
00110 {
00111 volume_seq.push_back(box.volume());
00112 box.add(boxes[indices[i]]);
00113 }
00114 box = boxes[indices[ind_size-1]];
00115 bool found_min = false;
00116 double best_ratio_factor = 1.0;
00117 for (unsigned int i=ind_size-1; i>0;)
00118 {
00119 double volume = box.volume();
00120 box.add(boxes[indices[--i]]);
00121 volume += volume_seq[i];
00122 if (volume <= min_volume) {
00123 double ratio_factor = vcl_abs(0.5 - double(i+1)/ind_size);
00124 if ( ratio_factor < 0.25 && ratio_factor < best_ratio_factor) {
00125 min_volume = volume;
00126 split_ind = i+1;
00127 found_min = true;
00128 best_ratio_factor = ratio_factor;
00129 }
00130 }
00131 }
00132 return found_min;
00133 }
00134
00135 };
00136
00137
00138
00139 vcl_auto_ptr<imesh_kd_tree_node>
00140 imesh_build_kd_tree_rec(const vcl_vector<vgl_box_3d<double> >& boxes,
00141 const vgl_box_3d<double>& outer_box,
00142 const vgl_box_3d<double>& inner_box,
00143 const vcl_vector< unsigned int >& indices)
00144 {
00145
00146 if (indices.size() == 1) {
00147 return vcl_auto_ptr<imesh_kd_tree_node>(new imesh_kd_tree_node( outer_box,
00148 inner_box,
00149 indices[0] ));
00150 }
00151
00152
00153 vcl_vector<vcl_vector<unsigned int> > sorted(3,indices);
00154 vcl_sort(sorted[0].begin(),sorted[0].end(), less_box_centroid_x(boxes));
00155 vcl_sort(sorted[1].begin(),sorted[1].end(), less_box_centroid_y(boxes));
00156 vcl_sort(sorted[2].begin(),sorted[2].end(), less_box_centroid_z(boxes));
00157 double min_volume = vcl_numeric_limits<double>::infinity();
00158 unsigned int split_ind=0;
00159 int dim = -1;
00160 if (best_split(boxes,sorted[0],min_volume,split_ind))
00161 dim = 0;
00162 if (best_split(boxes,sorted[1],min_volume,split_ind))
00163 dim = 1;
00164 if (best_split(boxes,sorted[2],min_volume,split_ind))
00165 dim = 2;
00166
00167
00168 vcl_vector<unsigned int> left_indices(sorted[dim].begin(),
00169 sorted[dim].begin()+split_ind);
00170 vcl_vector<unsigned int> right_indices(sorted[dim].begin()+split_ind,
00171 sorted[dim].end());
00172
00173
00174 vgl_box_3d<double> left_inner_box, right_inner_box;
00175 typedef vcl_vector<unsigned int>::const_iterator index_iterator;
00176 for ( index_iterator itr=left_indices.begin(); itr!=left_indices.end(); ++itr )
00177 left_inner_box.add(boxes[*itr]);
00178 for ( index_iterator itr=right_indices.begin(); itr!=right_indices.end(); ++itr )
00179 right_inner_box.add(boxes[*itr]);
00180 vgl_box_3d<double> left_outer_box(outer_box), right_outer_box(outer_box);
00181 switch (dim)
00182 {
00183 case 0:
00184 left_outer_box.set_max_x(left_inner_box.max_x());
00185 right_outer_box.set_min_x(right_inner_box.min_x());
00186 if (left_outer_box.max_x() < right_outer_box.min_x()) {
00187 double mean = (left_outer_box.max_x() + right_outer_box.min_x())/2.0;
00188 left_outer_box.set_max_x(mean);
00189 right_outer_box.set_min_x(mean);
00190 }
00191 break;
00192 case 1:
00193 left_outer_box.set_max_y(left_inner_box.max_y());
00194 right_outer_box.set_min_y(right_inner_box.min_y());
00195 if (left_outer_box.max_y() < right_outer_box.min_y()) {
00196 double mean = (left_outer_box.max_y() + right_outer_box.min_y())/2.0;
00197 left_outer_box.set_max_y(mean);
00198 right_outer_box.set_min_y(mean);
00199 }
00200 break;
00201 case 2:
00202 left_outer_box.set_max_z(left_inner_box.max_z());
00203 right_outer_box.set_min_z(right_inner_box.min_z());
00204 if (left_outer_box.max_z() < right_outer_box.min_z()) {
00205 double mean = (left_outer_box.max_z() + right_outer_box.min_z())/2.0;
00206 left_outer_box.set_max_z(mean);
00207 right_outer_box.set_min_z(mean);
00208 }
00209 break;
00210 default:
00211 break;
00212 }
00213
00214
00215 vcl_auto_ptr<imesh_kd_tree_node>
00216 left_child(imesh_build_kd_tree_rec(boxes,left_outer_box,left_inner_box,left_indices));
00217 vcl_auto_ptr<imesh_kd_tree_node>
00218 right_child(imesh_build_kd_tree_rec(boxes,right_outer_box,right_inner_box,right_indices));
00219
00220 return vcl_auto_ptr<imesh_kd_tree_node>(new imesh_kd_tree_node(outer_box,
00221 inner_box,
00222 left_child,
00223 right_child));
00224 }
00225
00226
00227
00228 vcl_auto_ptr<imesh_kd_tree_node>
00229 imesh_build_kd_tree(const vcl_vector<vgl_box_3d<double> >& boxes)
00230 {
00231
00232 double minv = -vcl_numeric_limits<double>::infinity();
00233 double maxv = vcl_numeric_limits<double>::infinity();
00234 vgl_box_3d<double> outer_box(minv,minv,minv, maxv,maxv,maxv);
00235
00236
00237 vcl_vector< unsigned int > indices( boxes.size() );
00238 for ( unsigned int i=0; i<indices.size(); ++i)
00239 indices[i] = i;
00240
00241
00242 vgl_box_3d<double> inner_box;
00243 for ( unsigned int i=0; i<boxes.size(); ++i ) {
00244 inner_box.add(boxes[i]);
00245 }
00246
00247
00248 vcl_auto_ptr<imesh_kd_tree_node> root(imesh_build_kd_tree_rec(boxes, outer_box, inner_box, indices));
00249
00250
00251
00252 vcl_vector<imesh_kd_tree_node*> internal_nodes;
00253 internal_nodes.push_back(root.get());
00254 for (unsigned int c=0; c<internal_nodes.size(); ++c) {
00255 if (!internal_nodes[c]->left_->is_leaf())
00256 internal_nodes.push_back(internal_nodes[c]->left_.get());
00257 if (!internal_nodes[c]->right_->is_leaf())
00258 internal_nodes.push_back(internal_nodes[c]->right_.get());
00259 }
00260 typedef vcl_vector<imesh_kd_tree_node*>::const_reverse_iterator critr;
00261 unsigned int index = boxes.size();
00262 for (critr itr = internal_nodes.rbegin(); itr != critr(internal_nodes.rend()); ++itr)
00263 (*itr)->index_ = index++;
00264
00265 return root;
00266 }
00267
00268
00269
00270 vcl_auto_ptr<imesh_kd_tree_node>
00271 imesh_build_kd_tree(const imesh_vertex_array<3>& verts,
00272 const imesh_face_array_base& faces)
00273 {
00274
00275 vcl_vector<vgl_box_3d<double> > boxes(faces.size());
00276 for ( unsigned int i=0; i<boxes.size(); ++i ) {
00277 for ( unsigned int j=0; j<faces.num_verts(i); ++j) {
00278 boxes[i].add(verts[faces(i,j)]);
00279 }
00280 }
00281
00282
00283 return imesh_build_kd_tree(boxes);
00284 }
00285
00286
00287 namespace {
00288 class tri_dist_func
00289 {
00290 public:
00291 tri_dist_func(const imesh_vertex_array<3>& v,
00292 const imesh_regular_face_array<3>& t)
00293 : verts(v), tris(t), closest_index(static_cast<unsigned int>(-1)),
00294 closest_dist(vcl_numeric_limits<double>::infinity()),
00295 closest_u(0), closest_v(0) {}
00296 const imesh_vertex_array<3>& verts;
00297 const imesh_regular_face_array<3>& tris;
00298 unsigned int closest_index;
00299 double closest_dist, closest_u, closest_v;
00300
00301 vgl_point_3d<double> closest_point() const
00302 {
00303 const imesh_regular_face<3>& tri = tris[closest_index];
00304 const double& u = closest_u;
00305 const double& v = closest_v;
00306 double t = 1.0-u-v;
00307 const imesh_vertex<3>& p0 = verts[tri[0]];
00308 const imesh_vertex<3>& p1 = verts[tri[1]];
00309 const imesh_vertex<3>& p2 = verts[tri[2]];
00310 return vgl_point_3d<double>(t*p0[0] + u*p1[0] + v*p2[0],
00311 t*p0[1] + u*p1[1] + v*p2[1],
00312 t*p0[2] + u*p1[2] + v*p2[2]);
00313 }
00314
00315 double operator () (const vgl_point_3d<double>& pt, unsigned int i)
00316 {
00317 const imesh_regular_face<3>& tri = tris[i];
00318 double dist,u,v;
00319
00320 imesh_triangle_closest_point(pt, verts[tri[0]],
00321 verts[tri[1]], verts[tri[2]],
00322 dist, u, v);
00323 if (dist < closest_dist) {
00324 closest_dist = dist;
00325 closest_index = i;
00326 closest_u = u;
00327 closest_v = v;
00328 }
00329 return dist;
00330 }
00331 };
00332
00333 }
00334
00335
00336
00337 unsigned int
00338 imesh_kd_tree_closest_point(const vgl_point_3d<double>& query,
00339 const imesh_mesh& mesh,
00340 const vcl_auto_ptr<imesh_kd_tree_node>& root,
00341 vgl_point_3d<double>& cp,
00342 vcl_vector<imesh_kd_tree_queue_entry>* dists)
00343 {
00344 const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00345 const imesh_regular_face_array<3>& faces = static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00346 tri_dist_func dist(verts,faces);
00347 unsigned int ind = imesh_closest_index<tri_dist_func&>(query,root,dist,dists);
00348 cp = dist.closest_point();
00349 return ind;
00350 }
00351
00352
00353
00354
00355
00356
00357 void imesh_kd_tree_traverse(const vgl_point_3d<double>& query,
00358 const vcl_auto_ptr<imesh_kd_tree_node>& root,
00359 vcl_vector<imesh_kd_tree_queue_entry>& leaf,
00360 vcl_vector<imesh_kd_tree_queue_entry>& internal_node)
00361 {
00362
00363 vcl_vector<imesh_kd_tree_node*> to_examine;
00364 to_examine.push_back(root.get());
00365 internal_node.clear();
00366 leaf.clear();
00367 for (unsigned int i=0; i<to_examine.size(); ++i) {
00368 imesh_kd_tree_node* current = to_examine[i];
00369 if (current->is_leaf()) {
00370 leaf.push_back(imesh_kd_tree_queue_entry(
00371 imesh_min_sq_dist(query,current->inner_box_),
00372 current) );
00373 continue;
00374 }
00375
00376 if (imesh_min_sq_dist(query,current->left_->outer_box_) <=0)
00377 to_examine.push_back(current->left_.get());
00378 else
00379 internal_node.push_back(imesh_kd_tree_queue_entry(
00380 imesh_min_sq_dist(query,current->left_->inner_box_),
00381 current->left_.get()));
00382
00383 if (imesh_min_sq_dist(query,current->right_->outer_box_) <=0)
00384 to_examine.push_back(current->right_.get());
00385 else
00386 internal_node.push_back(imesh_kd_tree_queue_entry(
00387 imesh_min_sq_dist(query,current->right_->inner_box_),
00388 current->right_.get()));
00389 }
00390 }
00391