mirror of https://codeberg.org/topola/topola.git
feat(planar-incr-embed): make PmgAstar's evaluate_navmesh interface way more ergonomic
This commit is contained in:
parent
bb1cfc76d9
commit
3a2c9deff0
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
algo::{Goal, PreparedGoal},
|
algo::{Goal, PreparedGoal},
|
||||||
|
mayrev::MaybeReversed,
|
||||||
navmesh::{EdgeIndex, EdgePaths, Navmesh, NavmeshRef, NavmeshRefMut},
|
navmesh::{EdgeIndex, EdgePaths, Navmesh, NavmeshRef, NavmeshRefMut},
|
||||||
Edge, NavmeshBase, NavmeshIndex, RelaxedPath,
|
Edge, NavmeshBase, NavmeshIndex, RelaxedPath,
|
||||||
};
|
};
|
||||||
|
|
@ -69,19 +70,28 @@ pub struct TaskResult<B: NavmeshBase, Ctx> {
|
||||||
pub context: Ctx,
|
pub context: Ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct InsertionInfo<B: NavmeshBase> {
|
||||||
|
pub prev_node: NavmeshIndex<B::PrimalNodeIndex>,
|
||||||
|
pub cur_node: NavmeshIndex<B::PrimalNodeIndex>,
|
||||||
|
pub edge_meta: Edge<B::PrimalNodeIndex>,
|
||||||
|
pub epi: MaybeReversed<usize, RelaxedPath<B::EtchedPath, B::GapComment>>,
|
||||||
|
|
||||||
|
/// the introduction position re: `prev_node` -edge-> `cur_node`
|
||||||
|
pub intro: usize,
|
||||||
|
|
||||||
|
pub maybe_new_goal: Option<B::EtchedPath>,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait EvaluateNavmesh<B: NavmeshBase, Ctx>:
|
pub trait EvaluateNavmesh<B: NavmeshBase, Ctx>:
|
||||||
Fn(NavmeshRef<B>, &Ctx, EdgeIndex<NavmeshIndex<B::PrimalNodeIndex>>) -> Option<(B::Scalar, Ctx)>
|
FnMut(NavmeshRef<B>, &Ctx, InsertionInfo<B>) -> Option<(B::Scalar, Ctx)>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B, Ctx, F> EvaluateNavmesh<B, Ctx> for F
|
impl<B, Ctx, F> EvaluateNavmesh<B, Ctx> for F
|
||||||
where
|
where
|
||||||
B: NavmeshBase,
|
B: NavmeshBase,
|
||||||
F: Fn(
|
F: FnMut(NavmeshRef<B>, &Ctx, InsertionInfo<B>) -> Option<(B::Scalar, Ctx)>,
|
||||||
NavmeshRef<B>,
|
|
||||||
&Ctx,
|
|
||||||
EdgeIndex<NavmeshIndex<B::PrimalNodeIndex>>,
|
|
||||||
) -> Option<(B::Scalar, Ctx)>,
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,54 +210,67 @@ impl<B: NavmeshBase<Scalar = Scalar>, Scalar: num_traits::Float + core::iter::Su
|
||||||
|
|
||||||
impl<B: NavmeshBase> PreparedGoal<B>
|
impl<B: NavmeshBase> PreparedGoal<B>
|
||||||
where
|
where
|
||||||
B::GapComment: Clone,
|
B::EtchedPath: PartialOrd,
|
||||||
B::Scalar: num_traits::Float + core::iter::Sum,
|
B::GapComment: PartialOrd + Clone,
|
||||||
|
B::Scalar: num_traits::Float + num_traits::float::TotalOrder + core::iter::Sum,
|
||||||
{
|
{
|
||||||
/// start processing the goal
|
/// start processing the goal
|
||||||
fn start_pmga<'a, Ctx, F: EvaluateNavmesh<B, Ctx>>(
|
fn start_pmga<Ctx, F: EvaluateNavmesh<B, Ctx>>(
|
||||||
&'a self,
|
&self,
|
||||||
navmesh: NavmeshRef<'a, B>,
|
navmesh: NavmeshRef<'_, B>,
|
||||||
goal_idx: usize,
|
goal_idx: usize,
|
||||||
env: &'a PmgAstar<B, Ctx>,
|
env: &PmgAstar<B, Ctx>,
|
||||||
context: &'a Ctx,
|
context: &Ctx,
|
||||||
evaluate_navmesh: &'a F,
|
evaluate_navmesh: &mut F,
|
||||||
) -> Option<impl Iterator<Item = Task<B, Ctx>> + 'a> {
|
) -> BinaryHeap<Task<B, Ctx>> {
|
||||||
let source = NavmeshIndex::Primal(self.source.clone());
|
let source = NavmeshIndex::Primal(self.source.clone());
|
||||||
let estimated_remaining_goals = env.estimate_remaining_goals_costs(goal_idx);
|
let estimated_remaining_goals = env.estimate_remaining_goals_costs(goal_idx);
|
||||||
Some(
|
let neighs = match navmesh.node_data(&source) {
|
||||||
navmesh
|
None => return BinaryHeap::new(),
|
||||||
.node_data(&source)?
|
Some(x) => &x.neighs,
|
||||||
.neighs
|
};
|
||||||
.iter()
|
|
||||||
.filter_map({
|
let mut ret = BinaryHeap::new();
|
||||||
|
|
||||||
|
// NOTE: this uses a `for` loop to get around borrowing problems with `evaluate_navmesh`
|
||||||
|
for (neigh, emeta, epi, edge_len) in neighs.iter().filter_map({
|
||||||
let source = source.clone();
|
let source = source.clone();
|
||||||
move |neigh| {
|
move |neigh| {
|
||||||
navmesh
|
navmesh
|
||||||
.resolve_edge_data(source.clone(), neigh.clone())
|
.resolve_edge_data(source.clone(), neigh.clone())
|
||||||
.map(|(_, epi)| {
|
.map(|(emeta, epi)| {
|
||||||
let edge_len = navmesh.access_edge_paths(epi).len();
|
let edge_len = navmesh.access_edge_paths(epi).len();
|
||||||
(neigh, epi, edge_len)
|
(neigh, emeta.to_owned(), epi, edge_len)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
}) {
|
||||||
.flat_map(move |(neigh, epi, edge_len)| {
|
|
||||||
let eidx = EdgeIndex::from((source.clone(), neigh.clone()));
|
|
||||||
let source = source.clone();
|
let source = source.clone();
|
||||||
// A*-like remaining costs estimation
|
// A*-like remaining costs estimation
|
||||||
let estimated_remaining =
|
let estimated_remaining =
|
||||||
self.estimate_costs_for_source::<B::GapComment>(navmesh, neigh);
|
self.estimate_costs_for_source::<B::GapComment>(navmesh, neigh);
|
||||||
(0..=edge_len).filter_map(move |i| {
|
for i in 0..=edge_len {
|
||||||
let mut edge_paths = Box::from(navmesh.edge_paths);
|
let mut edge_paths = Box::from(navmesh.edge_paths);
|
||||||
let mut navmesh = NavmeshRefMut {
|
let mut navmesh = NavmeshRefMut {
|
||||||
nodes: navmesh.nodes,
|
nodes: navmesh.nodes,
|
||||||
edges: navmesh.edges,
|
edges: navmesh.edges,
|
||||||
edge_paths: &mut edge_paths,
|
edge_paths: &mut edge_paths,
|
||||||
};
|
};
|
||||||
navmesh.access_edge_paths_mut(epi).with_borrow_mut(|mut j| {
|
navmesh
|
||||||
j.insert(i, RelaxedPath::Normal(self.label.clone()))
|
.access_edge_paths_mut(epi)
|
||||||
});
|
.with_borrow_mut(|mut j| j.insert(i, RelaxedPath::Normal(self.label.clone())));
|
||||||
evaluate_navmesh(navmesh.as_ref(), context, eidx.clone()).map(
|
if let Some(new_task) = (*evaluate_navmesh)(
|
||||||
|(costs, context)| Task {
|
navmesh.as_ref(),
|
||||||
|
context,
|
||||||
|
InsertionInfo {
|
||||||
|
prev_node: source.clone(),
|
||||||
|
cur_node: neigh.clone(),
|
||||||
|
edge_meta: emeta.clone(),
|
||||||
|
epi,
|
||||||
|
intro: i,
|
||||||
|
maybe_new_goal: Some(self.label.clone()),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(|(costs, context)| Task {
|
||||||
goal_idx,
|
goal_idx,
|
||||||
costs,
|
costs,
|
||||||
estimated_remaining,
|
estimated_remaining,
|
||||||
|
|
@ -257,11 +280,13 @@ where
|
||||||
prev_node: source.clone(),
|
prev_node: source.clone(),
|
||||||
cur_intro: edge_len - i,
|
cur_intro: edge_len - i,
|
||||||
context,
|
context,
|
||||||
},
|
}) {
|
||||||
)
|
ret.push(new_task);
|
||||||
})
|
}
|
||||||
}),
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,7 +334,7 @@ where
|
||||||
fn progress<F: EvaluateNavmesh<B, Ctx>>(
|
fn progress<F: EvaluateNavmesh<B, Ctx>>(
|
||||||
&self,
|
&self,
|
||||||
env: &mut PmgAstar<B, Ctx>,
|
env: &mut PmgAstar<B, Ctx>,
|
||||||
evaluate_navmesh: F,
|
mut evaluate_navmesh: F,
|
||||||
) -> Vec<NavmeshIndex<B::PrimalNodeIndex>> {
|
) -> Vec<NavmeshIndex<B::PrimalNodeIndex>> {
|
||||||
let goal_idx = self.goal_idx;
|
let goal_idx = self.goal_idx;
|
||||||
let navmesh = NavmeshRef {
|
let navmesh = NavmeshRef {
|
||||||
|
|
@ -345,11 +370,11 @@ where
|
||||||
edges: &env.edges,
|
edges: &env.edges,
|
||||||
edge_paths: &mut edge_paths,
|
edge_paths: &mut edge_paths,
|
||||||
};
|
};
|
||||||
let eidx = EdgeIndex::from((self.selected_node.clone(), neigh.clone()));
|
let (edge_meta, epi) = navmesh
|
||||||
let cur_intro = navmesh
|
.resolve_edge_data(self.selected_node.clone(), neigh.clone())
|
||||||
.edge_data_mut(self.selected_node.clone(), neigh.clone())
|
.unwrap();
|
||||||
.unwrap()
|
let edge_meta = edge_meta.to_owned();
|
||||||
.with_borrow_mut(|mut x| {
|
let cur_intro = navmesh.access_edge_paths_mut(epi).with_borrow_mut(|mut x| {
|
||||||
x.insert(
|
x.insert(
|
||||||
stop_data.insert_pos,
|
stop_data.insert_pos,
|
||||||
RelaxedPath::Normal(goal.label.clone()),
|
RelaxedPath::Normal(goal.label.clone()),
|
||||||
|
|
@ -357,8 +382,19 @@ where
|
||||||
x.len() - stop_data.insert_pos - 1
|
x.len() - stop_data.insert_pos - 1
|
||||||
});
|
});
|
||||||
ret.push(neigh.clone());
|
ret.push(neigh.clone());
|
||||||
evaluate_navmesh(navmesh.as_ref(), &self.context, eidx).map(|(costs, context)| {
|
evaluate_navmesh(
|
||||||
Task {
|
navmesh.as_ref(),
|
||||||
|
&self.context,
|
||||||
|
InsertionInfo {
|
||||||
|
prev_node: self.selected_node.clone(),
|
||||||
|
cur_node: neigh.clone(),
|
||||||
|
edge_meta,
|
||||||
|
epi,
|
||||||
|
intro: stop_data.insert_pos,
|
||||||
|
maybe_new_goal: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(|(costs, context)| Task {
|
||||||
goal_idx,
|
goal_idx,
|
||||||
costs,
|
costs,
|
||||||
estimated_remaining,
|
estimated_remaining,
|
||||||
|
|
@ -368,7 +404,6 @@ where
|
||||||
prev_node: self.selected_node.clone(),
|
prev_node: self.selected_node.clone(),
|
||||||
cur_intro,
|
cur_intro,
|
||||||
context,
|
context,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -405,7 +440,7 @@ where
|
||||||
navmesh: &Navmesh<B>,
|
navmesh: &Navmesh<B>,
|
||||||
goals: Vec<Goal<B::PrimalNodeIndex, B::EtchedPath>>,
|
goals: Vec<Goal<B::PrimalNodeIndex, B::EtchedPath>>,
|
||||||
context: &Ctx,
|
context: &Ctx,
|
||||||
evaluate_navmesh: F,
|
mut evaluate_navmesh: F,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
queue: BinaryHeap::new(),
|
queue: BinaryHeap::new(),
|
||||||
|
|
@ -428,14 +463,7 @@ where
|
||||||
edges: &this.edges,
|
edges: &this.edges,
|
||||||
edge_paths: &navmesh.edge_paths,
|
edge_paths: &navmesh.edge_paths,
|
||||||
};
|
};
|
||||||
let tmp = if let Some(iter) =
|
first_goal.start_pmga(navmesh, 0, &this, context, &mut evaluate_navmesh)
|
||||||
first_goal.start_pmga(navmesh, 0, &this, context, &evaluate_navmesh)
|
|
||||||
{
|
|
||||||
iter.collect()
|
|
||||||
} else {
|
|
||||||
BinaryHeap::new()
|
|
||||||
};
|
|
||||||
tmp
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -449,7 +477,7 @@ where
|
||||||
/// run one step of the path-search
|
/// run one step of the path-search
|
||||||
pub fn step<F: EvaluateNavmesh<B, Ctx>>(
|
pub fn step<F: EvaluateNavmesh<B, Ctx>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
evaluate_navmesh: F,
|
mut evaluate_navmesh: F,
|
||||||
) -> ControlFlow<
|
) -> ControlFlow<
|
||||||
Option<(
|
Option<(
|
||||||
B::Scalar,
|
B::Scalar,
|
||||||
|
|
@ -465,7 +493,7 @@ where
|
||||||
log::info!("found no complete result");
|
log::info!("found no complete result");
|
||||||
return ControlFlow::Break(None);
|
return ControlFlow::Break(None);
|
||||||
};
|
};
|
||||||
ControlFlow::Continue(match task.run(self, &evaluate_navmesh) {
|
ControlFlow::Continue(match task.run(self, &mut evaluate_navmesh) {
|
||||||
ControlFlow::Break(taskres) => {
|
ControlFlow::Break(taskres) => {
|
||||||
let next_goal_idx = taskres.goal_idx + 1;
|
let next_goal_idx = taskres.goal_idx + 1;
|
||||||
let navmesh = NavmeshRef {
|
let navmesh = NavmeshRef {
|
||||||
|
|
@ -496,17 +524,13 @@ where
|
||||||
edge_count,
|
edge_count,
|
||||||
taskres.costs,
|
taskres.costs,
|
||||||
);
|
);
|
||||||
let mut tmp = if let Some(iter) = next_goal.start_pmga(
|
let mut tmp = next_goal.start_pmga(
|
||||||
navmesh,
|
navmesh,
|
||||||
next_goal_idx,
|
next_goal_idx,
|
||||||
self,
|
self,
|
||||||
&taskres.context,
|
&taskres.context,
|
||||||
&evaluate_navmesh,
|
&mut evaluate_navmesh,
|
||||||
) {
|
);
|
||||||
iter.collect()
|
|
||||||
} else {
|
|
||||||
BinaryHeap::new()
|
|
||||||
};
|
|
||||||
let forks = tmp.iter().map(|i| i.selected_node.clone()).collect();
|
let forks = tmp.iter().map(|i| i.selected_node.clone()).collect();
|
||||||
self.queue.append(&mut tmp);
|
self.queue.append(&mut tmp);
|
||||||
IntermedResult {
|
IntermedResult {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,16 @@ impl<PNI> Edge<PNI> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<PNI: Clone> Edge<&PNI> {
|
||||||
|
#[inline]
|
||||||
|
pub fn to_owned(&self) -> Edge<PNI> {
|
||||||
|
Edge {
|
||||||
|
lhs: self.lhs.cloned(),
|
||||||
|
rhs: self.rhs.cloned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
any(test, feature = "serde"),
|
any(test, feature = "serde"),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue