autorouter: implement simple undo (untested, not in GUI yet)

This commit is contained in:
Mikolaj Wielgus 2024-05-14 14:22:47 +02:00
parent c006dcfd47
commit 1c09483873
6 changed files with 153 additions and 83 deletions

View File

@ -134,35 +134,45 @@ impl<R: RulesTrait> Autorouter<R> {
} }
pub fn autoroute_walk(&mut self, selection: &Selection) -> Option<Autoroute> { pub fn autoroute_walk(&mut self, selection: &Selection) -> Option<Autoroute> {
Autoroute::new( Autoroute::new(self.selected_ratlines(selection), self)
self.ratsnest
.graph()
.edge_indices()
.filter(|edge| {
let (from, to) = self.ratsnest.graph().edge_endpoints(*edge).unwrap();
let from_vertex = self
.ratsnest
.graph()
.node_weight(from)
.unwrap()
.vertex_index();
let to_vertex = self
.ratsnest
.graph()
.node_weight(to)
.unwrap()
.vertex_index();
selection.contains(&from_vertex.into()) && selection.contains(&to_vertex.into())
})
.collect::<Vec<_>>(),
self,
)
} }
pub fn undo_autoroute(&mut self, selection: &Selection) { pub fn undo_autoroute(&mut self, selection: &Selection) {
todo!(); for ratline in self.selected_ratlines(selection).iter() {
let band = self
.ratsnest
.graph()
.edge_weight(*ratline)
.unwrap()
.band
.unwrap();
self.layout.lock().unwrap().remove_band(band);
}
}
fn selected_ratlines(&self, selection: &Selection) -> Vec<EdgeIndex<usize>> {
self.ratsnest
.graph()
.edge_indices()
.filter(|ratline| {
let (from, to) = self.ratsnest.graph().edge_endpoints(*ratline).unwrap();
let from_vertex = self
.ratsnest
.graph()
.node_weight(from)
.unwrap()
.vertex_index();
let to_vertex = self
.ratsnest
.graph()
.node_weight(to)
.unwrap()
.vertex_index();
selection.contains(&from_vertex.into()) && selection.contains(&to_vertex.into())
})
.collect()
} }
pub fn layout(&self) -> &Arc<Mutex<Layout<R>>> { pub fn layout(&self) -> &Arc<Mutex<Layout<R>>> {

View File

@ -12,6 +12,7 @@ use spade::{HasPosition, InsertionError, Point2};
use crate::{ use crate::{
drawing::{ drawing::{
band::BandIndex,
dot::FixedDotIndex, dot::FixedDotIndex,
graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex}, graph::{GetMaybeNet, MakePrimitive, PrimitiveIndex},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
@ -23,7 +24,7 @@ use crate::{
zone::{MakePolyShape, ZoneWeight}, zone::{MakePolyShape, ZoneWeight},
Layout, Layout,
}, },
triangulation::{GetVertexIndex, Triangulation, TriangulationEdgeWeight}, triangulation::{GetVertexIndex, Triangulation},
}; };
#[enum_dispatch(GetNodeIndex)] #[enum_dispatch(GetNodeIndex)]
@ -61,8 +62,13 @@ impl HasPosition for VertexWeight {
} }
} }
#[derive(Debug, Default, Clone, Copy)]
pub struct EdgeWeight {
pub band: Option<BandIndex>,
}
pub struct Ratsnest { pub struct Ratsnest {
graph: UnGraph<VertexWeight, TriangulationEdgeWeight, usize>, graph: UnGraph<VertexWeight, EdgeWeight, usize>,
} }
impl Ratsnest { impl Ratsnest {
@ -140,7 +146,7 @@ impl Ratsnest {
target, target,
weight, weight,
} => { } => {
this.graph.add_edge(map[source], map[target], weight); this.graph.add_edge(map[source], map[target], weight.weight);
} }
} }
} }
@ -159,7 +165,7 @@ impl Ratsnest {
Ok(this) Ok(this)
} }
pub fn graph(&self) -> &UnGraph<VertexWeight, TriangulationEdgeWeight, usize> { pub fn graph(&self) -> &UnGraph<VertexWeight, EdgeWeight, usize> {
&self.graph &self.graph
} }
} }

View File

@ -1,5 +1,6 @@
use crate::drawing::seg::{LoneLooseSegIndex, SeqLooseSegIndex}; use crate::drawing::seg::{LoneLooseSegIndex, SeqLooseSegIndex};
#[derive(Debug, Clone, Copy)]
pub enum BandIndex { pub enum BandIndex {
Straight(LoneLooseSegIndex), Straight(LoneLooseSegIndex),
Bended(SeqLooseSegIndex), Bended(SeqLooseSegIndex),

View File

@ -4,6 +4,7 @@ use rstar::AABB;
use crate::{ use crate::{
drawing::{ drawing::{
band::BandIndex,
bend::LooseBendWeight, bend::LooseBendWeight,
dot::{DotIndex, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, dot::{DotIndex, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
graph::{GetLayer, GetMaybeNet, PrimitiveIndex, PrimitiveWeight, Retag}, graph::{GetLayer, GetMaybeNet, PrimitiveIndex, PrimitiveWeight, Retag},
@ -37,6 +38,10 @@ impl<R: RulesTrait> Layout<R> {
Self { drawing } Self { drawing }
} }
pub fn remove_band(&mut self, band: BandIndex) {
self.drawing.remove_band(band);
}
pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) { pub fn remove_segbend(&mut self, segbend: &Segbend, face: LooseDotIndex) {
self.drawing.remove_segbend(segbend, face) self.drawing.remove_segbend(segbend, face)
} }

View File

@ -58,19 +58,19 @@ impl From<TriangulationVertexIndex> for VertexIndex {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct TriangulationWeight { struct TriangulationVertexWeight {
vertex: TriangulationVertexIndex, vertex: TriangulationVertexIndex,
rails: Vec<LooseBendIndex>, rails: Vec<LooseBendIndex>,
pos: Point, pos: Point,
} }
impl GetVertexIndex<TriangulationVertexIndex> for TriangulationWeight { impl GetVertexIndex<TriangulationVertexIndex> for TriangulationVertexWeight {
fn vertex_index(&self) -> TriangulationVertexIndex { fn vertex_index(&self) -> TriangulationVertexIndex {
self.vertex self.vertex
} }
} }
impl HasPosition for TriangulationWeight { impl HasPosition for TriangulationVertexWeight {
type Scalar = f64; type Scalar = f64;
fn position(&self) -> Point2<Self::Scalar> { fn position(&self) -> Point2<Self::Scalar> {
Point2::new(self.pos.x(), self.pos.y()) Point2::new(self.pos.x(), self.pos.y())
@ -79,7 +79,7 @@ impl HasPosition for TriangulationWeight {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Navmesh { pub struct Navmesh {
triangulation: Triangulation<TriangulationVertexIndex, TriangulationWeight>, triangulation: Triangulation<TriangulationVertexIndex, TriangulationVertexWeight, ()>,
vertex_to_triangulation_vertex: Vec<Option<TriangulationVertexIndex>>, vertex_to_triangulation_vertex: Vec<Option<TriangulationVertexIndex>>,
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
@ -110,14 +110,14 @@ impl Navmesh {
if node == from.into() || node == to.into() || primitive_net != net { if node == from.into() || node == to.into() || primitive_net != net {
match node { match node {
PrimitiveIndex::FixedDot(dot) => { PrimitiveIndex::FixedDot(dot) => {
this.triangulation.add_vertex(TriangulationWeight { this.triangulation.add_vertex(TriangulationVertexWeight {
vertex: dot.into(), vertex: dot.into(),
rails: vec![], rails: vec![],
pos: primitive.shape().center(), pos: primitive.shape().center(),
})?; })?;
} }
PrimitiveIndex::FixedBend(bend) => { PrimitiveIndex::FixedBend(bend) => {
this.triangulation.add_vertex(TriangulationWeight { this.triangulation.add_vertex(TriangulationVertexWeight {
vertex: bend.into(), vertex: bend.into(),
rails: vec![], rails: vec![],
pos: primitive.shape().center(), pos: primitive.shape().center(),
@ -225,8 +225,8 @@ impl<'a> visit::IntoNeighbors for &'a Navmesh {
} }
fn edge_with_near_edges( fn edge_with_near_edges(
triangulation: &Triangulation<TriangulationVertexIndex, TriangulationWeight>, triangulation: &Triangulation<TriangulationVertexIndex, TriangulationVertexWeight, ()>,
edge: TriangulationEdgeReference<TriangulationVertexIndex>, edge: TriangulationEdgeReference<TriangulationVertexIndex, ()>,
) -> impl Iterator<Item = NavmeshEdgeReference> { ) -> impl Iterator<Item = NavmeshEdgeReference> {
let mut from_vertices = vec![edge.source().into()]; let mut from_vertices = vec![edge.source().into()];
@ -274,7 +274,7 @@ impl<'a> visit::IntoEdgeReferences for &'a Navmesh {
} }
fn vertex_edges( fn vertex_edges(
triangulation: &Triangulation<TriangulationVertexIndex, TriangulationWeight>, triangulation: &Triangulation<TriangulationVertexIndex, TriangulationVertexWeight, ()>,
from: VertexIndex, from: VertexIndex,
to: TriangulationVertexIndex, to: TriangulationVertexIndex,
) -> impl Iterator<Item = NavmeshEdgeReference> { ) -> impl Iterator<Item = NavmeshEdgeReference> {

View File

@ -1,4 +1,4 @@
use std::marker::PhantomData; use std::{cmp::Ordering, marker::PhantomData};
use geo::{point, EuclideanDistance, Point}; use geo::{point, EuclideanDistance, Point};
use petgraph::visit; use petgraph::visit;
@ -11,18 +11,25 @@ pub trait GetVertexIndex<I> {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Triangulation<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition> { pub struct Triangulation<
triangulation: DelaunayTriangulation<W>, I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition,
EW: Copy + Default,
> {
triangulation: DelaunayTriangulation<VW, EW>,
vertex_to_handle: Vec<Option<FixedVertexHandle>>, vertex_to_handle: Vec<Option<FixedVertexHandle>>,
index_marker: PhantomData<I>, index_marker: PhantomData<I>,
} }
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>> impl<
Triangulation<I, W> I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
EW: Copy + Default,
> Triangulation<I, VW, EW>
{ {
pub fn new(node_bound: usize) -> Self { pub fn new(node_bound: usize) -> Self {
let mut this = Self { let mut this = Self {
triangulation: <DelaunayTriangulation<W> as spade::Triangulation>::new(), triangulation: <DelaunayTriangulation<VW, EW> as spade::Triangulation>::new(),
vertex_to_handle: Vec::new(), vertex_to_handle: Vec::new(),
index_marker: PhantomData, index_marker: PhantomData,
}; };
@ -30,7 +37,7 @@ impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scal
this this
} }
pub fn add_vertex(&mut self, weight: W) -> Result<(), InsertionError> { pub fn add_vertex(&mut self, weight: VW) -> Result<(), InsertionError> {
let index = weight.vertex_index().node_index().index(); let index = weight.vertex_index().node_index().index();
self.vertex_to_handle[index] = Some(spade::Triangulation::insert( self.vertex_to_handle[index] = Some(spade::Triangulation::insert(
&mut self.triangulation, &mut self.triangulation,
@ -39,12 +46,12 @@ impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scal
Ok(()) Ok(())
} }
pub fn weight(&self, vertex: I) -> &W { pub fn weight(&self, vertex: I) -> &VW {
spade::Triangulation::s(&self.triangulation) spade::Triangulation::s(&self.triangulation)
.vertex_data(self.vertex_to_handle[vertex.node_index().index()].unwrap()) .vertex_data(self.vertex_to_handle[vertex.node_index().index()].unwrap())
} }
pub fn weight_mut(&mut self, vertex: I) -> &mut W { pub fn weight_mut(&mut self, vertex: I) -> &mut VW {
spade::Triangulation::vertex_data_mut( spade::Triangulation::vertex_data_mut(
&mut self.triangulation, &mut self.triangulation,
self.vertex_to_handle[vertex.node_index().index()].unwrap(), self.vertex_to_handle[vertex.node_index().index()].unwrap(),
@ -68,36 +75,55 @@ impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scal
} }
} }
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>> impl<
visit::GraphBase for Triangulation<I, W> I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
EW: Copy + Default,
> visit::GraphBase for Triangulation<I, VW, EW>
{ {
type NodeId = I; type NodeId = I;
type EdgeId = (I, I); type EdgeId = (I, I);
} }
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] #[derive(Debug, Clone, Copy)]
pub struct TriangulationEdgeWeight { pub struct TriangulationEdgeWeightWrapper<EW: Copy + Default> {
length: f64, length: f64,
pub weight: EW,
} }
impl<I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>> impl<EW: Copy + Default> PartialEq for TriangulationEdgeWeightWrapper<EW> {
visit::Data for Triangulation<I, W> fn eq(&self, other: &Self) -> bool {
self.length.eq(&other.length)
}
}
impl<EW: Copy + Default> PartialOrd for TriangulationEdgeWeightWrapper<EW> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.length.partial_cmp(&other.length)
}
}
impl<
I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
EW: Copy + Default,
> visit::Data for Triangulation<I, VW, EW>
{ {
type NodeWeight = W; type NodeWeight = VW;
type EdgeWeight = TriangulationEdgeWeight; type EdgeWeight = TriangulationEdgeWeightWrapper<EW>;
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct TriangulationEdgeReference<I> { pub struct TriangulationEdgeReference<I, EW: Copy + Default> {
from: I, from: I,
to: I, to: I,
weight: TriangulationEdgeWeight, weight: TriangulationEdgeWeightWrapper<EW>,
} }
impl<I: Copy> visit::EdgeRef for TriangulationEdgeReference<I> { impl<I: Copy, EW: Copy + Default> visit::EdgeRef for TriangulationEdgeReference<I, EW> {
type NodeId = I; type NodeId = I;
type EdgeId = (I, I); type EdgeId = (I, I);
type Weight = TriangulationEdgeWeight; type Weight = TriangulationEdgeWeightWrapper<EW>;
fn source(&self) -> Self::NodeId { fn source(&self) -> Self::NodeId {
self.from self.from
@ -116,8 +142,12 @@ impl<I: Copy> visit::EdgeRef for TriangulationEdgeReference<I> {
} }
} }
impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>> impl<
visit::IntoNeighbors for &'a Triangulation<I, W> 'a,
I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
EW: Copy + Default,
> visit::IntoNeighbors for &'a Triangulation<I, VW, EW>
{ {
type Neighbors = Box<dyn Iterator<Item = I> + 'a>; type Neighbors = Box<dyn Iterator<Item = I> + 'a>;
@ -130,22 +160,28 @@ impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<
} }
} }
impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>> impl<
visit::IntoEdgeReferences for &'a Triangulation<I, W> 'a,
I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
EW: Copy + Default,
> visit::IntoEdgeReferences for &'a Triangulation<I, VW, EW>
{ {
type EdgeRef = TriangulationEdgeReference<I>; type EdgeRef = TriangulationEdgeReference<I, EW>;
type EdgeReferences = Box<dyn Iterator<Item = TriangulationEdgeReference<I>> + 'a>; type EdgeReferences = Box<dyn Iterator<Item = TriangulationEdgeReference<I, EW>> + 'a>;
fn edge_references(self) -> Self::EdgeReferences { fn edge_references(self) -> Self::EdgeReferences {
Box::new( Box::new(
spade::Triangulation::directed_edges(&self.triangulation).map(|edge| { spade::Triangulation::directed_edges(&self.triangulation).map(|edge| {
let from = self.vertex(edge.from().fix()); let from = self.vertex(edge.from().fix());
let to = self.vertex(edge.to().fix()); let to = self.vertex(edge.to().fix());
TriangulationEdgeReference { TriangulationEdgeReference {
from, from,
to, to,
weight: TriangulationEdgeWeight { weight: TriangulationEdgeWeightWrapper {
length: self.position(from).euclidean_distance(&self.position(to)), length: self.position(from).euclidean_distance(&self.position(to)),
weight: *edge.data(),
}, },
} }
}), }),
@ -153,10 +189,14 @@ impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<
} }
} }
impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>> impl<
visit::IntoEdges for &'a Triangulation<I, W> 'a,
I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
EW: Copy + Default,
> visit::IntoEdges for &'a Triangulation<I, VW, EW>
{ {
type Edges = Box<dyn Iterator<Item = TriangulationEdgeReference<I>> + 'a>; type Edges = Box<dyn Iterator<Item = TriangulationEdgeReference<I, EW>> + 'a>;
fn edges(self, node: Self::NodeId) -> Self::Edges { fn edges(self, node: Self::NodeId) -> Self::Edges {
Box::new( Box::new(
@ -165,11 +205,13 @@ impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<
.map(|edge| { .map(|edge| {
let from = self.vertex(edge.from().fix()); let from = self.vertex(edge.from().fix());
let to = self.vertex(edge.to().fix()); let to = self.vertex(edge.to().fix());
TriangulationEdgeReference { TriangulationEdgeReference {
from, from,
to, to,
weight: TriangulationEdgeWeight { weight: TriangulationEdgeWeightWrapper {
length: self.position(from).euclidean_distance(&self.position(to)), length: self.position(from).euclidean_distance(&self.position(to)),
weight: *edge.data(),
}, },
} }
}), }),
@ -177,8 +219,12 @@ impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<
} }
} }
impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<Scalar = f64>> impl<
visit::IntoNodeIdentifiers for &'a Triangulation<I, W> 'a,
I: Copy + PartialEq + GetNodeIndex,
VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
EW: Copy + Default,
> visit::IntoNodeIdentifiers for &'a Triangulation<I, VW, EW>
{ {
type NodeIdentifiers = Box<dyn Iterator<Item = I> + 'a>; type NodeIdentifiers = Box<dyn Iterator<Item = I> + 'a>;
@ -194,14 +240,14 @@ impl<'a, I: Copy + PartialEq + GetNodeIndex, W: GetVertexIndex<I> + HasPosition<
} }
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct TriangulationVertexReference<'a, I: Copy, W> { pub struct TriangulationVertexReference<'a, I: Copy, VW> {
index: I, index: I,
weight: &'a W, weight: &'a VW,
} }
impl<'a, I: Copy, W: Copy> visit::NodeRef for TriangulationVertexReference<'a, I, W> { impl<'a, I: Copy, VW: Copy> visit::NodeRef for TriangulationVertexReference<'a, I, VW> {
type NodeId = I; type NodeId = I;
type Weight = W; type Weight = VW;
fn id(&self) -> Self::NodeId { fn id(&self) -> Self::NodeId {
self.index self.index
@ -215,11 +261,12 @@ impl<'a, I: Copy, W: Copy> visit::NodeRef for TriangulationVertexReference<'a, I
impl< impl<
'a, 'a,
I: Copy + PartialEq + GetNodeIndex, I: Copy + PartialEq + GetNodeIndex,
W: Copy + GetVertexIndex<I> + HasPosition<Scalar = f64>, VW: Copy + GetVertexIndex<I> + HasPosition<Scalar = f64>,
> visit::IntoNodeReferences for &'a Triangulation<I, W> EW: Copy + Default,
> visit::IntoNodeReferences for &'a Triangulation<I, VW, EW>
{ {
type NodeRef = TriangulationVertexReference<'a, I, W>; type NodeRef = TriangulationVertexReference<'a, I, VW>;
type NodeReferences = Box<dyn Iterator<Item = TriangulationVertexReference<'a, I, W>> + 'a>; type NodeReferences = Box<dyn Iterator<Item = TriangulationVertexReference<'a, I, VW>> + 'a>;
fn node_references(self) -> Self::NodeReferences { fn node_references(self) -> Self::NodeReferences {
Box::new( Box::new(
@ -237,8 +284,9 @@ impl<
impl< impl<
'a, 'a,
I: Copy + PartialEq + GetNodeIndex + std::fmt::Debug, I: Copy + PartialEq + GetNodeIndex + std::fmt::Debug,
W: GetVertexIndex<I> + HasPosition<Scalar = f64>, VW: GetVertexIndex<I> + HasPosition<Scalar = f64>,
> visit::NodeIndexable for &'a Triangulation<I, W> EW: Copy + Default,
> visit::NodeIndexable for &'a Triangulation<I, VW, EW>
{ {
fn node_bound(&self) -> usize { fn node_bound(&self) -> usize {
//spade::Triangulation::num_vertices(&self.triangulation) //spade::Triangulation::num_vertices(&self.triangulation)