Fix constrained snap when dragging by a compass rose axis and fix that axis line's jiggling (#2333)
* Fixes constrained snap when using compass axes; Fix line banding Fixes #2313 Fixes line banding[0] [0]: https://discord.com/channels/731730685944922173/931942323644928040/1345339390809083934 * Separate axis align and axis constraint logic * Final fix * Use projection instead of length --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
0570edc463
commit
39894b3b78
|
|
@ -101,3 +101,13 @@ impl Axis {
|
||||||
matches!(self, Self::X | Self::Y)
|
matches!(self, Self::X | Self::Y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Axis> for DVec2 {
|
||||||
|
fn from(value: Axis) -> Self {
|
||||||
|
match value {
|
||||||
|
Axis::X => DVec2::X,
|
||||||
|
Axis::Y => DVec2::Y,
|
||||||
|
Axis::None => DVec2::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||||
use crate::messages::portfolio::document::utility_types::transformation::OriginalTransforms;
|
use crate::messages::portfolio::document::utility_types::transformation::OriginalTransforms;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
use crate::messages::tool::common_functionality::compass_rose::Axis;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration;
|
use crate::messages::tool::common_functionality::snapping::SnapTypeConfiguration;
|
||||||
use glam::{DAffine2, DMat2, DVec2};
|
use glam::{DAffine2, DMat2, DVec2};
|
||||||
use graphene_core::renderer::Quad;
|
use graphene_core::renderer::Quad;
|
||||||
|
|
@ -286,25 +287,30 @@ impl SelectedEdges {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Aligns the mouse position to the closest axis
|
/// Aligns the mouse position to the closest axis
|
||||||
pub fn axis_align_drag(axis_align: bool, position: DVec2, start: DVec2) -> DVec2 {
|
pub fn axis_align_drag(axis_align: bool, axis: Axis, position: DVec2, start: DVec2) -> DVec2 {
|
||||||
if axis_align {
|
if axis_align {
|
||||||
let mouse_position = position - start;
|
let mouse_position = position - start;
|
||||||
let snap_resolution = SELECTION_DRAG_ANGLE.to_radians();
|
let snap_resolution = SELECTION_DRAG_ANGLE.to_radians();
|
||||||
let angle = -mouse_position.angle_to(DVec2::X);
|
let angle = -mouse_position.angle_to(DVec2::X);
|
||||||
let snapped_angle = (angle / snap_resolution).round() * snap_resolution;
|
let snapped_angle = (angle / snap_resolution).round() * snap_resolution;
|
||||||
|
let axis_vector = DVec2::from_angle(snapped_angle);
|
||||||
if snapped_angle.is_finite() {
|
if snapped_angle.is_finite() {
|
||||||
start + DVec2::new(snapped_angle.cos(), snapped_angle.sin()) * mouse_position.length()
|
start + axis_vector * mouse_position.dot(axis_vector).abs()
|
||||||
} else {
|
} else {
|
||||||
start
|
start
|
||||||
}
|
}
|
||||||
|
} else if axis.is_constraint() {
|
||||||
|
let mouse_position = position - start;
|
||||||
|
let axis_vector: DVec2 = axis.into();
|
||||||
|
start + axis_vector * mouse_position.dot(axis_vector)
|
||||||
} else {
|
} else {
|
||||||
position
|
position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Snaps a dragging event from the artboard or select tool
|
/// Snaps a dragging event from the artboard or select tool
|
||||||
pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &[SnapCandidatePoint]) -> DVec2 {
|
pub fn snap_drag(start: DVec2, current: DVec2, snap_to_axis: bool, axis: Axis, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &[SnapCandidatePoint]) -> DVec2 {
|
||||||
let mouse_position = axis_align_drag(axis_align, snap_data.input.mouse.position, start);
|
let mouse_position = axis_align_drag(snap_to_axis, axis, snap_data.input.mouse.position, start);
|
||||||
let document = snap_data.document;
|
let document = snap_data.document;
|
||||||
let total_mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - start);
|
let total_mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - start);
|
||||||
let mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - current);
|
let mouse_delta_document = document.metadata().document_to_viewport.inverse().transform_vector2(mouse_position - current);
|
||||||
|
|
@ -324,7 +330,8 @@ pub fn snap_drag(start: DVec2, current: DVec2, axis_align: bool, snap_data: Snap
|
||||||
let mut point = point.clone();
|
let mut point = point.clone();
|
||||||
point.document_point += total_mouse_delta_document;
|
point.document_point += total_mouse_delta_document;
|
||||||
|
|
||||||
let snapped = if axis_align {
|
let constrained_along_axis = snap_to_axis || axis.is_constraint();
|
||||||
|
let snapped = if constrained_along_axis {
|
||||||
let constraint = SnapConstraint::Line {
|
let constraint = SnapConstraint::Line {
|
||||||
origin: point.document_point,
|
origin: point.document_point,
|
||||||
direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X),
|
direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::messages::portfolio::document::graph_operation::utility_types::Transf
|
||||||
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
use crate::messages::portfolio::document::overlays::utility_types::OverlayContext;
|
||||||
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||||
|
use crate::messages::tool::common_functionality::compass_rose::Axis;
|
||||||
use crate::messages::tool::common_functionality::resize::Resize;
|
use crate::messages::tool::common_functionality::resize::Resize;
|
||||||
use crate::messages::tool::common_functionality::snapping;
|
use crate::messages::tool::common_functionality::snapping;
|
||||||
use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint;
|
use crate::messages::tool::common_functionality::snapping::SnapCandidatePoint;
|
||||||
|
|
@ -283,7 +284,7 @@ impl Fsm for ArtboardToolFsmState {
|
||||||
let snap_data = SnapData::ignore(document, input, &ignore);
|
let snap_data = SnapData::ignore(document, input, &ignore);
|
||||||
let document_to_viewport = document.metadata().document_to_viewport;
|
let document_to_viewport = document.metadata().document_to_viewport;
|
||||||
let [start, current] = [tool_data.drag_start, tool_data.drag_current].map(|point| document_to_viewport.transform_point2(point));
|
let [start, current] = [tool_data.drag_start, tool_data.drag_current].map(|point| document_to_viewport.transform_point2(point));
|
||||||
let mouse_delta = snap_drag(start, current, axis_align, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates);
|
let mouse_delta = snap_drag(start, current, axis_align, Axis::None, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates);
|
||||||
|
|
||||||
let size = bounds.bounds[1] - bounds.bounds[0];
|
let size = bounds.bounds[1] - bounds.bounds[0];
|
||||||
let position = bounds.bounds[0] + bounds.transform.inverse().transform_vector2(mouse_delta);
|
let position = bounds.bounds[0] + bounds.transform.inverse().transform_vector2(mouse_delta);
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,7 @@ struct SelectToolData {
|
||||||
cursor: MouseCursorIcon,
|
cursor: MouseCursorIcon,
|
||||||
pivot: Pivot,
|
pivot: Pivot,
|
||||||
compass_rose: CompassRose,
|
compass_rose: CompassRose,
|
||||||
|
line_center: DVec2,
|
||||||
skew_edge: EdgeBool,
|
skew_edge: EdgeBool,
|
||||||
nested_selection_behavior: NestedSelectionBehavior,
|
nested_selection_behavior: NestedSelectionBehavior,
|
||||||
selected_layers_count: usize,
|
selected_layers_count: usize,
|
||||||
|
|
@ -660,6 +661,9 @@ impl Fsm for SelectToolFsmState {
|
||||||
// Update compass rose
|
// Update compass rose
|
||||||
tool_data.compass_rose.refresh_position(document);
|
tool_data.compass_rose.refresh_position(document);
|
||||||
let compass_center = tool_data.compass_rose.compass_rose_position();
|
let compass_center = tool_data.compass_rose.compass_rose_position();
|
||||||
|
if !matches!(self, Self::Dragging { .. }) {
|
||||||
|
tool_data.line_center = compass_center;
|
||||||
|
}
|
||||||
overlay_context.compass_rose(compass_center, angle, show_compass_with_ring);
|
overlay_context.compass_rose(compass_center, angle, show_compass_with_ring);
|
||||||
|
|
||||||
let axis_state = if let SelectToolFsmState::Dragging { axis, .. } = self {
|
let axis_state = if let SelectToolFsmState::Dragging { axis, .. } = self {
|
||||||
|
|
@ -691,7 +695,8 @@ impl Fsm for SelectToolFsmState {
|
||||||
let color_string = &graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).rgba_hex();
|
let color_string = &graphene_std::Color::from_rgb_str(color.strip_prefix('#').unwrap()).unwrap().with_alpha(0.25).rgba_hex();
|
||||||
&format!("#{}", color_string)
|
&format!("#{}", color_string)
|
||||||
};
|
};
|
||||||
overlay_context.line(compass_center - direction * viewport_diagonal, compass_center + direction * viewport_diagonal, Some(color));
|
let line_center = tool_data.line_center;
|
||||||
|
overlay_context.line(line_center - direction * viewport_diagonal, line_center + direction * viewport_diagonal, Some(color));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -984,7 +989,7 @@ impl Fsm for SelectToolFsmState {
|
||||||
tool_data.stop_duplicates(document, responses);
|
tool_data.stop_duplicates(document, responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
tool_data.axis_align = input.keyboard.key(modifier_keys.axis_align) && !axis.is_constraint();
|
tool_data.axis_align = input.keyboard.key(modifier_keys.axis_align);
|
||||||
|
|
||||||
// Ignore the non duplicated layers if the current layers have not spawned yet.
|
// Ignore the non duplicated layers if the current layers have not spawned yet.
|
||||||
let layers_exist = tool_data.layers_dragging.iter().all(|&layer| document.metadata().click_targets(layer).is_some());
|
let layers_exist = tool_data.layers_dragging.iter().all(|&layer| document.metadata().click_targets(layer).is_some());
|
||||||
|
|
@ -992,12 +997,13 @@ impl Fsm for SelectToolFsmState {
|
||||||
|
|
||||||
let snap_data = SnapData::ignore(document, input, ignore);
|
let snap_data = SnapData::ignore(document, input, ignore);
|
||||||
let (start, current) = (tool_data.drag_start, tool_data.drag_current);
|
let (start, current) = (tool_data.drag_start, tool_data.drag_current);
|
||||||
let mouse_delta = snap_drag(start, current, tool_data.axis_align, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates);
|
|
||||||
let e0 = tool_data
|
let e0 = tool_data
|
||||||
.bounding_box_manager
|
.bounding_box_manager
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds))
|
.map(|bounding_box_manager| bounding_box_manager.transform * Quad::from_box(bounding_box_manager.bounds))
|
||||||
.map_or(DVec2::X, |quad| (quad.top_left() - quad.top_right()).normalize_or(DVec2::X));
|
.map_or(DVec2::X, |quad| (quad.top_left() - quad.top_right()).normalize_or(DVec2::X));
|
||||||
|
|
||||||
|
let mouse_delta = snap_drag(start, current, tool_data.axis_align, axis, snap_data, &mut tool_data.snap_manager, &tool_data.snap_candidates);
|
||||||
let mouse_delta = match axis {
|
let mouse_delta = match axis {
|
||||||
Axis::X => mouse_delta.project_onto(e0),
|
Axis::X => mouse_delta.project_onto(e0),
|
||||||
Axis::Y => mouse_delta.project_onto(e0.perp()),
|
Axis::Y => mouse_delta.project_onto(e0.perp()),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue