Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## [0.5.5] - 2025-11-01
- Opt 11 - find_endpoint_groups with spatial index (20% - 40%)

## [0.5.4] - 2025-11-01
- Opt 10 - using aabb presplit check (29%)

Expand Down
18 changes: 6 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions benches/bench_offset_multiple1000.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,11 @@ Total time for 50 offset operations: 3.936534119s
Average time per operation: 78.730682ms
Operations per second: 12.7
_________________________________________________________
Opt 11 - find_endpoint_groups with spatial index (40%)
Total time for 50 offset operations: 2.359176736s
Average time per operation: 47.183534ms
Operations per second: 21.2
_________________________________________________________


*/
7 changes: 5 additions & 2 deletions benches/bench_offset_multiple200.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ Total time for 1980 offset operations: 8.593364565s
Average time per operation: 4.340083ms
Operations per second: 230.4
__________________________________________________________


Opt 11 - find_endpoint_groups with spatial index (29%)
Total time for 1980 offset operations: 6.082281414s
Average time per operation: 3.071859ms
Operations per second: 325.5
__________________________________________________________
*/
5 changes: 5 additions & 0 deletions benches/bench_offset_multiple500.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,10 @@ Total time for 198 offset operations: 3.054654626s
Average time per operation: 15.427548ms
Operations per second: 64.8
_______________________________________________________________
Opt 11 - find_endpoint_groups with spatial index
Total time for 198 offset operations: 2.298718087s
Average time per operation: 11.609687ms
Operations per second: 86.1
_______________________________________________________________

*/
52 changes: 38 additions & 14 deletions src/graph/merge_ends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ fn find_endpoint_groups(arcs: &[Arc], tolerance: f64) -> Vec<EndpointGroup> {
all_endpoints.push((arc.b, arc_idx, EndpointType::End));
}

if all_endpoints.is_empty() {
return Vec::new();
}

// Build spatial index of all endpoints
let mut spatial_index = HilbertRTree::with_capacity(all_endpoints.len());
for (point, _, _) in &all_endpoints {
spatial_index.add_point(point.x, point.y);
}
spatial_index.build();

let mut groups = Vec::new();
let mut used = vec![false; all_endpoints.len()];

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

// Find all points within tolerance of any point in the current group
let mut changed = true;
while changed {
changed = false;
for j in 0..all_endpoints.len() {
if used[j] {
// Find all points within tolerance using spatial index (iterative expansion)
let mut queue = vec![point_i];

while !queue.is_empty() {
let current_point = queue.pop().unwrap();

// Query spatial index for points within tolerance of current_point
let mut nearby_indices = Vec::new();
spatial_index.query_circle(
current_point.x,
current_point.y,
tolerance,
&mut nearby_indices,
);

// Process each nearby point
for idx in nearby_indices {
if used[idx] {
continue;
}

let (point_j, arc_j, end_type_j) = all_endpoints[j];

// Check if point_j is close to any point in the current group
for &group_point in &group.points {
if (point_j - group_point).norm() <= tolerance {
// Get the actual point data from spatial index
if let Some((x, y)) = spatial_index.get_point(idx) {
let point_j = Point::new(x, y);
let (_, arc_j, end_type_j) = all_endpoints[idx];

// Verify actual distance (spatial index may be approximate)
if (point_j - current_point).norm() <= tolerance {
group.points.push(point_j);
group.arc_indices.push((arc_j, end_type_j));
used[j] = true;
changed = true;
break;
used[idx] = true;
queue.push(point_j); // Add to queue for further expansion
}
}
}
Expand Down