diff --git a/src/layout.rs b/src/layout.rs index cc6f1f2..e373a2b 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -29,9 +29,8 @@ impl Layout { } } - pub fn route_around(&mut self, from: DotIndex, around: DotIndex, cw: bool, width: f64) -> DotIndex { + pub fn route_around_dot(&mut self, from: DotIndex, around: DotIndex, cw: bool, width: f64) -> DotIndex { let from_circle = self.head_guidecircle(from, width); - let around_circle = self.mesh.weight(Index::Dot(around)).as_dot().unwrap().circle; let conditions = Conditions { lower_net: None, @@ -40,21 +39,32 @@ impl Layout { zone: None, }; - let to_circle = self.circle_shell(around_circle, width + 5.0, conditions); - - let maybe_bend = self.mesh.bend(from); - let from_cw = match maybe_bend { - Some(bend) => Some(self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw), - None => None, - }; + let to_circle = self.dot_guidecircle(around, width + 5.0, conditions); + let from_cw = self.mesh.cw(Index::Dot(from)); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); - if maybe_bend.is_some() { - self.stretch_head_bend(from, tangent_points.0); - } + self.extend_head(from, tangent_points.0); + self.route_seg_bend(from, Index::Dot(around), tangent_points.1, cw, width) + } - self.route_seg_bend(from, around, tangent_points.1, cw, width) + pub fn route_around_bend(&mut self, from: DotIndex, around: BendIndex, cw: bool, width: f64) -> DotIndex { + let from_circle = self.head_guidecircle(from, width); + + let conditions = Conditions { + lower_net: None, + higher_net: None, + layer: None, + zone: None, + }; + + let to_circle = self.bend_guidecircle(around, width, conditions); + + let from_cw = self.mesh.cw(Index::Dot(from)); + let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); + + self.extend_head(from, tangent_points.0); + self.route_seg_bend(from, Index::Bend(around), tangent_points.1, cw, width) } pub fn route_to(&mut self, from: DotIndex, to: DotIndex, width: f64) -> DotIndex { @@ -72,29 +82,27 @@ impl Layout { r: 0.0, }; - let maybe_bend = self.mesh.bend(from); - let from_cw = match maybe_bend { - Some(bend) => Some(self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw), - None => None, - }; - + let from_cw = self.mesh.cw(Index::Dot(from)); let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, None); - if maybe_bend.is_some() { - self.stretch_head_bend(from, tangent_points.0); - } - + self.extend_head(from, tangent_points.0); self.add_seg(from, to, width); to } - fn route_seg_bend(&mut self, from: DotIndex, around: DotIndex, to: Point, cw: bool, width: f64) -> DotIndex { + fn route_seg_bend(&mut self, from: DotIndex, around: Index, to: Point, cw: bool, width: f64) -> DotIndex { let bend_from = self.route_seg(from, to, width); let bend_to = self.add_dot(*self.mesh.primitive(Index::Dot(bend_from)).weight.as_dot().unwrap()); let from_primitive = self.mesh.primitive(Index::Dot(from)); let net = from_primitive.weight.as_dot().unwrap().net; - let bend = self.mesh.add_bend(bend_from, bend_to, BendWeight {net, around, cw}); + let mut layer = around; + while let Index::Bend(..) = layer { + layer = self.mesh.weight(layer).as_bend().unwrap().around; + } + let center = *layer.as_dot().unwrap(); + + let bend = self.mesh.add_bend(bend_from, bend_to, BendWeight {net, around, center, cw}); bend_to } @@ -125,8 +133,12 @@ impl Layout { match maybe_bend { Some(bend) => { let head_around = self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().around; - let circle = self.mesh.weight(Index::Dot(head_around)).as_dot().unwrap().circle; - self.circle_shell(circle, width + 5.0, conditions) + + match self.mesh.weight(head_around) { + Weight::Dot(..) => self.dot_guidecircle(*head_around.as_dot().unwrap(), width + 5.0, conditions), + Weight::Bend(..) => self.bend_guidecircle(*head_around.as_bend().unwrap(), width, conditions), + Weight::Seg(..) => unreachable!(), + } }, None => Circle { pos: self.mesh.weight(Index::Dot(head)).as_dot().unwrap().circle.pos, @@ -135,14 +147,42 @@ impl Layout { } } - fn circle_shell(&self, circle: Circle, 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; Circle { pos: circle.pos, r: circle.r + width + self.rules.ruleset(conditions).clearance.min, } } - fn stretch_head_bend(&mut self, dot: DotIndex, to: Point) { + fn bend_guidecircle(&self, bend: BendIndex, width: f64, conditions: Conditions) -> Circle { + let mut layer = Index::Bend(bend); + let mut r = width + self.rules.ruleset(conditions).clearance.min; + + while let Index::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; + Circle { + pos: circle.pos, + r: circle.r - 5.0 + r, + } + } + + fn extend_head(&mut self, from: DotIndex, to: Point) { + if let Some(..) = self.mesh.bend(from) { + self.extend_head_bend(from, to); + } else { + // 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); + } + } + + fn extend_head_bend(&mut self, dot: DotIndex, to: Point) { let bend = self.mesh.bend(dot).unwrap(); let dot_weight = *self.mesh.weight(Index::Dot(dot)).as_dot().unwrap(); let bend_weight = *self.mesh.weight(Index::Bend(bend)).as_bend().unwrap(); @@ -186,4 +226,8 @@ impl Layout { pub fn primitive(&self, index: Index) -> Primitive { return self.mesh.primitive(index); } + + pub fn bend(&self, index: DotIndex) -> Option { + return self.mesh.bend(index); + } } diff --git a/src/main.rs b/src/main.rs index b9f2504..1ea2541 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ fn main() { let mut i = 0; let mut layout = Layout::new(); - let index = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (150.5, 80.5).into(), r: 8.0}}); + /*let index = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (150.5, 80.5).into(), r: 8.0}}); //layout.route_seg(index, Point {x: 400.5, y: 350.5}, 6.0); let index2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (180.5, 150.5).into(), r: 8.0}}); @@ -51,11 +51,37 @@ fn main() { let barrier2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (190.5, 250.5).into(), r: 8.0}}); layout.add_seg(index3, barrier2, 16.0); - let index4 = layout.route_around(index, index2, true, 5.0); - let index5 = layout.route_around(index4, index3, false, 5.0); + let index4 = layout.route_around_dot(index, index2, true, 5.0); + let index5 = layout.route_around_dot(index4, index3, false, 5.0); let index6 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (140.5, 300.5).into(), r: 8.0}}); - let index7 = layout.route_to(index5, index6, 5.0); + let index7 = layout.route_to(index5, index6, 5.0);*/ + + let dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 150.5).into(), r: 8.0}}); + let dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (130.5, 150.5).into(), r: 8.0}}); + let dot3 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (160.5, 150.5).into(), r: 8.0}}); + + let obstacle_dot1 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (220.5, 250.5).into(), r: 8.0}}); + let obstacle_dot2 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (100.5, 250.5).into(), r: 8.0}}); + layout.add_seg(obstacle_dot1, obstacle_dot2, 16.0); + + let dot4 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (200.5, 350.5).into(), r: 8.0}}); + let dot5 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (220.5, 380.5).into(), r: 8.0}}); + let dot6 = layout.add_dot(DotWeight {net: 0, circle: Circle {pos: (290.5, 380.5).into(), r: 8.0}}); + + let index3_1 = layout.route_around_dot(dot3, obstacle_dot1, true, 5.0); + let index3_2 = layout.route_to(index3_1, dot4, 5.0); + + let index2_1 = layout.route_around_dot(dot2, dot3, true, 5.0); + let index2_2 = layout.route_around_bend(index2_1, layout.bend(index3_1).unwrap(), true, 5.0); + let index2_3 = layout.route_to(index2_2, dot5, 5.0); + + let index1_1 = layout.route_around_bend(dot1, layout.bend(index2_1).unwrap(), true, 5.0); + let index1_2 = layout.route_around_bend(index1_1, layout.bend(index2_2).unwrap(), true, 5.0); + let index1_3 = layout.route_to(index1_2, dot6, 5.0); + + // + //layout.route_around_bend(dot1, layout.bend(index2).unwrap(), true, 5.0); 'running: loop { i = (i + 1) % 255; @@ -91,11 +117,12 @@ fn main() { Color::RGB(200, 52, 52)); }, Weight::Bend(bend) => { + let circle = primitive.circle().unwrap(); let dot_neighbor_weights = primitive.dot_neighbor_weights; - let around_circle = primitive.around_weight.unwrap().circle; + //let around_circle = primitive.around_weight.unwrap().circle; - let delta1 = dot_neighbor_weights[0].circle.pos - around_circle.pos; - let delta2 = dot_neighbor_weights[1].circle.pos - around_circle.pos; + let delta1 = dot_neighbor_weights[0].circle.pos - circle.pos; + let delta2 = dot_neighbor_weights[1].circle.pos - circle.pos; let mut angle1 = delta1.y().atan2(delta1.x()); let mut angle2 = delta2.y().atan2(delta2.x()); @@ -106,9 +133,12 @@ fn main() { for d in -3..3 { let _ = canvas.arc( - around_circle.pos.x() as i16, - around_circle.pos.y() as i16, - (primitive.around_weight.unwrap().circle.r + 10.0 + (d as f64)) as i16, + //around_circle.pos.x() as i16, + //around_circle.pos.y() as i16, + circle.pos.x() as i16, + circle.pos.y() as i16, + //(primitive.around_weight.unwrap().circle.r + 10.0 + (d as f64)) as i16, + (circle.r + (d as f64)) as i16, angle1.to_degrees() as i16, angle2.to_degrees() as i16, Color::RGB(200, 52, 52)); diff --git a/src/math.rs b/src/math.rs index 80796a8..e34b9c8 100644 --- a/src/math.rs +++ b/src/math.rs @@ -1,14 +1,14 @@ use std::ops::Sub; use geo::geometry::Point; -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Line { pub a: f64, pub b: f64, pub c: f64, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Circle { pub pos: Point, pub r: f64, diff --git a/src/mesh.rs b/src/mesh.rs index 69e10a0..5e9f20e 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -11,7 +11,7 @@ pub type DotIndex = NodeIndex; pub type SegIndex = EdgeIndex; pub type BendIndex = EdgeIndex; -#[derive(EnumAsInner, Copy, Clone, PartialEq)] +#[derive(Debug, EnumAsInner, Copy, Clone, PartialEq)] pub enum Index { Dot(DotIndex), Seg(SegIndex), @@ -88,7 +88,19 @@ impl Mesh { .map(|index| *self.weight(index).as_dot().unwrap()) .collect(), around_weight: match index { - Index::Bend(bend_index) => Some(*self.weight(Index::Dot((*self.weight(index).as_bend().unwrap()).around)).as_dot().unwrap()), + Index::Bend(bend_index) => { + Some(self.weight((*self.weight(index).as_bend().unwrap()).around)) + }, + _ => None, + }, + center: match index { + Index::Bend(bend_index) => { + let mut layer = index; + while let Index::Bend(..) = layer { + layer = self.weight(layer).as_bend().unwrap().around; + } + Some(self.weight(layer).as_dot().unwrap().circle.pos) + }, _ => None, } } @@ -105,14 +117,43 @@ impl Mesh { } } - pub fn bend(&self, index: NodeIndex) -> Option { - let edges: Vec> = self.graph.edges(index).map(|r| r.id()).collect(); + pub fn cw(&self, index: Index) -> Option { + match index { + Index::Dot(node_index) => { + let maybe_bend = self.bend(node_index); + match maybe_bend { + Some(bend) => Some(self.weight(Index::Bend(bend)).as_bend().unwrap().cw), + None => None, + } + } + Index::Seg(edge_index) => None, + Index::Bend(edge_index) => Some(self.weight(index).as_bend().unwrap().cw), + } + } - if edges.len() != 1 { + pub fn bend(&self, index: DotIndex) -> Option { + //let edges: Vec> = self.graph.edges(index).map(|r| r.id()).collect(); + let bends: Vec> = self.graph.edges(index) + .filter_map(|r| match self.weight(Index::Bend(r.id())) { + Weight::Bend(..) => Some(r.id()), + _ => None, + }) + .collect(); + + if bends.len() != 1 { return None; } - return Some(edges[0]); + Some(bends[0]) + + /*if edges.len() == 0 { + return None; + }*/ + + /*if edges[0] + Some(edges[0])*/ + + //None } pub fn weight(&self, index: Index) -> Weight { diff --git a/src/primitive.rs b/src/primitive.rs index 7556108..258ddf1 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -1,12 +1,14 @@ +use geo::{Point, EuclideanDistance}; use rstar::{RTreeObject, AABB}; -use crate::weight::{Weight, DotWeight}; +use crate::{weight::{Weight, DotWeight}, math::Circle}; #[derive(PartialEq)] pub struct Primitive { pub weight: Weight, pub dot_neighbor_weights: Vec, - pub around_weight: Option, + pub around_weight: Option, + pub center: Option, } impl Primitive { @@ -23,16 +25,37 @@ impl Primitive { let points: Vec<[f64; 2]> = self.dot_neighbor_weights.iter() .map(|neighbor| [neighbor.circle.pos.x(), neighbor.circle.pos.y()]) - .collect(); return AABB::<[f64; 2]>::from_points(&points); }, } } - /*pub fn weight(&self) -> Weight { + pub fn circle(&self) -> Option { + match self.weight { + Weight::Dot(dot) => Some(dot.circle), + Weight::Seg(seg) => None, + Weight::Bend(bend) => { + let r = self.dot_neighbor_weights[0].circle.pos.euclidean_distance(&self.center.unwrap()); + Some(Circle { + pos: self.center.unwrap(), + r, + }) + } + } + } + + pub fn width(&self) -> f64 { + match self.weight { + Weight::Dot(dot) => dot.circle.r * 2.0, + Weight::Seg(seg) => seg.width, + Weight::Bend(bend) => self.dot_neighbor_weights[0].circle.r * 2.0, + } + } + + pub fn weight(&self) -> Weight { return self.weight; - }*/ + } } impl RTreeObject for Primitive { diff --git a/src/weight.rs b/src/weight.rs index 22df2b2..ffebc87 100644 --- a/src/weight.rs +++ b/src/weight.rs @@ -1,26 +1,27 @@ use enum_as_inner::EnumAsInner; -use crate::{math::Circle, mesh::DotIndex}; +use crate::{math::Circle, mesh::{Index, DotIndex}}; -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct DotWeight { pub net: i32, pub circle: Circle, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct BendWeight { pub net: i32, - pub around: DotIndex, + pub around: Index, + pub center: DotIndex, pub cw: bool, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct SegWeight { pub net: i32, pub width: f64, } -#[derive(EnumAsInner, Clone, Copy, PartialEq)] +#[derive(Debug, EnumAsInner, Clone, Copy, PartialEq)] pub enum Weight { Dot(DotWeight), Seg(SegWeight),