11#![ allow( dead_code) ]
22
33use togo:: prelude:: * ;
4+ use togo:: spatial:: HilbertRTree ;
45
56use crate :: offsetraw:: OffsetRaw ;
67
78// Prune arcs that are close to any of the arcs in the polyline.
89const PRUNE_EPSILON : f64 = 1e-8 ;
10+
11+ // Set to true to use brute-force algorithm (for testing/comparison)
12+ const USE_BRUTE_FORCE : bool = false ;
13+
914pub fn offset_prune_invalid (
1015 polyraws : & Vec < Vec < OffsetRaw > > ,
1116 offsets : & mut Vec < Arc > ,
1217 off : f64 ,
18+ ) -> Vec < Arc > {
19+ if USE_BRUTE_FORCE {
20+ offset_prune_invalid_brute_force ( polyraws, offsets, off)
21+ } else {
22+ offset_prune_invalid_spatial ( polyraws, offsets, off)
23+ }
24+ }
25+
26+ fn offset_prune_invalid_spatial (
27+ polyraws : & Vec < Vec < OffsetRaw > > ,
28+ offsets : & mut Vec < Arc > ,
29+ off : f64 ,
30+ ) -> Vec < Arc > {
31+ let mut valid = Vec :: new ( ) ;
32+ let polyarcs: Vec < Arc > = polyraws
33+ . iter ( )
34+ . flatten ( )
35+ . map ( |offset_raw| offset_raw. arc . clone ( ) )
36+ . filter ( |arc| arc. is_valid ( PRUNE_EPSILON ) )
37+ . collect ( ) ;
38+
39+ // Build spatial index containing both polyarcs and offsets
40+ let polyarc_count = polyarcs. len ( ) ;
41+ let mut spatial_index = HilbertRTree :: with_capacity ( polyarc_count + offsets. len ( ) ) ;
42+
43+ // Add polyarcs to index with offset + epsilon expansion (done once)
44+ let search_radius = off + PRUNE_EPSILON ;
45+ for arc in polyarcs. iter ( ) {
46+ let ( min_x, max_x, min_y, max_y) = arc_bounds_expanded ( arc, search_radius) ;
47+ spatial_index. add ( min_x, max_x, min_y, max_y) ;
48+ }
49+
50+ // Add offsets to index
51+ for arc in offsets. iter ( ) {
52+ let ( min_x, max_x, min_y, max_y) = arc_bounds ( arc) ;
53+ spatial_index. add ( min_x, max_x, min_y, max_y) ;
54+ }
55+
56+ spatial_index. build ( ) ;
57+
58+ while offsets. len ( ) > 0 {
59+ let offset = offsets. pop ( ) . unwrap ( ) ;
60+ valid. push ( offset. clone ( ) ) ;
61+
62+ // Query nearby arcs using spatial index
63+ let ( offset_min_x, offset_max_x, offset_min_y, offset_max_y) =
64+ arc_bounds ( & offset) ;
65+ let mut nearby_indices = Vec :: new ( ) ;
66+ spatial_index. query_intersecting (
67+ offset_min_x,
68+ offset_max_x,
69+ offset_min_y,
70+ offset_max_y,
71+ & mut nearby_indices,
72+ ) ;
73+
74+ // Check only nearby polyarcs for actual distance
75+ for idx in nearby_indices {
76+ if idx < polyarc_count {
77+ let p = & polyarcs[ idx] ;
78+ if p. id == offset. id {
79+ continue ; // skip self offsets
80+ }
81+ let dist = distance_element_element ( p, & offset) ;
82+ if dist < off - PRUNE_EPSILON {
83+ valid. pop ( ) ;
84+ break ;
85+ }
86+ }
87+ }
88+ }
89+ valid
90+ }
91+
92+ fn offset_prune_invalid_brute_force (
93+ polyraws : & Vec < Vec < OffsetRaw > > ,
94+ offsets : & mut Vec < Arc > ,
95+ off : f64 ,
1396) -> Vec < Arc > {
1497 let mut valid = Vec :: new ( ) ;
1598 let polyarcs: Vec < Arc > = polyraws
@@ -18,14 +101,13 @@ pub fn offset_prune_invalid(
18101 . map ( |offset_raw| offset_raw. arc . clone ( ) )
19102 . filter ( |arc| arc. is_valid ( PRUNE_EPSILON ) )
20103 . collect ( ) ;
21- let _zzz = polyarcs. len ( ) ;
22104
23105 while offsets. len ( ) > 0 {
24106 let offset = offsets. pop ( ) . unwrap ( ) ;
25107 valid. push ( offset. clone ( ) ) ;
26108 for p in polyarcs. iter ( ) {
27109 if p. id == offset. id {
28- continue ; // skip self ofsets
110+ continue ; // skip self offsets
29111 }
30112 let dist = distance_element_element ( & p, & offset) ;
31113 if dist < off - PRUNE_EPSILON {
@@ -37,6 +119,35 @@ pub fn offset_prune_invalid(
37119 valid
38120}
39121
122+ /// Get bounding box of an arc
123+ fn arc_bounds ( arc : & Arc ) -> ( f64 , f64 , f64 , f64 ) {
124+ if arc. is_seg ( ) {
125+ // For line segments, just return min/max of endpoints
126+ let min_x = arc. a . x . min ( arc. b . x ) ;
127+ let max_x = arc. a . x . max ( arc. b . x ) ;
128+ let min_y = arc. a . y . min ( arc. b . y ) ;
129+ let max_y = arc. a . y . max ( arc. b . y ) ;
130+ ( min_x, max_x, min_y, max_y)
131+ } else {
132+ // For arcs, return the bounding box of the circle (center ± radius)
133+ let cx = arc. c . x ;
134+ let cy = arc. c . y ;
135+ let r = arc. r ;
136+ ( cx - r, cx + r, cy - r, cy + r)
137+ }
138+ }
139+
140+ /// Get expanded bounding box of an arc (for spatial queries)
141+ fn arc_bounds_expanded ( arc : & Arc , expansion : f64 ) -> ( f64 , f64 , f64 , f64 ) {
142+ let ( min_x, max_x, min_y, max_y) = arc_bounds ( arc) ;
143+ (
144+ min_x - expansion,
145+ max_x + expansion,
146+ min_y - expansion,
147+ max_y + expansion,
148+ )
149+ }
150+
40151fn distance_element_element ( seg0 : & Arc , seg1 : & Arc ) -> f64 {
41152 let mut dist = std:: f64:: INFINITY ;
42153 if seg0. is_seg ( ) && seg1. is_seg ( ) {
0 commit comments