@@ -14,6 +14,133 @@ public DMeshAABBTree3(DMesh3 m)
14
14
}
15
15
16
16
17
+
18
+
19
+ public void Build ( )
20
+ {
21
+ build_by_one_rings ( ) ;
22
+ }
23
+
24
+
25
+
26
+
27
+ public int FindNearestTriangle ( Vector3d p )
28
+ {
29
+ double fNearestSqr = double . MaxValue ;
30
+ int tNearID = - 1 ;
31
+ find_nearest_tri ( root_index , p , ref fNearestSqr , ref tNearID ) ;
32
+ return tNearID ;
33
+ }
34
+ void find_nearest_tri ( int iBox , Vector3d p , ref double fNearestSqr , ref int tID )
35
+ {
36
+ int idx = box_to_index [ iBox ] ;
37
+ if ( idx < triangles_end ) { // triange-list case, array is [N t1 t2 ... tN]
38
+ int num_tris = index_list [ idx ] ;
39
+ for ( int i = 1 ; i <= num_tris ; ++ i ) {
40
+ int ti = index_list [ idx + i ] ;
41
+ double fTriDistSqr = MeshQueries . TriDistanceSqr ( mesh , ti , p ) ;
42
+ if ( fTriDistSqr < fNearestSqr ) {
43
+ fNearestSqr = fTriDistSqr ;
44
+ tID = ti ;
45
+ }
46
+ }
47
+
48
+ } else { // internal node, either 1 or 2 child boxes
49
+ int iChild1 = index_list [ idx ] ;
50
+ if ( iChild1 < 0 ) { // 1 child, descend if nearer than cur min-dist
51
+ iChild1 = ( - iChild1 ) - 1 ;
52
+ double fChild1DistSqr = box_distance_sqr ( iChild1 , p ) ;
53
+ if ( fChild1DistSqr <= fNearestSqr )
54
+ find_nearest_tri ( iChild1 , p , ref fNearestSqr , ref tID ) ;
55
+
56
+ } else { // 2 children, descend closest first
57
+ iChild1 = iChild1 - 1 ;
58
+ int iChild2 = index_list [ idx + 1 ] - 1 ;
59
+
60
+ double fChild1DistSqr = box_distance_sqr ( iChild1 , p ) ;
61
+ double fChild2DistSqr = box_distance_sqr ( iChild2 , p ) ;
62
+ if ( fChild1DistSqr < fChild2DistSqr ) {
63
+ if ( fChild1DistSqr < fNearestSqr ) {
64
+ find_nearest_tri ( iChild1 , p , ref fNearestSqr , ref tID ) ;
65
+ if ( fChild2DistSqr < fNearestSqr )
66
+ find_nearest_tri ( iChild2 , p , ref fNearestSqr , ref tID ) ;
67
+ }
68
+ } else {
69
+ if ( fChild2DistSqr < fNearestSqr ) {
70
+ find_nearest_tri ( iChild2 , p , ref fNearestSqr , ref tID ) ;
71
+ if ( fChild1DistSqr < fNearestSqr )
72
+ find_nearest_tri ( iChild1 , p , ref fNearestSqr , ref tID ) ;
73
+ }
74
+ }
75
+
76
+ }
77
+ }
78
+ }
79
+
80
+
81
+
82
+
83
+
84
+
85
+ // DoTraversal function will walk through tree and call NextBoxF for each
86
+ // internal box node, and NextTriangleF for each triangle.
87
+ // You can prune branches by returning false from NextBoxF
88
+ public class TreeTraversal
89
+ {
90
+ // return false to terminate this branch
91
+ public Func < AxisAlignedBox3f , bool > NextBoxF = ( x ) => { return true ; } ;
92
+
93
+ public Action < int > NextTriangleF = ( tID ) => { } ;
94
+ }
95
+
96
+
97
+ // walk over tree, calling functions in TreeTraversal object for internal nodes and triangles
98
+ public void DoTraversal ( TreeTraversal traversal )
99
+ {
100
+ tree_traversal ( root_index , traversal ) ;
101
+ }
102
+
103
+ // traversal implementation
104
+ private void tree_traversal ( int iBox , TreeTraversal traversal )
105
+ {
106
+ int idx = box_to_index [ iBox ] ;
107
+
108
+ if ( idx < triangles_end ) {
109
+ // triange-list case, array is [N t1 t2 ... tN]
110
+ int n = index_list [ idx ] ;
111
+ for ( int i = 1 ; i <= n ; ++ i ) {
112
+ int ti = index_list [ idx + i ] ;
113
+ traversal . NextTriangleF ( ti ) ;
114
+ }
115
+ } else {
116
+ int i0 = index_list [ idx ] ;
117
+ if ( i0 < 0 ) {
118
+ // negative index means we only have one 'child' box to descend into
119
+ i0 = ( - i0 ) - 1 ;
120
+ if ( traversal . NextBoxF ( get_box ( i0 ) ) )
121
+ tree_traversal ( i0 , traversal ) ;
122
+ } else {
123
+ // positive index, two sequential child box indices to descend into
124
+ i0 = i0 - 1 ;
125
+ if ( traversal . NextBoxF ( get_box ( i0 ) ) )
126
+ tree_traversal ( i0 , traversal ) ;
127
+ int i1 = index_list [ idx + 1 ] - 1 ;
128
+ if ( traversal . NextBoxF ( get_box ( i1 ) ) )
129
+ tree_traversal ( i0 , traversal ) ;
130
+ }
131
+ }
132
+ }
133
+
134
+
135
+
136
+
137
+ //
138
+ // Internals - data structures, construction, etc
139
+ //
140
+
141
+
142
+
143
+
17
144
// storage for box nodes.
18
145
// - box_to_index is a pointer into index_list
19
146
// - box_centers and box_extents are the centers/extents of the bounding boxes
@@ -50,7 +177,7 @@ public DMeshAABBTree3(DMesh3 m)
50
177
// 1b) second pass where we handle any missed tris
51
178
// 2) sequentially combine N leaf boxes into (N/2 + N%2) layer 2 boxes
52
179
// 3) repeat until layer K has only 1 box, which is root of tree
53
- public void BuildByOneRings ( )
180
+ void build_by_one_rings ( )
54
181
{
55
182
box_to_index = new DVector < int > ( ) ;
56
183
box_centers = new DVector < Vector3f > ( ) ;
@@ -120,7 +247,7 @@ public void BuildByOneRings()
120
247
// Appends a box that contains free triangles in one-ring of vertex vid.
121
248
// If tri count is < spill threshold, push onto spill list instead.
122
249
// Returns # of free tris found.
123
- public int add_one_ring_box ( int vid , byte [ ] used_triangles , int [ ] temp_tris ,
250
+ int add_one_ring_box ( int vid , byte [ ] used_triangles , int [ ] temp_tris ,
124
251
ref int iBoxCur , ref int iIndicesCur ,
125
252
DVector < int > spill , int nSpillThresh )
126
253
{
@@ -167,7 +294,7 @@ public int add_one_ring_box(int vid, byte[] used_triangles, int[] temp_tris,
167
294
// Except, of course, if N is odd, then we get N/2+1, where the +1
168
295
// box has a single child box (ie just a copy).
169
296
// [TODO] instead merge that extra box into on of parents? Reduces tree depth by 1
170
- public int cluster_boxes ( int iStart , int iCount , ref int iBoxCur , ref int iIndicesCur )
297
+ int cluster_boxes ( int iStart , int iCount , ref int iBoxCur , ref int iIndicesCur )
171
298
{
172
299
int [ ] indices = new int [ iCount ] ;
173
300
for ( int i = 0 ; i < iCount ; ++ i )
@@ -200,7 +327,7 @@ public int cluster_boxes(int iStart, int iCount, ref int iBoxCur, ref int iIndic
200
327
index_list . insert ( i1 + 1 , iIndicesCur ++ ) ;
201
328
202
329
box_centers . insert ( center , iBox ) ;
203
- box_extents . insert ( center , iBox ) ;
330
+ box_extents . insert ( extent , iBox ) ;
204
331
}
205
332
206
333
// [todo] could we merge with last other box? need a way to tell
@@ -231,7 +358,7 @@ public int cluster_boxes(int iStart, int iCount, ref int iBoxCur, ref int iIndic
231
358
232
359
233
360
// construct box that contains two boxes
234
- public void get_combined_box ( int b0 , int b1 , out Vector3f center , out Vector3f extent )
361
+ void get_combined_box ( int b0 , int b1 , out Vector3f center , out Vector3f extent )
235
362
{
236
363
Vector3f c0 = box_centers [ b0 ] ;
237
364
Vector3f e0 = box_extents [ b0 ] ;
@@ -250,7 +377,7 @@ public void get_combined_box(int b0, int b1, out Vector3f center, out Vector3f e
250
377
}
251
378
252
379
253
- public AxisAlignedBox3f get_box ( int iBox )
380
+ AxisAlignedBox3f get_box ( int iBox )
254
381
{
255
382
Vector3f c = box_centers [ iBox ] ;
256
383
Vector3f e = box_extents [ iBox ] ;
@@ -261,10 +388,21 @@ public AxisAlignedBox3f get_box(int iBox)
261
388
262
389
263
390
391
+ double box_distance_sqr ( int iBox , Vector3d p )
392
+ {
393
+ Vector3d c = box_centers [ iBox ] ;
394
+ Vector3d e = box_extents [ iBox ] ;
395
+ AxisAlignedBox3d box = new AxisAlignedBox3d ( c - e , c + e ) ;
396
+ return box . DistanceSquared ( p ) ;
397
+ }
398
+
399
+
400
+
264
401
265
402
266
403
267
- // make sure we can reach every tri in mesh through tree (also demo of how to traverse tree...)
404
+ // 1) make sure we can reach every tri in mesh through tree (also demo of how to traverse tree...)
405
+ // 2) make sure that triangles are contained in parent boxes
268
406
public void TestCoverage ( )
269
407
{
270
408
int [ ] tri_counts = new int [ mesh . MaxTriangleID ] ;
@@ -278,14 +416,19 @@ public void TestCoverage()
278
416
if ( tri_counts [ ti ] != 1 )
279
417
Util . gBreakToDebugger ( ) ;
280
418
}
281
- private void test_coverage ( int [ ] tri_counts , int [ ] parent_indices , int iCur )
419
+
420
+ // accumulate triangle counts and track each box-parent index.
421
+ // also checks that triangles are contained in boxes
422
+ private void test_coverage ( int [ ] tri_counts , int [ ] parent_indices , int iBox )
282
423
{
283
- int idx = box_to_index [ iCur ] ;
424
+ int idx = box_to_index [ iBox ] ;
425
+
426
+ debug_check_child_tris_in_box ( iBox ) ;
284
427
285
428
if ( idx < triangles_end ) {
286
429
// triange-list case, array is [N t1 t2 ... tN]
287
430
int n = index_list [ idx ] ;
288
- AxisAlignedBox3f box = get_box ( iCur ) ;
431
+ AxisAlignedBox3f box = get_box ( iBox ) ;
289
432
for ( int i = 1 ; i <= n ; ++ i ) {
290
433
int ti = index_list [ idx + i ] ;
291
434
tri_counts [ ti ] ++ ;
@@ -303,21 +446,53 @@ private void test_coverage(int[] tri_counts, int[] parent_indices, int iCur)
303
446
if ( i0 < 0 ) {
304
447
// negative index means we only have one 'child' box to descend into
305
448
i0 = ( - i0 ) - 1 ;
306
- parent_indices [ i0 ] = iCur ;
449
+ parent_indices [ i0 ] = iBox ;
307
450
test_coverage ( tri_counts , parent_indices , i0 ) ;
308
451
} else {
309
452
// positive index, two sequential child box indices to descend into
310
453
i0 = i0 - 1 ;
311
- parent_indices [ i0 ] = iCur ;
454
+ parent_indices [ i0 ] = iBox ;
312
455
test_coverage ( tri_counts , parent_indices , i0 ) ;
313
456
int i1 = index_list [ idx + 1 ] ;
314
457
i1 = i1 - 1 ;
315
- parent_indices [ i1 ] = iCur ;
458
+ parent_indices [ i1 ] = iBox ;
316
459
test_coverage ( tri_counts , parent_indices , i1 ) ;
317
460
}
318
461
}
319
462
}
463
+ // do full tree traversal below iBox and make sure that all triangles are further
464
+ // than box-distance-sqr
465
+ void debug_check_child_tri_distances ( int iBox , Vector3d p )
466
+ {
467
+ double fBoxDistSqr = box_distance_sqr ( iBox , p ) ;
468
+
469
+ TreeTraversal t = new TreeTraversal ( ) {
470
+ NextTriangleF = ( tID ) => {
471
+ double fTriDistSqr = MeshQueries . TriDistanceSqr ( mesh , tID , p ) ;
472
+ if ( fTriDistSqr < fBoxDistSqr )
473
+ if ( Math . Abs ( fTriDistSqr - fBoxDistSqr ) > MathUtil . ZeroTolerance * 100 )
474
+ Util . gBreakToDebugger ( ) ;
475
+ }
476
+ } ;
477
+ tree_traversal ( iBox , t ) ;
478
+ }
320
479
480
+ // do full tree traversal below iBox to make sure that all child triangles are contained
481
+ void debug_check_child_tris_in_box ( int iBox )
482
+ {
483
+ AxisAlignedBox3f box = get_box ( iBox ) ;
484
+ TreeTraversal t = new TreeTraversal ( ) {
485
+ NextTriangleF = ( tID ) => {
486
+ Index3i tv = mesh . GetTriangle ( tID ) ;
487
+ for ( int j = 0 ; j < 3 ; ++ j ) {
488
+ Vector3f v = ( Vector3f ) mesh . GetVertex ( tv [ j ] ) ;
489
+ if ( box . Contains ( v ) == false )
490
+ Util . gBreakToDebugger ( ) ;
491
+ }
492
+ }
493
+ } ;
494
+ tree_traversal ( iBox , t ) ;
495
+ }
321
496
322
497
323
498
0 commit comments