router: have two navvertices, CW and CCW, for each trianvertex

This commit is contained in:
Mikolaj Wielgus 2024-06-22 17:26:37 +02:00
parent d34554f075
commit 0777b781f4
5 changed files with 99 additions and 96 deletions

View File

@ -127,21 +127,21 @@ impl<M: MesadataTrait> Autorouter<M> {
.filter(|ratline| {
let (source, target) = self.ratsnest.graph().edge_endpoints(*ratline).unwrap();
let source_vertex = self
let source_navvertex = self
.ratsnest
.graph()
.node_weight(source)
.unwrap()
.node_index();
let to_vertex = self
let to_navvertex = self
.ratsnest
.graph()
.node_weight(target)
.unwrap()
.node_index();
selection.contains_node(&self.board, source_vertex.into())
&& selection.contains_node(&self.board, to_vertex.into())
selection.contains_node(&self.board, source_navvertex.into())
&& selection.contains_node(&self.board, to_navvertex.into())
})
.collect()
}

View File

@ -27,8 +27,7 @@ pub enum DrawException {
#[error("cannot finish in {0:?}")]
CannotFinishIn(FixedDotIndex, #[source] LayoutException),
#[error("cannot wrap around {0:?}")]
// neither of the exceptions is the source on its own, might be useful to give them names?
CannotWrapAround(WraparoundableIndex, LayoutException, LayoutException),
CannotWrapAround(WraparoundableIndex, #[source] LayoutException),
}
pub struct Draw<'a, R: RulesTrait> {
@ -98,43 +97,25 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
&mut self,
head: Head,
around: FixedDotIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException> {
let mut tangents = self
let tangent = self
.guide()
.head_around_dot_segments(&head, around.into(), width)?;
.head_around_dot_segment(&head, around.into(), cw, width)?;
let offset = self
.guide()
.head_around_dot_offset(&head, around.into(), width);
let mut dirs = [true, false];
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
tangents = (tangents.1, tangents.0);
dirs = [false, true];
}
let mut errs = vec![];
for (i, tangent) in [tangents.0, tangents.1].iter().enumerate() {
match self.cane_around(
self.cane_around(
head,
around.into(),
tangent.start_point(),
tangent.end_point(),
dirs[i],
cw,
width,
offset,
) {
Ok(ok) => return Ok(ok),
Err(err) => errs.push(err),
}
}
Err(DrawException::CannotWrapAround(
around.into(),
errs[0],
errs[1],
))
)
.map_err(|err| DrawException::CannotWrapAround(around.into(), err))
}
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))]
@ -143,43 +124,26 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
&mut self,
head: Head,
around: BendIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException> {
let mut tangents = self
let tangent = self
.guide()
.head_around_bend_segments(&head, around.into(), width)?;
.head_around_bend_segment(&head, around.into(), cw, width)?;
let offset = self
.guide()
.head_around_bend_offset(&head, around.into(), width);
let mut dirs = [true, false];
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
tangents = (tangents.1, tangents.0);
dirs = [false, true];
}
let mut errs = vec![];
for (i, tangent) in [tangents.0, tangents.1].iter().enumerate() {
match self.cane_around(
self.cane_around(
head,
around.into(),
tangent.start_point(),
tangent.end_point(),
dirs[i],
cw,
width,
offset,
) {
Ok(ok) => return Ok(ok),
Err(err) => errs.push(err),
}
}
Err(DrawException::CannotWrapAround(
around.into(),
errs[0],
errs[1],
))
)
.map_err(|err| DrawException::CannotWrapAround(around.into(), err))
}
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))]

View File

