Observe released router 715036e1 in frozen common harness
This commit is contained in:
@@ -846,19 +846,15 @@ fn route_edge(
|
||||
.enumerate()
|
||||
{
|
||||
let incoming = points.iter().rev().find(|&&p| p != start).copied();
|
||||
// Only the final leg has a known continuation. Intermediate
|
||||
// authored pins must not inherit the target's terminal direction.
|
||||
let outgoing = (index == pins.len()).then_some(b.point);
|
||||
let path =
|
||||
fast_path(start, end, &space, &occupied, incoming, outgoing).or_else(|| {
|
||||
if !search {
|
||||
return None;
|
||||
}
|
||||
let (path, hit_limit) =
|
||||
grid_path(start, end, &space, &occupied, incoming, outgoing, budget);
|
||||
exhausted |= hit_limit;
|
||||
path
|
||||
});
|
||||
let path = fast_path(start, end, &space, &occupied, incoming).or_else(|| {
|
||||
if !search {
|
||||
return None;
|
||||
}
|
||||
let (path, hit_limit) =
|
||||
grid_path(start, end, &space, &occupied, incoming, budget);
|
||||
exhausted |= hit_limit;
|
||||
path
|
||||
});
|
||||
let Some(path) = path else {
|
||||
failed = true;
|
||||
break;
|
||||
@@ -1055,7 +1051,6 @@ fn fast_path(
|
||||
space: &RoutingSpace<'_>,
|
||||
previous: &[Segment],
|
||||
incoming: Option<Position>,
|
||||
outgoing: Option<Position>,
|
||||
) -> Option<Vec<Position>> {
|
||||
let obstacles = space.obstacles;
|
||||
if obstacles
|
||||
@@ -1075,9 +1070,6 @@ fn fast_path(
|
||||
incoming
|
||||
.zip(path.get(1))
|
||||
.map_or(0.0, |(before, &after)| turn_cost(before, start, after))
|
||||
+ outgoing
|
||||
.zip(path.len().checked_sub(2).and_then(|i| path.get(i)))
|
||||
.map_or(0.0, |(after, &before)| turn_cost(before, end, after))
|
||||
};
|
||||
let estimate = |path: &[Position]| base_cost(path) + join(path);
|
||||
candidates.sort_by(|a, b| estimate(a).total_cmp(&estimate(b)));
|
||||
@@ -1149,14 +1141,12 @@ impl Ord for QueueItem {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn grid_path(
|
||||
start: Position,
|
||||
end: Position,
|
||||
space: &RoutingSpace<'_>,
|
||||
previous: &[Segment],
|
||||
incoming: Option<Position>,
|
||||
outgoing: Option<Position>,
|
||||
budget: &mut usize,
|
||||
) -> (Option<Vec<Position>>, bool) {
|
||||
let obstacles = space.obstacles;
|
||||
@@ -1247,10 +1237,6 @@ fn grid_path(
|
||||
let cost = current.cost
|
||||
+ manhattan(a, b)
|
||||
+ before.map_or(0.0, |before| turn_cost(before, a, b))
|
||||
// Charge before queueing the target so competing arrival
|
||||
// directions are compared by their complete terminal cost.
|
||||
+ outgoing.filter(|_| next == last)
|
||||
.map_or(0.0, |after| turn_cost(a, b, after))
|
||||
+ crossing_cost(a, b, previous);
|
||||
if cost >= costs[state] {
|
||||
continue;
|
||||
@@ -1605,146 +1591,3 @@ impl BoundsBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod terminal_join_tests {
|
||||
use super::*;
|
||||
|
||||
fn complete_cost(
|
||||
path: &[Position],
|
||||
before: Position,
|
||||
after: Position,
|
||||
occupied: &[Segment],
|
||||
) -> f32 {
|
||||
let mut complete = vec![before];
|
||||
complete.extend_from_slice(path);
|
||||
complete.push(after);
|
||||
path_cost(&complete, occupied)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_join_prefers_equal_bend_witness_without_shared_trunk() {
|
||||
// Four orientations prevent an accidental horizontal/right-only fix.
|
||||
for orientation in 0..4 {
|
||||
let transform = |p: Position| match orientation {
|
||||
0 => p,
|
||||
1 => pos(-p.x, p.y),
|
||||
2 => pos(p.y, p.x),
|
||||
_ => pos(-p.y, -p.x),
|
||||
};
|
||||
let start = transform(pos(0.0, 0.0));
|
||||
let end = transform(pos(46.0, 180.0));
|
||||
let before = transform(pos(-18.0, 0.0));
|
||||
let after = transform(pos(64.0, 180.0));
|
||||
let occupied = vec![Segment {
|
||||
a: start,
|
||||
b: transform(pos(46.0, 0.0)),
|
||||
count: 1,
|
||||
}];
|
||||
let space = RoutingSpace::new(&[]);
|
||||
let witness = vec![start, transform(pos(0.0, 180.0)), end];
|
||||
// Length262 + two turns48 =310. The other complete L path has
|
||||
// the same bends/length but pays46*0.12=5.52 in shared-run cost.
|
||||
assert!((complete_cost(&witness, before, after, &occupied) - 310.0).abs() < EPSILON);
|
||||
let fast = fast_path(start, end, &space, &occupied, Some(before), Some(after)).unwrap();
|
||||
assert_eq!(fast, witness);
|
||||
assert!((complete_cost(&fast, before, after, &occupied) - 310.0).abs() < EPSILON);
|
||||
// Exercise grid directly; public routing's valid fast path would
|
||||
// otherwise hide a target-state ordering regression in grid search.
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
end,
|
||||
&space,
|
||||
&occupied,
|
||||
Some(before),
|
||||
Some(after),
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
let grid = grid.unwrap();
|
||||
assert_eq!(grid, witness);
|
||||
assert!((complete_cost(&grid, before, after, &occupied) - 310.0).abs() < EPSILON);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unspecified_continuation_keeps_intermediate_leg_choice() {
|
||||
let start = pos(0.0, 0.0);
|
||||
let pin = pos(46.0, 180.0);
|
||||
let before = pos(-18.0, 0.0);
|
||||
let occupied = vec![Segment {
|
||||
a: start,
|
||||
b: pos(46.0, 0.0),
|
||||
count: 1,
|
||||
}];
|
||||
let space = RoutingSpace::new(&[]);
|
||||
let witness = vec![start, pos(46.0, 0.0), pin];
|
||||
let fast = fast_path(start, pin, &space, &occupied, Some(before), None).unwrap();
|
||||
assert_eq!(fast, witness);
|
||||
// An intermediate authored pin has no known outgoing continuation:
|
||||
// length226 + one turn24 + shared5.52 =255.52 for this leg.
|
||||
assert!((path_cost(&fast, &occupied) - 255.52).abs() < EPSILON);
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
pin,
|
||||
&space,
|
||||
&occupied,
|
||||
Some(before),
|
||||
None,
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
assert_eq!(grid.unwrap(), witness);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn straight_and_degenerate_terminal_legs_remain_exact() {
|
||||
let space = RoutingSpace::new(&[]);
|
||||
let start = pos(0.0, 0.0);
|
||||
let end = pos(46.0, 0.0);
|
||||
for after in [pos(64.0, 0.0), pos(28.0, 0.0)] {
|
||||
let before = pos(-18.0, 0.0);
|
||||
let fast = fast_path(start, end, &space, &[], Some(before), Some(after)).unwrap();
|
||||
let expected = if after.x > end.x { 82.0 } else { 130.0 };
|
||||
assert!((complete_cost(&fast, before, after, &[]) - expected).abs() < EPSILON);
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
end,
|
||||
&space,
|
||||
&[],
|
||||
Some(before),
|
||||
Some(after),
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
assert_eq!(grid.unwrap(), fast);
|
||||
}
|
||||
assert_eq!(
|
||||
fast_path(
|
||||
start,
|
||||
start,
|
||||
&space,
|
||||
&[],
|
||||
Some(pos(-18.0, 0.0)),
|
||||
Some(pos(18.0, 0.0))
|
||||
)
|
||||
.unwrap(),
|
||||
vec![start]
|
||||
);
|
||||
let mut budget = VIEW_SEARCH_BUDGET;
|
||||
let (grid, exhausted) = grid_path(
|
||||
start,
|
||||
start,
|
||||
&space,
|
||||
&[],
|
||||
Some(pos(-18.0, 0.0)),
|
||||
Some(pos(18.0, 0.0)),
|
||||
&mut budget,
|
||||
);
|
||||
assert!(!exhausted);
|
||||
assert_eq!(grid.unwrap(), vec![start]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user