11use super :: Error ;
22use crate :: geometry:: OrientedBoundingBox ;
33use crate :: geometry:: PointND ;
4+ use crate :: BoundingBox ;
45use nalgebra:: allocator:: Allocator ;
56use nalgebra:: ArrayStorage ;
67use nalgebra:: Const ;
@@ -25,17 +26,30 @@ struct Item<'p, const D: usize, W> {
2526 part : & ' p AtomicUsize ,
2627}
2728
29+ /// Return value of [rcb_split].
30+ struct SplitResult < W > {
31+ /// Index of the first item in the right part in the array of [Item]s.
32+ split_idx : usize ,
33+ /// Weight of the left part, used to compute the sum for the next iteration.
34+ weight_left : W ,
35+ /// Coordinate value of the split, used to compute the [BoundingBox]es.
36+ split_pos : f64 ,
37+ }
38+
2839fn rcb_split < const D : usize , W > (
2940 items : & mut [ Item < D , W > ] ,
3041 coord : usize ,
3142 tolerance : f64 ,
3243 mut min : f64 ,
3344 mut max : f64 ,
3445 sum : W ,
35- ) -> usize
46+ ) -> SplitResult < W >
3647where
3748 W : RcbWeight ,
3849{
50+ let span = tracing:: info_span!( "rcb_split" ) ;
51+ let _enter = span. enter ( ) ;
52+
3953 let mut prev_count_left = usize:: MAX ;
4054 loop {
4155 let split_target = ( min + max) / 2.0 ;
5771 f64:: abs ( ( weight_left - ideal_weight_left) / ideal_weight_left)
5872 } ;
5973 if count_left == prev_count_left || imbalance < tolerance {
60- return count_left;
74+ return SplitResult {
75+ split_idx : count_left,
76+ weight_left,
77+ split_pos : split_target,
78+ } ;
6179 }
6280 prev_count_left = count_left;
6381
@@ -76,6 +94,8 @@ fn rcb_recurse<const D: usize, W>(
7694 iter_id : usize ,
7795 coord : usize ,
7896 tolerance : f64 ,
97+ sum : W ,
98+ bb : BoundingBox < D > ,
7999) where
80100 W : RcbWeight ,
81101{
@@ -84,33 +104,35 @@ fn rcb_recurse<const D: usize, W>(
84104 return ;
85105 }
86106 if iter_count == 0 {
107+ let span = tracing:: info_span!(
108+ "rcb_recurse: apply_part_id" ,
109+ item_count = items. len( ) ,
110+ iter_id,
111+ ) ;
112+ let _enter = span. enter ( ) ;
113+
87114 items
88115 . into_par_iter ( )
89116 . for_each ( |item| item. part . store ( iter_id, Ordering :: Relaxed ) ) ;
90117 return ;
91118 }
92119
93- let sum: W = items. par_iter ( ) . map ( |item| item. weight ) . sum ( ) ;
94- let ( min, max) = items
95- . par_iter ( )
96- . fold (
97- || ( f64:: INFINITY , f64:: NEG_INFINITY ) ,
98- |( min, max) , item| {
99- (
100- f64:: min ( min, item. point [ coord] ) ,
101- f64:: max ( max, item. point [ coord] ) ,
102- )
103- } ,
104- )
105- . reduce (
106- || ( f64:: INFINITY , f64:: NEG_INFINITY ) ,
107- |( min0, max0) , ( min1, max1) | ( f64:: min ( min0, min1) , f64:: max ( max0, max1) ) ,
108- ) ;
120+ let span = tracing:: info_span!( "rcb_recurse" ) ;
121+ let enter = span. enter ( ) ;
109122
110- let split_idx = rcb_split ( items, coord, tolerance, min, max, sum) ;
123+ let min = bb. p_min [ coord] ;
124+ let max = bb. p_max [ coord] ;
125+ let SplitResult {
126+ split_idx,
127+ weight_left,
128+ split_pos,
129+ } = rcb_split ( items, coord, tolerance, min, max, sum) ;
111130 let ( left, right) = if split_idx == items. len ( ) {
112131 items. split_at_mut ( items. len ( ) )
113132 } else {
133+ let span = tracing:: info_span!( "select_nth_unstable" ) ;
134+ let _enter = span. enter ( ) ;
135+
114136 let ( left, _, _right_minus_one) = items
115137 . select_nth_unstable_by ( split_idx, |item1, item2| {
116138 f64:: partial_cmp ( & item1. point [ coord] , & item2. point [ coord] ) . unwrap ( )
@@ -119,6 +141,13 @@ fn rcb_recurse<const D: usize, W>(
119141 items. split_at_mut ( left_len)
120142 } ;
121143
144+ let mut bb_left = bb. clone ( ) ;
145+ bb_left. p_max [ coord] = split_pos;
146+ let mut bb_right = bb;
147+ bb_right. p_min [ coord] = split_pos;
148+
149+ mem:: drop ( enter) ;
150+
122151 rayon:: join (
123152 || {
124153 rcb_recurse (
@@ -127,6 +156,8 @@ fn rcb_recurse<const D: usize, W>(
127156 2 * iter_id + 1 ,
128157 ( coord + 1 ) % D ,
129158 tolerance,
159+ weight_left,
160+ bb_left,
130161 )
131162 } ,
132163 || {
@@ -136,6 +167,8 @@ fn rcb_recurse<const D: usize, W>(
136167 2 * iter_id + 2 ,
137168 ( coord + 1 ) % D ,
138169 tolerance,
170+ sum - weight_left,
171+ bb_right,
139172 )
140173 } ,
141174 ) ;
@@ -171,7 +204,7 @@ where
171204 } ) ;
172205 }
173206 if partition. is_empty ( ) {
174- // Would make the partition.min() at the end panic.
207+ // Would make BoundingBox::from_points and partition.min() panic.
175208 return Ok ( ( ) ) ;
176209 }
177210
@@ -184,9 +217,12 @@ where
184217 part,
185218 } )
186219 . collect ( ) ;
220+ let sum = items. par_iter ( ) . map ( |item| item. weight ) . sum ( ) ;
221+ let bb = BoundingBox :: from_points ( items. par_iter ( ) . map ( |item| item. point ) ) . unwrap ( ) ;
187222
188- rcb_recurse ( & mut items, iter_count, 0 , 0 , tolerance) ;
223+ rcb_recurse ( & mut items, iter_count, 0 , 0 , tolerance, sum , bb ) ;
189224
225+ // Part IDs must start from zero.
190226 let part_id_offset = * partition. par_iter ( ) . min ( ) . unwrap ( ) ;
191227 partition
192228 . par_iter_mut ( )
0 commit comments