aboutsummaryrefslogtreecommitdiff
path: root/src/smart_positioning.rs
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2025-12-16 11:38:28 +0100
committerRuben Beltran del Rio <jj@r.bdr.sh>2025-12-16 11:53:18 +0100
commit2ae9158285a22c023ebd0f88bbadd8b0832079ea (patch)
treebfcf1138975b4343f78b64d91d86d71293018569 /src/smart_positioning.rs
parent6deeee3848e291dee61e239f104dc29bb26f4608 (diff)
Performance improvements part 1
Diffstat (limited to 'src/smart_positioning.rs')
-rw-r--r--src/smart_positioning.rs96
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, &note_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, &note_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