Skip to content

Commit 117ce30

Browse files
0HyperCubeKeavon
andauthored
Fix regressions with G/R/S (#3355)
* Better local grab * Formatting * Multiply by document_to_viewport.matrix2.y_axis.length() * Fix logic errors --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 5ff399d commit 117ce30

File tree

3 files changed

+146
-247
lines changed

3 files changed

+146
-247
lines changed

editor/src/messages/portfolio/document/utility_types/transformation.rs

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ use crate::messages::portfolio::document::graph_operation::utility_types::{Modif
55
use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier};
66
use crate::messages::prelude::*;
77
use crate::messages::tool::common_functionality::shape_editor::ShapeState;
8+
use crate::messages::tool::transform_layer::transform_layer_message_handler::TransformationState;
89
use crate::messages::tool::utility_types::ToolType;
910
use glam::{DAffine2, DMat2, DVec2};
1011
use graphene_std::renderer::Quad;
1112
use graphene_std::vector::misc::{HandleId, ManipulatorPointId};
1213
use graphene_std::vector::{HandleExt, PointId, VectorModificationType};
1314
use std::collections::{HashMap, VecDeque};
14-
use std::f64::consts::PI;
1515

1616
#[derive(Debug, PartialEq, Clone, Copy)]
1717
struct AnchorPoint {
@@ -156,22 +156,25 @@ pub struct Translation {
156156
}
157157

158158
impl Translation {
159-
pub fn to_dvec(self, transform: DAffine2, increment_mode: bool) -> DVec2 {
159+
pub fn to_dvec(self, state: &TransformationState, document: &DocumentMessageHandler) -> DVec2 {
160+
let document_to_viewport = document.metadata().document_to_viewport;
160161
let displacement = if let Some(value) = self.typed_distance {
161162
match self.constraint {
162-
Axis::X => transform.transform_vector2(DVec2::new(value, 0.)),
163-
Axis::Y => transform.transform_vector2(DVec2::new(0., value)),
163+
Axis::X => DVec2::X * value,
164+
Axis::Y => DVec2::Y * value,
164165
Axis::Both => self.dragged_distance,
165166
}
166167
} else {
167168
match self.constraint {
168169
Axis::Both => self.dragged_distance,
169-
Axis::X => DVec2::new(self.dragged_distance.x, 0.),
170-
Axis::Y => DVec2::new(0., self.dragged_distance.y),
170+
Axis::X => DVec2::X * self.dragged_distance.dot(state.constraint_axis(self.constraint).unwrap_or_default()),
171+
Axis::Y => DVec2::Y * self.dragged_distance.dot(state.constraint_axis(self.constraint).unwrap_or_default()),
171172
}
172173
};
173-
let displacement = transform.inverse().transform_vector2(displacement);
174-
if increment_mode { displacement.round() } else { displacement }
174+
let displacement_viewport = displacement * document_to_viewport.matrix2.y_axis.length(); // Values are local to the viewport but scaled so values are relative to the current scale.
175+
let displacement_document = document_to_viewport.inverse().transform_vector2(displacement_viewport);
176+
let displacement_document = if state.is_rounded_to_intervals { displacement_document.round() } else { displacement_document }; // It rounds in document space?
177+
document_to_viewport.transform_vector2(displacement_document)
175178
}
176179

177180
#[must_use]
@@ -327,36 +330,19 @@ impl TransformType {
327330

328331
impl TransformOperation {
329332
#[allow(clippy::too_many_arguments)]
330-
pub fn apply_transform_operation(&self, selected: &mut Selected, increment_mode: bool, local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) {
331-
let local_axis_transform_angle = (quad.top_left() - quad.top_right()).to_angle();
333+
pub fn apply_transform_operation(&self, selected: &mut Selected, state: &TransformationState, document: &DocumentMessageHandler) {
332334
if self != &TransformOperation::None {
333-
let transformation = match self {
334-
TransformOperation::Grabbing(translation) => {
335-
let translate = DAffine2::from_translation(transform.transform_vector2(translation.to_dvec(local_transform, increment_mode)));
336-
if local {
337-
let resolved_angle = if local_axis_transform_angle > 0. {
338-
local_axis_transform_angle
339-
} else {
340-
local_axis_transform_angle - PI
341-
};
342-
DAffine2::from_angle(resolved_angle) * translate * DAffine2::from_angle(-resolved_angle)
343-
} else {
344-
translate
345-
}
346-
}
347-
TransformOperation::Rotating(rotation) => DAffine2::from_angle(rotation.to_f64(increment_mode)),
348-
TransformOperation::Scaling(scale) => {
349-
if local {
350-
DAffine2::from_angle(local_axis_transform_angle) * DAffine2::from_scale(scale.to_dvec(increment_mode)) * DAffine2::from_angle(-local_axis_transform_angle)
351-
} else {
352-
DAffine2::from_scale(scale.to_dvec(increment_mode))
353-
}
354-
}
335+
let mut transformation = match self {
336+
TransformOperation::Grabbing(translation) => DAffine2::from_translation(translation.to_dvec(state, document)),
337+
TransformOperation::Rotating(rotation) => DAffine2::from_angle(rotation.to_f64(state.is_rounded_to_intervals)),
338+
TransformOperation::Scaling(scale) => DAffine2::from_scale(scale.to_dvec(state.is_rounded_to_intervals)),
355339
TransformOperation::None => unreachable!(),
356340
};
341+
let normalized_transform = state.local_to_viewport_transform();
342+
transformation = normalized_transform * transformation * normalized_transform.inverse();
357343

358-
selected.update_transforms(transformation, Some(pivot), Some(*self));
359-
self.hints(selected.responses, local);
344+
selected.update_transforms(transformation, Some(state.pivot_viewport(document)), Some(*self));
345+
self.hints(selected.responses, state.is_transforming_in_local_space);
360346
}
361347
}
362348

@@ -373,32 +359,35 @@ impl TransformOperation {
373359
}
374360

375361
#[allow(clippy::too_many_arguments)]
376-
pub fn constrain_axis(&mut self, axis: Axis, selected: &mut Selected, increment_mode: bool, mut local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) -> bool {
377-
(*self, local) = match self {
362+
pub fn constrain_axis(&mut self, axis: Axis, selected: &mut Selected, state: &TransformationState, document: &DocumentMessageHandler) -> bool {
363+
let resulting_local;
364+
(*self, resulting_local) = match self {
378365
TransformOperation::Grabbing(translation) => {
379-
let (translation, local) = translation.with_constraint(axis, local);
380-
(TransformOperation::Grabbing(translation), local)
366+
let (translation, resulting_local) = translation.with_constraint(axis, state.is_transforming_in_local_space);
367+
(TransformOperation::Grabbing(translation), resulting_local)
381368
}
382369
TransformOperation::Scaling(scale) => {
383-
let (scale, local) = scale.with_constraint(axis, local);
384-
(TransformOperation::Scaling(scale), local)
370+
let (scale, resulting_local) = scale.with_constraint(axis, state.is_transforming_in_local_space);
371+
(TransformOperation::Scaling(scale), resulting_local)
385372
}
386373
_ => (*self, false),
387374
};
388-
self.apply_transform_operation(selected, increment_mode, local, quad, transform, pivot, local_transform);
389-
local
375+
376+
self.apply_transform_operation(selected, state, document);
377+
378+
resulting_local
390379
}
391380

392381
#[allow(clippy::too_many_arguments)]
393-
pub fn grs_typed(&mut self, typed: Option<f64>, selected: &mut Selected, increment_mode: bool, local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) {
382+
pub fn grs_typed(&mut self, typed: Option<f64>, selected: &mut Selected, state: &TransformationState, document: &DocumentMessageHandler) {
394383
match self {
395384
TransformOperation::None => (),
396385
TransformOperation::Grabbing(translation) => translation.typed_distance = typed,
397386
TransformOperation::Rotating(rotation) => rotation.typed_angle = typed,
398387
TransformOperation::Scaling(scale) => scale.typed_factor = typed,
399388
};
400389

401-
self.apply_transform_operation(selected, increment_mode, local, quad, transform, pivot, local_transform);
390+
self.apply_transform_operation(selected, state, document);
402391
}
403392

404393
pub fn hints(&self, responses: &mut VecDeque<Message>, local: bool) {
@@ -481,15 +470,16 @@ impl TransformOperation {
481470
}
482471

483472
#[allow(clippy::too_many_arguments)]
484-
pub fn negate(&mut self, selected: &mut Selected, increment_mode: bool, local: bool, quad: Quad, transform: DAffine2, pivot: DVec2, local_transform: DAffine2) {
473+
pub fn negate(&mut self, selected: &mut Selected, state: &TransformationState, document: &DocumentMessageHandler) {
485474
if *self != TransformOperation::None {
486475
*self = match self {
487476
TransformOperation::Scaling(scale) => TransformOperation::Scaling(scale.negate()),
488477
TransformOperation::Rotating(rotation) => TransformOperation::Rotating(rotation.negate()),
489478
TransformOperation::Grabbing(translation) => TransformOperation::Grabbing(translation.negate()),
490479
_ => *self,
491480
};
492-
self.apply_transform_operation(selected, increment_mode, local, quad, transform, pivot, local_transform);
481+
482+
self.apply_transform_operation(selected, state, document);
493483
}
494484
}
495485
}

editor/src/messages/tool/tool_messages/select_tool.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,19 @@ impl SelectToolData {
593593
}
594594
}
595595

596+
/// Bounding boxes are unfortunately not axis aligned. The bounding boxes are found after a transformation is applied to all of the layers.
597+
/// This uses some rather confusing logic to determine what transform that should be.
598+
pub fn create_bounding_box_transform(document: &DocumentMessageHandler) -> DAffine2 {
599+
// Update bounds
600+
document
601+
.network_interface
602+
.selected_nodes()
603+
.selected_visible_and_unlocked_layers(&document.network_interface)
604+
.find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
605+
.map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface))
606+
.unwrap_or_default()
607+
}
608+
596609
impl Fsm for SelectToolFsmState {
597610
type ToolData = SelectToolData;
598611
type ToolOptions = ();
@@ -633,14 +646,7 @@ impl Fsm for SelectToolFsmState {
633646
}
634647
}
635648

636-
// Update bounds
637-
let mut transform = document
638-
.network_interface
639-
.selected_nodes()
640-
.selected_visible_and_unlocked_layers(&document.network_interface)
641-
.find(|layer| !document.network_interface.is_artboard(&layer.to_node(), &[]))
642-
.map(|layer| document.metadata().transform_to_viewport_with_first_transform_node_if_group(layer, &document.network_interface))
643-
.unwrap_or_default();
649+
let mut transform = create_bounding_box_transform(document);
644650

645651
// Check if the matrix is not invertible
646652
let mut transform_tampered = false;

0 commit comments

Comments
 (0)