@@ -25,6 +25,92 @@ void point_segment_squared_distance(
2525 dist = (point - closest_point).squaredNorm ();
2626}
2727
28+ void point_triangle_squared_distance (
29+ const VectorMax3d& x,
30+ const std::array<VectorMax3d, 3 >& f,
31+ VectorMax3d& pt,
32+ double & dist)
33+ {
34+ const VectorMax3d& pa = f[0 ];
35+ const VectorMax3d& pb = f[1 ];
36+ const VectorMax3d& pc = f[2 ];
37+
38+ // source: real time collision detection
39+ // check if x in vertex region outside pa
40+ VectorMax3d ab = pb - pa;
41+ VectorMax3d ac = pc - pa;
42+ VectorMax3d ax = x - pa;
43+ const double d1 = ab.dot (ax);
44+ const double d2 = ac.dot (ax);
45+ if (d1 <= 0 && d2 <= 0 ) {
46+ // barycentric coordinates (1, 0, 0)
47+ pt = pa;
48+ dist = (x - pt).norm ();
49+ return ;
50+ }
51+
52+ // check if x in vertex region outside pb
53+ VectorMax3d bx = x - pb;
54+ const double d3 = ab.dot (bx);
55+ const double d4 = ac.dot (bx);
56+ if (d3 >= 0 .0f && d4 <= d3) {
57+ // barycentric coordinates (0, 1, 0)
58+ pt = pb;
59+ dist = (x - pt).norm ();
60+ return ;
61+ }
62+
63+ // check if x in vertex region outside pc
64+ VectorMax3d cx = x - pc;
65+ const double d5 = ab.dot (cx);
66+ const double d6 = ac.dot (cx);
67+ if (d6 >= 0 .0f && d5 <= d6) {
68+ // barycentric coordinates (0, 0, 1)
69+ pt = pc;
70+ dist = (x - pt).norm ();
71+ return ;
72+ }
73+
74+ // check if x in edge region of ab, if so return projection of x onto ab
75+ const double vc = d1 * d4 - d3 * d2;
76+ if (vc <= 0 .0f && d1 >= 0 .0f && d3 <= 0 .0f ) {
77+ // barycentric coordinates (1 - v, v, 0)
78+ const double v = d1 / (d1 - d3);
79+ pt = pa + ab * v;
80+ dist = (x - pt).norm ();
81+ return ;
82+ }
83+
84+ // check if x in edge region of ac, if so return projection of x onto ac
85+ const double vb = d5 * d2 - d1 * d6;
86+ if (vb <= 0 .0f && d2 >= 0 .0f && d6 <= 0 .0f ) {
87+ // barycentric coordinates (1 - w, 0, w)
88+ const double w = d2 / (d2 - d6);
89+ pt = pa + ac * w;
90+ dist = (x - pt).norm ();
91+ return ;
92+ }
93+
94+ // check if x in edge region of bc, if so return projection of x onto bc
95+ const double va = d3 * d6 - d5 * d4;
96+ if (va <= 0 .0f && (d4 - d3) >= 0 .0f && (d5 - d6) >= 0 .0f ) {
97+ // barycentric coordinates (0, 1 - w, w)
98+ const double w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
99+ pt = pb + (pc - pb) * w;
100+ dist = (x - pt).norm ();
101+ return ;
102+ }
103+
104+ // x inside face region. Compute pt through its barycentric coordinates (u,
105+ // v, w)
106+ const double denom = 1 / (va + vb + vc);
107+ const double v = vb * denom;
108+ const double w = vc * denom;
109+
110+ pt = pa + ab * v + ac * w; // = u*a + v*b + w*c, u = va*denom = 1.0f - v - w
111+ dist = (x - pt).norm ();
112+ }
113+
28114namespace {
29115 bool box_box_intersection (
30116 const VectorMax3d& min1,
@@ -245,6 +331,9 @@ void BVH::init(
245331 assert (F.cols () == 3 || F.cols () == 2 );
246332 assert (V.cols () == 3 || V.cols () == 2 );
247333
334+ vertices = V;
335+ faces = F;
336+
248337 std::vector<std::array<VectorMax3d, 2 >> cornerlist (F.rows ());
249338 if (F.cols () == 3 ) {
250339 for (int i = 0 ; i < F.rows (); i++) {
@@ -264,6 +353,18 @@ void BVH::init(
264353 cornerlist[i][0 ] = min.transpose ();
265354 cornerlist[i][1 ] = max.transpose ();
266355 }
356+
357+ set_leaf_distance_callback (
358+ [&](const VectorMax3d& p, int f, VectorMax3d& cp, double & dist) {
359+ point_triangle_squared_distance (
360+ p,
361+ { { vertices.row (faces (f, 0 )), vertices.row (faces (f, 1 )),
362+ vertices.row (faces (f, 2 )) } },
363+ cp, dist);
364+ });
365+ set_get_point_callback (
366+ [&](int f) { return vertices.row (faces (f, 0 )); });
367+
267368 } else if (F.cols () == 2 ) {
268369 for (int i = 0 ; i < F.rows (); i++) {
269370 const Eigen::RowVector2i face = F.row (i);
@@ -280,6 +381,15 @@ void BVH::init(
280381 cornerlist[i][0 ] = min.transpose ();
281382 cornerlist[i][1 ] = max.transpose ();
282383 }
384+
385+ set_leaf_distance_callback ([&](const VectorMax3d& p, int f,
386+ VectorMax3d& cp, double & dist) {
387+ point_segment_squared_distance (
388+ p, { { vertices.row (faces (f, 0 )), vertices.row (faces (f, 1 )) } },
389+ cp, dist);
390+ });
391+ set_get_point_callback (
392+ [&](int f) { return vertices.row (faces (f, 0 )); });
283393 }
284394
285395 init (cornerlist);
0 commit comments