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| { .filter(|ratline| {
let (source, target) = self.ratsnest.graph().edge_endpoints(*ratline).unwrap(); let (source, target) = self.ratsnest.graph().edge_endpoints(*ratline).unwrap();
let source_vertex = self let source_navvertex = self
.ratsnest .ratsnest
.graph() .graph()
.node_weight(source) .node_weight(source)
.unwrap() .unwrap()
.node_index(); .node_index();
let to_vertex = self let to_navvertex = self
.ratsnest .ratsnest
.graph() .graph()
.node_weight(target) .node_weight(target)
.unwrap() .unwrap()
.node_index(); .node_index();
selection.contains_node(&self.board, source_vertex.into()) selection.contains_node(&self.board, source_navvertex.into())
&& selection.contains_node(&self.board, to_vertex.into()) && selection.contains_node(&self.board, to_navvertex.into())
}) })
.collect() .collect()
} }

View File

@ -27,8 +27,7 @@ pub enum DrawException {
#[error("cannot finish in {0:?}")] #[error("cannot finish in {0:?}")]
CannotFinishIn(FixedDotIndex, #[source] LayoutException), CannotFinishIn(FixedDotIndex, #[source] LayoutException),
#[error("cannot wrap around {0:?}")] #[error("cannot wrap around {0:?}")]
// neither of the exceptions is the source on its own, might be useful to give them names? CannotWrapAround(WraparoundableIndex, #[source] LayoutException),
CannotWrapAround(WraparoundableIndex, LayoutException, LayoutException),
} }
pub struct Draw<'a, R: RulesTrait> { pub struct Draw<'a, R: RulesTrait> {
@ -98,43 +97,25 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
&mut self, &mut self,
head: Head, head: Head,
around: FixedDotIndex, around: FixedDotIndex,
cw: bool,
width: f64, width: f64,
) -> Result<CaneHead, DrawException> { ) -> Result<CaneHead, DrawException> {
let mut tangents = self let tangent = self
.guide() .guide()
.head_around_dot_segments(&head, around.into(), width)?; .head_around_dot_segment(&head, around.into(), cw, width)?;
let offset = self let offset = self
.guide() .guide()
.head_around_dot_offset(&head, around.into(), width); .head_around_dot_offset(&head, around.into(), width);
let mut dirs = [true, false]; self.cane_around(
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(
head, head,
around.into(), around.into(),
tangent.start_point(), tangent.start_point(),
tangent.end_point(), tangent.end_point(),
dirs[i], cw,
width, width,
offset, offset,
) { )
Ok(ok) => return Ok(ok), .map_err(|err| DrawException::CannotWrapAround(around.into(), err))
Err(err) => errs.push(err),
}
}
Err(DrawException::CannotWrapAround(
around.into(),
errs[0],
errs[1],
))
} }
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))] #[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, &mut self,
head: Head, head: Head,
around: BendIndex, around: BendIndex,
cw: bool,
width: f64, width: f64,
) -> Result<CaneHead, DrawException> { ) -> Result<CaneHead, DrawException> {
let mut tangents = self let tangent = self
.guide() .guide()
.head_around_bend_segments(&head, around.into(), width)?; .head_around_bend_segment(&head, around.into(), cw, width)?;
let offset = self let offset = self
.guide() .guide()
.head_around_bend_offset(&head, around.into(), width); .head_around_bend_offset(&head, around.into(), width);
let mut dirs = [true, false];
if tangents.1.euclidean_length() < tangents.0.euclidean_length() { self.cane_around(
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(
head, head,
around.into(), around.into(),
tangent.start_point(), tangent.start_point(),
tangent.end_point(), tangent.end_point(),
dirs[i], cw,
width, width,
offset, offset,
) { )
Ok(ok) => return Ok(ok), .map_err(|err| DrawException::CannotWrapAround(around.into(), err))
Err(err) => errs.push(err),
}
}
Err(DrawException::CannotWrapAround(
around.into(),
errs[0],
errs[1],
))
} }
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))] #[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)] #[derive(Debug, Clone)]
pub struct NavvertexWeight { pub struct NavvertexWeight {
pub node: BinavvertexNodeIndex, pub node: BinavvertexNodeIndex,
pub maybe_cw: Option<bool>,
} }
#[derive(Error, Debug, Clone)] #[derive(Error, Debug, Clone)]
@ -93,9 +94,9 @@ pub enum NavmeshError {
pub struct Navmesh { pub struct Navmesh {
graph: UnGraph<NavvertexWeight, (), usize>, graph: UnGraph<NavvertexWeight, (), usize>,
source: FixedDotIndex, source: FixedDotIndex,
source_vertex: NodeIndex<usize>, source_navvertex: NodeIndex<usize>,
target: FixedDotIndex, target: FixedDotIndex,
target_vertex: NodeIndex<usize>, target_navvertex: NodeIndex<usize>,
} }
impl Navmesh { impl Navmesh {
@ -138,36 +139,62 @@ impl Navmesh {
} }
let mut graph: UnGraph<NavvertexWeight, (), usize> = UnGraph::default(); let mut graph: UnGraph<NavvertexWeight, (), usize> = UnGraph::default();
let mut source_vertex = None; let mut source_navvertex = None;
let mut target_vertex = None; let mut target_navvertex = None;
// `HashMap` is obviously suboptimal here. // `HashMap` is obviously suboptimal here.
let mut map = HashMap::new(); let mut map = HashMap::new();
for trianvertex in triangulation.node_identifiers() { for trianvertex in triangulation.node_identifiers() {
let binavvertex = if trianvertex == source.into() {
let navvertex = graph.add_node(NavvertexWeight { let navvertex = graph.add_node(NavvertexWeight {
node: trianvertex.into(), node: trianvertex.into(),
maybe_cw: None,
}); });
if trianvertex == source.into() { source_navvertex = Some(navvertex);
source_vertex = Some(navvertex); (navvertex, navvertex)
} else if trianvertex == target.into() { } 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() { 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 { Ok(Self {
graph, graph,
source, source,
source_vertex: source_vertex.unwrap(), source_navvertex: source_navvertex.unwrap(),
target, target,
target_vertex: target_vertex.unwrap(), target_navvertex: target_navvertex.unwrap(),
}) })
} }
@ -179,15 +206,15 @@ impl Navmesh {
self.source self.source
} }
pub fn source_vertex(&self) -> NodeIndex<usize> { pub fn source_navvertex(&self) -> NodeIndex<usize> {
self.source_vertex self.source_navvertex
} }
pub fn target(&self) -> FixedDotIndex { pub fn target(&self) -> FixedDotIndex {
self.target self.target
} }
pub fn target_vertex(&self) -> NodeIndex<usize> { pub fn target_navvertex(&self) -> NodeIndex<usize> {
self.target_vertex self.target_navvertex
} }
} }

View File

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

View File

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