diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index dfa7531..4eff5e7 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -127,21 +127,21 @@ impl Autorouter { .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() } diff --git a/src/router/draw.rs b/src/router/draw.rs index cafb2ab..e777f05 100644 --- a/src/router/draw.rs +++ b/src/router/draw.rs @@ -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 { - 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( - head, - around.into(), - tangent.start_point(), - tangent.end_point(), - dirs[i], - width, - offset, - ) { - Ok(ok) => return Ok(ok), - Err(err) => errs.push(err), - } - } - - Err(DrawException::CannotWrapAround( + self.cane_around( + head, around.into(), - errs[0], - errs[1], - )) + tangent.start_point(), + tangent.end_point(), + cw, + width, + offset, + ) + .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 { - 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( - head, - around.into(), - tangent.start_point(), - tangent.end_point(), - dirs[i], - width, - offset, - ) { - Ok(ok) => return Ok(ok), - Err(err) => errs.push(err), - } - } - - Err(DrawException::CannotWrapAround( + self.cane_around( + head, around.into(), - errs[0], - errs[1], - )) + tangent.start_point(), + tangent.end_point(), + cw, + width, + offset, + ) + .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))] diff --git a/src/router/navmesh.rs b/src/router/navmesh.rs index 48e8d02..9186da2 100644 --- a/src/router/navmesh.rs +++ b/src/router/navmesh.rs @@ -81,6 +81,7 @@ impl HasPosition for TrianvertexWeight { #[derive(Debug, Clone)] pub struct NavvertexWeight { pub node: BinavvertexNodeIndex, + pub maybe_cw: Option, } #[derive(Error, Debug, Clone)] @@ -93,9 +94,9 @@ pub enum NavmeshError { pub struct Navmesh { graph: UnGraph, source: FixedDotIndex, - source_vertex: NodeIndex, + source_navvertex: NodeIndex, target: FixedDotIndex, - target_vertex: NodeIndex, + target_navvertex: NodeIndex, } impl Navmesh { @@ -138,36 +139,62 @@ impl Navmesh { } let mut graph: UnGraph = 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 navvertex = graph.add_node(NavvertexWeight { - node: trianvertex.into(), - }); + 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 { - self.source_vertex + pub fn source_navvertex(&self) -> NodeIndex { + self.source_navvertex } pub fn target(&self) -> FixedDotIndex { self.target } - pub fn target_vertex(&self) -> NodeIndex { - self.target_vertex + pub fn target_navvertex(&self) -> NodeIndex { + self.target_navvertex } } diff --git a/src/router/router.rs b/src/router/router.rs index 4648c98..0cf3fd7 100644 --- a/src/router/router.rs +++ b/src/router/router.rs @@ -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()), )?; diff --git a/src/router/tracer.rs b/src/router/tracer.rs index 858a0ff..ec066ed 100644 --- a/src/router/tracer.rs +++ b/src/router/tracer.rs @@ -38,11 +38,11 @@ impl<'a, R: RulesTrait> Tracer<'a, R> { &mut self, _graph: &UnGraph, source: FixedDotIndex, - source_vertex: NodeIndex, + source_navvertex: NodeIndex, 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, width: f64, ) -> Result { + 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, head: Head, around: FixedDotIndex, + cw: bool, width: f64, ) -> Result { - 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, head: Head, around: LooseBendIndex, + cw: bool, width: f64, ) -> Result { - 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, + navvertex: NodeIndex, + ) -> Option { + graph.node_weight(navvertex).unwrap().maybe_cw + } + fn binavvertex( &self, graph: &UnGraph, - vertex: NodeIndex, + navvertex: NodeIndex, ) -> BinavvertexNodeIndex { - graph.node_weight(vertex).unwrap().node + graph.node_weight(navvertex).unwrap().node } fn primitive( &self, graph: &UnGraph, - vertex: NodeIndex, + navvertex: NodeIndex, ) -> PrimitiveIndex { - self.binavvertex(graph, vertex).into() + self.binavvertex(graph, navvertex).into() } }