diff --git a/src/layout.rs b/src/layout.rs index 838ac2b..ebc10c6 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use geo::geometry::Point; 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::primitive::Primitive; 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 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 { @@ -67,7 +67,7 @@ impl Layout { let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); 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) { @@ -81,7 +81,7 @@ impl Layout { }; 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, }; @@ -92,14 +92,13 @@ impl Layout { 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 bend_to = self.add_dot(*self.mesh.primitive(Index::Dot(head.dot)).weight.as_dot().unwrap()); - let from_primitive = self.mesh.primitive(Index::Dot(head.dot)); - let net = from_primitive.weight.as_dot().unwrap().net; + let bend_to = self.add_dot(self.mesh.dot_weight(head.dot)); + let net = self.mesh.dot_weight(head.dot).net; let mut layer = around; - while let Index::Bend(..) = layer { + while let TaggedIndex::Bend(..) = layer { layer = self.mesh.weight(layer).as_bend().unwrap().around; } let center = *layer.as_dot().unwrap(); @@ -109,10 +108,9 @@ impl Layout { } fn route_seg(&mut self, head: Head, to: Point, width: f64) -> Head { - let from_primitive = self.mesh.primitive(Index::Dot(head.dot)); - let net = from_primitive.weight.as_dot().unwrap().net; + let net = self.mesh.dot_weight(head.dot).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 { net, @@ -134,7 +132,7 @@ impl Layout { match maybe_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) { Weight::Dot(..) => self.dot_guidecircle(*head_around.as_dot().unwrap(), width + 5.0, conditions), @@ -143,7 +141,7 @@ impl Layout { } }, 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, }, } @@ -151,13 +149,13 @@ impl Layout { fn head_cw(&self, head: &Head) -> Option { 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, } } 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 { pos: circle.pos, 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 { - let mut layer = Index::Bend(bend); + let mut layer = TaggedIndex::Bend(bend); 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; 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 { pos: circle.pos, r: circle.r - 5.0 + r, @@ -187,20 +185,20 @@ impl Layout { head // No assertion for now because we temporarily use floats. - //println!("{:?} {:?}", self.mesh.weight(Index::Dot(from)).as_dot().unwrap().circle.pos, to); - //assert!(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(TaggedIndex::Dot(from)).as_dot().unwrap().circle.pos == to); } } fn extend_head_bend(&mut self, head: Head, to: Point) -> Head { let bend = head.bend.unwrap(); - let dot_weight = *self.mesh.weight(Index::Dot(head.dot)).as_dot().unwrap(); - let bend_weight = *self.mesh.weight(Index::Bend(bend)).as_bend().unwrap(); + let dot_weight = self.mesh.dot_weight(head.dot); + 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() - .filter(|neighbor| *neighbor != Index::Dot(head.dot)) - .collect::>()[0]; + .filter(|neighbor| *neighbor != TaggedIndex::Dot(head.dot)) + .collect::>()[0]; self.mesh.remove_bend(bend); 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 { - let from_primitive = self.mesh.primitive(Index::Dot(from)); - let net = from_primitive.weight.as_dot().unwrap().net; + let net = self.mesh.dot_weight(from).net; self.mesh.add_seg(from, to, SegWeight {net, width}) } @@ -234,7 +231,7 @@ impl Layout { self.mesh.primitives() } - pub fn primitive(&self, index: Index) -> Primitive { + pub fn primitive(&self, index: TaggedIndex) -> Primitive { return self.mesh.primitive(index); } diff --git a/src/mesh.rs b/src/mesh.rs index b2f575b..9880142 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -1,3 +1,4 @@ +use std::marker::PhantomData; use enum_as_inner::EnumAsInner; use petgraph::stable_graph::{StableUnGraph, NodeIndex, EdgeIndex}; use petgraph::visit::EdgeRef; @@ -7,22 +8,62 @@ use rstar::primitives::GeomWithData; use crate::primitive::Primitive; use crate::weight::{Weight, DotWeight, SegWeight, BendWeight}; -pub type DotIndex = NodeIndex; -pub type SegIndex = EdgeIndex; -pub type BendIndex = EdgeIndex; + +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Index { + index: Ix, + marker: PhantomData, +} + +impl Index { + pub fn new(index: Ix) -> Self { + Self { + index, + marker: PhantomData, + } + } +} + +pub trait Tag { + fn tag(&self) -> TaggedIndex; +} + +pub type DotIndex = Index, DotWeight>; + +impl Tag for DotIndex { + fn tag(&self) -> TaggedIndex { + TaggedIndex::Dot(*self) + } +} + +pub type SegIndex = Index, SegWeight>; + +impl Tag for SegIndex { + fn tag(&self) -> TaggedIndex { + TaggedIndex::Seg(*self) + } +} + +pub type BendIndex = Index, BendWeight>; + +impl Tag for BendIndex { + fn tag(&self) -> TaggedIndex { + TaggedIndex::Bend(*self) + } +} #[derive(Debug, EnumAsInner, Copy, Clone, PartialEq)] -pub enum Index { +pub enum TaggedIndex { Dot(DotIndex), Seg(SegIndex), Bend(BendIndex), } -pub type IndexRTreeWrapper = GeomWithData; +pub type RTreeWrapper = GeomWithData; pub struct Mesh { - pub rtree: RTree, - pub graph: StableUnGraph, + pub rtree: RTree, + pub graph: StableUnGraph, } impl Mesh { @@ -34,63 +75,63 @@ impl Mesh { } pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex { - let dot_index = self.graph.add_node(Weight::Dot(weight)); - let index = Index::Dot(dot_index); - self.rtree.insert(IndexRTreeWrapper::new(self.primitive(index), index)); + let dot_index = DotIndex::new(self.graph.add_node(Weight::Dot(weight))); + let index = TaggedIndex::Dot(dot_index); + self.rtree.insert(RTreeWrapper::new(self.primitive(index), index)); dot_index } pub fn remove_dot(&mut self, dot: DotIndex) { - self.rtree.remove(&IndexRTreeWrapper::new(self.primitive(Index::Dot(dot)), Index::Dot(dot))); - self.graph.remove_node(dot); + self.rtree.remove(&RTreeWrapper::new(self.primitive(TaggedIndex::Dot(dot)), TaggedIndex::Dot(dot))); + self.graph.remove_node(dot.index); } 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 index = Index::Seg(seg_index); - self.rtree.insert(IndexRTreeWrapper::new(self.primitive(index), index)); + let seg_index = SegIndex::new(self.graph.add_edge(from.index, to.index, Weight::Seg(weight))); + let index = TaggedIndex::Seg(seg_index); + self.rtree.insert(RTreeWrapper::new(self.primitive(index), index)); seg_index } pub fn remove_seg(&mut self, seg: SegIndex) { - self.rtree.remove(&IndexRTreeWrapper::new(self.primitive(Index::Seg(seg)), Index::Seg(seg))); - self.graph.remove_edge(seg); + self.rtree.remove(&RTreeWrapper::new(self.primitive(TaggedIndex::Seg(seg)), TaggedIndex::Seg(seg))); + self.graph.remove_edge(seg.index); } 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 index = Index::Bend(bend_index); - self.rtree.insert(IndexRTreeWrapper::new(self.primitive(index), index)); + let bend_index = BendIndex::new(self.graph.add_edge(from.index, to.index, Weight::Bend(weight))); + let index = TaggedIndex::Bend(bend_index); + self.rtree.insert(RTreeWrapper::new(self.primitive(index), index)); bend_index } pub fn remove_bend(&mut self, bend: BendIndex) { - self.rtree.remove(&IndexRTreeWrapper::new(self.primitive(Index::Bend(bend)), Index::Bend(bend))); - self.graph.remove_edge(bend); + self.rtree.remove(&RTreeWrapper::new(self.primitive(TaggedIndex::Bend(bend)), TaggedIndex::Bend(bend))); + self.graph.remove_edge(bend.index); } pub fn primitives(&self) -> Box + '_> { 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 { weight: self.weight(index), dot_neighbor_weights: - self.dot_neighbors(index) + self.neighboring_dots(index) .into_iter() .map(|index| *self.weight(index).as_dot().unwrap()) .collect(), around_weight: match index { - Index::Bend(bend_index) => { + TaggedIndex::Bend(bend_index) => { Some(self.weight((*self.weight(index).as_bend().unwrap()).around)) }, _ => None, }, focus: match index { - Index::Bend(bend_index) => { + TaggedIndex::Bend(bend_index) => { let mut layer = index; - while let Index::Bend(..) = layer { + while let TaggedIndex::Bend(..) = layer { layer = self.weight(layer).as_bend().unwrap().around; } Some(self.weight(layer).as_dot().unwrap().circle.pos) @@ -100,22 +141,38 @@ impl Mesh { } } - pub fn dot_neighbors(&self, index: Index) -> Vec { + pub fn neighboring_dots(&self, index: TaggedIndex) -> Vec { match index { - Index::Dot(node_index) => - return self.graph.neighbors(node_index).map(|ni| Index::Dot(ni)).collect(), - Index::Seg(edge_index) | Index::Bend(edge_index) => { + TaggedIndex::Dot(DotIndex {index: node_index, ..}) => + return self.graph.neighbors(node_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(); - 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 { - Index::Dot(node_index) => + TaggedIndex::Dot(DotIndex {index: node_index, ..}) => *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(), } } diff --git a/src/weight.rs b/src/weight.rs index ffebc87..9ef720c 100644 --- a/src/weight.rs +++ b/src/weight.rs @@ -1,5 +1,5 @@ use enum_as_inner::EnumAsInner; -use crate::{math::Circle, mesh::{Index, DotIndex}}; +use crate::{math::Circle, mesh::{DotIndex, TaggedIndex}}; #[derive(Debug, Clone, Copy, PartialEq)] pub struct DotWeight { @@ -10,7 +10,7 @@ pub struct DotWeight { #[derive(Debug, Clone, Copy, PartialEq)] pub struct BendWeight { pub net: i32, - pub around: Index, + pub around: TaggedIndex, pub center: DotIndex, pub cw: bool, }