mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-24 08:05:04 +00:00
Better checks for invalid transforms in the transform cage (#831)
* Better checks for invalid transform * Fix resize cursor * Do not allow resizing with no width/height * Fix pivots for 0 width/height layers
This commit is contained in:
parent
e4dc368ecc
commit
fa7116133b
3 changed files with 43 additions and 13 deletions
|
@ -41,7 +41,15 @@ impl Default for Pivot {
|
|||
impl Pivot {
|
||||
/// Calculates the transform that gets from normalized pivot to viewspace.
|
||||
fn get_layer_pivot_transform(layer_path: &[LayerId], layer: &graphene::layers::layer_info::Layer, document: &DocumentMessageHandler, font_cache: &FontCache) -> DAffine2 {
|
||||
let [min, max] = layer.aabb_for_transform(DAffine2::IDENTITY, font_cache).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
let [mut min, max] = layer.aabb_for_transform(DAffine2::IDENTITY, font_cache).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
|
||||
// If the layer bounds are 0 in either axis then set them to one (to avoid div 0)
|
||||
if (max.x - min.x) < f64::EPSILON * 1000. {
|
||||
min.x = max.x - 1.;
|
||||
}
|
||||
if (max.y - min.y) < f64::EPSILON * 1000. {
|
||||
min.y = max.y - 1.;
|
||||
}
|
||||
let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min);
|
||||
let layer_transform = document.graphene_document.multiply_transforms(layer_path).unwrap_or(DAffine2::IDENTITY);
|
||||
layer_transform * bounds_transform
|
||||
|
|
|
@ -130,18 +130,19 @@ impl SelectedEdges {
|
|||
|
||||
/// Calculates the required scaling to resize the bounding box
|
||||
pub fn bounds_to_scale_transform(&self, position: DVec2, size: DVec2) -> (DAffine2, DVec2) {
|
||||
let mut enlargement_factor = size / (self.bounds[1] - self.bounds[0]);
|
||||
if enlargement_factor.x.is_nan() {
|
||||
enlargement_factor.x = 0.;
|
||||
let old_size = self.bounds[1] - self.bounds[0];
|
||||
let mut enlargement_factor = size / old_size;
|
||||
if !enlargement_factor.x.is_finite() || old_size.x.abs() < f64::EPSILON * 1000. {
|
||||
enlargement_factor.x = 1.;
|
||||
}
|
||||
if enlargement_factor.y.is_nan() {
|
||||
enlargement_factor.y = 0.;
|
||||
if !enlargement_factor.y.is_finite() || old_size.y.abs() < f64::EPSILON * 1000. {
|
||||
enlargement_factor.y = 1.;
|
||||
}
|
||||
let mut pivot = (self.bounds[0] * enlargement_factor - position) / (enlargement_factor - DVec2::splat(1.));
|
||||
if pivot.x.is_nan() {
|
||||
if !pivot.x.is_finite() {
|
||||
pivot.x = 0.;
|
||||
}
|
||||
if pivot.y.is_nan() {
|
||||
if !pivot.y.is_finite() {
|
||||
pivot.y = 0.;
|
||||
}
|
||||
(DAffine2::from_scale(enlargement_factor), pivot)
|
||||
|
@ -278,6 +279,8 @@ impl BoundingBoxOverlays {
|
|||
let mut bottom = (max.y - cursor.y).abs() < select_threshold;
|
||||
let mut left = (cursor.x - min.x).abs() < select_threshold;
|
||||
let mut right = (max.x - cursor.x).abs() < select_threshold;
|
||||
|
||||
// Prioritise single axis transformations on very small bounds
|
||||
if cursor.y - min.y + max.y - cursor.y < select_threshold * 2. && (left || right) {
|
||||
top = false;
|
||||
bottom = false;
|
||||
|
@ -287,6 +290,16 @@ impl BoundingBoxOverlays {
|
|||
right = false;
|
||||
}
|
||||
|
||||
// On bounds with no width/height, disallow transformation in the relevant axis
|
||||
if (max.x - min.x) < f64::EPSILON * 1000. {
|
||||
left = false;
|
||||
right = false;
|
||||
}
|
||||
if (max.y - min.y) < f64::EPSILON * 1000. {
|
||||
top = false;
|
||||
bottom = false;
|
||||
}
|
||||
|
||||
if top || bottom || left || right {
|
||||
return Some((top, bottom, left, right));
|
||||
}
|
||||
|
@ -313,10 +326,10 @@ impl BoundingBoxOverlays {
|
|||
pub fn get_cursor(&self, input: &InputPreprocessorMessageHandler, rotate: bool) -> MouseCursorIcon {
|
||||
if let Some(directions) = self.check_selected_edges(input.mouse.position) {
|
||||
match directions {
|
||||
(true, false, false, false) | (false, true, false, false) => MouseCursorIcon::NSResize,
|
||||
(false, false, true, false) | (false, false, false, true) => MouseCursorIcon::EWResize,
|
||||
(true, false, true, false) | (false, true, false, true) => MouseCursorIcon::NWSEResize,
|
||||
(true, false, false, true) | (false, true, true, false) => MouseCursorIcon::NESWResize,
|
||||
(true, _, false, false) | (_, true, false, false) => MouseCursorIcon::NSResize,
|
||||
(false, false, true, _) | (false, false, _, true) => MouseCursorIcon::EWResize,
|
||||
(true, _, true, _) | (_, true, _, true) => MouseCursorIcon::NWSEResize,
|
||||
(true, _, _, true) | (_, true, true, _) => MouseCursorIcon::NESWResize,
|
||||
_ => MouseCursorIcon::Default,
|
||||
}
|
||||
} else if rotate && self.check_rotate(input.mouse.position) {
|
||||
|
|
|
@ -374,7 +374,16 @@ impl Layer {
|
|||
}
|
||||
|
||||
pub fn layerspace_pivot(&self, font_cache: &FontCache) -> DVec2 {
|
||||
let [min, max] = self.aabb_for_transform(DAffine2::IDENTITY, font_cache).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
let [mut min, max] = self.aabb_for_transform(DAffine2::IDENTITY, font_cache).unwrap_or([DVec2::ZERO, DVec2::ONE]);
|
||||
|
||||
// If the layer bounds are 0 in either axis then set them to one (to avoid div 0)
|
||||
if (max.x - min.x) < f64::EPSILON * 1000. {
|
||||
min.x = max.x - 1.;
|
||||
}
|
||||
if (max.y - min.y) < f64::EPSILON * 1000. {
|
||||
min.y = max.y - 1.;
|
||||
}
|
||||
|
||||
self.pivot * (max - min) + min
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue