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 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<bool> {
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::<Vec<Index>>()[0];
.filter(|neighbor| *neighbor != TaggedIndex::Dot(head.dot))
.collect::<Vec<TaggedIndex>>()[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);
}

View File

@ -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<u32>;
pub type SegIndex = EdgeIndex<u32>;
pub type BendIndex = EdgeIndex<u32>;
#[derive(Debug, Copy, Clone, PartialEq)]
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)]
pub enum Index {
pub enum TaggedIndex {
Dot(DotIndex),
Seg(SegIndex),
Bend(BendIndex),
}
pub type IndexRTreeWrapper = GeomWithData<Primitive, Index>;
pub type RTreeWrapper = GeomWithData<Primitive, TaggedIndex>;
pub struct Mesh {
pub rtree: RTree<IndexRTreeWrapper>,
pub graph: StableUnGraph<Weight, Weight, u32>,
pub rtree: RTree<RTreeWrapper>,
pub graph: StableUnGraph<Weight, Weight, usize>,
}
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<dyn Iterator<Item=Primitive> + '_> {
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<Index> {
pub fn neighboring_dots(&self, index: TaggedIndex) -> Vec<TaggedIndex> {
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(),
}
}

View File

@ -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,
}