diff --git a/src/autorouter/ratsnest.rs b/src/autorouter/ratsnest.rs index ba3ef1a..2f66f96 100644 --- a/src/autorouter/ratsnest.rs +++ b/src/autorouter/ratsnest.rs @@ -114,7 +114,7 @@ impl Ratsnest { } for zone in layout.layer_zone_nodes(layer) { - if let Some(net) = layout.drawing().compound_weight(zone).maybe_net() { + if let Some(net) = layout.drawing().compound_weight(zone.into()).maybe_net() { if !triangulations.contains_key(&(layer, net)) { triangulations.insert( (layer, net), diff --git a/src/autorouter/selection.rs b/src/autorouter/selection.rs index ff49aef..b76f58d 100644 --- a/src/autorouter/selection.rs +++ b/src/autorouter/selection.rs @@ -5,8 +5,9 @@ use serde::{Deserialize, Serialize}; use crate::{ board::{mesadata::MesadataTrait, Board}, drawing::graph::{GetLayer, MakePrimitive, PrimitiveIndex}, - graph::GenericIndex, - layout::NodeIndex, + geometry::compound::CompoundManagerTrait, + graph::{GenericIndex, GetNodeIndex}, + layout::{zone::ZoneWeight, CompoundWeight, NodeIndex}, }; #[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] @@ -64,7 +65,17 @@ impl Selection { NodeIndex::Primitive(primitive) => { primitive.primitive(board.layout().drawing()).layer() } - NodeIndex::Compound(compound) => board.layout().zone(compound).layer(), + NodeIndex::Compound(compound) => { + if let CompoundWeight::Zone(..) = board.layout().drawing().compound_weight(compound) + { + board + .layout() + .zone(GenericIndex::::new(compound.node_index())) + .layer() + } else { + unreachable!() + } + } }; if let (Some(pinname), Some(layername)) = ( diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index 16f1c3f..b1aa631 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -386,7 +386,7 @@ impl eframe::App for App { for zone in board.layout().layer_zone_nodes(1) { let color = if overlay .selection() - .contains_node(board, GenericNode::Compound(zone)) + .contains_node(board, GenericNode::Compound(zone.into())) { egui::Color32::from_rgb(100, 100, 255) } else { @@ -413,7 +413,7 @@ impl eframe::App for App { for zone in board.layout().layer_zone_nodes(0) { let color = if overlay .selection() - .contains_node(board, GenericNode::Compound(zone)) + .contains_node(board, GenericNode::Compound(zone.into())) { egui::Color32::from_rgb(255, 100, 100) } else { diff --git a/src/bin/topola-egui/overlay.rs b/src/bin/topola-egui/overlay.rs index 633ac21..9a0cee3 100644 --- a/src/bin/topola-egui/overlay.rs +++ b/src/bin/topola-egui/overlay.rs @@ -15,7 +15,11 @@ use topola::{ compound::CompoundManagerTrait, shape::{Shape, ShapeTrait}, }, - layout::{zone::MakePolyShape, Layout, NodeIndex}, + graph::{GenericIndex, GetNodeIndex}, + layout::{ + zone::{MakePolyShape, Zone, ZoneWeight}, + CompoundWeight, Layout, NodeIndex, + }, }; pub struct Overlay { @@ -72,7 +76,17 @@ impl Overlay { NodeIndex::Primitive(primitive) => { primitive.primitive(board.layout().drawing()).shape().into() } - NodeIndex::Compound(compound) => board.layout().zone(compound).shape().into(), + NodeIndex::Compound(compound) => { + match board.layout().drawing().compound_weight(compound) { + CompoundWeight::Zone(zone) => Zone::new( + GenericIndex::::new(compound.node_index()), + board.layout(), + ) + .shape() + .into(), + CompoundWeight::Via(via) => unreachable!(), + } + } }; if shape.contains_point(p) { diff --git a/src/board/board.rs b/src/board/board.rs index 8570a85..d4d88d6 100644 --- a/src/board/board.rs +++ b/src/board/board.rs @@ -58,7 +58,7 @@ impl Board { ) -> Result { let dot = self.layout.add_zone_fixed_dot(weight, zone)?; - if let Some(pin) = self.node_pinname(GenericNode::Compound(zone)) { + if let Some(pin) = self.node_pinname(GenericNode::Compound(zone.into())) { self.node_to_pinname .insert(GenericNode::Primitive(dot.into()), pin.to_string()); } @@ -92,7 +92,7 @@ impl Board { ) -> Result { let seg = self.layout.add_zone_fixed_seg(from, to, weight, zone)?; - if let Some(pin) = self.node_pinname(GenericNode::Compound(zone)) { + if let Some(pin) = self.node_pinname(GenericNode::Compound(zone.into())) { self.node_to_pinname .insert(GenericNode::Primitive(seg.into()), pin.to_string()); } diff --git a/src/layout/layout.rs b/src/layout/layout.rs index 3e6b840..ad5f42d 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use enum_dispatch::enum_dispatch; use geo::Point; use petgraph::stable_graph::StableDiGraph; use rstar::AABB; @@ -26,19 +27,29 @@ use crate::{ GetWidth, SegWeightTrait, }, graph::{GenericIndex, GetNodeIndex}, - layout::zone::{GetMaybeApex, MakePolyShape, PourZoneIndex, SolidZoneIndex, Zone, ZoneWeight}, + layout::{ + via::ViaWeight, + zone::{GetMaybeApex, MakePolyShape, Zone, ZoneWeight}, + }, math::Circle, }; -pub type NodeIndex = GenericNode>; +#[derive(Debug, Clone, Copy)] +#[enum_dispatch(GetMaybeNet)] +pub enum CompoundWeight { + Zone(ZoneWeight), + Via(ViaWeight), +} + +pub type NodeIndex = GenericNode>; #[derive(Debug)] pub struct Layout { - drawing: Drawing, + drawing: Drawing, } impl Layout { - pub fn new(drawing: Drawing) -> Self { + pub fn new(drawing: Drawing) -> Self { Self { drawing } } @@ -63,6 +74,21 @@ impl Layout { .insert_segbend(from, around, dot_weight, seg_weight, bend_weight, cw) } + pub fn add_via(&mut self, weight: ViaWeight) -> Result, Infringement> { + let compound = self.drawing.add_compound(weight.into()); + + for layer in weight.from_layer..weight.to_layer { + let dot = self.drawing.add_fixed_dot(FixedDotWeight { + circle: weight.circle, + layer, + maybe_net: weight.maybe_net, + })?; + self.drawing.add_to_compound(dot, compound); + } + + Ok(GenericIndex::::new(compound.node_index())) + } + pub fn add_fixed_dot(&mut self, weight: FixedDotWeight) -> Result { self.drawing.add_fixed_dot(weight) } @@ -75,7 +101,7 @@ impl Layout { let maybe_dot = self.drawing.add_fixed_dot(weight); if let Ok(dot) = maybe_dot { - self.drawing.add_to_compound(dot, zone); + self.drawing.add_to_compound(dot, zone.into()); } maybe_dot @@ -100,7 +126,7 @@ impl Layout { let maybe_seg = self.add_fixed_seg(from, to, weight); if let Ok(seg) = maybe_seg { - self.drawing.add_to_compound(seg, zone); + self.drawing.add_to_compound(seg, zone.into()); } maybe_seg @@ -129,13 +155,17 @@ impl Layout { } pub fn add_zone(&mut self, weight: ZoneWeight) -> GenericIndex { - self.drawing.add_compound(weight) + GenericIndex::::new( + self.drawing + .add_compound(CompoundWeight::Zone(weight)) + .node_index(), + ) } pub fn zones( &self, node: GenericIndex, - ) -> impl Iterator> + '_ { + ) -> impl Iterator> + '_ { self.drawing.compounds(node) } @@ -171,11 +201,13 @@ impl Layout { pub fn zone_nodes(&self) -> impl Iterator> + '_ { self.drawing.rtree().iter().filter_map(|wrapper| { - if let NodeIndex::Compound(zone) = wrapper.data { - Some(zone) - } else { - None + if let NodeIndex::Compound(compound) = wrapper.data { + if let CompoundWeight::Zone(..) = self.drawing.compound_weight(compound) { + return Some(GenericIndex::::new(compound.node_index())); + } } + + None }) } @@ -190,11 +222,13 @@ impl Layout { [f64::INFINITY, f64::INFINITY, layer as f64], )) .filter_map(|wrapper| { - if let NodeIndex::Compound(zone) = wrapper.data { - Some(zone) - } else { - None + if let NodeIndex::Compound(compound) = wrapper.data { + if let CompoundWeight::Zone(..) = self.drawing.compound_weight(compound) { + return Some(GenericIndex::::new(compound.node_index())); + } } + + None }) } @@ -207,7 +241,7 @@ impl Layout { .compound_members(GenericIndex::new(zone.node_index())) } - pub fn drawing(&self) -> &Drawing { + pub fn drawing(&self) -> &Drawing { &self.drawing } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 1e5fef1..a0ea8e6 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,4 +1,5 @@ mod layout; +pub mod via; pub mod zone; pub use layout::*; diff --git a/src/layout/via.rs b/src/layout/via.rs new file mode 100644 index 0000000..3dcb7a8 --- /dev/null +++ b/src/layout/via.rs @@ -0,0 +1,48 @@ +use crate::{ + drawing::{graph::GetMaybeNet, rules::RulesTrait}, + geometry::compound::CompoundManagerTrait, + graph::{GenericIndex, GetNodeIndex}, + layout::{CompoundWeight, Layout}, + math::Circle, +}; + +#[derive(Debug)] +pub struct Via<'a, R: RulesTrait> { + pub index: GenericIndex, + layout: &'a Layout, +} + +impl<'a, R: RulesTrait> Via<'a, R> { + pub fn new(index: GenericIndex, layout: &'a Layout) -> Self { + Self { index, layout } + } +} + +impl<'a, R: RulesTrait> GetMaybeNet for Via<'a, R> { + fn maybe_net(&self) -> Option { + self.layout + .drawing() + .compound_weight(self.index.into()) + .maybe_net() + } +} + +#[derive(Debug, Clone, Copy)] +pub struct ViaWeight { + pub from_layer: u64, + pub to_layer: u64, + pub circle: Circle, + pub maybe_net: Option, +} + +impl GetMaybeNet for ViaWeight { + fn maybe_net(&self) -> Option { + self.maybe_net + } +} + +impl From> for GenericIndex { + fn from(via: GenericIndex) -> Self { + GenericIndex::::new(via.node_index()) + } +} diff --git a/src/layout/zone.rs b/src/layout/zone.rs index a270768..75d87e0 100644 --- a/src/layout/zone.rs +++ b/src/layout/zone.rs @@ -14,7 +14,7 @@ use crate::{ }, geometry::{compound::CompoundManagerTrait, poly::PolyShape, GetPos}, graph::{GenericIndex, GetNodeIndex}, - layout::Layout, + layout::{CompoundWeight, Layout}, }; #[enum_dispatch] @@ -52,7 +52,13 @@ impl<'a, R: RulesTrait> Zone<'a, R> { impl<'a, R: RulesTrait> GetLayer for Zone<'a, R> { fn layer(&self) -> u64 { - self.layout.drawing().compound_weight(self.index).layer() + if let CompoundWeight::Zone(weight) = + self.layout.drawing().compound_weight(self.index.into()) + { + weight.layer() + } else { + unreachable!(); + } } } @@ -60,7 +66,7 @@ impl<'a, R: RulesTrait> GetMaybeNet for Zone<'a, R> { fn maybe_net(&self) -> Option { self.layout .drawing() - .compound_weight(self.index) + .compound_weight(self.index.into()) .maybe_net() } } @@ -73,7 +79,7 @@ impl<'a, R: RulesTrait> MakePolyShape for Zone<'a, R> { self.layout .drawing() .geometry() - .compound_members(self.index) + .compound_members(self.index.into()) .filter_map(|primitive_node| { let PrimitiveIndex::FixedDot(dot) = primitive_node else { return None; @@ -104,7 +110,7 @@ impl<'a, R: RulesTrait> GetMaybeApex for Zone<'a, R> { self.layout .drawing() .geometry() - .compound_members(self.index) + .compound_members(self.index.into()) .find_map(|primitive_node| { if let PrimitiveIndex::FixedDot(dot) = primitive_node { if self.is_apex(dot) { @@ -124,25 +130,35 @@ pub enum ZoneWeight { Pour(PourZoneWeight), } +impl From> for GenericIndex { + fn from(zone: GenericIndex) -> Self { + GenericIndex::::new(zone.node_index()) + } +} + #[derive(Debug, Clone, Copy, PartialEq)] pub struct SolidZoneWeight { pub layer: u64, pub maybe_net: Option, } -impl<'a> GetLayer for SolidZoneWeight { +impl GetLayer for SolidZoneWeight { fn layer(&self) -> u64 { self.layer } } -impl<'a> GetMaybeNet for SolidZoneWeight { +impl GetMaybeNet for SolidZoneWeight { fn maybe_net(&self) -> Option { self.maybe_net } } -pub type SolidZoneIndex = GenericIndex; +impl From> for GenericIndex { + fn from(zone: GenericIndex) -> Self { + GenericIndex::::new(zone.node_index()) + } +} #[derive(Debug, Clone, Copy, PartialEq)] pub struct PourZoneWeight { @@ -162,4 +178,8 @@ impl<'a> GetMaybeNet for PourZoneWeight { } } -pub type PourZoneIndex = GenericIndex; +impl From> for GenericIndex { + fn from(zone: GenericIndex) -> Self { + GenericIndex::::new(zone.node_index()) + } +}