Fix quick measuring of skewed and rotated layers by using the viewport space AABB (#2396)

* Make sure that quick measure overlays are based on AABBs drawn in the viewport local space

* Draw overlays to visualise AABBs of selected and hovered shapes

* use pre-existing functions to render dashed lines

* Redraw selected bounds using existing BoundingBoxManager

* remove unused variables

* Render transform cage after overlay is drawn

* Bring overlay and transform cage render calls above(before) other  gizmos

* Add line length tolerance and render single line for singal edge alignment with one axis overlap

* Comments

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Utsav Singh
2025-03-12 10:53:58 +00:00
committed by GitHub
co-authored by Keavon Chambers
parent 2bcfe5ea0c
commit 927d7dd9b2
2 changed files with 87 additions and 47 deletions
@@ -1,7 +1,6 @@
use crate::consts::COLOR_OVERLAY_BLUE;
use crate::messages::portfolio::document::overlays::utility_types::{OverlayContext, Pivot};
use crate::messages::tool::tool_messages::tool_prelude::*;
use graphene_std::renderer::Rect;
/// Draws a dashed line between two points transformed by the given affine transformation.
@@ -25,29 +24,50 @@ fn draw_line_with_length(line_start: DVec2, line_end: DVec2, transform: DAffine2
.trim_end_matches('.')
.to_string();
const TEXT_PADDING: f64 = 5.;
// Calculate midpoint of the line
let midpoint = (min_viewport + max_viewport) / 2.;
const TOLERANCE: f64 = 0.01;
if transform_to_document.transform_vector2(line_end - line_start).length() >= TOLERANCE {
const TEXT_PADDING: f64 = 5.;
// Calculate midpoint of the line
let midpoint = (min_viewport + max_viewport) / 2.;
// Adjust text position based on line orientation and flags
// Determine text position based on line orientation and flags
let (pivot_x, pivot_y) = match (label_alignment.is_vertical_line, label_alignment.text_on_left, label_alignment.text_on_top) {
(true, true, _) => (Pivot::End, Pivot::Middle), // Vertical line, text on the left
(true, false, _) => (Pivot::Start, Pivot::Middle), // Vertical line, text on the right
(false, _, true) => (Pivot::Middle, Pivot::End), // Horizontal line, text on top
(false, _, false) => (Pivot::Middle, Pivot::Start), // Horizontal line, text on bottom
};
overlay_context.text(&length, COLOR_OVERLAY_BLUE, None, DAffine2::from_translation(midpoint), TEXT_PADDING, [pivot_x, pivot_y]);
// Adjust text position based on line orientation and flags
// Determine text position based on line orientation and flags
let (pivot_x, pivot_y) = match (label_alignment.is_vertical_line, label_alignment.text_on_left, label_alignment.text_on_top) {
(true, true, _) => (Pivot::End, Pivot::Middle), // Vertical line, text on the left
(true, false, _) => (Pivot::Start, Pivot::Middle), // Vertical line, text on the right
(false, _, true) => (Pivot::Middle, Pivot::End), // Horizontal line, text on top
(false, _, false) => (Pivot::Middle, Pivot::Start), // Horizontal line, text on bottom
};
overlay_context.text(&length, COLOR_OVERLAY_BLUE, None, DAffine2::from_translation(midpoint), TEXT_PADDING, [pivot_x, pivot_y]);
}
}
/// Draws a dashed outline around a rectangle to visualize the AABB
fn draw_dashed_rect_outline(rect: Rect, transform: DAffine2, overlay_context: &mut OverlayContext) {
let min = rect.min();
let max = rect.max();
// Create the four corners of the rectangle
let top_left = transform.transform_point2(DVec2::new(min.x, min.y));
let top_right = transform.transform_point2(DVec2::new(max.x, min.y));
let bottom_right = transform.transform_point2(DVec2::new(max.x, max.y));
let bottom_left = transform.transform_point2(DVec2::new(min.x, max.y));
// Draw the four sides as dashed lines
draw_dashed_line(top_left, top_right, transform, overlay_context);
draw_dashed_line(top_right, bottom_right, transform, overlay_context);
draw_dashed_line(bottom_right, bottom_left, transform, overlay_context);
draw_dashed_line(bottom_left, top_left, transform, overlay_context);
}
/// Checks if the selected bounds overlap with the hovered bounds on the Y-axis.
fn does_overlap_y(selected_bounds: Rect, hovered_bounds: Rect) -> bool {
selected_bounds.min().x < hovered_bounds.max().x && selected_bounds.max().x > hovered_bounds.min().x
selected_bounds.min().x <= hovered_bounds.max().x && selected_bounds.max().x >= hovered_bounds.min().x
}
/// Checks if the selected bounds overlap with the hovered bounds on the X-axis.
fn does_overlap_x(selected_bounds: Rect, hovered_bounds: Rect) -> bool {
selected_bounds.min().y < hovered_bounds.max().y && selected_bounds.max().y > hovered_bounds.min().y
selected_bounds.min().y <= hovered_bounds.max().y && selected_bounds.max().y >= hovered_bounds.min().y
}
/// Draws measurements when both X and Y axes are involved in the overlap between selected and hovered bounds.
@@ -91,8 +111,8 @@ fn draw_single_axis_zero_crossings(selected_bounds: Rect, hovered_bounds: Rect,
let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max());
let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max());
let overlap_y = does_overlap_y(selected_bounds, hovered_bounds);
let overlap_x = does_overlap_x(selected_bounds, hovered_bounds);
let overlap_y = does_overlap_y(selected_bounds, hovered_bounds) || does_overlap_y(hovered_bounds, selected_bounds);
let overlap_x = does_overlap_x(selected_bounds, hovered_bounds) || does_overlap_x(hovered_bounds, selected_bounds);
let selected_on_bottom = selected_bounds.center().y > hovered_bounds.center().y;
let selected_on_right = selected_bounds.center().x > hovered_bounds.center().x;
@@ -151,8 +171,8 @@ fn draw_single_axis_one_crossings(selected_bounds: Rect, hovered_bounds: Rect, t
let selected_center = selected_bounds.center();
let hovered_center = hovered_bounds.center();
let overlap_y = does_overlap_y(selected_bounds, hovered_bounds);
let overlap_x = does_overlap_x(selected_bounds, hovered_bounds);
let overlap_y = does_overlap_y(selected_bounds, hovered_bounds) || does_overlap_y(hovered_bounds, selected_bounds);
let overlap_x = does_overlap_x(selected_bounds, hovered_bounds) || does_overlap_x(hovered_bounds, selected_bounds);
if overlap_y {
let selected_facing_edge = if hovered_max.y < selected_min.y { selected_min.y } else { selected_max.y };
@@ -423,14 +443,14 @@ fn handle_two_axis_overlap(selected_bounds: Rect, hovered_bounds: Rect, transfor
/// Overlays measurement lines between selected and hovered bounds based on their spatial relationships.
pub fn overlay(selected_bounds: Rect, hovered_bounds: Rect, transform: DAffine2, document_to_viewport: DAffine2, overlay_context: &mut OverlayContext) {
// TODO: Apply object rotation to bounds before drawing lines for all cases.
draw_dashed_rect_outline(selected_bounds, transform, overlay_context);
draw_dashed_rect_outline(hovered_bounds, transform, overlay_context);
let (selected_min, selected_max) = (selected_bounds.min(), selected_bounds.max());
let (hovered_min, hovered_max) = (hovered_bounds.min(), hovered_bounds.max());
// Determine axis overlaps
let overlap_x = selected_min.x <= hovered_max.x && selected_max.x >= hovered_min.x;
let overlap_y = selected_min.y <= hovered_max.y && selected_max.y >= hovered_min.y;
let overlap_y = does_overlap_y(selected_bounds, hovered_bounds) || does_overlap_y(hovered_bounds, selected_bounds);
let overlap_x = does_overlap_x(selected_bounds, hovered_bounds) || does_overlap_x(hovered_bounds, selected_bounds);
let overlap_axes = match (overlap_x, overlap_y) {
(true, true) => 2,
(true, false) | (false, true) => 1,