mirror of https://codeberg.org/topola/topola.git
draw,guide: construct guides from rules
This commit is contained in:
parent
d2ff1826a0
commit
e5ddf47eb3
60
src/draw.rs
60
src/draw.rs
|
|
@ -11,9 +11,11 @@ use crate::{
|
|||
primitive::GetOtherJoint,
|
||||
seg::{LoneLooseSegWeight, SeqLooseSegWeight},
|
||||
},
|
||||
layout::{rules::RulesTrait, Infringement, Layout, LayoutException},
|
||||
layout::{
|
||||
rules::{Conditions, RulesTrait},
|
||||
Infringement, Layout, LayoutException,
|
||||
},
|
||||
math::{Circle, NoTangents},
|
||||
rules::{Conditions, Rules},
|
||||
wraparoundable::WraparoundableIndex,
|
||||
};
|
||||
|
||||
|
|
@ -31,16 +33,17 @@ pub enum DrawException {
|
|||
|
||||
pub struct Draw<'a, R: RulesTrait> {
|
||||
layout: &'a mut Layout<R>,
|
||||
rules: &'a Rules,
|
||||
}
|
||||
|
||||
impl<'a, R: RulesTrait> Draw<'a, R> {
|
||||
pub fn new(layout: &'a mut Layout<R>, rules: &'a Rules) -> Self {
|
||||
Self { layout, rules }
|
||||
pub fn new(layout: &'a mut Layout<R>) -> Self {
|
||||
Self { layout }
|
||||
}
|
||||
|
||||
pub fn start(&mut self, from: LooseDotIndex) -> Head {
|
||||
self.guide(&Default::default()).segbend_head(from).into()
|
||||
self.guide(&Default::default(), &Default::default())
|
||||
.segbend_head(from)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))]
|
||||
|
|
@ -52,7 +55,7 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
|||
width: f64,
|
||||
) -> Result<(), DrawException> {
|
||||
let tangent = self
|
||||
.guide(&Default::default())
|
||||
.guide(&Default::default(), &Default::default())
|
||||
.head_into_dot_segment(&head, into, width)
|
||||
.map_err(Into::<DrawException>::into)?;
|
||||
let head = self
|
||||
|
|
@ -95,13 +98,13 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
|||
head: Head,
|
||||
around: FixedDotIndex,
|
||||
width: f64,
|
||||
offset: f64,
|
||||
) -> Result<SegbendHead, DrawException> {
|
||||
let mut tangents = self.guide(&Default::default()).head_around_dot_segments(
|
||||
&head,
|
||||
around.into(),
|
||||
width,
|
||||
)?;
|
||||
let mut tangents = self
|
||||
.guide(&Default::default(), &Default::default())
|
||||
.head_around_dot_segments(&head, around.into(), width)?;
|
||||
let offset = self
|
||||
.guide(&Default::default(), &Default::default())
|
||||
.head_around_dot_offset(&head, around.into(), width);
|
||||
let mut dirs = [true, false];
|
||||
|
||||
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
|
||||
|
|
@ -118,8 +121,8 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
|||
tangent.start_point(),
|
||||
tangent.end_point(),
|
||||
dirs[i],
|
||||
offset,
|
||||
width,
|
||||
offset,
|
||||
) {
|
||||
Ok(ok) => return Ok(ok),
|
||||
Err(err) => errs.push(err),
|
||||
|
|
@ -140,13 +143,13 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
|||
head: Head,
|
||||
around: BendIndex,
|
||||
width: f64,
|
||||
offset: f64,
|
||||
) -> Result<SegbendHead, DrawException> {
|
||||
let mut tangents = self.guide(&Default::default()).head_around_bend_segments(
|
||||
&head,
|
||||
around.into(),
|
||||
width,
|
||||
)?;
|
||||
let mut tangents = self
|
||||
.guide(&Default::default(), &Default::default())
|
||||
.head_around_bend_segments(&head, around.into(), width)?;
|
||||
let offset = self
|
||||
.guide(&Default::default(), &Default::default())
|
||||
.head_around_bend_offset(&head, around.into(), width);
|
||||
let mut dirs = [true, false];
|
||||
|
||||
if tangents.1.euclidean_length() < tangents.0.euclidean_length() {
|
||||
|
|
@ -163,8 +166,8 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
|||
tangent.start_point(),
|
||||
tangent.end_point(),
|
||||
dirs[i],
|
||||
offset,
|
||||
width,
|
||||
offset,
|
||||
) {
|
||||
Ok(ok) => return Ok(ok),
|
||||
Err(err) => errs.push(err),
|
||||
|
|
@ -191,7 +194,7 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
|||
offset: f64,
|
||||
) -> Result<SegbendHead, LayoutException> {
|
||||
let head = self.extend_head(head, from)?;
|
||||
self.segbend(head, around, to, cw, offset, width)
|
||||
self.segbend(head, around, to, cw, width, offset)
|
||||
}
|
||||
|
||||
#[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))]
|
||||
|
|
@ -253,10 +256,17 @@ impl<'a, R: RulesTrait> Draw<'a, R> {
|
|||
let band = head.band;
|
||||
|
||||
self.layout.remove_segbend(&head.segbend, head.face);
|
||||
Some(self.guide(&Default::default()).head(prev_dot, band))
|
||||
Some(
|
||||
self.guide(&Default::default(), &Default::default())
|
||||
.head(prev_dot, band),
|
||||
)
|
||||
}
|
||||
|
||||
fn guide(&'a self, conditions: &'a Conditions) -> Guide<R> {
|
||||
Guide::new(self.layout, conditions)
|
||||
fn guide(
|
||||
&'a self,
|
||||
ref_conditions: &'a Conditions,
|
||||
guide_conditions: &'a Conditions,
|
||||
) -> Guide<R> {
|
||||
Guide::new(self.layout, ref_conditions, guide_conditions)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@ use crate::{
|
|||
Layout,
|
||||
},
|
||||
math::{self, Circle, NoTangents},
|
||||
rules::{Conditions, Rules},
|
||||
};
|
||||
|
||||
use super::{rules::RulesTrait, segbend::Segbend};
|
||||
use super::{
|
||||
rules::{Conditions, RulesTrait},
|
||||
segbend::Segbend,
|
||||
};
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait HeadTrait {
|
||||
|
|
@ -65,12 +67,21 @@ impl HeadTrait for SegbendHead {
|
|||
|
||||
pub struct Guide<'a, 'b, R: RulesTrait> {
|
||||
layout: &'a Layout<R>,
|
||||
conditions: &'b Conditions,
|
||||
ref_conditions: &'b Conditions,
|
||||
guide_conditions: &'b Conditions,
|
||||
}
|
||||
|
||||
impl<'a, 'b, R: RulesTrait> Guide<'a, 'b, R> {
|
||||
pub fn new(layout: &'a Layout<R>, conditions: &'b Conditions) -> Self {
|
||||
Self { layout, conditions }
|
||||
pub fn new(
|
||||
layout: &'a Layout<R>,
|
||||
ref_conditions: &'b Conditions,
|
||||
guide_conditions: &'b Conditions,
|
||||
) -> Self {
|
||||
Self {
|
||||
layout,
|
||||
ref_conditions,
|
||||
guide_conditions,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn head_into_dot_segment(
|
||||
|
|
@ -118,6 +129,12 @@ impl<'a, 'b, R: RulesTrait> Guide<'a, 'b, R> {
|
|||
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
|
||||
}
|
||||
|
||||
pub fn head_around_dot_offset(&self, head: &Head, around: DotIndex, width: f64) -> f64 {
|
||||
self.layout
|
||||
.rules()
|
||||
.clearance(self.ref_conditions, self.guide_conditions)
|
||||
}
|
||||
|
||||
pub fn head_around_bend_segments(
|
||||
&self,
|
||||
head: &Head,
|
||||
|
|
@ -147,6 +164,12 @@ impl<'a, 'b, R: RulesTrait> Guide<'a, 'b, R> {
|
|||
math::tangent_segment(from_circle, from_cw, to_circle, Some(cw))
|
||||
}
|
||||
|
||||
pub fn head_around_bend_offset(&self, head: &Head, around: BendIndex, width: f64) -> f64 {
|
||||
self.layout
|
||||
.rules()
|
||||
.clearance(self.ref_conditions, self.guide_conditions)
|
||||
}
|
||||
|
||||
pub fn head_cw(&self, head: &Head) -> Option<bool> {
|
||||
if let Head::Segbend(head) = head {
|
||||
Some(self.layout.primitive(head.segbend.bend).weight().cw)
|
||||
|
|
@ -156,13 +179,6 @@ impl<'a, 'b, R: RulesTrait> Guide<'a, 'b, R> {
|
|||
}
|
||||
|
||||
fn head_circle(&self, head: &Head, width: f64) -> Circle {
|
||||
let _conditions = Conditions {
|
||||
lower_net: None,
|
||||
higher_net: None,
|
||||
layer: None,
|
||||
zone: None,
|
||||
};
|
||||
|
||||
match *head {
|
||||
Head::Bare(head) => Circle {
|
||||
pos: head.face().primitive(self.layout).shape().center(), // TODO.
|
||||
|
|
@ -189,7 +205,12 @@ impl<'a, 'b, R: RulesTrait> Guide<'a, 'b, R> {
|
|||
|
||||
Circle {
|
||||
pos: outer_circle.pos,
|
||||
r: outer_circle.r + width,
|
||||
r: outer_circle.r
|
||||
+ width / 2.0
|
||||
+ self
|
||||
.layout
|
||||
.rules()
|
||||
.clearance(self.ref_conditions, self.guide_conditions),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +218,12 @@ impl<'a, 'b, R: RulesTrait> Guide<'a, 'b, R> {
|
|||
let shape = dot.primitive(self.layout).shape();
|
||||
Circle {
|
||||
pos: shape.center(),
|
||||
r: shape.width() / 2.0 + width + 0.0,
|
||||
r: shape.width() / 2.0
|
||||
+ width / 2.0
|
||||
+ self
|
||||
.layout
|
||||
.rules()
|
||||
.clearance(self.ref_conditions, self.guide_conditions),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -413,8 +413,9 @@ impl<R: RulesTrait> Layout<R> {
|
|||
let cw = primitive.weight().cw;
|
||||
let ends = primitive.joints();
|
||||
|
||||
let conditions = Default::default();
|
||||
let guide = Guide::new(self, &conditions);
|
||||
let default1 = Default::default();
|
||||
let default2 = Default::default();
|
||||
let guide = Guide::new(self, &default1, &default2);
|
||||
|
||||
let from_head = guide.rear_head(ends.1);
|
||||
let to_head = guide.rear_head(ends.0);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
#[derive(Debug, Default)]
|
||||
pub struct Conditions {
|
||||
layer: Option<String>,
|
||||
region: Option<String>,
|
||||
netclass: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LayerNetclassConditions {
|
||||
region: Option<String>,
|
||||
}
|
||||
|
||||
pub trait RulesTrait {
|
||||
fn clearance(conditions1: &Conditions, conditions2: &Conditions) -> f64;
|
||||
fn clearance(&self, conditions1: &Conditions, conditions2: &Conditions) -> f64;
|
||||
fn clearance_limit(
|
||||
&self,
|
||||
layer: String,
|
||||
netclass: String,
|
||||
conditions: &LayerNetclassConditions,
|
||||
|
|
|
|||
16
src/main.rs
16
src/main.rs
|
|
@ -16,7 +16,6 @@ mod layout;
|
|||
mod math;
|
||||
mod mesh;
|
||||
mod router;
|
||||
mod rules;
|
||||
mod tracer;
|
||||
mod triangulation;
|
||||
mod wraparoundable;
|
||||
|
|
@ -61,14 +60,15 @@ use crate::router::Router;
|
|||
struct ConstantClearance {}
|
||||
|
||||
impl RulesTrait for ConstantClearance {
|
||||
fn clearance(conditions1: &Conditions, conditions2: &Conditions) -> f64 {
|
||||
3.0
|
||||
fn clearance(&self, _conditions1: &Conditions, _conditions2: &Conditions) -> f64 {
|
||||
10.0
|
||||
}
|
||||
|
||||
fn clearance_limit(
|
||||
layer: String,
|
||||
netclass: String,
|
||||
conditions: &LayerNetclassConditions,
|
||||
&self,
|
||||
_layer: String,
|
||||
_netclass: String,
|
||||
_conditions: &LayerNetclassConditions,
|
||||
) -> f64 {
|
||||
3.0
|
||||
}
|
||||
|
|
@ -507,6 +507,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
let _ = router.route_band(
|
||||
dot_start,
|
||||
dot_end,
|
||||
3.0,
|
||||
//&mut EmptyRouterObserver,
|
||||
&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context),
|
||||
)?;
|
||||
|
|
@ -539,6 +540,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
let band2 = router.route_band(
|
||||
dot_start2,
|
||||
dot_end2,
|
||||
3.0,
|
||||
//&mut EmptyRouterObserver,
|
||||
&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context),
|
||||
)?;
|
||||
|
|
@ -560,6 +562,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
let band3 = router.route_band(
|
||||
dot_start3,
|
||||
dot_end3,
|
||||
3.0,
|
||||
//&mut EmptyRouterObserver,
|
||||
&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context),
|
||||
)?;
|
||||
|
|
@ -667,6 +670,7 @@ fn render_times(
|
|||
.reroute_band(
|
||||
band,
|
||||
point! {x: state.x() as f64, y: state.y() as f64},
|
||||
3.0,
|
||||
&mut DebugRouterObserver::new(
|
||||
event_pump,
|
||||
window,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ use crate::layout::{
|
|||
|
||||
use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
|
||||
|
||||
use crate::rules::Rules;
|
||||
use crate::tracer::{Trace, Tracer};
|
||||
|
||||
#[derive(Error, Debug, Clone, Copy)]
|
||||
|
|
@ -55,7 +54,6 @@ pub trait RouterObserverTrait<R: RulesTrait> {
|
|||
|
||||
pub struct Router<R: RulesTrait> {
|
||||
pub layout: Layout<R>,
|
||||
rules: Rules,
|
||||
}
|
||||
|
||||
struct RouterAstarStrategy<'a, RO: RouterObserverTrait<R>, R: RulesTrait> {
|
||||
|
|
@ -132,7 +130,6 @@ impl<R: RulesTrait> Router<R> {
|
|||
pub fn new(rules: R) -> Self {
|
||||
Router {
|
||||
layout: Layout::new(rules),
|
||||
rules: Rules::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,6 +137,7 @@ impl<R: RulesTrait> Router<R> {
|
|||
&mut self,
|
||||
from: FixedDotIndex,
|
||||
to: FixedDotIndex,
|
||||
width: f64,
|
||||
observer: &mut impl RouterObserverTrait<R>,
|
||||
) -> Result<BandIndex, RoutingError> {
|
||||
// XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look
|
||||
|
|
@ -153,7 +151,7 @@ impl<R: RulesTrait> Router<R> {
|
|||
})?;
|
||||
|
||||
let mut tracer = self.tracer(&mesh);
|
||||
let trace = tracer.start(from, 3.0);
|
||||
let trace = tracer.start(from, width);
|
||||
let band = trace.head.band();
|
||||
|
||||
let (_cost, _path) = astar(
|
||||
|
|
@ -174,16 +172,17 @@ impl<R: RulesTrait> Router<R> {
|
|||
&mut self,
|
||||
band: BandIndex,
|
||||
to: Point,
|
||||
width: f64,
|
||||
observer: &mut impl RouterObserverTrait<R>,
|
||||
) -> Result<BandIndex, RoutingError> {
|
||||
let from_dot = self.layout.band(band).from();
|
||||
let to_dot = self.layout.band(band).to().unwrap();
|
||||
self.layout.remove_band(band);
|
||||
self.layout.move_dot(to_dot.into(), to).unwrap(); // TODO: Remove `.unwrap()`.
|
||||
self.route_band(from_dot, to_dot, observer)
|
||||
self.route_band(from_dot, to_dot, width, observer)
|
||||
}
|
||||
|
||||
pub fn tracer<'a>(&'a mut self, mesh: &'a Mesh) -> Tracer<R> {
|
||||
Tracer::new(&mut self.layout, &self.rules, mesh)
|
||||
Tracer::new(&mut self.layout, mesh)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
89
src/rules.rs
89
src/rules.rs
|
|
@ -1,89 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub struct Conditions {
|
||||
pub lower_net: Option<i64>,
|
||||
pub higher_net: Option<i64>,
|
||||
pub layer: Option<i64>,
|
||||
pub zone: Option<i64>,
|
||||
}
|
||||
|
||||
impl Conditions {
|
||||
pub fn priority(&self) -> i64 {
|
||||
let mut priority = 0;
|
||||
priority += (self.lower_net.is_some() as i64) * 1;
|
||||
priority += (self.higher_net.is_some() as i64) * 2;
|
||||
priority += (self.layer.is_some() as i64) * 4;
|
||||
priority += (self.zone.is_some() as i64) * 8;
|
||||
priority
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Rules {
|
||||
rulesets: [Option<HashMap<Conditions, Ruleset>>; 16],
|
||||
}
|
||||
|
||||
impl Rules {
|
||||
pub fn new() -> Self {
|
||||
let mut this = Self {
|
||||
rulesets: Default::default(),
|
||||
};
|
||||
this.rulesets[0] = Some(HashMap::from([(
|
||||
Conditions {
|
||||
lower_net: None,
|
||||
higher_net: None,
|
||||
layer: None,
|
||||
zone: None,
|
||||
},
|
||||
Ruleset::new(),
|
||||
)]));
|
||||
this
|
||||
}
|
||||
|
||||
pub fn ruleset(&self, conditions: &Conditions) -> &Ruleset {
|
||||
let priority = conditions.priority();
|
||||
|
||||
for index in (1..(priority + 1)).rev() {
|
||||
if let Some(ruleset_hashmap) = &self.rulesets[index as usize] {
|
||||
if let Some(ruleset) = ruleset_hashmap.get(&conditions) {
|
||||
return ruleset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&self.rulesets[0].as_ref().unwrap()[&conditions]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Ruleset {
|
||||
pub length: Rule,
|
||||
pub clearance: Rule,
|
||||
}
|
||||
|
||||
impl Ruleset {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
length: Rule::new(),
|
||||
clearance: Rule::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct Rule {
|
||||
pub min: f64,
|
||||
pub opt: Option<f64>,
|
||||
pub max: f64,
|
||||
}
|
||||
|
||||
impl Rule {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
min: 0.0,
|
||||
opt: None,
|
||||
max: f64::INFINITY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ use crate::{
|
|||
Layout,
|
||||
},
|
||||
mesh::{Mesh, VertexIndex},
|
||||
rules::Rules,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -21,17 +20,12 @@ pub struct Trace {
|
|||
|
||||
pub struct Tracer<'a, R: RulesTrait> {
|
||||
pub layout: &'a mut Layout<R>,
|
||||
pub rules: &'a Rules,
|
||||
pub mesh: &'a Mesh,
|
||||
}
|
||||
|
||||
impl<'a, R: RulesTrait> Tracer<'a, R> {
|
||||
pub fn new(layout: &'a mut Layout<R>, rules: &'a Rules, mesh: &'a Mesh) -> Self {
|
||||
Tracer {
|
||||
layout,
|
||||
rules,
|
||||
mesh,
|
||||
}
|
||||
pub fn new(layout: &'a mut Layout<R>, mesh: &'a Mesh) -> Self {
|
||||
Tracer { layout, mesh }
|
||||
}
|
||||
|
||||
pub fn start(&mut self, from: FixedDotIndex, width: f64) -> Trace {
|
||||
|
|
@ -129,9 +123,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
|||
around: FixedDotIndex,
|
||||
width: f64,
|
||||
) -> Result<SegbendHead, DrawException> {
|
||||
let head = self
|
||||
.draw()
|
||||
.segbend_around_dot(head, around.into(), width, 3.0)?;
|
||||
let head = self.draw().segbend_around_dot(head, around.into(), width)?;
|
||||
Ok(head)
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +135,7 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
|||
) -> Result<SegbendHead, DrawException> {
|
||||
let head = self
|
||||
.draw()
|
||||
.segbend_around_bend(head, around.into(), width, 3.0)?;
|
||||
.segbend_around_bend(head, around.into(), width)?;
|
||||
|
||||
Ok(head)
|
||||
}
|
||||
|
|
@ -160,6 +152,6 @@ impl<'a, R: RulesTrait> Tracer<'a, R> {
|
|||
}
|
||||
|
||||
fn draw(&mut self) -> Draw<R> {
|
||||
Draw::new(&mut self.layout, &self.rules)
|
||||
Draw::new(&mut self.layout)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue