mirror of https://codeberg.org/topola/topola.git
router: have two navvertices, CW and CCW, for each trianvertex
This commit is contained in:
parent
d34554f075
commit
0777b781f4
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
head,
|
||||||
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(
|
|
||||||
around.into(),
|
around.into(),
|
||||||
errs[0],
|
tangent.start_point(),
|
||||||
errs[1],
|
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))]
|
#[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);
|
head,
|
||||||
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(
|
|
||||||
around.into(),
|
around.into(),
|
||||||
errs[0],
|
tangent.start_point(),
|
||||||
errs[1],
|
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))]
|
#[debug_ensures(ret.is_ok() -> self.layout.drawing().node_count() == old(self.layout.drawing().node_count() + 4))]
|
||||||
|
|
|
||||||
|
|
@ -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 navvertex = graph.add_node(NavvertexWeight {
|
let binavvertex = if trianvertex == source.into() {
|
||||||
node: trianvertex.into(),
|
let navvertex = graph.add_node(NavvertexWeight {
|
||||||
});
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue