Add some utility functions for working with `Index`es and `Weight`s

This commit is contained in:
Mikolaj Wielgus 2023-07-14 00:17:46 +02:00
parent dabe364420
commit bedd7c744a
3 changed files with 120 additions and 66 deletions

View File

@ -3,7 +3,7 @@ use std::rc::Rc;
use geo::geometry::Point; use geo::geometry::Point;
use crate::math::Circle; use crate::math::Circle;
use crate::mesh::{Mesh, Index, IndexRTreeWrapper, DotIndex, SegIndex, BendIndex}; use crate::mesh::{Mesh, TaggedIndex, RTreeWrapper, DotIndex, SegIndex, BendIndex};
use crate::rules::{Rules, Conditions}; use crate::rules::{Rules, Conditions};
use crate::primitive::Primitive; use crate::primitive::Primitive;
use crate::weight::{Weight, DotWeight, SegWeight, BendWeight}; use crate::weight::{Weight, DotWeight, SegWeight, BendWeight};
@ -48,7 +48,7 @@ impl Layout {
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw));
let head = self.extend_head(head, tangent_points.0); let head = self.extend_head(head, tangent_points.0);
self.route_seg_bend(head, Index::Dot(around), tangent_points.1, cw, width) self.route_seg_bend(head, TaggedIndex::Dot(around), tangent_points.1, cw, width)
} }
pub fn route_around_bend(&mut self, head: Head, around: BendIndex, cw: bool, width: f64) -> Head { pub fn route_around_bend(&mut self, head: Head, around: BendIndex, cw: bool, width: f64) -> Head {
@ -67,7 +67,7 @@ impl Layout {
let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw));
let head = self.extend_head(head, tangent_points.0); let head = self.extend_head(head, tangent_points.0);
self.route_seg_bend(head, Index::Bend(around), tangent_points.1, cw, width) self.route_seg_bend(head, TaggedIndex::Bend(around), tangent_points.1, cw, width)
} }
pub fn route_end(&mut self, head: Head, to: DotIndex, width: f64) { pub fn route_end(&mut self, head: Head, to: DotIndex, width: f64) {
@ -81,7 +81,7 @@ impl Layout {
}; };
let to_circle = Circle { let to_circle = Circle {
pos: self.mesh.weight(Index::Dot(to)).as_dot().unwrap().circle.pos, pos: self.mesh.dot_weight(to).circle.pos,
r: 0.0, r: 0.0,
}; };
@ -92,14 +92,13 @@ impl Layout {
self.add_seg(head.dot, to, width); self.add_seg(head.dot, to, width);
} }
fn route_seg_bend(&mut self, head: Head, around: Index, to: Point, cw: bool, width: f64) -> Head { fn route_seg_bend(&mut self, head: Head, around: TaggedIndex, to: Point, cw: bool, width: f64) -> Head {
let head = self.route_seg(head, to, width); let head = self.route_seg(head, to, width);
let bend_to = self.add_dot(*self.mesh.primitive(Index::Dot(head.dot)).weight.as_dot().unwrap()); let bend_to = self.add_dot(self.mesh.dot_weight(head.dot));
let from_primitive = self.mesh.primitive(Index::Dot(head.dot)); let net = self.mesh.dot_weight(head.dot).net;
let net = from_primitive.weight.as_dot().unwrap().net;
let mut layer = around; let mut layer = around;
while let Index::Bend(..) = layer { while let TaggedIndex::Bend(..) = layer {
layer = self.mesh.weight(layer).as_bend().unwrap().around; layer = self.mesh.weight(layer).as_bend().unwrap().around;
} }
let center = *layer.as_dot().unwrap(); let center = *layer.as_dot().unwrap();
@ -109,10 +108,9 @@ impl Layout {
} }
fn route_seg(&mut self, head: Head, to: Point, width: f64) -> Head { fn route_seg(&mut self, head: Head, to: Point, width: f64) -> Head {
let from_primitive = self.mesh.primitive(Index::Dot(head.dot)); let net = self.mesh.dot_weight(head.dot).net;
let net = from_primitive.weight.as_dot().unwrap().net;
assert!(width <= from_primitive.weight.as_dot().unwrap().circle.r * 2.0); assert!(width <= self.mesh.dot_weight(head.dot).circle.r * 2.0);
let to_index = self.mesh.add_dot(DotWeight { let to_index = self.mesh.add_dot(DotWeight {
net, net,
@ -134,7 +132,7 @@ impl Layout {
match maybe_bend { match maybe_bend {
Some(bend) => { Some(bend) => {
let head_around = self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().around; let head_around = self.mesh.bend_weight(bend).around;
match self.mesh.weight(head_around) { match self.mesh.weight(head_around) {
Weight::Dot(..) => self.dot_guidecircle(*head_around.as_dot().unwrap(), width + 5.0, conditions), Weight::Dot(..) => self.dot_guidecircle(*head_around.as_dot().unwrap(), width + 5.0, conditions),
@ -143,7 +141,7 @@ impl Layout {
} }
}, },
None => Circle { None => Circle {
pos: self.mesh.weight(Index::Dot(head.dot)).as_dot().unwrap().circle.pos, pos: self.mesh.dot_weight(head.dot).circle.pos,
r: 0.0, r: 0.0,
}, },
} }
@ -151,13 +149,13 @@ impl Layout {
fn head_cw(&self, head: &Head) -> Option<bool> { fn head_cw(&self, head: &Head) -> Option<bool> {
match head.bend { match head.bend {
Some(bend) => Some(self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw,), Some(bend) => Some(self.mesh.bend_weight(bend).cw),
None => None, None => None,
} }
} }
fn dot_guidecircle(&self, dot: DotIndex, width: f64, conditions: Conditions) -> Circle { fn dot_guidecircle(&self, dot: DotIndex, width: f64, conditions: Conditions) -> Circle {
let circle = self.mesh.weight(Index::Dot(dot)).as_dot().unwrap().circle; let circle = self.mesh.dot_weight(dot).circle;
Circle { Circle {
pos: circle.pos, pos: circle.pos,
r: circle.r + width + self.rules.ruleset(conditions).clearance.min, r: circle.r + width + self.rules.ruleset(conditions).clearance.min,
@ -165,15 +163,15 @@ impl Layout {
} }
fn bend_guidecircle(&self, bend: BendIndex, width: f64, conditions: Conditions) -> Circle { fn bend_guidecircle(&self, bend: BendIndex, width: f64, conditions: Conditions) -> Circle {
let mut layer = Index::Bend(bend); let mut layer = TaggedIndex::Bend(bend);
let mut r = width + self.rules.ruleset(conditions).clearance.min; let mut r = width + self.rules.ruleset(conditions).clearance.min;
while let Index::Bend(..) = layer { while let TaggedIndex::Bend(..) = layer {
layer = self.mesh.weight(layer).as_bend().unwrap().around; layer = self.mesh.weight(layer).as_bend().unwrap().around;
r += 5.0 + self.mesh.primitive(layer).width(); r += 5.0 + self.mesh.primitive(layer).width();
} }
let circle = self.primitive(layer).weight.as_dot().unwrap().circle; let circle = self.mesh.weight(layer).as_dot().unwrap().circle;
Circle { Circle {
pos: circle.pos, pos: circle.pos,
r: circle.r - 5.0 + r, r: circle.r - 5.0 + r,
@ -187,20 +185,20 @@ impl Layout {
head head
// No assertion for now because we temporarily use floats. // No assertion for now because we temporarily use floats.
//println!("{:?} {:?}", self.mesh.weight(Index::Dot(from)).as_dot().unwrap().circle.pos, to); //println!("{:?} {:?}", self.mesh.weight(TaggedIndex::Dot(from)).as_dot().unwrap().circle.pos, to);
//assert!(self.mesh.weight(Index::Dot(from)).as_dot().unwrap().circle.pos == to); //assert!(self.mesh.weight(TaggedIndex::Dot(from)).as_dot().unwrap().circle.pos == to);
} }
} }
fn extend_head_bend(&mut self, head: Head, to: Point) -> Head { fn extend_head_bend(&mut self, head: Head, to: Point) -> Head {
let bend = head.bend.unwrap(); let bend = head.bend.unwrap();
let dot_weight = *self.mesh.weight(Index::Dot(head.dot)).as_dot().unwrap(); let dot_weight = self.mesh.dot_weight(head.dot);
let bend_weight = *self.mesh.weight(Index::Bend(bend)).as_bend().unwrap(); let bend_weight = self.mesh.bend_weight(bend);
let fixed_dot: Index = self.mesh.dot_neighbors(Index::Bend(bend)) let fixed_dot: TaggedIndex = self.mesh.neighboring_dots(TaggedIndex::Bend(bend))
.into_iter() .into_iter()
.filter(|neighbor| *neighbor != Index::Dot(head.dot)) .filter(|neighbor| *neighbor != TaggedIndex::Dot(head.dot))
.collect::<Vec<Index>>()[0]; .collect::<Vec<TaggedIndex>>()[0];
self.mesh.remove_bend(bend); self.mesh.remove_bend(bend);
self.mesh.remove_dot(head.dot); self.mesh.remove_dot(head.dot);
@ -225,8 +223,7 @@ impl Layout {
} }
pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, width: f64) -> SegIndex { pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, width: f64) -> SegIndex {
let from_primitive = self.mesh.primitive(Index::Dot(from)); let net = self.mesh.dot_weight(from).net;
let net = from_primitive.weight.as_dot().unwrap().net;
self.mesh.add_seg(from, to, SegWeight {net, width}) self.mesh.add_seg(from, to, SegWeight {net, width})
} }
@ -234,7 +231,7 @@ impl Layout {
self.mesh.primitives() self.mesh.primitives()
} }
pub fn primitive(&self, index: Index) -> Primitive { pub fn primitive(&self, index: TaggedIndex) -> Primitive {
return self.mesh.primitive(index); return self.mesh.primitive(index);
} }

View File

@ -1,3 +1,4 @@
use std::marker::PhantomData;
use enum_as_inner::EnumAsInner; use enum_as_inner::EnumAsInner;
use petgraph::stable_graph::{StableUnGraph, NodeIndex, EdgeIndex}; use petgraph::stable_graph::{StableUnGraph, NodeIndex, EdgeIndex};
use petgraph::visit::EdgeRef; use petgraph::visit::EdgeRef;
@ -7,22 +8,62 @@ use rstar::primitives::GeomWithData;
use crate::primitive::Primitive; use crate::primitive::Primitive;
use crate::weight::{Weight, DotWeight, SegWeight, BendWeight}; use crate::weight::{Weight, DotWeight, SegWeight, BendWeight};
pub type DotIndex = NodeIndex<u32>;
pub type SegIndex = EdgeIndex<u32>; #[derive(Debug, Copy, Clone, PartialEq)]
pub type BendIndex = EdgeIndex<u32>; pub struct Index<Ix, T> {
index: Ix,
marker: PhantomData<T>,
}
impl<Ix, T> Index<Ix, T> {
pub fn new(index: Ix) -> Self {
Self {
index,
marker: PhantomData,
}
}
}
pub trait Tag {
fn tag(&self) -> TaggedIndex;
}
pub type DotIndex = Index<NodeIndex<usize>, DotWeight>;
impl Tag for DotIndex {
fn tag(&self) -> TaggedIndex {
TaggedIndex::Dot(*self)
}
}
pub type SegIndex = Index<EdgeIndex<usize>, SegWeight>;
impl Tag for SegIndex {
fn tag(&self) -> TaggedIndex {
TaggedIndex::Seg(*self)
}
}
pub type BendIndex = Index<EdgeIndex<usize>, BendWeight>;
impl Tag for BendIndex {
fn tag(&self) -> TaggedIndex {
TaggedIndex::Bend(*self)
}
}
#[derive(Debug, EnumAsInner, Copy, Clone, PartialEq)] #[derive(Debug, EnumAsInner, Copy, Clone, PartialEq)]
pub enum Index { pub enum TaggedIndex {
Dot(DotIndex), Dot(DotIndex),
Seg(SegIndex), Seg(SegIndex),
Bend(BendIndex), Bend(BendIndex),
} }
pub type IndexRTreeWrapper = GeomWithData<Primitive, Index>; pub type RTreeWrapper = GeomWithData<Primitive, TaggedIndex>;
pub struct Mesh { pub struct Mesh {
pub rtree: RTree<IndexRTreeWrapper>, pub rtree: RTree<RTreeWrapper>,
pub graph: StableUnGraph<Weight, Weight, u32>, pub graph: StableUnGraph<Weight, Weight, usize>,
} }
impl Mesh { impl Mesh {
@ -34,63 +75,63 @@ impl Mesh {
} }
pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex { pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex {
let dot_index = self.graph.add_node(Weight::Dot(weight)); let dot_index = DotIndex::new(self.graph.add_node(Weight::Dot(weight)));
let index = Index::Dot(dot_index); let index = TaggedIndex::Dot(dot_index);
self.rtree.insert(IndexRTreeWrapper::new(self.primitive(index), index)); self.rtree.insert(RTreeWrapper::new(self.primitive(index), index));
dot_index dot_index
} }
pub fn remove_dot(&mut self, dot: DotIndex) { pub fn remove_dot(&mut self, dot: DotIndex) {
self.rtree.remove(&IndexRTreeWrapper::new(self.primitive(Index::Dot(dot)), Index::Dot(dot))); self.rtree.remove(&RTreeWrapper::new(self.primitive(TaggedIndex::Dot(dot)), TaggedIndex::Dot(dot)));
self.graph.remove_node(dot); self.graph.remove_node(dot.index);
} }
pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, weight: SegWeight) -> SegIndex { pub fn add_seg(&mut self, from: DotIndex, to: DotIndex, weight: SegWeight) -> SegIndex {
let seg_index = self.graph.add_edge(from, to, Weight::Seg(weight)); let seg_index = SegIndex::new(self.graph.add_edge(from.index, to.index, Weight::Seg(weight)));
let index = Index::Seg(seg_index); let index = TaggedIndex::Seg(seg_index);
self.rtree.insert(IndexRTreeWrapper::new(self.primitive(index), index)); self.rtree.insert(RTreeWrapper::new(self.primitive(index), index));
seg_index seg_index
} }
pub fn remove_seg(&mut self, seg: SegIndex) { pub fn remove_seg(&mut self, seg: SegIndex) {
self.rtree.remove(&IndexRTreeWrapper::new(self.primitive(Index::Seg(seg)), Index::Seg(seg))); self.rtree.remove(&RTreeWrapper::new(self.primitive(TaggedIndex::Seg(seg)), TaggedIndex::Seg(seg)));
self.graph.remove_edge(seg); self.graph.remove_edge(seg.index);
} }
pub fn add_bend(&mut self, from: DotIndex, to: DotIndex, weight: BendWeight) -> BendIndex { pub fn add_bend(&mut self, from: DotIndex, to: DotIndex, weight: BendWeight) -> BendIndex {
let bend_index = self.graph.add_edge(from, to, Weight::Bend(weight)); let bend_index = BendIndex::new(self.graph.add_edge(from.index, to.index, Weight::Bend(weight)));
let index = Index::Bend(bend_index); let index = TaggedIndex::Bend(bend_index);
self.rtree.insert(IndexRTreeWrapper::new(self.primitive(index), index)); self.rtree.insert(RTreeWrapper::new(self.primitive(index), index));
bend_index bend_index
} }
pub fn remove_bend(&mut self, bend: BendIndex) { pub fn remove_bend(&mut self, bend: BendIndex) {
self.rtree.remove(&IndexRTreeWrapper::new(self.primitive(Index::Bend(bend)), Index::Bend(bend))); self.rtree.remove(&RTreeWrapper::new(self.primitive(TaggedIndex::Bend(bend)), TaggedIndex::Bend(bend)));
self.graph.remove_edge(bend); self.graph.remove_edge(bend.index);
} }
pub fn primitives(&self) -> Box<dyn Iterator<Item=Primitive> + '_> { pub fn primitives(&self) -> Box<dyn Iterator<Item=Primitive> + '_> {
Box::new(self.rtree.iter().map(|wrapper| self.primitive(wrapper.data))) Box::new(self.rtree.iter().map(|wrapper| self.primitive(wrapper.data)))
} }
pub fn primitive(&self, index: Index) -> Primitive { pub fn primitive(&self, index: TaggedIndex) -> Primitive {
Primitive { Primitive {
weight: self.weight(index), weight: self.weight(index),
dot_neighbor_weights: dot_neighbor_weights:
self.dot_neighbors(index) self.neighboring_dots(index)
.into_iter() .into_iter()
.map(|index| *self.weight(index).as_dot().unwrap()) .map(|index| *self.weight(index).as_dot().unwrap())
.collect(), .collect(),
around_weight: match index { around_weight: match index {
Index::Bend(bend_index) => { TaggedIndex::Bend(bend_index) => {
Some(self.weight((*self.weight(index).as_bend().unwrap()).around)) Some(self.weight((*self.weight(index).as_bend().unwrap()).around))
}, },
_ => None, _ => None,
}, },
focus: match index { focus: match index {
Index::Bend(bend_index) => { TaggedIndex::Bend(bend_index) => {
let mut layer = index; let mut layer = index;
while let Index::Bend(..) = layer { while let TaggedIndex::Bend(..) = layer {
layer = self.weight(layer).as_bend().unwrap().around; layer = self.weight(layer).as_bend().unwrap().around;
} }
Some(self.weight(layer).as_dot().unwrap().circle.pos) Some(self.weight(layer).as_dot().unwrap().circle.pos)
@ -100,22 +141,38 @@ impl Mesh {
} }
} }
pub fn dot_neighbors(&self, index: Index) -> Vec<Index> { pub fn neighboring_dots(&self, index: TaggedIndex) -> Vec<TaggedIndex> {
match index { match index {
Index::Dot(node_index) => TaggedIndex::Dot(DotIndex {index: node_index, ..}) =>
return self.graph.neighbors(node_index).map(|ni| Index::Dot(ni)).collect(), return self.graph.neighbors(node_index)
Index::Seg(edge_index) | Index::Bend(edge_index) => { .map(|ni| TaggedIndex::Dot(Index::new(ni))).collect(),
TaggedIndex::Seg(SegIndex {index: edge_index, ..})
| TaggedIndex::Bend(BendIndex {index: edge_index, ..}) => {
let endpoints = self.graph.edge_endpoints(edge_index).unwrap(); let endpoints = self.graph.edge_endpoints(edge_index).unwrap();
return vec![Index::Dot(endpoints.0), Index::Dot(endpoints.1)] return vec![TaggedIndex::Dot(DotIndex::new(endpoints.0)),
TaggedIndex::Dot(DotIndex::new(endpoints.1))]
} }
} }
} }
pub fn weight(&self, index: Index) -> Weight { pub fn dot_weight(&self, dot: DotIndex) -> DotWeight {
*self.weight(dot.tag()).as_dot().unwrap()
}
pub fn seg_weight(&self, seg: SegIndex) -> SegWeight {
*self.weight(seg.tag()).as_seg().unwrap()
}
pub fn bend_weight(&self, bend: BendIndex) -> BendWeight {
*self.weight(bend.tag()).as_bend().unwrap()
}
pub fn weight(&self, index: TaggedIndex) -> Weight {
match index { match index {
Index::Dot(node_index) => TaggedIndex::Dot(DotIndex {index: node_index, ..}) =>
*self.graph.node_weight(node_index).unwrap(), *self.graph.node_weight(node_index).unwrap(),
Index::Seg(edge_index) | Index::Bend(edge_index) => TaggedIndex::Seg(SegIndex {index: edge_index, ..})
| TaggedIndex::Bend(BendIndex {index: edge_index, ..}) =>
*self.graph.edge_weight(edge_index).unwrap(), *self.graph.edge_weight(edge_index).unwrap(),
} }
} }

View File

@ -1,5 +1,5 @@
use enum_as_inner::EnumAsInner; use enum_as_inner::EnumAsInner;
use crate::{math::Circle, mesh::{Index, DotIndex}}; use crate::{math::Circle, mesh::{DotIndex, TaggedIndex}};
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct DotWeight { pub struct DotWeight {
@ -10,7 +10,7 @@ pub struct DotWeight {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct BendWeight { pub struct BendWeight {
pub net: i32, pub net: i32,
pub around: Index, pub around: TaggedIndex,
pub center: DotIndex, pub center: DotIndex,
pub cw: bool, pub cw: bool,
} }