Skip to content

Commit f11b349

Browse files
committed
Fix PTZ coordinate drift during drag operations
This shifts all dragging offset calculations in TransformLayer, SelectTool, and PathTool to document space, removing any dependency on cached viewport projections for state logic. Both BoundingBoxManager's interactions and custom Path selection behaviors now properly invalidate and lazily reload viewport layouts on CanvasTransformed updates, resolving issues with geometry moving opposite the viewport during pan/tilt/zoom.
1 parent 203910a commit f11b349

6 files changed

Lines changed: 375 additions & 130 deletions

File tree

editor/src/messages/tool/common_functionality/transformation_cage.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,52 @@ pub fn snap_drag(start: DVec2, current: DVec2, snap_to_axis: bool, axis: Axis, s
368368
document.metadata().document_to_viewport.transform_vector2(offset)
369369
}
370370

371+
/// Snaps a dragging event using document-space drag state so PTZ changes do not invalidate the drag anchor.
372+
pub fn snap_drag_from_document(start: DVec2, current: DVec2, snap_to_axis: bool, axis: Axis, snap_data: SnapData, snap_manager: &mut SnapManager, candidates: &[SnapCandidatePoint]) -> DVec2 {
373+
let document = snap_data.document;
374+
let document_to_viewport = document.metadata().document_to_viewport;
375+
let start_viewport = document_to_viewport.transform_point2(start);
376+
let mouse_position = axis_align_drag(snap_to_axis, axis, snap_data.input.mouse.position, start_viewport);
377+
let aligned_document = document_to_viewport.inverse().transform_point2(mouse_position);
378+
let total_mouse_delta_document = aligned_document - start;
379+
let mut offset = aligned_document - current;
380+
let mut best_snap = SnappedPoint::infinite_snap(aligned_document);
381+
382+
let bbox = Rect::point_iter(candidates.iter().map(|candidate| candidate.document_point + total_mouse_delta_document));
383+
384+
for (index, point) in candidates.iter().enumerate() {
385+
let config = SnapTypeConfiguration {
386+
bbox,
387+
accept_distribution: true,
388+
use_existing_candidates: index != 0,
389+
..Default::default()
390+
};
391+
392+
let mut point = point.clone();
393+
point.document_point += total_mouse_delta_document;
394+
395+
let constrained_along_axis = snap_to_axis || axis.is_constraint();
396+
let snapped = if constrained_along_axis {
397+
let constraint = SnapConstraint::Line {
398+
origin: point.document_point,
399+
direction: total_mouse_delta_document.try_normalize().unwrap_or(DVec2::X),
400+
};
401+
snap_manager.constrained_snap(&snap_data, &point, constraint, config)
402+
} else {
403+
snap_manager.free_snap(&snap_data, &point, config)
404+
};
405+
406+
if best_snap.other_snap_better(&snapped) {
407+
offset = snapped.snapped_point_document - point.document_point + (aligned_document - current);
408+
best_snap = snapped;
409+
}
410+
}
411+
412+
snap_manager.update_indicator(best_snap);
413+
414+
offset
415+
}
416+
371417
/// Contains info on the overlays for the bounding box and transform handles
372418
#[derive(Clone, Debug, Default)]
373419
pub struct BoundingBoxManager {
@@ -379,10 +425,12 @@ pub struct BoundingBoxManager {
379425
pub transform_tampered: bool,
380426
/// The transform to viewport space for the bounds co-ordinates when the transformation was started.
381427
pub original_bound_transform: DAffine2,
428+
pub original_bounds_to_document: DAffine2,
382429
pub selected_edges: Option<SelectedEdges>,
383430
pub original_transforms: OriginalTransforms,
384431
pub opposite_pivot: DVec2,
385432
pub center_of_transformation: DVec2,
433+
pub center_of_transformation_doc: DVec2,
386434
}
387435

388436
impl BoundingBoxManager {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod tool_prelude {
1717
pub use crate::messages::input_mapper::utility_types::input_keyboard::{Key, MouseMotion};
1818
pub use crate::messages::layout::utility_types::widget_prelude::*;
1919
pub use crate::messages::prelude::*;
20-
pub use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionMessageContext, ToolMetadata, ToolTransition, ToolType};
20+
pub use crate::messages::tool::utility_types::{DragState, EventToMessageMap, Fsm, ToolActionMessageContext, ToolMetadata, ToolTransition, ToolType};
2121
pub use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
2222
pub use glam::{DAffine2, DVec2};
2323
}

0 commit comments

Comments
 (0)