diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-16 11:38:28 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <jj@r.bdr.sh> | 2025-12-16 11:53:18 +0100 |
| commit | 2ae9158285a22c023ebd0f88bbadd8b0832079ea (patch) | |
| tree | bfcf1138975b4343f78b64d91d86d71293018569 /src/smart_positioning.rs | |
| parent | 6deeee3848e291dee61e239f104dc29bb26f4608 (diff) | |
Performance improvements part 1
Diffstat (limited to 'src/smart_positioning.rs')
| -rw-r--r-- | src/smart_positioning.rs | 96 |
1 files changed, 32 insertions, 64 deletions
diff --git a/src/smart_positioning.rs b/src/smart_positioning.rs index 2def897..77fd1b6 100644 --- a/src/smart_positioning.rs +++ b/src/smart_positioning.rs @@ -8,15 +8,16 @@ pub struct LabelPosition { pub y: f64, } -/// Calculate the optimal position for a vertex label to minimize collisions -pub fn calculate_optimal_label_position( +/// Calculate the optimal position for a vertex label with pre-cached collision data +pub fn calculate_optimal_label_position_cached( component: &Component, - map: &Map, map_width: f64, map_height: f64, vertex_size: f64, ctx: &cairo::Context, font_size: f64, + all_lines: &[Line], + note_rects: &[Rect], ) -> Result<LabelPosition, cairo::Error> { let vertex_pixel_x = percent_to_pixel(component.coordinates.0, map_width); let vertex_pixel_y = percent_to_pixel(component.coordinates.1, map_height); @@ -36,12 +37,6 @@ pub fn calculate_optimal_label_position( label_height, ); - // Collect all lines (dependencies, evolutions, axis lines) - let all_lines = collect_all_lines(map, map_width, map_height, vertex_size); - - // Collect note rectangles - let note_rects = collect_note_rects(map, map_width, map_height, ctx, font_size)?; - // Check if default position (right) has no collisions let default_position = &candidates[0]; let default_rect = Rect::new( @@ -51,8 +46,8 @@ pub fn calculate_optimal_label_position( label_height, ); - if count_line_collisions(&default_rect, &all_lines) == 0 - && count_note_collisions(&default_rect, ¬e_rects) == 0 + if count_line_collisions(&default_rect, all_lines) == 0 + && count_note_collisions(&default_rect, note_rects) == 0 { return Ok(default_position.clone()); } @@ -64,8 +59,8 @@ pub fn calculate_optimal_label_position( for (index, position) in candidates.iter().enumerate() { let label_rect = Rect::new(position.x, position.y, label_width, label_height); - let collision_count = count_line_collisions(&label_rect, &all_lines); - let note_collision_count = count_note_collisions(&label_rect, ¬e_rects); + let collision_count = count_line_collisions(&label_rect, all_lines); + let note_collision_count = count_note_collisions(&label_rect, note_rects); // Distance from label center to vertex center let label_center_x = position.x + label_width / 2.0; @@ -76,13 +71,11 @@ pub fn calculate_optimal_label_position( + (label_center_y - vertex_center_y).powi(2)) .sqrt(); - // Calculate ownership penalty - let ownership_penalty = calculate_ownership_penalty( + // Calculate ownership penalty (simplified to avoid O(n²)) + let ownership_penalty = calculate_ownership_penalty_fast( &label_rect, - component, - &map.components, - map_width, - map_height, + vertex_pixel_x, + vertex_pixel_y, vertex_size, ); @@ -102,6 +95,7 @@ pub fn calculate_optimal_label_position( Ok(best_position) } + /// Generate 8 candidate positions around a vertex fn generate_candidate_positions( vertex_x: f64, @@ -157,19 +151,15 @@ fn generate_candidate_positions( } /// Collect all lines from dependencies, evolutions, and axis lines -fn collect_all_lines(map: &Map, map_width: f64, map_height: f64, vertex_size: f64) -> Vec<Line> { - use std::collections::HashMap; - +pub fn collect_all_lines( + map: &Map, + map_width: f64, + map_height: f64, + vertex_size: f64, + component_map: &std::collections::HashMap<String, (f64, f64)>, +) -> Vec<Line> { let mut lines = Vec::new(); - // Build component position map - let mut component_map: HashMap<String, (f64, f64)> = HashMap::new(); - for component in &map.components { - let x = percent_to_pixel(component.coordinates.0, map_width); - let y = percent_to_pixel(component.coordinates.1, map_height); - component_map.insert(component.label.to_lowercase(), (x, y)); - } - // Collect dependency lines for dependency in &map.dependencies { if let (Some(&origin), Some(&destination)) = ( @@ -227,7 +217,7 @@ fn collect_all_lines(map: &Map, map_width: f64, map_height: f64, vertex_size: f6 } /// Collect rectangles for all notes -fn collect_note_rects( +pub fn collect_note_rects( map: &Map, map_width: f64, map_height: f64, @@ -269,47 +259,25 @@ fn count_note_collisions(label_rect: &Rect, note_rects: &[Rect]) -> usize { .count() } -/// Calculate ownership penalty if label is closer to another vertex -fn calculate_ownership_penalty( +/// Fast ownership penalty calculation without O(n²) iteration +fn calculate_ownership_penalty_fast( label_rect: &Rect, - own_component: &Component, - all_components: &[Component], - map_width: f64, - map_height: f64, + vertex_x: f64, + vertex_y: f64, vertex_size: f64, ) -> f64 { - if all_components.is_empty() { - return 0.0; - } - let label_center_x = label_rect.x + label_rect.width / 2.0; let label_center_y = label_rect.y + label_rect.height / 2.0; - let own_vertex_x = percent_to_pixel(own_component.coordinates.0, map_width); - let own_vertex_y = percent_to_pixel(own_component.coordinates.1, map_height); - let own_center_x = own_vertex_x + vertex_size / 2.0; - let own_center_y = own_vertex_y + vertex_size / 2.0; + let vertex_center_x = vertex_x + vertex_size / 2.0; + let vertex_center_y = vertex_y + vertex_size / 2.0; - let distance_to_own = - ((label_center_x - own_center_x).powi(2) + (label_center_y - own_center_y).powi(2)).sqrt(); + let distance = + ((label_center_x - vertex_center_x).powi(2) + (label_center_y - vertex_center_y).powi(2)).sqrt(); - for other_component in all_components { - if other_component.label == own_component.label { - continue; - } - - let other_vertex_x = percent_to_pixel(other_component.coordinates.0, map_width); - let other_vertex_y = percent_to_pixel(other_component.coordinates.1, map_height); - let other_center_x = other_vertex_x + vertex_size / 2.0; - let other_center_y = other_vertex_y + vertex_size / 2.0; - - let distance_to_other = ((label_center_x - other_center_x).powi(2) - + (label_center_y - other_center_y).powi(2)) - .sqrt(); - - if distance_to_other < distance_to_own { - return 50.0; - } + // Apply penalty if label is too far from its vertex + if distance > 100.0 { + return 25.0; } 0.0 |