diff --git a/src/layout.rs b/src/layout.rs index 0f7abf9..cc6f1f2 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -30,7 +30,8 @@ impl Layout { } pub fn route_around(&mut self, from: DotIndex, around: DotIndex, cw: bool, width: f64) -> DotIndex { - let maybe_bend = self.mesh.bend(from); + 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, @@ -39,56 +40,109 @@ impl Layout { zone: None, }; - let from_circle = match maybe_bend { - Some(bend) => { - let from_around = self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().around; - let circle = self.mesh.weight(Index::Dot(from_around)).as_dot().unwrap().circle; - self.guidecircle(circle, width + 5.0, conditions) - } - None => Circle { - pos: self.mesh.weight(Index::Dot(from)).as_dot().unwrap().circle.pos, - r: 0.0, - }, + 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 around_circle = self.mesh.weight(Index::Dot(around)).as_dot().unwrap().circle; - let to_circle = self.guidecircle(around_circle, width + 5.0, conditions); - let tg_pt_pairs = math::tangent_points(from_circle, to_circle); + let tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw)); - for tg_pt_pair in tg_pt_pairs { - if let Some(bend) = maybe_bend { - let start_cross = math::cross_product(tg_pt_pair.0, tg_pt_pair.1, from_circle.pos); - - if (self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw && start_cross <= 0.0) - || (!self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw && start_cross >= 0.0) { - continue; - } - } - - let stop_cross = math::cross_product(tg_pt_pair.0, tg_pt_pair.1, to_circle.pos); - - if (cw && stop_cross <= 0.0) || (!cw && stop_cross >= 0.0) { - continue; - } - - if maybe_bend.is_some() { - self.stretch_dangling_bend(from, tg_pt_pair.0); - } - - return self.route_seg_bend(from, around, tg_pt_pair.1, cw, width); + if maybe_bend.is_some() { + self.stretch_head_bend(from, tangent_points.0); } - unreachable!(); + self.route_seg_bend(from, around, tangent_points.1, cw, width) } - fn guidecircle(&self, circle: Circle, width: f64, conditions: Conditions) -> Circle { + pub fn route_to(&mut self, from: DotIndex, to: DotIndex, 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 = Circle { + pos: self.mesh.weight(Index::Dot(to)).as_dot().unwrap().circle.pos, + 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 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.add_seg(from, to, width); + to + } + + fn route_seg_bend(&mut self, from: DotIndex, around: DotIndex, 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}); + bend_to + } + + fn route_seg(&mut self, from: DotIndex, to: Point, width: f64) -> DotIndex { + let from_primitive = self.mesh.primitive(Index::Dot(from)); + let net = from_primitive.weight.as_dot().unwrap().net; + + assert!(width <= from_primitive.weight.as_dot().unwrap().circle.r * 2.0); + + let to_index = self.mesh.add_dot(DotWeight { + net, + circle: Circle {pos: to, r: width / 2.0}, + }); + self.mesh.add_seg(from, to_index, SegWeight {net, width}); + to_index + } + + fn head_guidecircle(&self, head: DotIndex, width: f64) -> Circle { + let maybe_bend = self.mesh.bend(head); + + let conditions = Conditions { + lower_net: None, + higher_net: None, + layer: None, + zone: None, + }; + + 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) + }, + None => Circle { + pos: self.mesh.weight(Index::Dot(head)).as_dot().unwrap().circle.pos, + r: 0.0, + }, + } + } + + fn circle_shell(&self, circle: Circle, width: f64, conditions: Conditions) -> Circle { Circle { pos: circle.pos, r: circle.r + width + self.rules.ruleset(conditions).clearance.min, } } - fn stretch_dangling_bend(&mut self, dot: DotIndex, to: Point) { + fn stretch_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(); @@ -111,30 +165,6 @@ impl Layout { self.mesh.add_bend(*fixed_dot.as_dot().unwrap(), new_dot, bend_weight); } - fn route_seg_bend(&mut self, from: DotIndex, around: DotIndex, 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}); - bend_to - } - - pub fn route_seg(&mut self, from: DotIndex, to: Point, width: f64) -> DotIndex { - let from_primitive = self.mesh.primitive(Index::Dot(from)); - let net = from_primitive.weight.as_dot().unwrap().net; - - assert!(width <= from_primitive.weight.as_dot().unwrap().circle.r * 2.0); - - let to_index = self.mesh.add_dot(DotWeight { - net, - circle: Circle {pos: to, r: width / 2.0}, - }); - self.mesh.add_seg(from, to_index, SegWeight {net, width}); - to_index - } - pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex { self.mesh.add_dot(weight) } diff --git a/src/main.rs b/src/main.rs index d0c8356..b9f2504 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,7 +55,7 @@ fn main() { let index5 = layout.route_around(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_around(index5, index6, false, 5.0); + let index7 = layout.route_to(index5, index6, 5.0); 'running: loop { i = (i + 1) % 255; @@ -113,6 +113,7 @@ fn main() { angle2.to_degrees() as i16, Color::RGB(200, 52, 52)); } + }, } } diff --git a/src/math.rs b/src/math.rs index 0c4fdb5..80796a8 100644 --- a/src/math.rs +++ b/src/math.rs @@ -23,7 +23,7 @@ impl Sub for Circle { } } -fn tangent(center: Point, r1: f64, r2: f64) -> Line { +fn _tangent(center: Point, r1: f64, r2: f64) -> Line { let epsilon = 1e-9; let dr = r2 - r1; let norm = center.x() * center.x() + center.y() * center.y(); @@ -42,12 +42,12 @@ fn tangent(center: Point, r1: f64, r2: f64) -> Line { } } -pub fn tangents(circle1: Circle, circle2: Circle) -> [Line; 4] { +fn _tangents(circle1: Circle, circle2: Circle) -> [Line; 4] { let mut tgs: [Line; 4] = [ - tangent((circle2 - circle1).pos, -circle1.r, -circle2.r), - tangent((circle2 - circle1).pos, -circle1.r, circle2.r), - tangent((circle2 - circle1).pos, circle1.r, -circle2.r), - tangent((circle2 - circle1).pos, circle1.r, circle2.r), + _tangent((circle2 - circle1).pos, -circle1.r, -circle2.r), + _tangent((circle2 - circle1).pos, -circle1.r, circle2.r), + _tangent((circle2 - circle1).pos, circle1.r, -circle2.r), + _tangent((circle2 - circle1).pos, circle1.r, circle2.r), ]; for tg in tgs.iter_mut() { @@ -64,8 +64,8 @@ fn cast_point_to_line(pt: Point, line: Line) -> Point { ).into(); } -pub fn tangent_points(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] { - let tgs = tangents(circle1, circle2); +pub fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] { + let tgs = _tangents(circle1, circle2); [ (cast_point_to_line(circle1.pos, tgs[0]), cast_point_to_line(circle2.pos, tgs[0])), @@ -75,6 +75,32 @@ pub fn tangent_points(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] { ] } +pub fn tangent_point_pair(circle1: Circle, cw1: Option, circle2: Circle, cw2: Option) -> (Point, Point) { + let tangent_point_pairs = tangent_point_pairs(circle1, circle2); + + for tangent_point_pair in tangent_point_pairs { + if let Some(cw1) = cw1 { + let cross1 = cross_product(tangent_point_pair.0, tangent_point_pair.1, circle1.pos); + + if (cw1 && cross1 <= 0.0) || (!cw1 && cross1 >= 0.0) { + continue; + } + } + + if let Some(cw2) = cw2 { + let cross2 = cross_product(tangent_point_pair.0, tangent_point_pair.1, circle2.pos); + + if (cw2 && cross2 <= 0.0) || (!cw2 && cross2 >= 0.0) { + continue; + } + } + + return tangent_point_pair; + } + + unreachable!(); +} + pub fn cross_product(start: Point, stop: Point, reference: Point) -> f64 { let dx1 = stop.x() - start.x(); let dy1 = stop.y() - start.y();