00001
00002 #include "imesh_intersect.h"
00003
00004
00005
00006 #include <vcl_limits.h>
00007 #include <vcl_cassert.h>
00008
00009 #include <vgl/vgl_triangle_3d.h>
00010 #include <vgl/vgl_distance.h>
00011
00012
00013 namespace {
00014
00015
00016 void compute_barycentric(const vgl_point_3d<double>& p,
00017 const vgl_point_3d<double>& a,
00018 const vgl_point_3d<double>& b,
00019 const vgl_point_3d<double>& c,
00020 double& u, double& v)
00021 {
00022 vgl_vector_3d<double> vp(p-a);
00023 vgl_vector_3d<double> vu(b-a);
00024 vgl_vector_3d<double> vv(c-a);
00025 vgl_vector_3d<double> n(cross_product(vu,vv));
00026 vgl_vector_3d<double> nxu(cross_product(n,vu));
00027 vgl_vector_3d<double> nxv(cross_product(n,vv));
00028 u = dot_product(vp,nxv)/dot_product(vu,nxv);
00029 v = dot_product(vp,nxu)/dot_product(vv,nxu);
00030 }
00031
00032 };
00033
00034
00035
00036
00037
00038
00039 bool imesh_intersect_triangle(const vgl_point_3d<double>& p,
00040 const vgl_vector_3d<double>& d,
00041 const vgl_point_3d<double>& a,
00042 const vgl_point_3d<double>& b,
00043 const vgl_point_3d<double>& c,
00044 double& dist,
00045 double& u, double& v)
00046 {
00047 vgl_vector_3d<double> n(cross_product(b-a,c-a));
00048 return imesh_intersect_triangle(p,d,a,b,c,n,dist,u,v);
00049 }
00050
00051
00052
00053
00054
00055
00056
00057 bool imesh_intersect_triangle(const vgl_point_3d<double>& p,
00058 const vgl_vector_3d<double>& d,
00059 const vgl_point_3d<double>& a,
00060 const vgl_point_3d<double>& b,
00061 const vgl_point_3d<double>& c,
00062 const vgl_vector_3d<double>& n,
00063 double& dist,
00064 double& u, double& v)
00065 {
00066 double denom = -dot_product(d,n);
00067 if (denom <= 0)
00068 return false;
00069
00070 vgl_vector_3d<double> ap(p-a);
00071 vgl_vector_3d<double> t(cross_product(d,ap));
00072 v = dot_product(b-p,t);
00073 if (v < 0.0 || v>denom)
00074 return false;
00075
00076 u = -dot_product(c-p,t);
00077 if (u < 0.0 || u+v > denom)
00078 return false;
00079
00080 dist = dot_product(ap,n);
00081 if (dist < 0.0)
00082 return false;
00083
00084 u /= denom;
00085 v /= denom;
00086 dist /= denom;
00087
00088 return true;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097 bool imesh_intersect_triangle_min_dist(const vgl_point_3d<double>& p,
00098 const vgl_vector_3d<double>& d,
00099 const vgl_point_3d<double>& a,
00100 const vgl_point_3d<double>& b,
00101 const vgl_point_3d<double>& c,
00102 const vgl_vector_3d<double>& n,
00103 double& dist,
00104 double& u, double& v)
00105 {
00106 double denom = -dot_product(d,n);
00107 if (denom <= 0)
00108 return false;
00109
00110 vgl_vector_3d<double> ap(p-a);
00111 double new_dist = dot_product(ap,n)/denom;
00112 if (new_dist < 0.0 || new_dist > dist)
00113 return false;
00114
00115 vgl_vector_3d<double> t(cross_product(d,ap));
00116 v = dot_product(b-p,t);
00117 if (v < 0.0 || v>denom)
00118 return false;
00119
00120 u = -dot_product(c-p,t);
00121 if (u < 0.0 || u+v > denom)
00122 return false;
00123
00124 dist = new_dist;
00125 u /= denom;
00126 v /= denom;
00127
00128 return true;
00129 }
00130
00131
00132
00133
00134
00135
00136 int imesh_intersect_min_dist(const vgl_point_3d<double>& p,
00137 const vgl_vector_3d<double>& d,
00138 const imesh_mesh& mesh,
00139 double& dist, double* u, double* v)
00140 {
00141 double ut, vt;
00142
00143 assert(mesh.faces().regularity() == 3);
00144 const imesh_regular_face_array<3>& faces
00145 = static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00146
00147 const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00148
00149 assert(faces.has_normals());
00150 assert((cross_product(vgl_point_3d<double>(verts[faces[0][1]])-vgl_point_3d<double>(verts[faces[0][0]]),
00151 vgl_point_3d<double>(verts[faces[0][2]])-vgl_point_3d<double>(verts[faces[0][0]]))
00152 -faces.normal(0)).length() < 1e-14);
00153
00154 int isect = -1;
00155 dist = vcl_numeric_limits<double>::infinity();
00156 for (unsigned int i=0; i<faces.size(); ++i)
00157 {
00158 const imesh_regular_face<3>& f = faces[i];
00159 if (imesh_intersect_triangle_min_dist(p,d,verts[f[0]],verts[f[1]],verts[f[2]],
00160 faces.normal(i),dist,ut,vt))
00161 {
00162 isect = i;
00163 if (u) *u = ut;
00164 if (v) *v = vt;
00165 }
00166 }
00167 return isect;
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 unsigned char
00185 imesh_triangle_closest_point(const vgl_point_3d<double>& p,
00186 const vgl_point_3d<double>& a,
00187 const vgl_point_3d<double>& b,
00188 const vgl_point_3d<double>& c,
00189 const vgl_vector_3d<double>& n,
00190 double& dist,
00191 double& u, double& v)
00192 {
00193 double denom = 1.0/dot_product(n,n);
00194
00195 vgl_vector_3d<double> ap(p-a);
00196 vgl_vector_3d<double> bp(p-b);
00197 vgl_vector_3d<double> cp(p-c);
00198
00199 vgl_vector_3d<double> t(cross_product(n,ap));
00200 v = dot_product(bp,t) * denom;
00201 u = -dot_product(cp,t) * denom;
00202
00203 vgl_vector_3d<double> ab(b-a);
00204 vgl_vector_3d<double> bc(c-b);
00205 vgl_vector_3d<double> ca(a-c);
00206
00207 double eps = vcl_numeric_limits<double>::epsilon();
00208
00209 unsigned char state = 0;
00210 double uv;
00211 if (u <= eps) {
00212 double p_v = v - u * dot_product(ab,ca)/dot_product(ca,ca);
00213 if (p_v <= eps) {
00214 state = 1;
00215 }
00216 else if (p_v >= 1.0) {
00217 state = 4;
00218 }
00219 else {
00220 u = 0.0; v = p_v;
00221 dist = ((1-v)*ap + v*cp).length();
00222 return 5;
00223 }
00224 }
00225 if (v <= eps) {
00226 double p_u = u - v * dot_product(ca,ab)/dot_product(ab,ab);
00227 if (p_u <= eps) {
00228 state = 1;
00229 }
00230 else if (p_u >= 1.0) {
00231 state = 2;
00232 }
00233 else {
00234 u = p_u; v = 0.0;
00235 dist = ((1-u)*ap + u*bp).length();
00236 return 3;
00237 }
00238 }
00239 if ((uv = 1.0-u-v) <= eps) {
00240 double s = -dot_product(ca,bc)/dot_product(bc,bc);
00241 double p_u = u + uv * s;
00242 double p_v = v + uv * (1.0-s);
00243 if (p_v <= eps) {
00244 state = 2;
00245 }
00246 else if (p_u <= eps) {
00247 state = 4;
00248 }
00249 else {
00250 u=p_u; v=p_v;
00251 dist = (u*bp + v*cp).length();
00252 return 6;
00253 }
00254 }
00255
00256 switch (state)
00257 {
00258 case 1:
00259 u=0.0; v=0.0;
00260 dist = ap.length();
00261 return 1;
00262 case 2:
00263 u=1.0; v=0.0;
00264 dist = bp.length();
00265 return 2;
00266 case 4:
00267 u=0.0; v=1.0;
00268 dist = cp.length();
00269 return 4;
00270 default:
00271 dist = vcl_abs(dot_product(ap,n) * vcl_sqrt(denom));
00272 return 7;
00273 }
00274
00275 return 0;
00276 }
00277
00278
00279
00280
00281
00282
00283 unsigned char
00284 imesh_triangle_closest_point(const vgl_point_3d<double>& p,
00285 const vgl_point_3d<double>& a,
00286 const vgl_point_3d<double>& b,
00287 const vgl_point_3d<double>& c,
00288 double& dist,
00289 double& u, double& v)
00290 {
00291 vgl_vector_3d<double> n(cross_product(b-a,c-a));
00292 return imesh_triangle_closest_point(p,a,b,c,n,dist,u,v);
00293 }
00294
00295
00296
00297
00298 vgl_point_3d<double>
00299 imesh_triangle_closest_point(const vgl_point_3d<double>& p,
00300 const vgl_point_3d<double>& a,
00301 const vgl_point_3d<double>& b,
00302 const vgl_point_3d<double>& c,
00303 double& dist)
00304 {
00305 double u,v;
00306 imesh_triangle_closest_point(p,a,b,c,dist,u,v);
00307 double t = 1-u-v;
00308 return vgl_point_3d<double>(t*a.x() + u*b.x() + v*c.x(),
00309 t*a.y() + u*b.y() + v*c.y(),
00310 t*a.z() + u*b.z() + v*c.z());
00311 }
00312
00313
00314
00315
00316
00317 int imesh_closest_point(const vgl_point_3d<double>& p,
00318 const imesh_mesh& mesh,
00319 vgl_point_3d<double>& cp,
00320 double* u, double* v)
00321 {
00322 assert(mesh.faces().regularity() == 3);
00323 const imesh_regular_face_array<3>& faces
00324 = static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00325
00326 const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00327
00328 int isect = -1;
00329 double dist = vcl_numeric_limits<double>::infinity();
00330 for (unsigned int i=0; i<faces.size(); ++i)
00331 {
00332 const imesh_regular_face<3>& f = faces[i];
00333 vgl_point_3d<double> cpt = vgl_triangle_3d_closest_point(p,verts[f[0]],verts[f[1]],verts[f[2]]);
00334 double cp_dist = vgl_distance(cpt,p);
00335 if (cp_dist < dist)
00336 {
00337 isect = i;
00338 dist = cp_dist;
00339 cp = cpt;
00340 double ut, vt;
00341 compute_barycentric(cp,verts[f[0]],verts[f[1]],verts[f[2]],ut,vt);
00342 if (u) *u = ut;
00343 if (v) *v = vt;
00344 }
00345 }
00346 return isect;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 unsigned char
00362 imesh_triangle_intersect(const vgl_point_2d<double>& p,
00363 const vgl_vector_2d<double>& d,
00364 const vgl_point_2d<double>& a,
00365 const vgl_point_2d<double>& b,
00366 const vgl_point_2d<double>& c,
00367 double& u, double& v)
00368 {
00369 vgl_vector_2d<double> v1(b-a), v2(c-a), vp(p-a);
00370 vgl_vector_2d<double> v1n(v1.y(), -v1.x());
00371 v1n /= dot_product(v1n,v2);
00372 vgl_vector_2d<double> v2n(v2.y(), -v2.x());
00373 v2n /= dot_product(v2n,v1);
00374 v = dot_product(v1n,vp);
00375 u = dot_product(v2n,vp);
00376
00377 double dv = dot_product(d,v1n);
00378 double du = dot_product(d,v2n);
00379
00380 return imesh_triangle_intersect(u,v,du,dv);
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 unsigned char
00396 imesh_triangle_intersect(double& u, double& v,
00397 const double& du, const double& dv,
00398 const double& eps)
00399 {
00400 unsigned char state = 0;
00401 double best_t = vcl_numeric_limits<double>::infinity();
00402 if (du > 0.0)
00403 {
00404 double t = -u/du;
00405 double vi = v + t*dv;
00406 if (vi > eps && vi+eps < 1.0)
00407 {
00408 best_t = t;
00409 state = 5;
00410 }
00411 else if (vcl_abs(vi) <= eps)
00412 {
00413 best_t = t;
00414 state = 1;
00415 }
00416 else if (vcl_abs(1-vi) <= eps)
00417 {
00418 best_t = t;
00419 state = 4;
00420 }
00421 }
00422 if (dv > 0.0)
00423 {
00424 double t = -v/dv;
00425 double ui = u + t*du;
00426 if (ui > eps && ui+eps < 1.0)
00427 {
00428 best_t = t;
00429 state = 3;
00430 }
00431 else if (vcl_abs(ui) <= eps)
00432 {
00433 best_t = t;
00434 state = 1;
00435 }
00436 else if (vcl_abs(1-ui) <= eps)
00437 {
00438 best_t = t;
00439 state = 2;
00440 }
00441 }
00442 if (du+dv < 0.0)
00443 {
00444 double t = (1-u-v)/(du+dv);
00445 double ui = u + t*du;
00446 double vi = v + t*dv;
00447 if (ui > eps && vi > eps)
00448 {
00449 best_t = t;
00450 state = 6;
00451 }
00452 else if (vcl_abs(ui) <= eps)
00453 {
00454 best_t = t;
00455 state = 4;
00456 }
00457 else if (vcl_abs(vi) <= eps)
00458 {
00459 best_t = t;
00460 state = 2;
00461 }
00462 }
00463
00464 u+=best_t*du;
00465 v+=best_t*dv;
00466
00467 return state;
00468 }