router: store every vertex (fails tests but almost functional)

Previously, rail vertices were not stored but generated on demand from
data stored in a `Triangulation<...>`. This functionality is removed in
favor of storing every vertex in `Navmesh`'s own graph built from the
`Triangulation<...>`, which is now afterwards discarded.

Tests still fail and rails aren't added yet, but this is close enough to
completion for me to commit so that I can now go to sleep without
worrying.
This commit is contained in:
Mikolaj Wielgus 2024-06-20 01:32:27 +02:00
parent d4a310a5c0
commit ae2a862e0e
6 changed files with 202 additions and 275 deletions

View File

@ -33,7 +33,7 @@ use topola::{
math::Circle,
router::{
draw::DrawException,
navmesh::{Navmesh, NavmeshEdgeReference, NavvertexNodeIndex},
navmesh::{BinavvertexNodeIndex, Navmesh},
tracer::{Trace, Tracer},
},
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
@ -49,7 +49,7 @@ pub struct SharedData {
pub from: Option<FixedDotIndex>,
pub to: Option<FixedDotIndex>,
pub navmesh: Option<Navmesh>,
pub path: Vec<NavvertexNodeIndex>,
pub path: Vec<BinavvertexNodeIndex>,
pub ghosts: Vec<PrimitiveShape>,
pub highlighteds: Vec<PrimitiveIndex>,
}

View File

@ -5,7 +5,10 @@ use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use topola::{
autorouter::invoker::{Command, Invoker},
board::mesadata::MesadataTrait,
drawing::{graph::MakePrimitive, primitive::MakePrimitiveShape},
drawing::{
graph::{MakePrimitive, PrimitiveIndex},
primitive::MakePrimitiveShape,
},
geometry::{shape::ShapeTrait, GenericNode},
layout::{via::ViaWeight, zone::MakePolyShape},
math::Circle,
@ -165,14 +168,12 @@ impl Viewport {
}
if let Some(navmesh) = &shared_data.navmesh {
for edge in navmesh.edge_references() {
let from = edge
.source()
for edge in navmesh.graph().edge_references() {
let from = PrimitiveIndex::from(navmesh.graph().node_weight(edge.source()).unwrap().node)
.primitive(board.layout().drawing())
.shape()
.center();
let to = edge
.target()
let to = PrimitiveIndex::from(navmesh.graph().node_weight(edge.target()).unwrap().node)
.primitive(board.layout().drawing())
.shape()
.center();
@ -182,11 +183,11 @@ impl Viewport {
shared_data
.path
.iter()
.position(|node| *node == edge.source()),
.position(|node| *node == navmesh.graph().node_weight(edge.source()).unwrap().node),
shared_data
.path
.iter()
.position(|node| *node == edge.target()),
.position(|node| *node == navmesh.graph().node_weight(edge.target()).unwrap().node),
) {
if target_pos == source_pos + 1
|| source_pos == target_pos + 1

View File

@ -101,9 +101,9 @@ where
K: Measure + Copy,
G::NodeId: Eq + Hash,
{
fn is_goal(&mut self, node: G::NodeId, tracker: &PathTracker<G>) -> Option<R>;
fn edge_cost(&mut self, edge: G::EdgeRef) -> Option<K>;
fn estimate_cost(&mut self, node: G::NodeId) -> K;
fn is_goal(&mut self, graph: &G, node: G::NodeId, tracker: &PathTracker<G>) -> Option<R>;
fn edge_cost(&mut self, graph: &G, edge: G::EdgeRef) -> Option<K>;
fn estimate_cost(&mut self, graph: &G, node: G::NodeId) -> K;
}
pub struct Astar<G, K>
@ -153,7 +153,7 @@ where
let zero_score = K::default();
this.scores.insert(start, zero_score);
this.visit_next
.push(MinScored(strategy.estimate_cost(start), start));
.push(MinScored(strategy.estimate_cost(&&graph, start), start));
this
}
@ -165,7 +165,7 @@ where
return Err(AstarError::NotFound);
};
if let Some(result) = strategy.is_goal(node, &self.path_tracker) {
if let Some(result) = strategy.is_goal(&self.graph, node, &self.path_tracker) {
let path = self.path_tracker.reconstruct_path_to(node);
let cost = self.scores[&node];
return Ok(AstarStatus::Finished(cost, path, result));
@ -190,7 +190,7 @@ where
}
for edge in self.graph.edges(node) {
if let Some(edge_cost) = strategy.edge_cost(edge) {
if let Some(edge_cost) = strategy.edge_cost(&self.graph, edge) {
let next = edge.target();
let next_score = node_score + edge_cost;
@ -209,7 +209,7 @@ where
}
self.path_tracker.set_predecessor(next, node);
let next_estimate_score = next_score + strategy.estimate_cost(next);
let next_estimate_score = next_score + strategy.estimate_cost(&self.graph, next);
self.visit_next.push(MinScored(next_estimate_score, next));
}
}

View File

@ -1,37 +1,46 @@
use std::iter;
use enum_dispatch::enum_dispatch;
use geo::Point;
use itertools::Itertools;
use petgraph::visit::{self, NodeIndexable};
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef};
use petgraph::{
graph::UnGraph,
stable_graph::NodeIndex,
visit::{IntoNodeIdentifiers, NodeIndexable},
};
use spade::{HasPosition, InsertionError, Point2};
use thiserror::Error;
use crate::drawing::graph::{GetLayer, GetMaybeNet};
use crate::geometry::shape::ShapeTrait;
use crate::{
drawing::{
bend::{FixedBendIndex, LooseBendIndex},
dot::FixedDotIndex,
graph::{MakePrimitive, PrimitiveIndex},
primitive::{GetCore, MakePrimitiveShape, Primitive},
graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex},
primitive::{MakePrimitiveShape, Primitive},
rules::RulesTrait,
Drawing,
},
geometry::shape::ShapeTrait,
graph::GetPetgraphIndex,
layout::Layout,
triangulation::{GetTrianvertexNodeIndex, Triangulation, TriangulationEdgeReference},
triangulation::{GetTrianvertexNodeIndex, Triangulation},
};
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
pub enum NavvertexNodeIndex {
pub enum BinavvertexNodeIndex {
FixedDot(FixedDotIndex),
FixedBend(FixedBendIndex),
LooseBend(LooseBendIndex),
}
impl From<BinavvertexNodeIndex> for PrimitiveIndex {
fn from(vertex: BinavvertexNodeIndex) -> Self {
match vertex {
BinavvertexNodeIndex::FixedDot(dot) => PrimitiveIndex::FixedDot(dot),
BinavvertexNodeIndex::FixedBend(bend) => PrimitiveIndex::FixedBend(bend),
BinavvertexNodeIndex::LooseBend(bend) => PrimitiveIndex::LooseBend(bend),
}
}
}
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
enum TrianvertexNodeIndex {
@ -39,30 +48,19 @@ enum TrianvertexNodeIndex {
FixedBend(FixedBendIndex),
}
impl From<NavvertexNodeIndex> for PrimitiveIndex {
fn from(vertex: NavvertexNodeIndex) -> Self {
match vertex {
NavvertexNodeIndex::FixedDot(dot) => PrimitiveIndex::FixedDot(dot),
NavvertexNodeIndex::FixedBend(bend) => PrimitiveIndex::FixedBend(bend),
NavvertexNodeIndex::LooseBend(bend) => PrimitiveIndex::LooseBend(bend),
}
}
}
impl From<TrianvertexNodeIndex> for NavvertexNodeIndex {
impl From<TrianvertexNodeIndex> for BinavvertexNodeIndex {
fn from(vertex: TrianvertexNodeIndex) -> Self {
match vertex {
TrianvertexNodeIndex::FixedDot(dot) => NavvertexNodeIndex::FixedDot(dot),
TrianvertexNodeIndex::FixedBend(bend) => NavvertexNodeIndex::FixedBend(bend),
TrianvertexNodeIndex::FixedDot(dot) => BinavvertexNodeIndex::FixedDot(dot),
TrianvertexNodeIndex::FixedBend(bend) => BinavvertexNodeIndex::FixedBend(bend),
}
}
}
#[derive(Debug, Clone)]
struct TrianvertexWeight {
node: TrianvertexNodeIndex,
rails: Vec<LooseBendIndex>,
pos: Point,
pub node: TrianvertexNodeIndex,
pub pos: Point,
}
impl GetTrianvertexNodeIndex<TrianvertexNodeIndex> for TrianvertexWeight {
@ -79,11 +77,8 @@ impl HasPosition for TrianvertexWeight {
}
#[derive(Debug, Clone)]
pub struct Navmesh {
triangulation: Triangulation<TrianvertexNodeIndex, TrianvertexWeight, ()>,
navvertex_to_trianvertex: Vec<Option<TrianvertexNodeIndex>>,
source: FixedDotIndex,
target: FixedDotIndex,
pub struct NavvertexWeight {
pub node: BinavvertexNodeIndex,
}
#[derive(Error, Debug, Clone)]
@ -92,20 +87,23 @@ pub enum NavmeshError {
Insertion(#[from] InsertionError),
}
#[derive(Debug, Clone)]
pub struct Navmesh {
graph: UnGraph<NavvertexWeight, (), usize>,
source: FixedDotIndex,
source_vertex: NodeIndex<usize>,
target: FixedDotIndex,
target_vertex: NodeIndex<usize>,
}
impl Navmesh {
pub fn new(
layout: &Layout<impl RulesTrait>,
source: FixedDotIndex,
target: FixedDotIndex,
) -> Result<Self, NavmeshError> {
let mut this = Self {
triangulation: Triangulation::new(layout.drawing().geometry().graph().node_bound()),
navvertex_to_trianvertex: Vec::new(),
source,
target,
};
this.navvertex_to_trianvertex
.resize(layout.drawing().geometry().graph().node_bound(), None);
let mut triangulation: Triangulation<TrianvertexNodeIndex, TrianvertexWeight, ()> =
Triangulation::new(layout.drawing().geometry().graph().node_bound());
let layer = layout.drawing().primitive(source).layer();
let maybe_net = layout.drawing().primitive(source).maybe_net();
@ -120,16 +118,14 @@ impl Navmesh {
{
match node {
PrimitiveIndex::FixedDot(dot) => {
this.triangulation.add_vertex(TrianvertexWeight {
triangulation.add_vertex(TrianvertexWeight {
node: dot.into(),
rails: vec![],
pos: primitive.shape().center(),
})?;
}
PrimitiveIndex::FixedBend(bend) => {
this.triangulation.add_vertex(TrianvertexWeight {
triangulation.add_vertex(TrianvertexWeight {
node: bend.into(),
rails: vec![],
pos: primitive.shape().center(),
})?;
}
@ -139,185 +135,48 @@ impl Navmesh {
}
}
for node in layout.drawing().layer_primitive_nodes(layer) {
// Add rails as vertices. This is how the navmesh differs from the triangulation.
match node {
PrimitiveIndex::LooseBend(bend) => {
this.triangulation
.weight_mut(layout.drawing().primitive(bend).core().into())
.rails
.push(bend.into());
this.navvertex_to_trianvertex[bend.petgraph_index().index()] =
Some(layout.drawing().primitive(bend).core().into());
}
_ => (),
let mut graph: UnGraph<NavvertexWeight, (), usize> = UnGraph::default();
let mut source_vertex = None;
let mut target_vertex = None;
for trianvertex in triangulation.node_identifiers() {
let navvertex = graph.add_node(NavvertexWeight {
node: trianvertex.into(),
});
if trianvertex == source.into() {
source_vertex = Some(navvertex);
} else if trianvertex == target.into() {
target_vertex = Some(navvertex);
}
}
Ok(this)
Ok(Self {
graph,
source,
source_vertex: source_vertex.unwrap(),
target,
target_vertex: target_vertex.unwrap(),
})
}
fn trianvertex(&self, vertex: NavvertexNodeIndex) -> TrianvertexNodeIndex {
match vertex {
NavvertexNodeIndex::FixedDot(dot) => TrianvertexNodeIndex::FixedDot(dot),
NavvertexNodeIndex::FixedBend(bend) => TrianvertexNodeIndex::FixedBend(bend),
NavvertexNodeIndex::LooseBend(bend) => {
self.navvertex_to_trianvertex[bend.petgraph_index().index()].unwrap()
}
}
pub fn graph(&self) -> &UnGraph<NavvertexWeight, (), usize> {
&self.graph
}
pub fn source(&self) -> FixedDotIndex {
self.source
}
pub fn source_vertex(&self) -> NodeIndex<usize> {
self.source_vertex
}
pub fn target(&self) -> FixedDotIndex {
self.target
}
}
impl visit::GraphBase for Navmesh {
type NodeId = NavvertexNodeIndex;
type EdgeId = (NavvertexNodeIndex, NavvertexNodeIndex);
}
impl visit::Data for Navmesh {
type NodeWeight = ();
type EdgeWeight = ();
}
#[derive(Debug, Clone, Copy)]
pub struct NavmeshEdgeReference {
from: NavvertexNodeIndex,
to: NavvertexNodeIndex,
}
impl visit::EdgeRef for NavmeshEdgeReference {
type NodeId = NavvertexNodeIndex;
type EdgeId = (NavvertexNodeIndex, NavvertexNodeIndex);
type Weight = ();
fn source(&self) -> Self::NodeId {
self.from
}
fn target(&self) -> Self::NodeId {
self.to
}
fn weight(&self) -> &Self::Weight {
&()
}
fn id(&self) -> Self::EdgeId {
(self.from, self.to)
}
}
impl<'a> visit::IntoNeighbors for &'a Navmesh {
type Neighbors = Box<dyn Iterator<Item = NavvertexNodeIndex> + 'a>;
fn neighbors(self, vertex: Self::NodeId) -> Self::Neighbors {
Box::new(
self.triangulation
.neighbors(self.trianvertex(vertex))
.flat_map(|neighbor| {
iter::once(neighbor.into()).chain(
self.triangulation
.weight(neighbor)
.rails
.iter()
.map(|index| NavvertexNodeIndex::from(*index)),
)
}),
)
}
}
fn edge_with_near_edges(
triangulation: &Triangulation<TrianvertexNodeIndex, TrianvertexWeight, ()>,
edge: TriangulationEdgeReference<TrianvertexNodeIndex, ()>,
) -> impl Iterator<Item = NavmeshEdgeReference> {
let mut from_vertices = vec![edge.source().into()];
// Append rails to the source.
from_vertices.extend(
triangulation
.weight(edge.source())
.rails
.iter()
.map(|bend| NavvertexNodeIndex::from(*bend)),
);
let mut to_vertices = vec![edge.target().into()];
// Append rails to the target.
to_vertices.extend(
triangulation
.weight(edge.target())
.rails
.iter()
.map(|bend| NavvertexNodeIndex::from(*bend)),
);
// Return cartesian product.
from_vertices
.into_iter()
.cartesian_product(to_vertices.into_iter())
.map(|pair| NavmeshEdgeReference {
from: pair.0,
to: pair.1.into(),
})
}
impl<'a> visit::IntoEdgeReferences for &'a Navmesh {
type EdgeRef = NavmeshEdgeReference;
type EdgeReferences = Box<dyn Iterator<Item = NavmeshEdgeReference> + 'a>;
fn edge_references(self) -> Self::EdgeReferences {
Box::new(
self.triangulation
.edge_references()
.flat_map(move |edge| edge_with_near_edges(&self.triangulation, edge)),
)
}
}
fn vertex_edges(
triangulation: &Triangulation<TrianvertexNodeIndex, TrianvertexWeight, ()>,
from: NavvertexNodeIndex,
to: TrianvertexNodeIndex,
) -> impl Iterator<Item = NavmeshEdgeReference> {
let from_vertices = vec![from];
let mut to_vertices = vec![to.into()];
// Append rails to the target.
to_vertices.extend(
triangulation
.weight(to)
.rails
.iter()
.map(|bend| NavvertexNodeIndex::from(*bend)),
);
// Return cartesian product.
from_vertices
.into_iter()
.cartesian_product(to_vertices.into_iter())
.map(|pair| NavmeshEdgeReference {
from: pair.0,
to: pair.1,
})
}
impl<'a> visit::IntoEdges for &'a Navmesh {
type Edges = Box<dyn Iterator<Item = NavmeshEdgeReference> + 'a>;
fn edges(self, vertex: Self::NodeId) -> Self::Edges {
Box::new(
self.triangulation
.edges(self.trianvertex(vertex))
.flat_map(move |edge| vertex_edges(&self.triangulation, vertex, edge.target())),
)
pub fn target_vertex(&self) -> NodeIndex<usize> {
self.target_vertex
}
}

View File

@ -1,5 +1,8 @@
use geo::EuclideanDistance;
use petgraph::visit::EdgeRef;
use petgraph::{
graph::{EdgeReference, NodeIndex, UnGraph},
visit::EdgeRef,
};
use thiserror::Error;
use crate::{
@ -11,11 +14,12 @@ use crate::{
rules::RulesTrait,
},
geometry::shape::ShapeTrait,
graph::GetPetgraphIndex,
layout::Layout,
router::{
astar::{astar, AstarError, AstarStrategy, PathTracker},
draw::DrawException,
navmesh::{Navmesh, NavmeshEdgeReference, NavmeshError, NavvertexNodeIndex},
navmesh::{BinavvertexNodeIndex, Navmesh, NavmeshError, NavvertexWeight},
tracer::{Trace, Tracer},
},
};
@ -35,55 +39,75 @@ pub struct Router<'a, R: RulesTrait> {
struct RouterAstarStrategy<'a, R: RulesTrait> {
tracer: Tracer<'a, R>,
trace: Trace,
to: FixedDotIndex,
target: FixedDotIndex,
}
impl<'a, R: RulesTrait> RouterAstarStrategy<'a, R> {
pub fn new(tracer: Tracer<'a, R>, trace: Trace, to: FixedDotIndex) -> Self {
Self { tracer, trace, to }
pub fn new(tracer: Tracer<'a, R>, trace: Trace, target: FixedDotIndex) -> Self {
Self {
tracer,
trace,
target,
}
}
}
impl<'a, R: RulesTrait> AstarStrategy<&Navmesh, f64, BandFirstSegIndex>
impl<'a, R: RulesTrait> AstarStrategy<&UnGraph<NavvertexWeight, (), usize>, f64, BandFirstSegIndex>
for RouterAstarStrategy<'a, R>
{
fn is_goal(
&mut self,
vertex: NavvertexNodeIndex,
tracker: &PathTracker<&Navmesh>,
graph: &&UnGraph<NavvertexWeight, (), usize>,
vertex: NodeIndex<usize>,
tracker: &PathTracker<&UnGraph<NavvertexWeight, (), usize>>,
) -> Option<BandFirstSegIndex> {
let new_path = tracker.reconstruct_path_to(vertex);
/*.into_iter()
.map(|ni| graph.node_weight(ni).unwrap().node)
.collect();*/
let width = self.trace.width;
self.tracer
.rework_path(&mut self.trace, &new_path, width)
.rework_path(*graph, &mut self.trace, &new_path[..], width)
.unwrap();
self.tracer.finish(&mut self.trace, self.to, width).ok()
self.tracer
.finish(*graph, &mut self.trace, self.target, width)
.ok()
}
fn edge_cost(&mut self, edge: NavmeshEdgeReference) -> Option<f64> {
if edge.target() == self.to.into() {
fn edge_cost(
&mut self,
graph: &&UnGraph<NavvertexWeight, (), usize>,
edge: EdgeReference<(), usize>,
) -> Option<f64> {
if edge.target() == self.target.petgraph_index() {
return None;
}
let before_probe_length = 0.0; //self.tracer.layout.band_length(self.trace.head.face());
let width = self.trace.width;
let result = self.tracer.step(&mut self.trace, edge.target(), width);
let result = self
.tracer
.step(*graph, &mut self.trace, edge.target(), width);
let probe_length = 0.0; //self.tracer.layout.band_length(self.trace.head.face());
if result.is_ok() {
self.tracer.undo_step(&mut self.trace);
self.tracer.undo_step(*graph, &mut self.trace);
Some(probe_length - before_probe_length)
} else {
None
}
}
fn estimate_cost(&mut self, vertex: NavvertexNodeIndex) -> f64 {
let start_point = PrimitiveIndex::from(vertex)
fn estimate_cost(
&mut self,
graph: &&UnGraph<NavvertexWeight, (), usize>,
vertex: NodeIndex<usize>,
) -> f64 {
let start_point = PrimitiveIndex::from(graph.node_weight(vertex).unwrap().node)
.primitive(self.tracer.layout.drawing())
.shape()
.center();
@ -91,7 +115,7 @@ impl<'a, R: RulesTrait> AstarStrategy<&Navmesh, f64, BandFirstSegIndex>
.tracer
.layout
.drawing()
.primitive(self.to)
.primitive(self.target)
.shape()
.center();
@ -114,15 +138,18 @@ impl<'a, R: RulesTrait> Router<'a, R> {
}
pub fn route_band(&mut self, width: f64) -> Result<BandFirstSegIndex, RouterError> {
let from = self.navmesh.source();
let to = self.navmesh.target();
let mut tracer = Tracer::new(self.layout);
let trace = tracer.start(from, width);
let trace = tracer.start(
self.navmesh.graph(),
self.navmesh.source(),
self.navmesh.source_vertex(),
width,
);
let (_cost, _path, band) = astar(
&self.navmesh,
from.into(),
&mut RouterAstarStrategy::new(tracer, trace, to),
self.navmesh.graph(),
self.navmesh.source_vertex(),
&mut RouterAstarStrategy::new(tracer, trace, self.navmesh.target()),
)?;
Ok(band)

View File

@ -1,23 +1,25 @@
use contracts::debug_ensures;
use contracts::{debug_ensures, debug_requires};
use petgraph::graph::{NodeIndex, UnGraph};
use crate::{
drawing::{
band::BandFirstSegIndex,
bend::LooseBendIndex,
dot::FixedDotIndex,
graph::PrimitiveIndex,
guide::{BareHead, CaneHead, Head},
rules::RulesTrait,
},
layout::Layout,
router::{
draw::{Draw, DrawException},
navmesh::NavvertexNodeIndex,
navmesh::{BinavvertexNodeIndex, NavvertexWeight},
},
};
#[derive(Debug)]
pub struct Trace {
pub path: Vec<NavvertexNodeIndex>,
pub path: Vec<NodeIndex<usize>>,
pub head: Head,
pub width: f64,
}
@ -32,28 +34,37 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
Tracer { layout }
}
pub fn start(&mut self, from: FixedDotIndex, width: f64) -> Trace {
pub fn start(
&mut self,
_graph: &UnGraph<NavvertexWeight, (), usize>,
source: FixedDotIndex,
source_vertex: NodeIndex<usize>,
width: f64,
) -> Trace {
Trace {
path: vec![from.into()],
head: BareHead { dot: from }.into(),
path: vec![source_vertex],
head: BareHead { dot: source }.into(),
width,
}
}
pub fn finish(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
trace: &mut Trace,
into: FixedDotIndex,
target: FixedDotIndex,
width: f64,
) -> Result<BandFirstSegIndex, DrawException> {
Draw::new(self.layout).finish_in_dot(trace.head, into, width)
Draw::new(self.layout).finish_in_dot(trace.head, target, width)
}
#[debug_requires(path[0] == trace.path[0])]
#[debug_ensures(ret.is_ok() -> trace.path.len() == path.len())]
pub fn rework_path(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
trace: &mut Trace,
path: &[NavvertexNodeIndex],
path: &[NodeIndex<usize>],
width: f64,
) -> Result<(), DrawException> {
let prefix_length = trace
@ -64,20 +75,21 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
.count();
let length = trace.path.len();
self.undo_path(trace, length - prefix_length);
self.path(trace, &path[prefix_length..], width)
self.undo_path(graph, trace, length - prefix_length);
self.path(graph, trace, &path[prefix_length..], width)
}
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))]
pub fn path(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
trace: &mut Trace,
path: &[NavvertexNodeIndex],
path: &[NodeIndex<usize>],
width: f64,
) -> Result<(), DrawException> {
for (i, vertex) in path.iter().enumerate() {
if let Err(err) = self.step(trace, *vertex, width) {
self.undo_path(trace, i);
if let Err(err) = self.step(graph, trace, *vertex, width) {
self.undo_path(graph, trace, i);
return Err(err);
}
}
@ -86,21 +98,28 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
}
#[debug_ensures(trace.path.len() == old(trace.path.len() - step_count))]
pub fn undo_path(&mut self, trace: &mut Trace, step_count: usize) {
pub fn undo_path(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
trace: &mut Trace,
step_count: usize,
) {
for _ in 0..step_count {
self.undo_step(trace);
self.undo_step(graph, trace);
}
}
#[debug_ensures(ret.is_ok() -> matches!(trace.head, Head::Bare(..)))]
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + 1))]
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
pub fn step(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
trace: &mut Trace,
to: NavvertexNodeIndex,
to: NodeIndex<usize>,
width: f64,
) -> Result<(), DrawException> {
trace.head = self.wrap(trace.head, to, width)?.into();
trace.head = self.wrap(graph, trace.head, to, width)?.into();
trace.path.push(to);
Ok::<(), DrawException>(())
@ -108,21 +127,25 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
fn wrap(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
head: Head,
around: NavvertexNodeIndex,
around: NodeIndex<usize>,
width: f64,
) -> Result<CaneHead, DrawException> {
match around {
NavvertexNodeIndex::FixedDot(dot) => self.wrap_around_fixed_dot(head, dot, width),
NavvertexNodeIndex::FixedBend(_fixed_bend) => todo!(),
NavvertexNodeIndex::LooseBend(loose_bend) => {
self.wrap_around_loose_bend(head, loose_bend, width)
match self.binavvertex(graph, around) {
BinavvertexNodeIndex::FixedDot(dot) => {
self.wrap_around_fixed_dot(graph, head, dot, width)
}
BinavvertexNodeIndex::FixedBend(_fixed_bend) => todo!(),
BinavvertexNodeIndex::LooseBend(loose_bend) => {
self.wrap_around_loose_bend(graph, head, loose_bend, width)
}
}
}
fn wrap_around_fixed_dot(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
head: Head,
around: FixedDotIndex,
width: f64,
@ -133,6 +156,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
fn wrap_around_loose_bend(
&mut self,
graph: &UnGraph<NavvertexWeight, (), usize>,
head: Head,
around: LooseBendIndex,
width: f64,
@ -143,8 +167,8 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
}
#[debug_ensures(trace.path.len() == old(trace.path.len() - 1))]
pub fn undo_step(&mut self, trace: &mut Trace) {
if let Head::Cane(head) = trace.head {
pub fn undo_step(&mut self, graph: &UnGraph<NavvertexWeight, (), usize>, trace: &mut Trace) {
if let Head::Cane(head) = dbg!(trace.head) {
trace.head = Draw::new(self.layout).undo_cane(head).unwrap();
} else {
panic!();
@ -152,4 +176,20 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
trace.path.pop();
}
fn binavvertex(
&self,
graph: &UnGraph<NavvertexWeight, (), usize>,
vertex: NodeIndex<usize>,
) -> BinavvertexNodeIndex {
graph.node_weight(vertex).unwrap().node
}
fn primitive(
&self,
graph: &UnGraph<NavvertexWeight, (), usize>,
vertex: NodeIndex<usize>,
) -> PrimitiveIndex {
self.binavvertex(graph, vertex).into()
}
}