Implement routing *into* dots

This commit is contained in:
Mikolaj Wielgus 2023-07-11 07:59:18 +02:00
parent cf6460a3db
commit dfcfc99413
3 changed files with 128 additions and 71 deletions

View File

@ -30,7 +30,8 @@ impl Layout {
} }
pub fn route_around(&mut self, from: DotIndex, around: DotIndex, cw: bool, width: f64) -> DotIndex { 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 { let conditions = Conditions {
lower_net: None, lower_net: None,
@ -39,56 +40,109 @@ impl Layout {
zone: None, zone: None,
}; };
let from_circle = match maybe_bend { let to_circle = self.circle_shell(around_circle, width + 5.0, conditions);
Some(bend) => {
let from_around = self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().around; let maybe_bend = self.mesh.bend(from);
let circle = self.mesh.weight(Index::Dot(from_around)).as_dot().unwrap().circle; let from_cw = match maybe_bend {
self.guidecircle(circle, width + 5.0, conditions) Some(bend) => Some(self.mesh.weight(Index::Bend(bend)).as_bend().unwrap().cw),
} None => None,
None => Circle {
pos: self.mesh.weight(Index::Dot(from)).as_dot().unwrap().circle.pos,
r: 0.0,
},
}; };
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 tangent_points = math::tangent_point_pair(from_circle, from_cw, to_circle, Some(cw));
let tg_pt_pairs = math::tangent_points(from_circle, to_circle);
for tg_pt_pair in tg_pt_pairs { if maybe_bend.is_some() {
if let Some(bend) = maybe_bend { self.stretch_head_bend(from, tangent_points.0);
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);
} }
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 { 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,
} }
} }
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 bend = self.mesh.bend(dot).unwrap();
let dot_weight = *self.mesh.weight(Index::Dot(dot)).as_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(); 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); 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 { pub fn add_dot(&mut self, weight: DotWeight) -> DotIndex {
self.mesh.add_dot(weight) self.mesh.add_dot(weight)
} }

View File

@ -55,7 +55,7 @@ fn main() {
let index5 = layout.route_around(index4, index3, false, 5.0); 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 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 { 'running: loop {
i = (i + 1) % 255; i = (i + 1) % 255;
@ -113,6 +113,7 @@ fn main() {
angle2.to_degrees() as i16, angle2.to_degrees() as i16,
Color::RGB(200, 52, 52)); Color::RGB(200, 52, 52));
} }
}, },
} }
} }

View File

@ -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 epsilon = 1e-9;
let dr = r2 - r1; let dr = r2 - r1;
let norm = center.x() * center.x() + center.y() * center.y(); 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] = [ 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() { for tg in tgs.iter_mut() {
@ -64,8 +64,8 @@ fn cast_point_to_line(pt: Point, line: Line) -> Point {
).into(); ).into();
} }
pub fn tangent_points(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] { pub fn tangent_point_pairs(circle1: Circle, circle2: Circle) -> [(Point, Point); 4] {
let tgs = tangents(circle1, circle2); let tgs = _tangents(circle1, circle2);
[ [
(cast_point_to_line(circle1.pos, tgs[0]), cast_point_to_line(circle2.pos, tgs[0])), (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<bool>, circle2: Circle, cw2: Option<bool>) -> (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 { pub fn cross_product(start: Point, stop: Point, reference: Point) -> f64 {
let dx1 = stop.x() - start.x(); let dx1 = stop.x() - start.x();
let dy1 = stop.y() - start.y(); let dy1 = stop.y() - start.y();