00001
00002 #include "imesh_imls_surface.h"
00003
00004
00005
00006 #include <imesh/imesh_operations.h>
00007 #include <imesh/algo/imesh_intersect.h>
00008 #include <imesh/algo/imesh_kd_tree.txx>
00009 #include <vcl_cmath.h>
00010 #include <vcl_limits.h>
00011 #include <vcl_cassert.h>
00012
00013 #include <vcl_iostream.h>
00014 #include <vnl/vnl_math.h>
00015 #include <vnl/vnl_double_3.h>
00016
00017
00018
00019 imesh_imls_surface::imesh_imls_surface(const imesh_mesh& mesh, double eps, double lambda,
00020 bool enforce_bounded,
00021 const vcl_set<unsigned int>& no_normal_faces)
00022 : verts_(mesh.num_verts()), phi_(mesh.num_verts(),0.0),
00023 eps2_(eps*eps), lambda_(lambda), iso_level_(0.0), bounded_(enforce_bounded)
00024 {
00025 const imesh_vertex_array<3>& v = mesh.vertices<3>();
00026
00027 for (unsigned int i=0; i<v.size(); ++i)
00028 verts_[i] = vgl_point_3d<double>(v[i]);
00029
00030 if (mesh.faces().regularity() != 3)
00031 triangles_ = imesh_triangulate(mesh.faces());
00032 else
00033 triangles_.reset(static_cast<imesh_regular_face_array<3>*>
00034 (mesh.faces().clone()));
00035
00036 if (bounded_)
00037 {
00038
00039 vgl_box_3d<double> box;
00040 for (unsigned int i=0; i<verts_.size(); ++i) {
00041 box.add(verts_[i]);
00042 }
00043 box.expand_about_centroid(1);
00044 unsigned int base = verts_.size();
00045 verts_.push_back(vgl_point_3d<double>(box.min_x(),box.min_y(),box.min_z()));
00046 verts_.push_back(vgl_point_3d<double>(box.min_x(),box.min_y(),box.max_z()));
00047 verts_.push_back(vgl_point_3d<double>(box.min_x(),box.max_y(),box.min_z()));
00048 verts_.push_back(vgl_point_3d<double>(box.min_x(),box.max_y(),box.max_z()));
00049 verts_.push_back(vgl_point_3d<double>(box.max_x(),box.min_y(),box.min_z()));
00050 verts_.push_back(vgl_point_3d<double>(box.max_x(),box.min_y(),box.max_z()));
00051 verts_.push_back(vgl_point_3d<double>(box.max_x(),box.max_y(),box.min_z()));
00052 verts_.push_back(vgl_point_3d<double>(box.max_x(),box.max_y(),box.max_z()));
00053 triangles_->push_back(imesh_tri(base+0,base+1,base+2));
00054 triangles_->push_back(imesh_tri(base+1,base+3,base+2));
00055 triangles_->push_back(imesh_tri(base+0,base+6,base+4));
00056 triangles_->push_back(imesh_tri(base+0,base+2,base+6));
00057 triangles_->push_back(imesh_tri(base+2,base+7,base+6));
00058 triangles_->push_back(imesh_tri(base+2,base+3,base+7));
00059 triangles_->push_back(imesh_tri(base+3,base+5,base+7));
00060 triangles_->push_back(imesh_tri(base+3,base+1,base+5));
00061 triangles_->push_back(imesh_tri(base+1,base+4,base+5));
00062 triangles_->push_back(imesh_tri(base+1,base+0,base+4));
00063 triangles_->push_back(imesh_tri(base+4,base+7,base+5));
00064 triangles_->push_back(imesh_tri(base+4,base+6,base+7));
00065 phi_.resize(verts_.size(),1.0);
00066 }
00067
00068 vcl_vector<vgl_box_3d<double> > boxes(triangles_->size());
00069 for ( unsigned int i=0; i<boxes.size(); ++i ) {
00070 const imesh_regular_face<3>& tri = (*triangles_)[i];
00071 boxes[i].add(verts_[tri[0]]);
00072 boxes[i].add(verts_[tri[1]]);
00073 boxes[i].add(verts_[tri[2]]);
00074 }
00075
00076 kd_tree_ = imesh_build_kd_tree(boxes);
00077 unsigned num_tree_nodes = triangles_->size()*2-1;
00078
00079 unweighted_.resize(num_tree_nodes);
00080 centroid_.resize(num_tree_nodes);
00081 normals_.resize(num_tree_nodes);
00082 normal_len_.resize(num_tree_nodes);
00083 area_.resize(num_tree_nodes);
00084
00085
00086 compute_centroids_rec(kd_tree_, no_normal_faces);
00087 compute_unweighed_rec(kd_tree_);
00088
00089 compute_enclosing_phi();
00090 }
00091
00092
00093
00094 imesh_imls_surface::imesh_imls_surface(const imesh_imls_surface& other)
00095 : verts_(other.verts_),
00096 triangles_(other.triangles_.get() ?
00097 new imesh_regular_face_array<3>(*other.triangles_) :
00098 0),
00099 kd_tree_(other.kd_tree_.get() ?
00100 new imesh_kd_tree_node(*other.kd_tree_) :
00101 0),
00102 phi_(other.phi_),
00103 area_(other.area_),
00104 unweighted_(other.unweighted_),
00105 centroid_(other.centroid_),
00106 normals_(other.normals_),
00107 normal_len_(other.normal_len_),
00108 eps2_(other.eps2_),
00109 lambda_(other.lambda_),
00110 iso_level_(other.iso_level_)
00111 {
00112 }
00113
00114
00115
00116 void imesh_imls_surface::compute_iso_level()
00117 {
00118 double mean = 0.0;
00119 for (unsigned int i=0; i<verts_.size(); ++i)
00120 mean += (*this)(verts_[i]);
00121 iso_level_ = mean / verts_.size();
00122 }
00123
00124
00125
00126
00127 void imesh_imls_surface::compute_enclosing_phi()
00128 {
00129 typedef vcl_pair<unsigned int,double> pair_id;
00130 vcl_vector<pair_id> outside;
00131 double mean = 0.0;
00132 const unsigned int num_verts = bounded_ ?
00133 verts_.size() :
00134 verts_.size() - 8;
00135 for (unsigned int i=0; i<num_verts; ++i) {
00136 double val = (*this)(verts_[i]);
00137 mean += val;
00138 if (val > 0)
00139 outside.push_back(pair_id(i,val));
00140 }
00141 iso_level_ = mean / verts_.size();
00142
00143 for (double s=1.0; !outside.empty(); s*=2) {
00144 vcl_cout << outside.size() << " outside" << vcl_endl;
00145 for (vcl_vector<pair_id>::const_iterator i=outside.begin();
00146 i!=outside.end(); ++i) {
00147 phi_[i->first] -= s*i->second;
00148 }
00149 compute_unweighed_rec(kd_tree_);
00150 vcl_vector<pair_id> next_outside;
00151 for (vcl_vector<pair_id>::const_iterator i=outside.begin();
00152 i!=outside.end(); ++i) {
00153 double val = (*this)(verts_[i->first]);
00154 if (val > vcl_abs(vcl_numeric_limits<double>::epsilon()*phi_[i->first])) {
00155 next_outside.push_back(pair_id(i->first,val));
00156 }
00157 }
00158 outside.swap(next_outside);
00159 }
00160 }
00161
00162
00163
00164 void imesh_imls_surface::
00165 compute_centroids_rec(const vcl_auto_ptr<imesh_kd_tree_node>& node,
00166 const vcl_set<unsigned int>& no_normal_faces)
00167 {
00168 const unsigned int& i = node->index_;
00169 if (node->is_leaf()) {
00170 const imesh_regular_face<3>& tri = (*triangles_)[i];
00171 const vgl_point_3d<double>& v0 = verts_[tri[0]];
00172 const vgl_point_3d<double>& v1 = verts_[tri[1]];
00173 const vgl_point_3d<double>& v2 = verts_[tri[2]];
00174 vgl_vector_3d<double>& n = normals_[i];
00175 n = cross_product(v1-v0,v2-v0)/2.0;
00176 normal_len_[i] = n.length();
00177 area_[i] = normal_len_[i];
00178 centroid_[i] = centre(v0,v1,v2);
00179 if (no_normal_faces.find(i) != no_normal_faces.end()) {
00180 n = vgl_vector_3d<double>(0,0,0);
00181 normal_len_[i] = 0.0;
00182 }
00183 return;
00184 }
00185
00186 compute_centroids_rec(node->left_,no_normal_faces);
00187 compute_centroids_rec(node->right_,no_normal_faces);
00188
00189 const unsigned int& i_left = node->left_->index_;
00190 const unsigned int& i_right = node->right_->index_;
00191
00192 const vgl_point_3d<double>& cl = centroid_[i_left];
00193 const double& al = area_[i_left];
00194 const vgl_point_3d<double>& cr = centroid_[i_right];
00195 const double& ar = area_[i_right];
00196 double& at = area_[i];
00197 at = al + ar;
00198 centroid_[i].set((ar*cr.x() + al*cl.x()) / at,
00199 (ar*cr.y() + al*cl.y()) / at,
00200 (ar*cr.z() + al*cl.z()) / at);
00201
00202 normals_[i] = normals_[i_left] + normals_[i_right];
00203 normal_len_[i] = normals_[i].length();
00204 }
00205
00206
00207
00208 void imesh_imls_surface::
00209 compute_unweighed_rec(const vcl_auto_ptr<imesh_kd_tree_node>& node)
00210 {
00211 const unsigned int& i = node->index_;
00212 if (node->is_leaf()) {
00213 const imesh_regular_face<3>& tri = (*triangles_)[i];
00214 unweighted_[i] = (phi_[tri[0]]
00215 + phi_[tri[1]]
00216 + phi_[tri[2]])/3.0 * area_[i];
00217
00218 return;
00219 }
00220
00221 compute_unweighed_rec(node->left_);
00222 compute_unweighed_rec(node->right_);
00223
00224 const unsigned int& i_left = node->left_->index_;
00225 const unsigned int& i_right = node->right_->index_;
00226 unweighted_[i] = unweighted_[i_left] + unweighted_[i_right];
00227 }
00228
00229
00230
00231 vgl_box_3d<double> imesh_imls_surface::bounding_box() const
00232 {
00233 return kd_tree_->inner_box_;
00234 }
00235
00236
00237
00238 void imesh_imls_surface::set_epsilon(double eps)
00239 {
00240 eps2_ = eps*eps;
00241 iso_level_ = 0.0;
00242
00243
00244 for (unsigned i=0; i<phi_.size(); ++i)
00245 phi_[i] = 0.0;
00246
00247 compute_unweighed_rec(kd_tree_);
00248
00249 compute_enclosing_phi();
00250 }
00251
00252
00253 namespace {
00254 class tri_dist_func
00255 {
00256 public:
00257 tri_dist_func(const vcl_vector<vgl_point_3d<double> >& v,
00258 const imesh_regular_face_array<3>& t)
00259 : verts(v), tris(t), closest_index(static_cast<unsigned int>(-1)),
00260 closest_dist(vcl_numeric_limits<double>::infinity()) {}
00261 const vcl_vector<vgl_point_3d<double> >& verts;
00262 const imesh_regular_face_array<3>& tris;
00263 unsigned int closest_index;
00264 double closest_dist, closest_u, closest_v;
00265
00266 double operator () (const vgl_point_3d<double>& pt, unsigned int i)
00267 {
00268 const imesh_regular_face<3>& tri = tris[i];
00269 double dist,u,v;
00270
00271 imesh_triangle_closest_point(pt,
00272 verts[tri[0]], verts[tri[1]], verts[tri[2]],
00273 dist, u, v);
00274 if (dist < closest_dist) {
00275 closest_dist = dist;
00276 closest_index = i;
00277 closest_u = u;
00278 closest_v = v;
00279 }
00280 return dist;
00281 }
00282 };
00283
00284 }
00285
00286
00287
00288 double imesh_imls_surface::operator() (const vgl_point_3d<double>& p) const
00289 {
00290 double sum=0.0, sum_phi = 0.0;
00291
00292 vcl_vector<imesh_kd_tree_queue_entry> remain;
00293 tri_dist_func dist(verts_,*triangles_);
00294
00295 imesh_closest_index<tri_dist_func&>(p,kd_tree_,dist,&remain);
00296
00297
00298
00299 vcl_vector<imesh_kd_tree_queue_entry>::iterator itr = remain.begin();
00300 for (; itr != remain.end(); ++itr) {
00301 double min = w2(itr->val_);
00302 double max = w2(imesh_max_sq_dist(p,itr->node_->inner_box_));
00303 itr->val_ = (max - min)*area_[itr->node_->index_];
00304 }
00305 vcl_make_heap( remain.begin(), remain.end() );
00306
00307 vcl_pop_heap( remain.begin(), remain.end() );
00308 while (!remain.empty() && -remain.back().val_ > lambda_*sum)
00309 {
00310 imesh_kd_tree_node* current = remain.back().node_;
00311 remain.pop_back();
00312
00313 if (current->is_leaf())
00314 {
00315 unsigned int i = current->index_;
00316 const imesh_regular_face<3>& tri = (*triangles_)[i];
00317 unsigned int i1=tri[0], i2=tri[1], i3=tri[2];
00318 typedef vgl_vector_2d<double> T;
00319 typedef vgl_vector_2d<double> (*F) (const vgl_point_3d<double>&, const vgl_point_3d<double>&,
00320 const vgl_point_3d<double>&, const vgl_point_3d<double>&,
00321 double, double, double, double);
00322 vgl_vector_2d<double> I = triangle_quadrature<T,F>(split_triangle_quadrature,
00323 p,verts_[i1],verts_[i2],verts_[i3],
00324 normals_[i]*2.0,
00325 phi_[i1],phi_[i2],phi_[i3],eps2_);
00326 assert(!vnl_math_isnan(I.x()) && !vnl_math_isnan(I.y()));
00327
00328 sum_phi += I.x();
00329 if (normal_len_[i]>0.0)
00330 sum_phi += dot_product(normals_[i],p-verts_[i1]) * I.y() / normal_len_[i];
00331 sum += I.y();
00332 }
00333 else
00334 {
00335 double min = w2(imesh_min_sq_dist(p,current->left_->inner_box_));
00336 double max = w2(imesh_max_sq_dist(p,current->left_->inner_box_));
00337 remain.push_back(imesh_kd_tree_queue_entry((max - min)*area_[current->left_->index_],
00338 current->left_.get()));
00339 vcl_push_heap(remain.begin(), remain.end());
00340
00341 min = w2(imesh_min_sq_dist(p,current->right_->inner_box_));
00342 max = w2(imesh_max_sq_dist(p,current->right_->inner_box_));
00343 remain.push_back(imesh_kd_tree_queue_entry((max - min)*area_[current->right_->index_],
00344 current->right_.get()));
00345 vcl_push_heap(remain.begin(), remain.end());
00346 }
00347 if (!remain.empty())
00348 vcl_pop_heap( remain.begin(), remain.end() );
00349 }
00350
00351
00352 for (itr = remain.begin(); itr != remain.end(); ++itr) {
00353
00354 unsigned int i = itr->node_->index_;
00355 vgl_vector_3d<double> v(p-centroid_[i]);
00356 double w = w2(v.sqr_length());
00357
00358 sum_phi += w*unweighted_[i] + dot_product(normals_[i],v)*w;
00359 sum += w*area_[i];
00360 }
00361
00362 assert(sum != 0.0);
00363 return sum_phi / sum - iso_level_;
00364 }
00365
00366
00367
00368 double imesh_imls_surface::deriv(const vgl_point_3d<double>& p,
00369 vgl_vector_3d<double>& dp) const
00370 {
00371 integral_data sums;
00372
00373 vcl_vector<imesh_kd_tree_queue_entry> remain;
00374 tri_dist_func dist(verts_,*triangles_);
00375
00376 imesh_closest_index<tri_dist_func&>(p,kd_tree_,dist,&remain);
00377
00378
00379
00380 vcl_vector<imesh_kd_tree_queue_entry>::iterator itr = remain.begin();
00381 for (; itr != remain.end(); ++itr) {
00382 double min = w2(itr->val_);
00383 double max = w2(imesh_max_sq_dist(p,itr->node_->inner_box_));
00384 itr->val_ = (max - min)*area_[itr->node_->index_];
00385 }
00386 vcl_make_heap( remain.begin(), remain.end() );
00387
00388 vcl_pop_heap( remain.begin(), remain.end() );
00389 while (!remain.empty() && -remain.back().val_ > lambda_*sums.I)
00390 {
00391 imesh_kd_tree_node* current = remain.back().node_;
00392 remain.pop_back();
00393
00394 if (current->is_leaf())
00395 {
00396 unsigned int i = current->index_;
00397 const imesh_regular_face<3>& tri = (*triangles_)[i];
00398 unsigned int i1=tri[0], i2=tri[1], i3=tri[2];
00399 typedef integral_data T;
00400 typedef integral_data (*F) (const vgl_point_3d<double>&, const vgl_point_3d<double>&,
00401 const vgl_point_3d<double>&, const vgl_point_3d<double>&,
00402 double, double, double, double);
00403 integral_data Id = triangle_quadrature<T,F>(split_triangle_quadrature_with_deriv,
00404 p,verts_[i1],verts_[i2],verts_[i3],
00405 normals_[i]*2.0,
00406 phi_[i1],phi_[i2],phi_[i3],eps2_);
00407 assert(!vnl_math_isnan(Id.I) && !vnl_math_isnan(Id.I_phi));
00408
00409
00410 sums.I += Id.I;
00411 sums.I_phi += Id.I_phi;
00412 sums.dI += Id.dI;
00413 sums.dI_phi += Id.dI_phi;
00414
00415 if (normal_len_[i]>0.0) {
00416 const vgl_vector_3d<double>& n = normals_[i];
00417 double plane_dist = dot_product(n,p-verts_[i1])/normal_len_[i];
00418 sums.I_phi += plane_dist*Id.I;
00419 sums.dI_phi += n*(Id.I/normal_len_[i]) + plane_dist*Id.dI;
00420 }
00421 }
00422 else
00423 {
00424 double min = w2(imesh_min_sq_dist(p,current->left_->inner_box_));
00425 double max = w2(imesh_max_sq_dist(p,current->left_->inner_box_));
00426 remain.push_back(imesh_kd_tree_queue_entry((max - min)*area_[current->left_->index_],
00427 current->left_.get()));
00428 vcl_push_heap(remain.begin(), remain.end());
00429
00430 min = w2(imesh_min_sq_dist(p,current->right_->inner_box_));
00431 max = w2(imesh_max_sq_dist(p,current->right_->inner_box_));
00432 remain.push_back(imesh_kd_tree_queue_entry((max - min)*area_[current->right_->index_],
00433 current->right_.get()));
00434 vcl_push_heap(remain.begin(), remain.end());
00435 }
00436 if (!remain.empty())
00437 vcl_pop_heap( remain.begin(), remain.end() );
00438 }
00439
00440
00441 for (itr = remain.begin(); itr != remain.end(); ++itr) {
00442
00443 unsigned int i = itr->node_->index_;
00444 vgl_vector_3d<double> v(p-centroid_[i]);
00445 double w = 1.0/(v.sqr_length() + eps2_);
00446 vgl_vector_3d<double> dw(v);
00447 dw *= -4*w;
00448 w *= w;
00449 dw *= w;
00450
00451 const vgl_vector_3d<double>& n = normals_[i];
00452 double plane_dist = dot_product(n,v);
00453 sums.I += w*area_[i];
00454 sums.I_phi += w*unweighted_[i] + plane_dist*w;
00455 sums.dI += dw*area_[i];
00456 sums.dI_phi += n*w + dw*(unweighted_[i] + plane_dist);
00457 }
00458
00459
00460 assert(sums.I != 0.0);
00461 dp = (-sums.I_phi/(sums.I*sums.I))*sums.dI + sums.dI_phi/sums.I;
00462 return sums.I_phi / sums.I - iso_level_;
00463 }
00464
00465
00466
00467 double imesh_imls_surface::deriv2(const vgl_point_3d<double>& p,
00468 vgl_vector_3d<double>& dp,
00469 vnl_double_3x3& ddp) const
00470 {
00471 double eps = 1e-8;
00472 double val = this->deriv(p,dp);
00473 vgl_vector_3d<double> dpx,dpy,dpz;
00474 this->deriv(p+vgl_vector_3d<double>(eps,0,0),dpx);
00475 this->deriv(p+vgl_vector_3d<double>(0,eps,0),dpy);
00476 this->deriv(p+vgl_vector_3d<double>(0,0,eps),dpz);
00477 dpx -= dp;
00478 dpx /= eps;
00479 dpy -= dp;
00480 dpy /= eps;
00481 dpz -= dp;
00482 dpz /= eps;
00483 ddp(0,0) = dpx.x(); ddp(0,1) = dpy.x(); ddp(0,2) = dpz.x();
00484 ddp(1,0) = dpx.y(); ddp(1,1) = dpy.y(); ddp(1,2) = dpz.y();
00485 ddp(2,0) = dpx.z(); ddp(2,1) = dpy.z(); ddp(2,2) = dpz.z();
00486 return val;
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 void
00496 imesh_imls_surface::line_integrals(double k1, double k2, double& I1, double& Ix)
00497 {
00498 double sqrt_k2 = vcl_sqrt(k2);
00499 double k1_p1 = k1+1.0;
00500 I1 = Ix = (vcl_atan(k1_p1/sqrt_k2) - vcl_atan(k1/sqrt_k2) ) / (2.0*k2*sqrt_k2);
00501 Ix *= -k1;
00502
00503 double denom = 1.0/(2.0*k2*(k1_p1*k1_p1+k2));
00504
00505 Ix += k1_p1 * denom;
00506 I1 += (k2 - k1*k1_p1)*denom / (k1*k1+k2);
00507 }
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525 void
00526 imesh_imls_surface::line_integrals(double k1, double k2,
00527 double& I1, double& Ix,
00528 double& dI1, double& dIx, double& dIx2)
00529 {
00530 double sqrt_k2 = vcl_sqrt(k2);
00531 double k1_p1 = k1+1.0;
00532 double k1_2 = k1*k1;
00533 double k2_2 = k2*k2;
00534 double k1_p1_2 = k1_p1*k1_p1;
00535 double t1 = k2 + k1_p1_2;
00536 double t2 = k2 + k1_2;
00537 double t3 = 3*k1_p1_2*k1_p1*k1;
00538
00539
00540 I1 = dI1 = (vcl_atan(k1_p1/sqrt_k2) - vcl_atan(k1/sqrt_k2) ) / (2.0*k2*sqrt_k2);
00541 dI1 *= 0.75/k2;
00542 Ix = -k1 * I1;
00543 dIx = -k1 * dI1;
00544 dIx2 = 0.25*I1*(3*k1_2+k2)/k2;
00545
00546
00547 double denom = 0.5/(k2*t1);
00548 double ddenom = 0.125/(k2_2*t2*t2*t1*t1);
00549
00550 I1 += (k2 - k1*k1_p1)*denom / t2;
00551 Ix += k1_p1 * denom;
00552
00553 dI1 += (5*k2*k2_2 - (k1*k1_p1-3)*k2_2 - k1*k1_p1*(9*k1*k1_p1+5)*k2 - k1_2*t3 )*ddenom;
00554 dIx += t2*((3*k1_p1+1)*k2_2 + k1_p1*(6*k1_2+3*k1+2)*k2 + k1*t3)*ddenom;
00555 dIx2 -= t2*t2*(k2_2 + k1_p1*(4*k1-1)*k2 + t3)*ddenom;
00556 }
00557
00558
00559
00560
00561
00562 double
00563 imesh_imls_surface::line_integral(const vgl_point_3d<double>& x,
00564 const vgl_point_3d<double>& p0,
00565 const vgl_point_3d<double>& p1,
00566 double v0, double v1, double eps2)
00567 {
00568 vgl_vector_3d<double> ab(p1-p0);
00569 vgl_vector_3d<double> xa(p0-x);
00570 double denom = 1.0/ab.sqr_length();
00571 double k1 = dot_product(ab,xa)*denom;
00572 double k2 = (xa.sqr_length()+eps2)*denom - k1*k1;
00573 double I1,Ix;
00574 line_integrals(k1,k2,I1,Ix);
00575 return (v0*I1 + (v1-v0)*Ix)*vcl_sqrt(denom)*denom;
00576 }
00577
00578
00579
00580 vgl_vector_3d<double>
00581 imesh_imls_surface::line_integral_deriv(const vgl_point_3d<double>& x,
00582 const vgl_point_3d<double>& p0,
00583 const vgl_point_3d<double>& p1,
00584 double v0, double v1, double eps2)
00585 {
00586 vgl_vector_3d<double> ab(p1-p0);
00587 vgl_vector_3d<double> xa(p0-x);
00588 double denom = 1.0/ab.sqr_length();
00589 double k1 = dot_product(ab,xa)*denom;
00590 double k2 = (xa.sqr_length()+eps2)*denom - k1*k1;
00591 double I1,Ix,dI1,dIx,dIx2;
00592 line_integrals(k1,k2,I1,Ix,dI1,dIx,dIx2);
00593 denom = 4*vcl_sqrt(denom)*denom*denom;
00594
00595 return (xa*(v0*dI1+(v1-v0)*dIx)
00596 + ab*(v0*dIx + (v1-v0)*dIx2))*denom;
00597 }
00598
00599
00600
00601
00602
00603
00604
00605 vgl_vector_2d<double>
00606 imesh_imls_surface::split_triangle_quadrature(const vgl_point_3d<double>& x,
00607 const vgl_point_3d<double>& pm,
00608 const vgl_point_3d<double>& p1,
00609 const vgl_point_3d<double>& p2,
00610 double vm, double v1, double v2,
00611 double eps)
00612 {
00613 vgl_point_3d<double> pp(p1), pn(p2);
00614 double vp(v1), vn(v2);
00615 if ((pp-x).length() > (pn-x).length()) {
00616
00617 pp = p2; pn = p1;
00618 vp = v2; vn = v1;
00619 }
00620
00621 vgl_vector_3d<double> d1(pp-pm);
00622 vgl_vector_3d<double> d2(pn-pm);
00623 vgl_vector_3d<double> d3(pm-x);
00624
00625 double t1 = d1.sqr_length();
00626 double t2 = dot_product(d1,d2);
00627 double t3 = dot_product(d1,d3);
00628 double t4 = d2.sqr_length();
00629 double t5 = dot_product(d2,d3) * 2;
00630 double t6 = d3.sqr_length() + eps;
00631
00632
00633
00634 double height = t4/t1 - t2*t2/(t1*t1);
00635 if (!(height > 0.0))
00636 return vgl_vector_2d<double>(0,0);
00637 height = vcl_sqrt(height)/2.0;
00638
00639 double vt1 = vn-vm;
00640 double vt2 = vp-vm;
00641
00642 double alpha = 2.0/3.0;
00643 double sum1 = 0.0, sum2 = 0.0;
00644 double weight = (1.0/alpha-alpha);
00645 double I1,Ix,u_1,denom,k1,k2;
00646 double u = alpha;
00647 double last_li1 = 0.0, last_li2 = 0.0;
00648
00649 for (; u>0.01; u*=alpha) {
00650 sum1 += last_li1;
00651 sum2 += last_li2;
00652 u_1 = 1.0-u;
00653 denom = 1.0/(u_1*u_1*t1);
00654 k1 = (t3 + u*t2)*u_1*denom;
00655 k2 = (t6 + u*t5 + u*u*t4)*denom - k1*k1;
00656 line_integrals(k1,k2,I1,Ix);
00657 denom *= u / u_1;
00658 last_li1 = ((vm+u*vt1)*I1 + u_1*vt2*Ix) * denom;
00659 last_li2 = I1 * denom;
00660 }
00661 sum1 *= weight;
00662 sum1 += last_li1/alpha;
00663 sum2 *= weight;
00664 sum2 += last_li2/alpha;
00665
00666
00667 denom = 1.0/t1;
00668 k1 = t3*denom;
00669 k2 = t6*denom - k1*k1;
00670 line_integrals(k1,k2,I1,Ix);
00671 denom *= u/alpha;
00672 sum1 += (vm*I1 + vt2*Ix) * denom;
00673 sum2 += I1 * denom;
00674
00675 sum1 *= height;
00676 sum2 *= height;
00677
00678
00679 return vgl_vector_2d<double>(sum1,sum2);
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689 imesh_imls_surface::integral_data imesh_imls_surface::
00690 split_triangle_quadrature_with_deriv(const vgl_point_3d<double>& x,
00691 const vgl_point_3d<double>& pm,
00692 const vgl_point_3d<double>& p1,
00693 const vgl_point_3d<double>& p2,
00694 double vm, double v1, double v2,
00695 double eps)
00696 {
00697 vgl_point_3d<double> pp(p1), pn(p2);
00698 double vp(v1), vn(v2);
00699 if ((pp-x).length() > (pn-x).length()) {
00700
00701 pp = p2; pn = p1;
00702 vp = v2; vn = v1;
00703 }
00704
00705 vgl_vector_3d<double> d1(pp-pm);
00706 vgl_vector_3d<double> d2(pn-pm);
00707 vgl_vector_3d<double> d3(pm-x);
00708
00709 double t1 = d1.sqr_length();
00710 double t2 = dot_product(d1,d2);
00711 double t3 = dot_product(d1,d3);
00712 double t4 = d2.sqr_length();
00713 double t5 = dot_product(d2,d3) * 2;
00714 double t6 = d3.sqr_length() + eps;
00715
00716
00717
00718 double height = t4/t1 - t2*t2/(t1*t1);
00719 if (!(height > 0.0))
00720 return integral_data();
00721 height = vcl_sqrt(height)/2.0;
00722
00723 double vt1 = vn-vm;
00724 double vt2 = vp-vm;
00725
00726 double alpha = 2.0/3.0;
00727 integral_data i_data, last_i_data;
00728 double weight = (1.0/alpha-alpha);
00729 double I1,Ix,dI1,dIx,dIx2,u_1,denom,k1,k2;
00730 double u = alpha;
00731
00732 const double lower_bound = 0.01;
00733 for (; u>lower_bound; u*=alpha) {
00734 i_data += last_i_data;
00735 u_1 = 1.0-u;
00736 denom = 1.0/(u_1*u_1*t1);
00737 k1 = (t3 + u*t2)*u_1*denom;
00738 k2 = (t6 + u*t5 + u*u*t4)*denom - k1*k1;
00739 line_integrals(k1,k2,I1,Ix,dI1,dIx,dIx2);
00740 double phi_c = vm+u*vt1;
00741 double phi_x = u_1*vt2;
00742 last_i_data.I = I1;
00743 last_i_data.I_phi = (phi_c*I1 + phi_x*Ix);
00744
00745 vgl_vector_3d<double> d_c(d3+u*d2), d_x(d1*u_1);
00746 last_i_data.dI = (d_c*dI1 + d_x*dIx)*denom;
00747 last_i_data.dI_phi = ( d_c*(phi_c*dI1 + phi_x*dIx)
00748 + d_x*(phi_c*dIx + phi_x*dIx2) ) * denom;
00749
00750 denom *= u / u_1;
00751 last_i_data *= denom;
00752 }
00753 i_data *= weight;
00754 last_i_data *= 1.0/alpha;
00755 i_data += last_i_data;
00756
00757
00758
00759 denom = 1.0/t1;
00760 k1 = t3*denom;
00761 k2 = t6*denom - k1*k1;
00762 line_integrals(k1,k2,I1,Ix,dI1,dIx,dIx2);
00763 denom *= u/alpha;
00764
00765 i_data.I += I1 * denom;
00766 i_data.I_phi += (vm*I1 + vt2*Ix) * denom;
00767 denom /= t1;
00768 i_data.dI += (d3*dI1 + d1*dIx)*denom;
00769 i_data.dI_phi += ( d3*(vm*dI1 + vt2*dIx)
00770 + d1*(vm*dIx + vt2*dIx2) ) * denom;
00771
00772 i_data *= height;
00773 i_data.dI *= 4.0;
00774 i_data.dI_phi *= 4.0;
00775
00776 return i_data;
00777 }
00778
00779
00780
00781
00782
00783
00784
00785 vgl_point_3d<double> bisect(const imesh_imls_surface& f,
00786 vgl_point_3d<double> pp,
00787 vgl_point_3d<double> pn,
00788 double feps, double xeps)
00789 {
00790 assert(f(pp) > 0.0);
00791 assert(f(pn) < 0.0);
00792 vgl_point_3d<double> pm=centre(pp,pn);
00793 const unsigned num_itr =
00794 static_cast<unsigned>(vcl_ceil(vcl_log((pp-pn).length()
00795 / xeps)
00796 / 0.301029995663981));
00797 vgl_vector_3d<double> dp;
00798 double val = f.deriv(pm,dp);
00799 val /= dp.length();
00800 for (unsigned int i=0; i<num_itr; ++i) {
00801 if (vcl_abs(val) < feps)
00802 return pm;
00803 else if (val > 0.0)
00804 pp = pm;
00805 else
00806 pn = pm;
00807 pm=centre(pp,pn);
00808 val = f.deriv(pm,dp);
00809 val /= dp.length();
00810 }
00811 return pm;
00812 }
00813
00814
00815
00816
00817 bool snap_to_surface(const imesh_imls_surface& f,
00818 vgl_point_3d<double>& p,
00819 double step, double eps)
00820 {
00821 vgl_point_3d<double> p1(p);
00822 vgl_vector_3d<double> dp;
00823 double val1 = f.deriv(p1,dp);
00824 double dl = dp.length();
00825 val1 /= dl;
00826 if (vcl_abs(val1) < eps)
00827 return true;
00828
00829 vgl_point_3d<double> p2 = p1 - (step*val1/dl)*dp;
00830 dl = dp.length();
00831 double val2 = f.deriv(p2,dp);
00832 val2 /= dl;
00833 unsigned int i=0;
00834 for (; i<100 && val1*val2 > 0.0; ++i) {
00835 p1 = p2;
00836 val1 = val2;
00837 p2 -= (step*val2/dl)*dp;
00838 val2 = f.deriv(p2,dp);
00839 dl = dp.length();
00840 val2 /= dl;
00841 if (vcl_abs(val2) < eps) {
00842 p = p2;
00843 return true;
00844 }
00845 }
00846 if (i >= 100)
00847 return false;
00848
00849 if (val1 > 0.0)
00850 p = bisect(f,p1,p2,eps);
00851 else
00852 p = bisect(f,p2,p1,eps);
00853
00854
00855 return true;
00856 }
00857
00858
00859 namespace{
00860 double func(const vgl_vector_3d<double>& n,
00861 double v,
00862 const vgl_vector_3d<double>& dp)
00863 {
00864 v *= v;
00865 v /= dp.sqr_length();
00866 double tmp = dot_product(n,dp)/dp.length() - 1.0;
00867 return v + tmp*tmp;
00868 }
00869
00870 vgl_vector_3d<double> dfunc(const vgl_vector_3d<double>& n,
00871 double v,
00872 const vgl_vector_3d<double>& dp,
00873 const vnl_double_3x3& ddp)
00874 {
00875 vnl_double_3 nn(n.x(),n.y(),n.z());
00876 vnl_double_3 ndp(dp.x(), dp.y(), dp.z());
00877 double sqr_len = dp.sqr_length();
00878 double len = vcl_sqrt(sqr_len);
00879 double n_dot_dp = dot_product(nn,ndp);
00880 vnl_double_3 df = (2*v/sqr_len)*ndp;
00881 df += ddp.transpose() * ( ((-2*v*v/(sqr_len*sqr_len))*ndp) +
00882 (2/len*(n_dot_dp/len - 1)*(nn - (n_dot_dp/sqr_len)*ndp)) );
00883 return vgl_vector_3d<double>(df[0],df[1],df[2]);
00884 }
00885
00886 }
00887
00888
00889
00890 bool snap_to_surface_with_normal(const imesh_imls_surface& f,
00891 vgl_point_3d<double>& p,
00892 vgl_vector_3d<double> n,
00893 double step, double eps)
00894 {
00895 vgl_point_3d<double> p1(p);
00896 normalize(n);
00897 vgl_vector_3d<double> dp;
00898 vnl_double_3x3 ddp;
00899 double val = f.deriv2(p1, dp, ddp);
00900 double f1 = func(n,val,dp);
00901 if (f1 < eps)
00902 return true;
00903
00904 vgl_vector_3d<double> df = dfunc(n,val,dp,ddp);
00905 double dl = df.sqr_length();
00906 unsigned int i;
00907 for (i=0; i<1000; ++i) {
00908 vgl_point_3d<double> p2 = p1 - (step*f1/dl)*df;
00909 val = f.deriv2(p2,dp,ddp);
00910 double f2 = func(n,val,dp);
00911
00912 if ( f2 > f1) {
00913 step /= 2;
00914 continue;
00915 }
00916 if (f2 < eps || step < eps) {
00917 p = p2;
00918 return true;
00919 }
00920 f1 = f2;
00921 p1 = p2;
00922 df = dfunc(n,val,dp,ddp);
00923 dl = df.sqr_length();
00924 step *= 2;
00925 }
00926 if (i >= 100)
00927 return true;
00928
00929 p = p1;
00930 return true;
00931 }
00932
00933
00934
00935
00936 bool snap_to_surface(const imesh_imls_surface& f,
00937 vgl_vector_3d<double> dir,
00938 vgl_point_3d<double>& p,
00939 double step, double eps)
00940 {
00941 vgl_point_3d<double> p1(p);
00942 normalize(dir);
00943 vgl_vector_3d<double> dp;
00944 double val1 = f.deriv(p1,dp);
00945 dp = dir * dot_product(dp,dir);
00946 double dl = dp.length();
00947 val1 /= dl;
00948 if (vcl_abs(val1) < eps)
00949 return true;
00950
00951 vgl_point_3d<double> p2 = p1 - (step*val1/dl)*dp;
00952 dl = dp.length();
00953 double val2 = f.deriv(p2,dp);
00954 val2 /= dl;
00955 unsigned int i=0;
00956 for (; i<100 && val1*val2 > 0.0; ++i) {
00957 p1 = p2;
00958 val1 = val2;
00959 p2 -= (step*val2/dl)*dp;
00960 val2 = f.deriv(p2,dp);
00961 dp = dir * dot_product(dp,dir);
00962 dl = dp.length();
00963 val2 /= dl;
00964 if (vcl_abs(val2) < eps) {
00965 p = p2;
00966 return true;
00967 }
00968 }
00969 if (i >= 100)
00970 return false;
00971
00972 if (val1 > 0.0)
00973 p = bisect(f,p1,p2,eps);
00974 else
00975 p = bisect(f,p2,p1,eps);
00976
00977
00978 return true;
00979 }
00980
00981
00982 #include <imesh/algo/imesh_imls_surface.txx>
00983 IMESH_IMLS_SURFACE_INSTANTATE(vgl_vector_2d<double>,vgl_point_3d<double>);
00984 IMESH_IMLS_SURFACE_INSTANTATE(imesh_imls_surface::integral_data,vgl_point_3d<double>);