44#include < iostream>
55
66namespace SimpleBVH {
7+
8+ void point_segment_squared_distance (
9+ const VectorMax3d& point,
10+ const std::array<VectorMax3d, 2 >& f,
11+ VectorMax3d& closest_point,
12+ double & dist)
13+ {
14+ const double l2 = (f[0 ] - f[1 ]).norm ();
15+ const double t = (point - f[0 ]).dot (f[1 ] - f[0 ]);
16+ if (t <= 0.0 || l2 == 0.0 ) {
17+ closest_point = f[0 ];
18+ } else if (t > l2) {
19+ closest_point = f[1 ];
20+ } else {
21+ const double lambda1 = t / l2;
22+ const double lambda0 = 1.0 - lambda1;
23+ closest_point = lambda0 * f[0 ] + lambda1 * f[1 ];
24+ }
25+ dist = (point - closest_point).squaredNorm ();
26+ }
27+
728namespace {
829 bool box_box_intersection (
9- const Eigen::Vector3d& min1,
10- const Eigen::Vector3d& max1,
11- const Eigen::Vector3d& min2,
12- const Eigen::Vector3d& max2)
30+ const VectorMax3d& min1,
31+ const VectorMax3d& max1,
32+ const VectorMax3d& min2,
33+ const VectorMax3d& max2)
34+ {
35+ if (min1.size () == 3 ) {
36+ if (max1[0 ] < min2[0 ] || max1[1 ] < min2[1 ] || max1[2 ] < min2[2 ])
37+ return 0 ;
38+ if (max2[0 ] < min1[0 ] || max2[1 ] < min1[1 ] || max2[2 ] < min1[2 ])
39+ return 0 ;
40+ return 1 ;
41+ } else {
42+ if (max1[0 ] < min2[0 ] || max1[1 ] < min2[1 ])
43+ return 0 ;
44+ if (max2[0 ] < min1[0 ] || max2[1 ] < min1[1 ])
45+ return 0 ;
46+ return 1 ;
47+ }
48+ }
49+
50+ double point_box_center_squared_distance (
51+ const VectorMax3d& p, const std::array<VectorMax3d, 2 >& B)
52+ {
53+ return (p - (B[0 ] + B[1 ]) / 2 ).norm ();
54+ }
55+
56+ double inner_point_box_squared_distance (
57+ const VectorMax3d& p, const std::array<VectorMax3d, 2 >& B)
58+ {
59+ assert (p.size () == B[0 ].size ());
60+
61+ double result = std::pow (p[0 ] - B[0 ][0 ], 2 );
62+ result = std::min (result, std::pow (p[0 ] - B[1 ][0 ], 2 ));
63+ for (int c = 1 ; c < p.size (); ++c) {
64+ result = std::min (result, std::pow (p[c] - B[0 ][c], 2 ));
65+ result = std::min (result, std::pow (p[c] - B[1 ][c], 2 ));
66+ }
67+ return result;
68+ }
69+
70+ double point_box_signed_squared_distance (
71+ const VectorMax3d& p, const std::array<VectorMax3d, 2 >& B)
1372 {
14- if (max1[0 ] < min2[0 ] || max1[1 ] < min2[1 ] || max1[2 ] < min2[2 ])
15- return 0 ;
16- if (max2[0 ] < min1[0 ] || max2[1 ] < min1[1 ] || max2[2 ] < min1[2 ])
17- return 0 ;
18- return 1 ;
73+ assert (p.size () == B[0 ].size ());
74+
75+ bool inside = true ;
76+ double result = 0.0 ;
77+ for (int c = 0 ; c < p.size (); c++) {
78+ if (p[c] < B[0 ][c]) {
79+ inside = false ;
80+ result += std::pow (p[c] - B[0 ][c], 2 );
81+ } else if (p[c] > B[1 ][c]) {
82+ inside = false ;
83+ result += std::pow (p[c] - B[1 ][c], 2 );
84+ }
85+ }
86+ if (inside) {
87+ result = -inner_point_box_squared_distance (p, B);
88+ }
89+ return result;
1990 }
2091} // namespace
2192
2293void BVH::init_boxes_recursive (
23- const std::vector<std::array<Eigen::Vector3d , 2 >>& cornerlist,
94+ const std::vector<std::array<VectorMax3d , 2 >>& cornerlist,
2495 int node_index,
2596 int b,
2697 int e)
@@ -44,7 +115,7 @@ void BVH::init_boxes_recursive(
44115
45116 assert (childl < boxlist.size ());
46117 assert (childr < boxlist.size ());
47- for (int c = 0 ; c < 3 ; ++c) {
118+ for (int c = 0 ; c < cornerlist[ 0 ]. size () ; ++c) {
48119 boxlist[node_index][0 ][c] =
49120 std::min (boxlist[childl][0 ][c], boxlist[childr][0 ][c]);
50121 boxlist[node_index][1 ][c] =
@@ -53,8 +124,8 @@ void BVH::init_boxes_recursive(
53124}
54125
55126void BVH::box_search_recursive (
56- const Eigen::Vector3d & bbd0,
57- const Eigen::Vector3d & bbd1,
127+ const VectorMax3d & bbd0,
128+ const VectorMax3d & bbd1,
58129 std::vector<unsigned int >& list,
59130 int n,
60131 int b,
@@ -99,25 +170,25 @@ int BVH::max_node_index(int node_index, int b, int e)
99170 return std::max (max_node_index (childl, b, m), max_node_index (childr, m, e));
100171}
101172
102- void BVH::init (const std::vector<std::array<Eigen::Vector3d , 2 >>& cornerlist)
173+ void BVH::init (const std::vector<std::array<VectorMax3d , 2 >>& cornerlist)
103174{
104175 n_corners = cornerlist.size ();
105176
106- Eigen::MatrixXd box_centers (n_corners, 3 );
177+ Eigen::MatrixXd box_centers (n_corners, cornerlist[ 0 ][ 0 ]. size () );
107178 for (int i = 0 ; i < n_corners; ++i) {
108179 box_centers.row (i) = (cornerlist[i][0 ] + cornerlist[i][1 ]) / 2 ;
109180 }
110181
111- const Eigen::RowVector3d vmin = box_centers.colwise ().minCoeff ();
112- const Eigen::RowVector3d vmax = box_centers.colwise ().maxCoeff ();
113- const Eigen::RowVector3d center = (vmin + vmax) / 2 ;
182+ const VectorMax3d vmin = box_centers.colwise ().minCoeff ();
183+ const VectorMax3d vmax = box_centers.colwise ().maxCoeff ();
184+ const VectorMax3d center = (vmin + vmax) / 2 ;
114185 for (int i = 0 ; i < n_corners; i++) {
115186 // make box centered at origin
116187 box_centers.row (i) -= center;
117188 }
118189
119190 // after placing box at origin, vmax and vmin are symetric.
120- const Eigen::Vector3d scale_point = vmax - center;
191+ const VectorMax3d scale_point = vmax - center;
121192 const double scale = scale_point.lpNorm <Eigen::Infinity>();
122193 // if the box is too big, resize it
123194 if (scale > 100 ) {
@@ -135,8 +206,8 @@ void BVH::init(const std::vector<std::array<Eigen::Vector3d, 2>>& cornerlist)
135206 for (int i = 0 ; i < n_corners; i++) {
136207 const Eigen::MatrixXd tmp = box_centers.row (i) * multi;
137208
138- list[i].morton =
139- Resorting::MortonCode64 ( int (tmp (0 )), int (tmp (1 )), int (tmp (2 )));
209+ list[i].morton = Resorting::MortonCode64 (
210+ int (tmp (0 )), int (tmp (1 )), tmp. size () == 3 ? int (tmp (2 )) : 0 );
140211 list[i].order = i;
141212 }
142213
@@ -150,7 +221,7 @@ void BVH::init(const std::vector<std::array<Eigen::Vector3d, 2>>& cornerlist)
150221 new2old[i] = list[i].order ;
151222 }
152223
153- std::vector<std::array<Eigen::Vector3d , 2 >> sorted_cornerlist (n_corners);
224+ std::vector<std::array<VectorMax3d , 2 >> sorted_cornerlist (n_corners);
154225
155226 for (int i = 0 ; i < n_corners; i++) {
156227 sorted_cornerlist[i] = cornerlist[list[i].order ];
@@ -160,45 +231,151 @@ void BVH::init(const std::vector<std::array<Eigen::Vector3d, 2>>& cornerlist)
160231 max_node_index (1 , 0 , n_corners)
161232 + 1 // <-- this is because size == max_index + 1 !!!
162233 );
234+ for (auto & b : boxlist) {
235+ b[0 ].resize (cornerlist[0 ][0 ].size ());
236+ b[1 ].resize (cornerlist[0 ][0 ].size ());
237+ }
163238
164239 init_boxes_recursive (sorted_cornerlist, 1 , 0 , n_corners);
165240}
166241
167242void BVH::init (
168243 const Eigen::MatrixXd& V, const Eigen::MatrixXi& F, const double tol)
169244{
170- assert (F.cols () == 3 );
171- assert (V.cols () == 3 );
172-
173- std::vector<std::array<Eigen::Vector3d, 2 >> cornerlist (F.rows ());
174-
175- for (int i = 0 ; i < F.rows (); i++) {
176- const Eigen::RowVector3i face = F.row (i);
177- const Eigen::RowVector3d v0 = V.row (face (0 ));
178- const Eigen::RowVector3d v1 = V.row (face (1 ));
179- const Eigen::RowVector3d v2 = V.row (face (2 ));
180-
181- Eigen::Matrix3d tmp;
182- tmp.row (0 ) = v0;
183- tmp.row (1 ) = v1;
184- tmp.row (2 ) = v2;
185-
186- const Eigen::RowVector3d min = tmp.colwise ().minCoeff ().array () - tol;
187- const Eigen::RowVector3d max = tmp.colwise ().maxCoeff ().array () + tol;
188-
189- cornerlist[i][0 ] = min.transpose ();
190- cornerlist[i][1 ] = max.transpose ();
245+ assert (F.cols () == 3 || F.cols () == 2 );
246+ assert (V.cols () == 3 || V.cols () == 2 );
247+
248+ std::vector<std::array<VectorMax3d, 2 >> cornerlist (F.rows ());
249+ if (F.cols () == 3 ) {
250+ for (int i = 0 ; i < F.rows (); i++) {
251+ const Eigen::RowVector3i face = F.row (i);
252+ const VectorMax3d v0 = V.row (face (0 ));
253+ const VectorMax3d v1 = V.row (face (1 ));
254+ const VectorMax3d v2 = V.row (face (2 ));
255+
256+ Eigen::MatrixXd tmp (3 , v0.size ());
257+ tmp.row (0 ) = v0.transpose ();
258+ tmp.row (1 ) = v1.transpose ();
259+ tmp.row (2 ) = v2.transpose ();
260+
261+ const VectorMax3d min = tmp.colwise ().minCoeff ().array () - tol;
262+ const VectorMax3d max = tmp.colwise ().maxCoeff ().array () + tol;
263+
264+ cornerlist[i][0 ] = min.transpose ();
265+ cornerlist[i][1 ] = max.transpose ();
266+ }
267+ } else if (F.cols () == 2 ) {
268+ for (int i = 0 ; i < F.rows (); i++) {
269+ const Eigen::RowVector2i face = F.row (i);
270+ const VectorMax3d v0 = V.row (face (0 ));
271+ const VectorMax3d v1 = V.row (face (1 ));
272+
273+ Eigen::MatrixXd tmp (2 , v0.size ());
274+ tmp.row (0 ) = v0.transpose ();
275+ tmp.row (1 ) = v1.transpose ();
276+
277+ const VectorMax3d min = tmp.colwise ().minCoeff ().array () - tol;
278+ const VectorMax3d max = tmp.colwise ().maxCoeff ().array () + tol;
279+
280+ cornerlist[i][0 ] = min.transpose ();
281+ cornerlist[i][1 ] = max.transpose ();
282+ }
191283 }
192284
193285 init (cornerlist);
194286}
195287
196288bool BVH::box_intersects_box (
197- const Eigen::Vector3d & bbd0, const Eigen::Vector3d & bbd1, int index) const
289+ const VectorMax3d & bbd0, const VectorMax3d & bbd1, int index) const
198290{
199291 const auto & bmin = boxlist[index][0 ];
200292 const auto & bmax = boxlist[index][1 ];
201293
202294 return box_box_intersection (bbd0, bbd1, bmin, bmax);
203295}
296+
297+ void BVH::get_nearest_facet_hint (
298+ const VectorMax3d& p,
299+ int & nearest_f,
300+ VectorMax3d& nearest_point,
301+ double & sq_dist) const
302+ {
303+ int b = 0 ;
304+ int e = n_corners;
305+ int n = 1 ;
306+ while (e != b + 1 ) {
307+ int m = b + (e - b) / 2 ;
308+ int childl = 2 * n;
309+ int childr = 2 * n + 1 ;
310+ if (point_box_center_squared_distance (p, boxlist[childl])
311+ < point_box_center_squared_distance (p, boxlist[childr])) {
312+ e = m;
313+ n = childl;
314+ } else {
315+ b = m;
316+ n = childr;
317+ }
318+ }
319+ nearest_f = b;
320+
321+ nearest_point = getPoint (nearest_f);
322+ sq_dist = (p - nearest_point).norm ();
323+ }
324+
325+ void BVH::nearest_facet_recursive (
326+ const VectorMax3d& p,
327+ int & nearest_f,
328+ VectorMax3d& nearest_point,
329+ double & sq_dist,
330+ int n,
331+ int b,
332+ int e) const
333+ {
334+ assert (e > b);
335+
336+ // If node is a leaf: compute point-facet distance
337+ // and replace current if nearer
338+ if (b + 1 == e) {
339+ VectorMax3d cur_nearest_point;
340+ double cur_sq_dist;
341+ leafCallback (p, new2old[b], cur_nearest_point, cur_sq_dist);
342+ if (cur_sq_dist < sq_dist) {
343+ nearest_f = b;
344+ nearest_point = cur_nearest_point;
345+ sq_dist = cur_sq_dist;
346+ }
347+ return ;
348+ }
349+ int m = b + (e - b) / 2 ;
350+ int childl = 2 * n;
351+ int childr = 2 * n + 1 ;
352+
353+ assert (childl < boxlist.size ());
354+ assert (childr < boxlist.size ());
355+
356+ double dl = point_box_signed_squared_distance (p, boxlist[childl]);
357+ double dr = point_box_signed_squared_distance (p, boxlist[childr]);
358+
359+ // Traverse the "nearest" child first, so that it has more chances
360+ // to prune the traversal of the other child.
361+ if (dl < dr) {
362+ if (dl < sq_dist) {
363+ nearest_facet_recursive (
364+ p, nearest_f, nearest_point, sq_dist, childl, b, m);
365+ }
366+ if (dr < sq_dist) {
367+ nearest_facet_recursive (
368+ p, nearest_f, nearest_point, sq_dist, childr, m, e);
369+ }
370+ } else {
371+ if (dr < sq_dist) {
372+ nearest_facet_recursive (
373+ p, nearest_f, nearest_point, sq_dist, childr, m, e);
374+ }
375+ if (dl < sq_dist) {
376+ nearest_facet_recursive (
377+ p, nearest_f, nearest_point, sq_dist, childl, b, m);
378+ }
379+ }
380+ }
204381} // namespace SimpleBVH
0 commit comments