Handle uneven swap lanes and clearance grouping
This commit is contained in:
parent
313323888b
commit
6c133018aa
2 changed files with 127 additions and 11 deletions
|
|
@ -448,7 +448,11 @@ pub(crate) fn validate_phase_paths(
|
|||
.map_err(MultiphasePlanFailure::Validation)
|
||||
}
|
||||
|
||||
pub(crate) fn partition_motion_groups(windows: &[MultiphaseWindow]) -> Vec<Vec<usize>> {
|
||||
pub(crate) fn partition_motion_groups(
|
||||
windows: &[MultiphaseWindow],
|
||||
clearance: i32,
|
||||
) -> Vec<Vec<usize>> {
|
||||
let clearance = clearance.max(0);
|
||||
let mut groups = vec![];
|
||||
let mut seen = vec![false; windows.len()];
|
||||
for start in 0..windows.len() {
|
||||
|
|
@ -460,9 +464,11 @@ pub(crate) fn partition_motion_groups(windows: &[MultiphaseWindow]) -> Vec<Vec<u
|
|||
let mut pending = vec![start];
|
||||
while let Some(idx) = pending.pop() {
|
||||
group.push(idx);
|
||||
let bounds = motion_bounds(windows[idx]);
|
||||
let bounds = motion_bounds_with_clearance(windows[idx], clearance);
|
||||
for other in 0..windows.len() {
|
||||
if seen[other] || !bounds.intersects(&motion_bounds(windows[other])) {
|
||||
if seen[other]
|
||||
|| !bounds.intersects(&motion_bounds_with_clearance(windows[other], clearance))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
seen[other] = true;
|
||||
|
|
@ -819,8 +825,7 @@ fn plan_axis_crossing_lanes(
|
|||
.max()
|
||||
.ok_or(MultiphasePlanFailure::NoPattern)?;
|
||||
if moving_windows.iter().any(|window| {
|
||||
main_size(window.from, axis) != main_size(window.to, axis)
|
||||
|| orth_start(window.from, axis) != orth_min
|
||||
orth_start(window.from, axis) != orth_min
|
||||
|| orth_end(window.from, axis) != orth_max
|
||||
|| orth_start(window.to, axis) != orth_min
|
||||
|| orth_end(window.to, axis) != orth_max
|
||||
|
|
@ -859,6 +864,7 @@ fn plan_axis_crossing_lanes(
|
|||
let mut phase1 = vec![];
|
||||
let mut phase2 = vec![];
|
||||
let mut phase3 = vec![];
|
||||
let mut phase4 = vec![];
|
||||
let mut lane_start = orth_min;
|
||||
for (idx, window) in windows.iter().enumerate() {
|
||||
let extra = if lane_remainder > 0 {
|
||||
|
|
@ -875,9 +881,11 @@ fn plan_axis_crossing_lanes(
|
|||
main_start(window.to, axis),
|
||||
main_end(window.to, axis),
|
||||
);
|
||||
let lane_move = crossing_lane_move_rect(lane_from, window.to, axis);
|
||||
push_step(&mut phase1, window.node_id, window.from, lane_from);
|
||||
push_step(&mut phase2, window.node_id, lane_from, lane_to);
|
||||
push_step(&mut phase3, window.node_id, lane_to, window.to);
|
||||
push_step(&mut phase2, window.node_id, lane_from, lane_move);
|
||||
push_step(&mut phase3, window.node_id, lane_move, lane_to);
|
||||
push_step(&mut phase4, window.node_id, lane_to, window.to);
|
||||
if idx + 1 < windows.len() {
|
||||
lane_start = lane_end + clearance;
|
||||
}
|
||||
|
|
@ -902,14 +910,31 @@ fn plan_axis_crossing_lanes(
|
|||
),
|
||||
phase_draft(
|
||||
PhaseKind::Scale,
|
||||
axis.other(),
|
||||
axis,
|
||||
phase3,
|
||||
PhaseReason::SameAxisRedistribution,
|
||||
),
|
||||
phase_draft(
|
||||
PhaseKind::Scale,
|
||||
axis.other(),
|
||||
phase4,
|
||||
PhaseReason::GrowOutOfLanes,
|
||||
),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
fn crossing_lane_move_rect(from: Rect, target: Rect, axis: PhaseAxis) -> Rect {
|
||||
let size = main_size(from, axis);
|
||||
if main_start(target, axis) > main_start(from, axis) {
|
||||
let end = main_end(target, axis);
|
||||
with_main_interval(from, axis, end - size, end)
|
||||
} else {
|
||||
let start = main_start(target, axis);
|
||||
with_main_interval(from, axis, start, start + size)
|
||||
}
|
||||
}
|
||||
|
||||
fn lane_index_for_direction(window: MultiphaseWindow, axis: PhaseAxis) -> Option<usize> {
|
||||
let delta = main_start(window.to, axis) - main_start(window.from, axis);
|
||||
match delta.cmp(&0) {
|
||||
|
|
@ -1535,6 +1560,16 @@ fn motion_bounds(window: MultiphaseWindow) -> Rect {
|
|||
window.from.union(window.to)
|
||||
}
|
||||
|
||||
fn motion_bounds_with_clearance(window: MultiphaseWindow, clearance: i32) -> Rect {
|
||||
let bounds = motion_bounds(window);
|
||||
Rect::new_saturating(
|
||||
bounds.x1().saturating_sub(clearance),
|
||||
bounds.y1().saturating_sub(clearance),
|
||||
bounds.x2().saturating_add(clearance),
|
||||
bounds.y2().saturating_add(clearance),
|
||||
)
|
||||
}
|
||||
|
||||
fn interval_changed(from: Rect, to: Rect, axis: PhaseAxis) -> bool {
|
||||
main_start(from, axis) != main_start(to, axis) || main_end(from, axis) != main_end(to, axis)
|
||||
}
|
||||
|
|
@ -2055,6 +2090,67 @@ mod tests {
|
|||
assert!(validate_plan_continuous(&req, &planned.plan));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uneven_swap_lanes_split_move_and_same_axis_scale() {
|
||||
let req = request(vec![
|
||||
window(1, rect(0, 0, 101, 100), rect(101, 0, 201, 100)),
|
||||
window(2, rect(101, 0, 201, 100), rect(0, 0, 101, 100)),
|
||||
]);
|
||||
let planned = plan_no_overlap_explained(&req).unwrap();
|
||||
let plan = &planned.plan;
|
||||
|
||||
assert_eq!(
|
||||
planned.explanation.strategy,
|
||||
PlanStrategy::SwapLanes {
|
||||
axis: PhaseAxis::Horizontal,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
actions(plan),
|
||||
vec![
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Vertical,
|
||||
},
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Move,
|
||||
axis: PhaseAxis::Horizontal,
|
||||
},
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Horizontal,
|
||||
},
|
||||
PhaseAction {
|
||||
kind: PhaseKind::Scale,
|
||||
axis: PhaseAxis::Vertical,
|
||||
},
|
||||
]
|
||||
);
|
||||
assert_eq!(step_to(plan, 1, id(1)), rect(100, 0, 201, 50));
|
||||
assert_eq!(step_to(plan, 1, id(2)), rect(0, 50, 100, 100));
|
||||
assert_eq!(step_to(plan, 2, id(1)), rect(101, 0, 201, 50));
|
||||
assert_eq!(step_to(plan, 2, id(2)), rect(0, 50, 101, 100));
|
||||
assert!(validate_plan_continuous(&req, plan));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uneven_swap_lanes_tolerate_stationary_sibling_in_odd_layout() {
|
||||
let req = request(vec![
|
||||
window(1, rect(0, 0, 101, 100), rect(101, 0, 201, 100)),
|
||||
window(2, rect(101, 0, 201, 100), rect(0, 0, 101, 100)),
|
||||
window(3, rect(201, 0, 300, 100), rect(201, 0, 300, 100)),
|
||||
]);
|
||||
let planned = plan_no_overlap_explained(&req).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
planned.explanation.strategy,
|
||||
PlanStrategy::SwapLanes {
|
||||
axis: PhaseAxis::Horizontal,
|
||||
}
|
||||
);
|
||||
assert!(validate_plan_continuous(&req, &planned.plan));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vertical_swap_lanes_follow_motion_direction_not_node_id() {
|
||||
let req = request(vec![
|
||||
|
|
@ -3118,7 +3214,7 @@ mod tests {
|
|||
hierarchy: Default::default(),
|
||||
},
|
||||
];
|
||||
assert_eq!(partition_motion_groups(&windows), vec![vec![0, 1], vec![2]]);
|
||||
assert_eq!(partition_motion_groups(&windows, 0), vec![vec![0, 1], vec![2]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -3143,6 +3239,26 @@ mod tests {
|
|||
hierarchy: Default::default(),
|
||||
},
|
||||
];
|
||||
assert_eq!(partition_motion_groups(&windows), vec![vec![0, 1, 2]]);
|
||||
assert_eq!(partition_motion_groups(&windows, 0), vec![vec![0, 1, 2]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn motion_groups_join_across_animation_clearance() {
|
||||
let windows = vec![
|
||||
MultiphaseWindow {
|
||||
node_id: id(1),
|
||||
from: rect(0, 0, 100, 100),
|
||||
to: rect(0, 0, 80, 100),
|
||||
hierarchy: Default::default(),
|
||||
},
|
||||
MultiphaseWindow {
|
||||
node_id: id(2),
|
||||
from: rect(120, 0, 220, 100),
|
||||
to: rect(110, 0, 210, 100),
|
||||
hierarchy: Default::default(),
|
||||
},
|
||||
];
|
||||
assert_eq!(partition_motion_groups(&windows, 0), vec![vec![0], vec![1]]);
|
||||
assert_eq!(partition_motion_groups(&windows, 10), vec![vec![0, 1]]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1640,7 +1640,7 @@ impl State {
|
|||
)
|
||||
})
|
||||
.collect();
|
||||
for group in partition_motion_groups(&windows) {
|
||||
for group in partition_motion_groups(&windows, self.layout_animation_clearance()) {
|
||||
if self.start_multiphase_layout_animation(&candidates, &windows, &group, now) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue