Observe released router 715036e1 in frozen common harness
This commit is contained in:
@@ -846,19 +846,15 @@ fn route_edge(
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let incoming = points.iter().rev().find(|&&p| p != start).copied();
|
let incoming = points.iter().rev().find(|&&p| p != start).copied();
|
||||||
// Only the final leg has a known continuation. Intermediate
|
let path = fast_path(start, end, &space, &occupied, incoming).or_else(|| {
|
||||||
// authored pins must not inherit the target's terminal direction.
|
if !search {
|
||||||
let outgoing = (index == pins.len()).then_some(b.point);
|
return None;
|
||||||
let path =
|
}
|
||||||
fast_path(start, end, &space, &occupied, incoming, outgoing).or_else(|| {
|
let (path, hit_limit) =
|
||||||
if !search {
|
grid_path(start, end, &space, &occupied, incoming, budget);
|
||||||
return None;
|
exhausted |= hit_limit;
|
||||||
}
|
path
|
||||||
let (path, hit_limit) =
|
});
|
||||||
grid_path(start, end, &space, &occupied, incoming, outgoing, budget);
|
|
||||||
exhausted |= hit_limit;
|
|
||||||
path
|
|
||||||
});
|
|
||||||
let Some(path) = path else {
|
let Some(path) = path else {
|
||||||
failed = true;
|
failed = true;
|
||||||
break;
|
break;
|
||||||
@@ -1055,7 +1051,6 @@ fn fast_path(
|
|||||||
space: &RoutingSpace<'_>,
|
space: &RoutingSpace<'_>,
|
||||||
previous: &[Segment],
|
previous: &[Segment],
|
||||||
incoming: Option<Position>,
|
incoming: Option<Position>,
|
||||||
outgoing: Option<Position>,
|
|
||||||
) -> Option<Vec<Position>> {
|
) -> Option<Vec<Position>> {
|
||||||
let obstacles = space.obstacles;
|
let obstacles = space.obstacles;
|
||||||
if obstacles
|
if obstacles
|
||||||
@@ -1075,9 +1070,6 @@ fn fast_path(
|
|||||||
incoming
|
incoming
|
||||||
.zip(path.get(1))
|
.zip(path.get(1))
|
||||||
.map_or(0.0, |(before, &after)| turn_cost(before, start, after))
|
.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);
|
let estimate = |path: &[Position]| base_cost(path) + join(path);
|
||||||
candidates.sort_by(|a, b| estimate(a).total_cmp(&estimate(b)));
|
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(
|
fn grid_path(
|
||||||
start: Position,
|
start: Position,
|
||||||
end: Position,
|
end: Position,
|
||||||
space: &RoutingSpace<'_>,
|
space: &RoutingSpace<'_>,
|
||||||
previous: &[Segment],
|
previous: &[Segment],
|
||||||
incoming: Option<Position>,
|
incoming: Option<Position>,
|
||||||
outgoing: Option<Position>,
|
|
||||||
budget: &mut usize,
|
budget: &mut usize,
|
||||||
) -> (Option<Vec<Position>>, bool) {
|
) -> (Option<Vec<Position>>, bool) {
|
||||||
let obstacles = space.obstacles;
|
let obstacles = space.obstacles;
|
||||||
@@ -1247,10 +1237,6 @@ fn grid_path(
|
|||||||
let cost = current.cost
|
let cost = current.cost
|
||||||
+ manhattan(a, b)
|
+ manhattan(a, b)
|
||||||
+ before.map_or(0.0, |before| turn_cost(before, 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);
|
+ crossing_cost(a, b, previous);
|
||||||
if cost >= costs[state] {
|
if cost >= costs[state] {
|
||||||
continue;
|
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