@ -81,6 +81,7 @@ impl HasPosition for TrianvertexWeight {
#[derive(Debug, Clone)]
pub struct NavvertexWeight {
pub node: BinavvertexNodeIndex,
pub maybe_cw: Option<bool>,
}
#[derive(Error, Debug, Clone)]
@ -93,9 +94,9 @@ pub enum NavmeshError {
pub struct Navmesh {
graph: UnGraph<NavvertexWeight, (), usize>,
source: FixedDotIndex,
source_vertex: NodeIndex<usize>,
source_navvertex: NodeIndex<usize>,
target: FixedDotIndex,
target_vertex: NodeIndex<usize>,
target_navvertex: NodeIndex<usize>,
}
impl Navmesh {
@ -138,36 +139,62 @@ impl Navmesh {
}
let mut graph: UnGraph<NavvertexWeight, (), usize> = UnGraph::default();
let mut source_vertex = None;
let mut target_vertex = None;
let mut source_navvertex = None;
let mut target_navvertex = None;
// `HashMap` is obviously suboptimal here.
let mut map = HashMap::new();
for trianvertex in triangulation.node_identifiers() {
let binavvertex = if trianvertex == source.into() {
let navvertex = graph.add_node(NavvertexWeight {
node: trianvertex.into(),
maybe_cw: None,
});
if trianvertex == source.into() {
source_vertex = Some(navvertex);
source_navvertex = Some(navvertex);
(navvertex, navvertex)
} else if trianvertex == target.into() {
target_vertex = Some(navvertex);
}
let navvertex = graph.add_node(NavvertexWeight {
node: trianvertex.into(),
maybe_cw: None,
});
map.insert(trianvertex, navvertex);
target_navvertex = Some(navvertex);
(navvertex, navvertex)
} else {
let navvertex1 = graph.add_node(NavvertexWeight {
node: trianvertex.into(),
maybe_cw: Some(false),
});
let navvertex2 = graph.add_node(NavvertexWeight {
node: trianvertex.into(),
maybe_cw: Some(true),
});
(navvertex1, navvertex2)
};
map.insert(trianvertex, binavvertex);
}
for edge in triangulation.edge_references() {
graph.add_edge(map[&edge.source()], map[&edge.target()], ());
let (from_navvertex1, from_navvertex2) = map[&edge.source()];
let (to_navvertex1, to_navvertex2) = map[&edge.target()];
graph.update_edge(from_navvertex1, to_navvertex1, ());
graph.update_edge(from_navvertex1, to_navvertex2, ());
graph.update_edge(from_navvertex2, to_navvertex1, ());
graph.update_edge(from_navvertex2, to_navvertex2, ());
}
Ok(Self {
graph,
source,
source_vertex: source_vertex.unwrap(),
source_navvertex: source_navvertex.unwrap(),
target,
target_vertex: target_vertex.unwrap(),
target_navvertex: target_navvertex.unwrap(),
})
}
@ -179,15 +206,15 @@ impl Navmesh {
self.source
}
pub fn source_vertex(&self) -> NodeIndex<usize> {
self.source_vertex
pub fn source_navvertex(&self) -> NodeIndex<usize> {
self.source_navvertex
}
pub fn target(&self) -> FixedDotIndex {
self.target
}
pub fn target_vertex(&self) -> NodeIndex<usize> {
self.target_vertex
pub fn target_navvertex(&self) -> NodeIndex<usize> {
self.target_navvertex
}
}

View File

@ -142,13 +142,13 @@ impl<'a, R: RulesTrait> Router<'a, R> {
let trace = tracer.start(
self.navmesh.graph(),
self.navmesh.source(),
self.navmesh.source_vertex(),
self.navmesh.source_navvertex(),
width,
);
let (_cost, _path, band) = astar(
self.navmesh.graph(),
self.navmesh.source_vertex(),
self.navmesh.source_navvertex(),
&mut RouterAstarStrategy::new(tracer, trace, self.navmesh.target()),
)?;

View File

@ -38,11 +38,11 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
&mut self,
_graph: &UnGraph<NavvertexWeight, (), usize>,
source: FixedDotIndex,
source_vertex: NodeIndex<usize>,
source_navvertex: NodeIndex<usize>,
width: f64,
) -> Trace {
Trace {
path: vec![source_vertex],
path: vec![source_navvertex],
head: BareHead { dot: source }.into(),
width,
}
@ -132,13 +132,15 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
around: NodeIndex<usize>,
width: f64,
) -> Result<CaneHead, DrawException> {
let cw = self.maybe_cw(graph, around).unwrap();
match self.binavvertex(graph, around) {
BinavvertexNodeIndex::FixedDot(dot) => {
self.wrap_around_fixed_dot(graph, head, dot, width)
self.wrap_around_fixed_dot(graph, head, dot, cw, width)
}
BinavvertexNodeIndex::FixedBend(_fixed_bend) => todo!(),
BinavvertexNodeIndex::LooseBend(loose_bend) => {
self.wrap_around_loose_bend(graph, head, loose_bend, width)
self.wrap_around_loose_bend(graph, head, loose_bend, cw, width)
}
}
}
@ -148,9 +150,10 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
graph: &UnGraph<NavvertexWeight, (), usize>,
head: Head,
around: FixedDotIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException> {
let head = Draw::new(self.layout).cane_around_dot(head, around.into(), width)?;
let head = Draw::new(self.layout).cane_around_dot(head, around.into(), cw, width)?;
Ok(head)
}
@ -159,9 +162,10 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
graph: &UnGraph<NavvertexWeight, (), usize>,
head: Head,
around: LooseBendIndex,
cw: bool,
width: f64,
) -> Result<CaneHead, DrawException> {
let head = Draw::new(self.layout).cane_around_bend(head, around.into(), width)?;
let head = Draw::new(self.layout).cane_around_bend(head, around.into(), cw, width)?;
Ok(head)
}
@ -177,19 +181,27 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
trace.path.pop();
}
fn maybe_cw(
&self,
graph: &UnGraph<NavvertexWeight, (), usize>,
navvertex: NodeIndex<usize>,
) -> Option<bool> {
graph.node_weight(navvertex).unwrap().maybe_cw
}
fn binavvertex(
&self,
graph: &UnGraph<NavvertexWeight, (), usize>,
vertex: NodeIndex<usize>,
navvertex: NodeIndex<usize>,
) -> BinavvertexNodeIndex {
graph.node_weight(vertex).unwrap().node
graph.node_weight(navvertex).unwrap().node
}
fn primitive(
&self,
graph: &UnGraph<NavvertexWeight, (), usize>,
vertex: NodeIndex<usize>,
navvertex: NodeIndex<usize>,
) -> PrimitiveIndex {
self.binavvertex(graph, vertex).into()
self.binavvertex(graph, navvertex).into()
}
}