1
0
Fork 0
forked from wry/wry

Choose swap lanes by motion direction

This commit is contained in:
atagen 2026-05-21 19:48:13 +10:00
parent b109cdf6f2
commit a712786ecf
2 changed files with 69 additions and 3 deletions

View file

@ -217,6 +217,9 @@ Preferred approach:
Current pure planner status: Current pure planner status:
- Two-window same-axis swaps use shrink lanes, move, then grow. - Two-window same-axis swaps use shrink lanes, move, then grow.
- Swap lane choice follows motion direction, not node identity: right/down
moving windows take the first lane, and left/up moving windows take the second
lane.
- Stack extraction/return patterns are covered in both horizontal and vertical - Stack extraction/return patterns are covered in both horizontal and vertical
orientations: peer/container space scales first, the extracted child moves orientations: peer/container space scales first, the extracted child moves
only after space exists, and orthogonal growth happens in the final phase. only after space exists, and orthogonal growth happens in the final phase.

View file

@ -173,7 +173,12 @@ fn plan_axis_crossing_lanes(
} }
let mut windows = request.windows.clone(); let mut windows = request.windows.clone();
windows.sort_by_key(|window| window.node_id.0); windows.sort_by_key(|window| lane_index_for_direction(*window, axis));
if windows.windows(2).any(|pair| {
lane_index_for_direction(pair[0], axis) == lane_index_for_direction(pair[1], axis)
}) {
return None;
}
let mut phase1 = vec![]; let mut phase1 = vec![];
let mut phase2 = vec![]; let mut phase2 = vec![];
let mut phase3 = vec![]; let mut phase3 = vec![];
@ -205,6 +210,15 @@ fn plan_axis_crossing_lanes(
) )
} }
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) {
std::cmp::Ordering::Greater => Some(0),
std::cmp::Ordering::Less => Some(1),
std::cmp::Ordering::Equal => None,
}
}
fn plan_space_then_orthogonal_growth( fn plan_space_then_orthogonal_growth(
request: &MultiphaseRequest, request: &MultiphaseRequest,
axis: PhaseAxis, axis: PhaseAxis,
@ -627,6 +641,15 @@ mod tests {
plan.phases.iter().map(|phase| phase.action).collect() plan.phases.iter().map(|phase| phase.action).collect()
} }
fn step_to(plan: &MultiphasePlan, phase: usize, node_id: NodeId) -> Rect {
plan.phases[phase]
.steps
.iter()
.find(|step| step.node_id == node_id)
.unwrap()
.to
}
#[test] #[test]
fn horizontal_swap_shrinks_moves_then_grows_without_overlap() { fn horizontal_swap_shrinks_moves_then_grows_without_overlap() {
let req = request(vec![ let req = request(vec![
@ -679,8 +702,48 @@ mod tests {
}, },
]); ]);
let plan = plan_no_overlap(&req).unwrap(); let plan = plan_no_overlap(&req).unwrap();
assert_eq!(plan.phases[0].steps[0].to, rect(100, 0, 200, 50)); assert_eq!(step_to(&plan, 0, id(2)), rect(0, 0, 100, 50));
assert_eq!(plan.phases[0].steps[1].to, rect(0, 50, 100, 100)); assert_eq!(step_to(&plan, 0, id(1)), rect(100, 50, 200, 100));
assert!(validate_plan_continuous(&req, &plan));
}
#[test]
fn horizontal_swap_lanes_follow_motion_direction_not_node_id() {
let req = request(vec![
MultiphaseWindow {
node_id: id(1),
from: rect(100, 0, 200, 100),
to: rect(0, 0, 100, 100),
},
MultiphaseWindow {
node_id: id(2),
from: rect(0, 0, 100, 100),
to: rect(100, 0, 200, 100),
},
]);
let plan = plan_no_overlap(&req).unwrap();
assert_eq!(step_to(&plan, 0, id(2)), rect(0, 0, 100, 50));
assert_eq!(step_to(&plan, 0, id(1)), rect(100, 50, 200, 100));
assert!(validate_plan_continuous(&req, &plan));
}
#[test]
fn vertical_swap_lanes_follow_motion_direction_not_node_id() {
let req = request(vec![
MultiphaseWindow {
node_id: id(1),
from: rect(0, 100, 100, 200),
to: rect(0, 0, 100, 100),
},
MultiphaseWindow {
node_id: id(2),
from: rect(0, 0, 100, 100),
to: rect(0, 100, 100, 200),
},
]);
let plan = plan_no_overlap(&req).unwrap();
assert_eq!(step_to(&plan, 0, id(2)), rect(0, 0, 50, 100));
assert_eq!(step_to(&plan, 0, id(1)), rect(50, 100, 100, 200));
assert!(validate_plan_continuous(&req, &plan)); assert!(validate_plan_continuous(&req, &plan));
} }