mirror of https://codeberg.org/topola/topola.git
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:
parent
d4a310a5c0
commit
ae2a862e0e
|
|
@ -33,7 +33,7 @@ use topola::{
|
||||||
math::Circle,
|
math::Circle,
|
||||||
router::{
|
router::{
|
||||||
draw::DrawException,
|
draw::DrawException,
|
||||||
navmesh::{Navmesh, NavmeshEdgeReference, NavvertexNodeIndex},
|
navmesh::{BinavvertexNodeIndex, Navmesh},
|
||||||
tracer::{Trace, Tracer},
|
tracer::{Trace, Tracer},
|
||||||
},
|
},
|
||||||
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata},
|
||||||
|
|
@ -49,7 +49,7 @@ pub struct SharedData {
|
||||||
pub from: Option<FixedDotIndex>,
|
pub from: Option<FixedDotIndex>,
|
||||||
pub to: Option<FixedDotIndex>,
|
pub to: Option<FixedDotIndex>,
|
||||||
pub navmesh: Option<Navmesh>,
|
pub navmesh: Option<Navmesh>,
|
||||||
pub path: Vec<NavvertexNodeIndex>,
|
pub path: Vec<BinavvertexNodeIndex>,
|
||||||
pub ghosts: Vec<PrimitiveShape>,
|
pub ghosts: Vec<PrimitiveShape>,
|
||||||
pub highlighteds: Vec<PrimitiveIndex>,
|
pub highlighteds: Vec<PrimitiveIndex>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ use petgraph::visit::{EdgeRef, IntoEdgeReferences};
|
||||||
use topola::{
|
use topola::{
|
||||||
autorouter::invoker::{Command, Invoker},
|
autorouter::invoker::{Command, Invoker},
|
||||||
board::mesadata::MesadataTrait,
|
board::mesadata::MesadataTrait,
|
||||||
drawing::{graph::MakePrimitive, primitive::MakePrimitiveShape},
|
drawing::{
|
||||||
|
graph::{MakePrimitive, PrimitiveIndex},
|
||||||
|
primitive::MakePrimitiveShape,
|
||||||
|
},
|
||||||
geometry::{shape::ShapeTrait, GenericNode},
|
geometry::{shape::ShapeTrait, GenericNode},
|
||||||
layout::{via::ViaWeight, zone::MakePolyShape},
|
layout::{via::ViaWeight, zone::MakePolyShape},
|
||||||
math::Circle,
|
math::Circle,
|
||||||
|
|
@ -165,14 +168,12 @@ impl Viewport {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(navmesh) = &shared_data.navmesh {
|
if let Some(navmesh) = &shared_data.navmesh {
|
||||||
for edge in navmesh.edge_references() {
|
for edge in navmesh.graph().edge_references() {
|
||||||
let from = edge
|
let from = PrimitiveIndex::from(navmesh.graph().node_weight(edge.source()).unwrap().node)
|
||||||
.source()
|
|
||||||
.primitive(board.layout().drawing())
|
.primitive(board.layout().drawing())
|
||||||
.shape()
|
.shape()
|
||||||
.center();
|
.center();
|
||||||
let to = edge
|
let to = PrimitiveIndex::from(navmesh.graph().node_weight(edge.target()).unwrap().node)
|
||||||
.target()
|
|
||||||
.primitive(board.layout().drawing())
|
.primitive(board.layout().drawing())
|
||||||
.shape()
|
.shape()
|
||||||
.center();
|
.center();
|
||||||
|
|
@ -182,11 +183,11 @@ impl Viewport {
|
||||||
shared_data
|
shared_data
|
||||||
.path
|
.path
|
||||||
.iter()
|
.iter()
|
||||||
.position(|node| *node == edge.source()),
|
.position(|node| *node == navmesh.graph().node_weight(edge.source()).unwrap().node),
|
||||||
shared_data
|
shared_data
|
||||||
.path
|
.path
|
||||||
.iter()
|
.iter()
|
||||||
.position(|node| *node == edge.target()),
|
.position(|node| *node == navmesh.graph().node_weight(edge.target()).unwrap().node),
|
||||||
) {
|
) {
|
||||||
if target_pos == source_pos + 1
|
if target_pos == source_pos + 1
|
||||||
|| source_pos == target_pos + 1
|
|| source_pos == target_pos + 1
|
||||||
|
|
|
||||||
|
|
@ -101,9 +101,9 @@ where
|
||||||
K: Measure + Copy,
|
K: Measure + Copy,
|
||||||
G::NodeId: Eq + Hash,
|
G::NodeId: Eq + Hash,
|
||||||
{
|
{
|
||||||
fn is_goal(&mut self, node: G::NodeId, tracker: &PathTracker<G>) -> Option<R>;
|
fn is_goal(&mut self, graph: &G, node: G::NodeId, tracker: &PathTracker<G>) -> Option<R>;
|
||||||
fn edge_cost(&mut self, edge: G::EdgeRef) -> Option<K>;
|
fn edge_cost(&mut self, graph: &G, edge: G::EdgeRef) -> Option<K>;
|
||||||
fn estimate_cost(&mut self, node: G::NodeId) -> K;
|
fn estimate_cost(&mut self, graph: &G, node: G::NodeId) -> K;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Astar<G, K>
|
pub struct Astar<G, K>
|
||||||
|
|
@ -153,7 +153,7 @@ where
|
||||||
let zero_score = K::default();
|
let zero_score = K::default();
|
||||||
this.scores.insert(start, zero_score);
|
this.scores.insert(start, zero_score);
|
||||||
this.visit_next
|
this.visit_next
|
||||||
.push(MinScored(strategy.estimate_cost(start), start));
|
.push(MinScored(strategy.estimate_cost(&&graph, start), start));
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,7 +165,7 @@ where
|
||||||
return Err(AstarError::NotFound);
|
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 path = self.path_tracker.reconstruct_path_to(node);
|
||||||
let cost = self.scores[&node];
|
let cost = self.scores[&node];
|
||||||
return Ok(AstarStatus::Finished(cost, path, result));
|
return Ok(AstarStatus::Finished(cost, path, result));
|
||||||
|
|
@ -190,7 +190,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
for edge in self.graph.edges(node) {
|
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 = edge.target();
|
||||||
let next_score = node_score + edge_cost;
|
let next_score = node_score + edge_cost;
|
||||||
|
|
||||||
|
|
@ -209,7 +209,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
self.path_tracker.set_predecessor(next, node);
|
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));
|
self.visit_next.push(MinScored(next_estimate_score, next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,46 @@
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
use itertools::Itertools;
|
use petgraph::{
|
||||||
use petgraph::visit::{self, NodeIndexable};
|
graph::UnGraph,
|
||||||
use petgraph::{stable_graph::NodeIndex, visit::EdgeRef};
|
stable_graph::NodeIndex,
|
||||||
|
visit::{IntoNodeIdentifiers, NodeIndexable},
|
||||||
|
};
|
||||||
use spade::{HasPosition, InsertionError, Point2};
|
use spade::{HasPosition, InsertionError, Point2};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::drawing::graph::{GetLayer, GetMaybeNet};
|
|
||||||
use crate::geometry::shape::ShapeTrait;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing::{
|
drawing::{
|
||||||
bend::{FixedBendIndex, LooseBendIndex},
|
bend::{FixedBendIndex, LooseBendIndex},
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
graph::{MakePrimitive, PrimitiveIndex},
|
graph::{GetLayer, GetMaybeNet, MakePrimitive, PrimitiveIndex},
|
||||||
primitive::{GetCore, MakePrimitiveShape, Primitive},
|
primitive::{MakePrimitiveShape, Primitive},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
Drawing,
|
Drawing,
|
||||||
},
|
},
|
||||||
|
geometry::shape::ShapeTrait,
|
||||||
graph::GetPetgraphIndex,
|
graph::GetPetgraphIndex,
|
||||||
layout::Layout,
|
layout::Layout,
|
||||||
triangulation::{GetTrianvertexNodeIndex, Triangulation, TriangulationEdgeReference},
|
triangulation::{GetTrianvertexNodeIndex, Triangulation},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
||||||
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum NavvertexNodeIndex {
|
pub enum BinavvertexNodeIndex {
|
||||||
FixedDot(FixedDotIndex),
|
FixedDot(FixedDotIndex),
|
||||||
FixedBend(FixedBendIndex),
|
FixedBend(FixedBendIndex),
|
||||||
LooseBend(LooseBendIndex),
|
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)]
|
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
|
||||||
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)]
|
||||||
enum TrianvertexNodeIndex {
|
enum TrianvertexNodeIndex {
|
||||||
|
|
@ -39,30 +48,19 @@ enum TrianvertexNodeIndex {
|
||||||
FixedBend(FixedBendIndex),
|
FixedBend(FixedBendIndex),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NavvertexNodeIndex> for PrimitiveIndex {
|
impl From<TrianvertexNodeIndex> for BinavvertexNodeIndex {
|
||||||
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 {
|
|
||||||
fn from(vertex: TrianvertexNodeIndex) -> Self {
|
fn from(vertex: TrianvertexNodeIndex) -> Self {
|
||||||
match vertex {
|
match vertex {
|
||||||
TrianvertexNodeIndex::FixedDot(dot) => NavvertexNodeIndex::FixedDot(dot),
|
TrianvertexNodeIndex::FixedDot(dot) => BinavvertexNodeIndex::FixedDot(dot),
|
||||||
TrianvertexNodeIndex::FixedBend(bend) => NavvertexNodeIndex::FixedBend(bend),
|
TrianvertexNodeIndex::FixedBend(bend) => BinavvertexNodeIndex::FixedBend(bend),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct TrianvertexWeight {
|
struct TrianvertexWeight {
|
||||||
node: TrianvertexNodeIndex,
|
pub node: TrianvertexNodeIndex,
|
||||||
rails: Vec<LooseBendIndex>,
|
pub pos: Point,
|
||||||
pos: Point,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetTrianvertexNodeIndex<TrianvertexNodeIndex> for TrianvertexWeight {
|
impl GetTrianvertexNodeIndex<TrianvertexNodeIndex> for TrianvertexWeight {
|
||||||
|
|
@ -79,11 +77,8 @@ impl HasPosition for TrianvertexWeight {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Navmesh {
|
pub struct NavvertexWeight {
|
||||||
triangulation: Triangulation<TrianvertexNodeIndex, TrianvertexWeight, ()>,
|
pub node: BinavvertexNodeIndex,
|
||||||
navvertex_to_trianvertex: Vec<Option<TrianvertexNodeIndex>>,
|
|
||||||
source: FixedDotIndex,
|
|
||||||
target: FixedDotIndex,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, Clone)]
|
#[derive(Error, Debug, Clone)]
|
||||||
|
|
@ -92,20 +87,23 @@ pub enum NavmeshError {
|
||||||
Insertion(#[from] InsertionError),
|
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 {
|
impl Navmesh {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
layout: &Layout<impl RulesTrait>,
|
layout: &Layout<impl RulesTrait>,
|
||||||
source: FixedDotIndex,
|
source: FixedDotIndex,
|
||||||
target: FixedDotIndex,
|
target: FixedDotIndex,
|
||||||
) -> Result<Self, NavmeshError> {
|
) -> Result<Self, NavmeshError> {
|
||||||
let mut this = Self {
|
let mut triangulation: Triangulation<TrianvertexNodeIndex, TrianvertexWeight, ()> =
|
||||||
triangulation: Triangulation::new(layout.drawing().geometry().graph().node_bound()),
|
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 layer = layout.drawing().primitive(source).layer();
|
let layer = layout.drawing().primitive(source).layer();
|
||||||
let maybe_net = layout.drawing().primitive(source).maybe_net();
|
let maybe_net = layout.drawing().primitive(source).maybe_net();
|
||||||
|
|
@ -120,16 +118,14 @@ impl Navmesh {
|
||||||
{
|
{
|
||||||
match node {
|
match node {
|
||||||
PrimitiveIndex::FixedDot(dot) => {
|
PrimitiveIndex::FixedDot(dot) => {
|
||||||
this.triangulation.add_vertex(TrianvertexWeight {
|
triangulation.add_vertex(TrianvertexWeight {
|
||||||
node: dot.into(),
|
node: dot.into(),
|
||||||
rails: vec![],
|
|
||||||
pos: primitive.shape().center(),
|
pos: primitive.shape().center(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
PrimitiveIndex::FixedBend(bend) => {
|
PrimitiveIndex::FixedBend(bend) => {
|
||||||
this.triangulation.add_vertex(TrianvertexWeight {
|
triangulation.add_vertex(TrianvertexWeight {
|
||||||
node: bend.into(),
|
node: bend.into(),
|
||||||
rails: vec![],
|
|
||||||
pos: primitive.shape().center(),
|
pos: primitive.shape().center(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
@ -139,185 +135,48 @@ impl Navmesh {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for node in layout.drawing().layer_primitive_nodes(layer) {
|
let mut graph: UnGraph<NavvertexWeight, (), usize> = UnGraph::default();
|
||||||
// Add rails as vertices. This is how the navmesh differs from the triangulation.
|
let mut source_vertex = None;
|
||||||
match node {
|
let mut target_vertex = None;
|
||||||
PrimitiveIndex::LooseBend(bend) => {
|
|
||||||
this.triangulation
|
for trianvertex in triangulation.node_identifiers() {
|
||||||
.weight_mut(layout.drawing().primitive(bend).core().into())
|
let navvertex = graph.add_node(NavvertexWeight {
|
||||||
.rails
|
node: trianvertex.into(),
|
||||||
.push(bend.into());
|
});
|
||||||
this.navvertex_to_trianvertex[bend.petgraph_index().index()] =
|
|
||||||
Some(layout.drawing().primitive(bend).core().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 {
|
pub fn graph(&self) -> &UnGraph<NavvertexWeight, (), usize> {
|
||||||
match vertex {
|
&self.graph
|
||||||
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 source(&self) -> FixedDotIndex {
|
pub fn source(&self) -> FixedDotIndex {
|
||||||
self.source
|
self.source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn source_vertex(&self) -> NodeIndex<usize> {
|
||||||
|
self.source_vertex
|
||||||
|
}
|
||||||
|
|
||||||
pub fn target(&self) -> FixedDotIndex {
|
pub fn target(&self) -> FixedDotIndex {
|
||||||
self.target
|
self.target
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl visit::GraphBase for Navmesh {
|
pub fn target_vertex(&self) -> NodeIndex<usize> {
|
||||||
type NodeId = NavvertexNodeIndex;
|
self.target_vertex
|
||||||
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())),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
use geo::EuclideanDistance;
|
use geo::EuclideanDistance;
|
||||||
use petgraph::visit::EdgeRef;
|
use petgraph::{
|
||||||
|
graph::{EdgeReference, NodeIndex, UnGraph},
|
||||||
|
visit::EdgeRef,
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -11,11 +14,12 @@ use crate::{
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
},
|
},
|
||||||
geometry::shape::ShapeTrait,
|
geometry::shape::ShapeTrait,
|
||||||
|
graph::GetPetgraphIndex,
|
||||||
layout::Layout,
|
layout::Layout,
|
||||||
router::{
|
router::{
|
||||||
astar::{astar, AstarError, AstarStrategy, PathTracker},
|
astar::{astar, AstarError, AstarStrategy, PathTracker},
|
||||||
draw::DrawException,
|
draw::DrawException,
|
||||||
navmesh::{Navmesh, NavmeshEdgeReference, NavmeshError, NavvertexNodeIndex},
|
navmesh::{BinavvertexNodeIndex, Navmesh, NavmeshError, NavvertexWeight},
|
||||||
tracer::{Trace, Tracer},
|
tracer::{Trace, Tracer},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -35,55 +39,75 @@ pub struct Router<'a, R: RulesTrait> {
|
||||||
struct RouterAstarStrategy<'a, R: RulesTrait> {
|
struct RouterAstarStrategy<'a, R: RulesTrait> {
|
||||||
tracer: Tracer<'a, R>,
|
tracer: Tracer<'a, R>,
|
||||||
trace: Trace,
|
trace: Trace,
|
||||||
to: FixedDotIndex,
|
target: FixedDotIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R: RulesTrait> RouterAstarStrategy<'a, R> {
|
impl<'a, R: RulesTrait> RouterAstarStrategy<'a, R> {
|
||||||
pub fn new(tracer: Tracer<'a, R>, trace: Trace, to: FixedDotIndex) -> Self {
|
pub fn new(tracer: Tracer<'a, R>, trace: Trace, target: FixedDotIndex) -> Self {
|
||||||
Self { tracer, trace, to }
|
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>
|
for RouterAstarStrategy<'a, R>
|
||||||
{
|
{
|
||||||
fn is_goal(
|
fn is_goal(
|
||||||
&mut self,
|
&mut self,
|
||||||
vertex: NavvertexNodeIndex,
|
graph: &&UnGraph<NavvertexWeight, (), usize>,
|
||||||
tracker: &PathTracker<&Navmesh>,
|
vertex: NodeIndex<usize>,
|
||||||
|
tracker: &PathTracker<&UnGraph<NavvertexWeight, (), usize>>,
|
||||||
) -> Option<BandFirstSegIndex> {
|
) -> Option<BandFirstSegIndex> {
|
||||||
let new_path = tracker.reconstruct_path_to(vertex);
|
let new_path = tracker.reconstruct_path_to(vertex);
|
||||||
|
/*.into_iter()
|
||||||
|
.map(|ni| graph.node_weight(ni).unwrap().node)
|
||||||
|
.collect();*/
|
||||||
let width = self.trace.width;
|
let width = self.trace.width;
|
||||||
|
|
||||||
self.tracer
|
self.tracer
|
||||||
.rework_path(&mut self.trace, &new_path, width)
|
.rework_path(*graph, &mut self.trace, &new_path[..], width)
|
||||||
.unwrap();
|
.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> {
|
fn edge_cost(
|
||||||
if edge.target() == self.to.into() {
|
&mut self,
|
||||||
|
graph: &&UnGraph<NavvertexWeight, (), usize>,
|
||||||
|
edge: EdgeReference<(), usize>,
|
||||||
|
) -> Option<f64> {
|
||||||
|
if edge.target() == self.target.petgraph_index() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let before_probe_length = 0.0; //self.tracer.layout.band_length(self.trace.head.face());
|
let before_probe_length = 0.0; //self.tracer.layout.band_length(self.trace.head.face());
|
||||||
|
|
||||||
let width = self.trace.width;
|
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());
|
let probe_length = 0.0; //self.tracer.layout.band_length(self.trace.head.face());
|
||||||
|
|
||||||
if result.is_ok() {
|
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)
|
Some(probe_length - before_probe_length)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn estimate_cost(&mut self, vertex: NavvertexNodeIndex) -> f64 {
|
fn estimate_cost(
|
||||||
let start_point = PrimitiveIndex::from(vertex)
|
&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())
|
.primitive(self.tracer.layout.drawing())
|
||||||
.shape()
|
.shape()
|
||||||
.center();
|
.center();
|
||||||
|
|
@ -91,7 +115,7 @@ impl<'a, R: RulesTrait> AstarStrategy<&Navmesh, f64, BandFirstSegIndex>
|
||||||
.tracer
|
.tracer
|
||||||
.layout
|
.layout
|
||||||
.drawing()
|
.drawing()
|
||||||
.primitive(self.to)
|
.primitive(self.target)
|
||||||
.shape()
|
.shape()
|
||||||
.center();
|
.center();
|
||||||
|
|
||||||
|
|
@ -114,15 +138,18 @@ impl<'a, R: RulesTrait> Router<'a, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn route_band(&mut self, width: f64) -> Result<BandFirstSegIndex, RouterError> {
|
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 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(
|
let (_cost, _path, band) = astar(
|
||||||
&self.navmesh,
|
self.navmesh.graph(),
|
||||||
from.into(),
|
self.navmesh.source_vertex(),
|
||||||
&mut RouterAstarStrategy::new(tracer, trace, to),
|
&mut RouterAstarStrategy::new(tracer, trace, self.navmesh.target()),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(band)
|
Ok(band)
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,25 @@
|
||||||
use contracts::debug_ensures;
|
use contracts::{debug_ensures, debug_requires};
|
||||||
|
use petgraph::graph::{NodeIndex, UnGraph};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing::{
|
drawing::{
|
||||||
band::BandFirstSegIndex,
|
band::BandFirstSegIndex,
|
||||||
bend::LooseBendIndex,
|
bend::LooseBendIndex,
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
|
graph::PrimitiveIndex,
|
||||||
guide::{BareHead, CaneHead, Head},
|
guide::{BareHead, CaneHead, Head},
|
||||||
rules::RulesTrait,
|
rules::RulesTrait,
|
||||||
},
|
},
|
||||||
layout::Layout,
|
layout::Layout,
|
||||||
router::{
|
router::{
|
||||||
draw::{Draw, DrawException},
|
draw::{Draw, DrawException},
|
||||||
navmesh::NavvertexNodeIndex,
|
navmesh::{BinavvertexNodeIndex, NavvertexWeight},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Trace {
|
pub struct Trace {
|
||||||
pub path: Vec<NavvertexNodeIndex>,
|
pub path: Vec<NodeIndex<usize>>,
|
||||||
pub head: Head,
|
pub head: Head,
|
||||||
pub width: f64,
|
pub width: f64,
|
||||||
}
|
}
|
||||||
|
|
@ -32,28 +34,37 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
Tracer { layout }
|
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 {
|
Trace {
|
||||||
path: vec![from.into()],
|
path: vec![source_vertex],
|
||||||
head: BareHead { dot: from }.into(),
|
head: BareHead { dot: source }.into(),
|
||||||
width,
|
width,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish(
|
pub fn finish(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
graph: &UnGraph<NavvertexWeight, (), usize>,
|
||||||
trace: &mut Trace,
|
trace: &mut Trace,
|
||||||
into: FixedDotIndex,
|
target: FixedDotIndex,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<BandFirstSegIndex, DrawException> {
|
) -> 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())]
|
#[debug_ensures(ret.is_ok() -> trace.path.len() == path.len())]
|
||||||
pub fn rework_path(
|
pub fn rework_path(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
graph: &UnGraph<NavvertexWeight, (), usize>,
|
||||||
trace: &mut Trace,
|
trace: &mut Trace,
|
||||||
path: &[NavvertexNodeIndex],
|
path: &[NodeIndex<usize>],
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<(), DrawException> {
|
) -> Result<(), DrawException> {
|
||||||
let prefix_length = trace
|
let prefix_length = trace
|
||||||
|
|
@ -64,20 +75,21 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
let length = trace.path.len();
|
let length = trace.path.len();
|
||||||
self.undo_path(trace, length - prefix_length);
|
self.undo_path(graph, trace, length - prefix_length);
|
||||||
self.path(trace, &path[prefix_length..], width)
|
self.path(graph, trace, &path[prefix_length..], width)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))]
|
#[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() + path.len()))]
|
||||||
pub fn path(
|
pub fn path(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
graph: &UnGraph<NavvertexWeight, (), usize>,
|
||||||
trace: &mut Trace,
|
trace: &mut Trace,
|
||||||
path: &[NavvertexNodeIndex],
|
path: &[NodeIndex<usize>],
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<(), DrawException> {
|
) -> Result<(), DrawException> {
|
||||||
for (i, vertex) in path.iter().enumerate() {
|
for (i, vertex) in path.iter().enumerate() {
|
||||||
if let Err(err) = self.step(trace, *vertex, width) {
|
if let Err(err) = self.step(graph, trace, *vertex, width) {
|
||||||
self.undo_path(trace, i);
|
self.undo_path(graph, trace, i);
|
||||||
return Err(err);
|
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))]
|
#[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 {
|
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_ok() -> trace.path.len() == old(trace.path.len() + 1))]
|
||||||
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
|
#[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))]
|
||||||
pub fn step(
|
pub fn step(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
graph: &UnGraph<NavvertexWeight, (), usize>,
|
||||||
trace: &mut Trace,
|
trace: &mut Trace,
|
||||||
to: NavvertexNodeIndex,
|
to: NodeIndex<usize>,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<(), DrawException> {
|
) -> 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);
|
trace.path.push(to);
|
||||||
|
|
||||||
Ok::<(), DrawException>(())
|
Ok::<(), DrawException>(())
|
||||||
|
|
@ -108,21 +127,25 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
|
|
||||||
fn wrap(
|
fn wrap(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
graph: &UnGraph<NavvertexWeight, (), usize>,
|
||||||
head: Head,
|
head: Head,
|
||||||
around: NavvertexNodeIndex,
|
around: NodeIndex<usize>,
|
||||||
width: f64,
|
width: f64,
|
||||||
) -> Result<CaneHead, DrawException> {
|
) -> Result<CaneHead, DrawException> {
|
||||||
match around {
|
match self.binavvertex(graph, around) {
|
||||||
NavvertexNodeIndex::FixedDot(dot) => self.wrap_around_fixed_dot(head, dot, width),
|
BinavvertexNodeIndex::FixedDot(dot) => {
|
||||||
NavvertexNodeIndex::FixedBend(_fixed_bend) => todo!(),
|
self.wrap_around_fixed_dot(graph, head, dot, width)
|
||||||
NavvertexNodeIndex::LooseBend(loose_bend) => {
|
}
|
||||||
self.wrap_around_loose_bend(head, loose_bend, 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(
|
fn wrap_around_fixed_dot(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
graph: &UnGraph<NavvertexWeight, (), usize>,
|
||||||
head: Head,
|
head: Head,
|
||||||
around: FixedDotIndex,
|
around: FixedDotIndex,
|
||||||
width: f64,
|
width: f64,
|
||||||
|
|
@ -133,6 +156,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
|
|
||||||
fn wrap_around_loose_bend(
|
fn wrap_around_loose_bend(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
graph: &UnGraph<NavvertexWeight, (), usize>,
|
||||||
head: Head,
|
head: Head,
|
||||||
around: LooseBendIndex,
|
around: LooseBendIndex,
|
||||||
width: f64,
|
width: f64,
|
||||||
|
|
@ -143,8 +167,8 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_ensures(trace.path.len() == old(trace.path.len() - 1))]
|
#[debug_ensures(trace.path.len() == old(trace.path.len() - 1))]
|
||||||
pub fn undo_step(&mut self, trace: &mut Trace) {
|
pub fn undo_step(&mut self, graph: &UnGraph<NavvertexWeight, (), usize>, trace: &mut Trace) {
|
||||||
if let Head::Cane(head) = trace.head {
|
if let Head::Cane(head) = dbg!(trace.head) {
|
||||||
trace.head = Draw::new(self.layout).undo_cane(head).unwrap();
|
trace.head = Draw::new(self.layout).undo_cane(head).unwrap();
|
||||||
} else {
|
} else {
|
||||||
panic!();
|
panic!();
|
||||||
|
|
@ -152,4 +176,20 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||||
|
|
||||||
trace.path.pop();
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue