Skip to content

Commit a2a1fa9

Browse files
authored
Merge pull request #6 from radevgit/merge_close_edpoints
Opt 11 - find_endpoint_groups with spatial index
2 parents 9f0a8bc + 498f1fc commit a2a1fa9

File tree

6 files changed

+63
-28
lines changed

6 files changed

+63
-28
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## [0.5.5] - 2025-11-01
4+
- Opt 11 - find_endpoint_groups with spatial index (20% - 40%)
5+
36
## [0.5.4] - 2025-11-01
47
- Opt 10 - using aabb presplit check (29%)
58

Cargo.lock

Lines changed: 6 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

benches/bench_offset_multiple1000.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,11 @@ Total time for 50 offset operations: 3.936534119s
6161
Average time per operation: 78.730682ms
6262
Operations per second: 12.7
6363
_________________________________________________________
64+
Opt 11 - find_endpoint_groups with spatial index (40%)
65+
Total time for 50 offset operations: 2.359176736s
66+
Average time per operation: 47.183534ms
67+
Operations per second: 21.2
68+
_________________________________________________________
69+
6470
6571
*/

benches/bench_offset_multiple200.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ Total time for 1980 offset operations: 8.593364565s
7676
Average time per operation: 4.340083ms
7777
Operations per second: 230.4
7878
__________________________________________________________
79-
80-
79+
Opt 11 - find_endpoint_groups with spatial index (29%)
80+
Total time for 1980 offset operations: 6.082281414s
81+
Average time per operation: 3.071859ms
82+
Operations per second: 325.5
83+
__________________________________________________________
8184
*/

benches/bench_offset_multiple500.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,10 @@ Total time for 198 offset operations: 3.054654626s
6161
Average time per operation: 15.427548ms
6262
Operations per second: 64.8
6363
_______________________________________________________________
64+
Opt 11 - find_endpoint_groups with spatial index
65+
Total time for 198 offset operations: 2.298718087s
66+
Average time per operation: 11.609687ms
67+
Operations per second: 86.1
68+
_______________________________________________________________
6469
6570
*/

src/graph/merge_ends.rs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ fn find_endpoint_groups(arcs: &[Arc], tolerance: f64) -> Vec<EndpointGroup> {
6363
all_endpoints.push((arc.b, arc_idx, EndpointType::End));
6464
}
6565

66+
if all_endpoints.is_empty() {
67+
return Vec::new();
68+
}
69+
70+
// Build spatial index of all endpoints
71+
let mut spatial_index = HilbertRTree::with_capacity(all_endpoints.len());
72+
for (point, _, _) in &all_endpoints {
73+
spatial_index.add_point(point.x, point.y);
74+
}
75+
spatial_index.build();
76+
6677
let mut groups = Vec::new();
6778
let mut used = vec![false; all_endpoints.len()];
6879

@@ -84,25 +95,38 @@ fn find_endpoint_groups(arcs: &[Arc], tolerance: f64) -> Vec<EndpointGroup> {
8495
group.arc_indices.push((arc_i, end_type_i));
8596
used[i] = true;
8697

87-
// Find all points within tolerance of any point in the current group
88-
let mut changed = true;
89-
while changed {
90-
changed = false;
91-
for j in 0..all_endpoints.len() {
92-
if used[j] {
98+
// Find all points within tolerance using spatial index (iterative expansion)
99+
let mut queue = vec![point_i];
100+
101+
while !queue.is_empty() {
102+
let current_point = queue.pop().unwrap();
103+
104+
// Query spatial index for points within tolerance of current_point
105+
let mut nearby_indices = Vec::new();
106+
spatial_index.query_circle(
107+
current_point.x,
108+
current_point.y,
109+
tolerance,
110+
&mut nearby_indices,
111+
);
112+
113+
// Process each nearby point
114+
for idx in nearby_indices {
115+
if used[idx] {
93116
continue;
94117
}
95118

96-
let (point_j, arc_j, end_type_j) = all_endpoints[j];
97-
98-
// Check if point_j is close to any point in the current group
99-
for &group_point in &group.points {
100-
if (point_j - group_point).norm() <= tolerance {
119+
// Get the actual point data from spatial index
120+
if let Some((x, y)) = spatial_index.get_point(idx) {
121+
let point_j = Point::new(x, y);
122+
let (_, arc_j, end_type_j) = all_endpoints[idx];
123+
124+
// Verify actual distance (spatial index may be approximate)
125+
if (point_j - current_point).norm() <= tolerance {
101126
group.points.push(point_j);
102127
group.arc_indices.push((arc_j, end_type_j));
103-
used[j] = true;
104-
changed = true;
105-
break;
128+
used[idx] = true;
129+
queue.push(point_j); // Add to queue for further expansion
106130
}
107131
}
108132
}

0 commit comments

Comments
 (0)