mirror of https://codeberg.org/topola/topola.git
fix(board): make Poly' apex generation non-lazy
- insert polygon parts before polygon compound
This commit is contained in:
parent
3a2c9deff0
commit
122ff0122f
|
|
@ -77,7 +77,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
|||
.node_index()
|
||||
{
|
||||
RatvertexIndex::FixedDot(dot) => dot,
|
||||
RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
|
||||
RatvertexIndex::Poly(poly) => self.board.layout().poly(poly).apex(),
|
||||
};
|
||||
|
||||
PointrouteExecutionStepper::new(self, origin_dot, point, options)
|
||||
|
|
@ -195,7 +195,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
|||
.node_index()
|
||||
{
|
||||
RatvertexIndex::FixedDot(dot) => dot,
|
||||
RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
|
||||
RatvertexIndex::Poly(poly) => self.board.layout().poly(poly).apex(),
|
||||
};
|
||||
|
||||
let target_dot = match self
|
||||
|
|
@ -206,7 +206,7 @@ impl<M: AccessMesadata> Autorouter<M> {
|
|||
.node_index()
|
||||
{
|
||||
RatvertexIndex::FixedDot(dot) => dot,
|
||||
RatvertexIndex::Poly(poly) => self.board.poly_apex(&mut LayoutEdit::new(), poly),
|
||||
RatvertexIndex::Poly(poly) => self.board.layout().poly(poly).apex(),
|
||||
};
|
||||
|
||||
(source_dot, target_dot)
|
||||
|
|
|
|||
|
|
@ -16,18 +16,14 @@ use crate::{
|
|||
drawing::{
|
||||
band::BandUid,
|
||||
bend::{BendIndex, BendWeight},
|
||||
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, GeneralDotWeight},
|
||||
graph::{GetMaybeNet, PrimitiveIndex},
|
||||
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight},
|
||||
graph::PrimitiveIndex,
|
||||
seg::{FixedSegIndex, FixedSegWeight, SegIndex, SegWeight},
|
||||
Collect,
|
||||
},
|
||||
geometry::{edit::ApplyGeometryEdit, shape::AccessShape, GenericNode, GetLayer},
|
||||
geometry::{edit::ApplyGeometryEdit, GenericNode, GetLayer},
|
||||
graph::GenericIndex,
|
||||
layout::{
|
||||
poly::{GetMaybeApex, MakePolygon, PolyWeight},
|
||||
CompoundWeight, Layout, LayoutEdit, NodeIndex,
|
||||
},
|
||||
math::Circle,
|
||||
layout::{poly::PolyWeight, CompoundWeight, Layout, LayoutEdit, NodeIndex},
|
||||
};
|
||||
|
||||
/// Represents a band between two pins.
|
||||
|
|
@ -122,27 +118,6 @@ impl<M: AccessMesadata> Board<M> {
|
|||
dot
|
||||
}
|
||||
|
||||
/// Adds a fixed segment between two dots with an optional pin name.
|
||||
///
|
||||
/// Adds the segment to the layout and maps the pin name to the created segment if provided.
|
||||
pub fn add_poly_fixed_dot_infringably(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
weight: FixedDotWeight,
|
||||
poly: GenericIndex<PolyWeight>,
|
||||
) -> FixedDotIndex {
|
||||
let dot = self
|
||||
.layout
|
||||
.add_poly_fixed_dot_infringably(recorder, weight, poly);
|
||||
|
||||
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
|
||||
self.node_to_pinname
|
||||
.insert(GenericNode::Primitive(dot.into()), pin.to_string());
|
||||
}
|
||||
|
||||
dot
|
||||
}
|
||||
|
||||
/// Adds a fixed segment associated with a polygon in the layout.
|
||||
///
|
||||
/// Adds the segment to the layout and updates the internal mapping if necessary.
|
||||
|
|
@ -166,41 +141,27 @@ impl<M: AccessMesadata> Board<M> {
|
|||
seg
|
||||
}
|
||||
|
||||
/// Adds a fixed segment associated with a polygon in the layout.
|
||||
///
|
||||
/// Adds the segment to the layout and updates the internal mapping if necessary.
|
||||
pub fn add_poly_fixed_seg_infringably(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
from: FixedDotIndex,
|
||||
to: FixedDotIndex,
|
||||
weight: FixedSegWeight,
|
||||
poly: GenericIndex<PolyWeight>,
|
||||
) -> FixedSegIndex {
|
||||
let seg = self
|
||||
.layout
|
||||
.add_poly_fixed_seg_infringably(recorder, from, to, weight, poly);
|
||||
|
||||
if let Some(pin) = self.node_pinname(&GenericNode::Compound(poly.into())) {
|
||||
self.node_to_pinname
|
||||
.insert(GenericNode::Primitive(seg.into()), pin.to_string());
|
||||
}
|
||||
|
||||
seg
|
||||
}
|
||||
|
||||
/// Adds a new polygon to the layout with an optional pin name.
|
||||
///
|
||||
/// Inserts the polygon into the layout and, if a pin name is provided, maps it to the created polygon's node.
|
||||
pub fn add_poly(
|
||||
pub fn add_poly_with_nodes(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
weight: PolyWeight,
|
||||
maybe_pin: Option<String>,
|
||||
nodes: &[PrimitiveIndex],
|
||||
) -> GenericIndex<PolyWeight> {
|
||||
let poly = self.layout.add_poly(recorder, weight);
|
||||
let (poly, apex) = self.layout.add_poly_with_nodes(recorder, weight, nodes);
|
||||
|
||||
if let Some(pin) = maybe_pin {
|
||||
for i in nodes {
|
||||
self.node_to_pinname
|
||||
.insert(GenericNode::Primitive(*i), pin.clone());
|
||||
}
|
||||
|
||||
self.node_to_pinname
|
||||
.insert(GenericNode::Primitive(apex.into()), pin.clone());
|
||||
|
||||
self.node_to_pinname
|
||||
.insert(GenericNode::Compound(poly.into()), pin);
|
||||
}
|
||||
|
|
@ -208,33 +169,6 @@ impl<M: AccessMesadata> Board<M> {
|
|||
poly
|
||||
}
|
||||
|
||||
/// Retrieves or creates the apex (center point) of a polygon in the layout.
|
||||
///
|
||||
/// If the polygon already has an apex, returns it. Otherwise, creates and returns a new fixed dot as the apex.
|
||||
pub fn poly_apex(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
poly: GenericIndex<PolyWeight>,
|
||||
) -> FixedDotIndex {
|
||||
let resolved_poly = self.layout.poly(poly);
|
||||
if let Some(apex) = resolved_poly.maybe_apex() {
|
||||
apex
|
||||
} else {
|
||||
self.add_poly_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
pos: resolved_poly.shape().center(),
|
||||
r: 100.0,
|
||||
},
|
||||
layer: resolved_poly.layer(),
|
||||
maybe_net: resolved_poly.maybe_net(),
|
||||
}),
|
||||
poly,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the pin name associated with a given node.
|
||||
pub fn node_pinname(&self, node: &NodeIndex) -> Option<&String> {
|
||||
self.node_to_pinname.get(node)
|
||||
|
|
|
|||
|
|
@ -32,14 +32,14 @@ use crate::{
|
|||
edit::ApplyGeometryEdit,
|
||||
primitive::{AccessPrimitiveShape, PrimitiveShape, SegShape},
|
||||
shape::{AccessShape, Shape},
|
||||
GenericNode, GetSetPos,
|
||||
GenericNode, GetLayer, GetSetPos,
|
||||
},
|
||||
graph::{GenericIndex, GetPetgraphIndex},
|
||||
layout::{
|
||||
poly::{MakePolygon, Poly, PolyWeight},
|
||||
poly::{is_apex, MakePolygon, Poly, PolyWeight},
|
||||
via::{Via, ViaWeight},
|
||||
},
|
||||
math::{LineIntersection, NormalLine},
|
||||
math::{Circle, LineIntersection, NormalLine},
|
||||
};
|
||||
|
||||
/// Represents a weight for various compounds
|
||||
|
|
@ -271,6 +271,48 @@ impl<R: AccessRules> Layout<R> {
|
|||
)
|
||||
}
|
||||
|
||||
/// insert a polygon based upon the border nodes, and computes + returns the
|
||||
/// associated apex
|
||||
pub fn add_poly_with_nodes(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
weight: PolyWeight,
|
||||
nodes: &[PrimitiveIndex],
|
||||
) -> (GenericIndex<PolyWeight>, FixedDotIndex) {
|
||||
let layer = weight.layer();
|
||||
let maybe_net = weight.maybe_net();
|
||||
let poly = self.add_poly(recorder, weight);
|
||||
let poly_compound = poly.into();
|
||||
|
||||
for i in nodes {
|
||||
self.drawing.add_to_compound(
|
||||
recorder,
|
||||
GenericIndex::<()>::new(i.petgraph_index()),
|
||||
poly_compound,
|
||||
);
|
||||
}
|
||||
|
||||
let shape = self.poly(poly).shape();
|
||||
let apex = self.add_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
pos: shape.center(),
|
||||
r: 100.0,
|
||||
},
|
||||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
);
|
||||
|
||||
// maybe this should be a different edge kind
|
||||
self.drawing.add_to_compound(recorder, apex, poly_compound);
|
||||
|
||||
assert!(is_apex(&self.drawing, apex));
|
||||
|
||||
(poly, apex)
|
||||
}
|
||||
|
||||
pub fn remove_band(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
|
|
|
|||
|
|
@ -27,30 +27,47 @@ pub trait MakePolygon {
|
|||
fn shape(&self) -> Polygon;
|
||||
}
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait GetMaybeApex {
|
||||
fn maybe_apex(&self) -> Option<FixedDotIndex>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Poly<'a, R> {
|
||||
pub index: GenericIndex<PolyWeight>,
|
||||
drawing: &'a Drawing<CompoundWeight, R>,
|
||||
}
|
||||
|
||||
pub(super) fn is_apex<'a, R: AccessRules>(
|
||||
drawing: &'a Drawing<CompoundWeight, R>,
|
||||
dot: FixedDotIndex,
|
||||
) -> bool {
|
||||
!drawing
|
||||
.primitive(dot)
|
||||
.segs()
|
||||
.iter()
|
||||
.any(|seg| matches!(seg, SegIndex::Fixed(..)))
|
||||
&& drawing.primitive(dot).bends().is_empty()
|
||||
}
|
||||
|
||||
impl<'a, R: AccessRules> Poly<'a, R> {
|
||||
pub fn new(index: GenericIndex<PolyWeight>, drawing: &'a Drawing<CompoundWeight, R>) -> Self {
|
||||
Self { index, drawing }
|
||||
}
|
||||
|
||||
fn is_apex(&self, dot: FixedDotIndex) -> bool {
|
||||
!self
|
||||
.drawing
|
||||
.primitive(dot)
|
||||
.segs()
|
||||
.iter()
|
||||
.any(|seg| matches!(seg, SegIndex::Fixed(..)))
|
||||
&& self.drawing.primitive(dot).bends().is_empty()
|
||||
is_apex(self.drawing, dot)
|
||||
}
|
||||
|
||||
pub fn apex(&self) -> FixedDotIndex {
|
||||
self.drawing
|
||||
.geometry()
|
||||
.compound_members(self.index.into())
|
||||
.find_map(|primitive_node| {
|
||||
if let PrimitiveIndex::FixedDot(dot) = primitive_node {
|
||||
if self.is_apex(dot) {
|
||||
return Some(dot);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,23 +112,6 @@ impl<R: AccessRules> MakePolygon for Poly<'_, R> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<R: AccessRules> GetMaybeApex for Poly<'_, R> {
|
||||
fn maybe_apex(&self) -> Option<FixedDotIndex> {
|
||||
self.drawing
|
||||
.geometry()
|
||||
.compound_members(self.index.into())
|
||||
.find_map(|primitive_node| {
|
||||
if let PrimitiveIndex::FixedDot(dot) = primitive_node {
|
||||
if self.is_apex(dot) {
|
||||
return Some(dot);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_dispatch(GetLayer, GetMaybeNet)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum PolyWeight {
|
||||
|
|
|
|||
|
|
@ -456,14 +456,8 @@ impl SpecctraDesign {
|
|||
maybe_net: Option<usize>,
|
||||
maybe_pin: Option<String>,
|
||||
) {
|
||||
let poly = board.add_poly(
|
||||
recorder,
|
||||
SolidPolyWeight { layer, maybe_net }.into(),
|
||||
maybe_pin,
|
||||
);
|
||||
|
||||
// Corners.
|
||||
let dot_1_1 = board.add_poly_fixed_dot_infringably(
|
||||
let dot_1_1 = board.add_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
|
|
@ -473,9 +467,9 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
let dot_2_1 = board.add_poly_fixed_dot_infringably(
|
||||
let dot_2_1 = board.add_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
|
|
@ -485,9 +479,9 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
let dot_2_2 = board.add_poly_fixed_dot_infringably(
|
||||
let dot_2_2 = board.add_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
|
|
@ -497,9 +491,9 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
let dot_1_2 = board.add_poly_fixed_dot_infringably(
|
||||
let dot_1_2 = board.add_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
|
|
@ -509,10 +503,10 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
// Sides.
|
||||
board.add_poly_fixed_seg_infringably(
|
||||
let seg1 = board.add_fixed_seg_infringably(
|
||||
recorder,
|
||||
dot_1_1,
|
||||
dot_2_1,
|
||||
|
|
@ -521,9 +515,9 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
board.add_poly_fixed_seg_infringably(
|
||||
let seg2 = board.add_fixed_seg_infringably(
|
||||
recorder,
|
||||
dot_2_1,
|
||||
dot_2_2,
|
||||
|
|
@ -532,9 +526,9 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
board.add_poly_fixed_seg_infringably(
|
||||
let seg3 = board.add_fixed_seg_infringably(
|
||||
recorder,
|
||||
dot_2_2,
|
||||
dot_1_2,
|
||||
|
|
@ -543,9 +537,9 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
board.add_poly_fixed_seg_infringably(
|
||||
let seg4 = board.add_fixed_seg_infringably(
|
||||
recorder,
|
||||
dot_1_2,
|
||||
dot_1_1,
|
||||
|
|
@ -554,7 +548,23 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
|
||||
board.add_poly_with_nodes(
|
||||
recorder,
|
||||
SolidPolyWeight { layer, maybe_net }.into(),
|
||||
maybe_pin,
|
||||
&[
|
||||
dot_1_1.into(),
|
||||
dot_1_2.into(),
|
||||
dot_2_2.into(),
|
||||
dot_2_1.into(),
|
||||
seg1.into(),
|
||||
seg2.into(),
|
||||
seg3.into(),
|
||||
seg4.into(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -634,14 +644,10 @@ impl SpecctraDesign {
|
|||
maybe_net: Option<usize>,
|
||||
maybe_pin: Option<String>,
|
||||
) {
|
||||
let poly = board.add_poly(
|
||||
recorder,
|
||||
SolidPolyWeight { layer, maybe_net }.into(),
|
||||
maybe_pin,
|
||||
);
|
||||
let mut nodes = Vec::with_capacity(coords.len() * 2 - 1);
|
||||
|
||||
// add the first coordinate in the wire path as a dot and save its index
|
||||
let mut prev_index = board.add_poly_fixed_dot_infringably(
|
||||
let mut prev_index = board.add_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
|
|
@ -651,14 +657,13 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
// TODO: This manual retagging shouldn't be necessary, `.into()` should suffice.
|
||||
//GenericIndex::new(poly.petgraph_index()).into(),
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
nodes.push(prev_index.into());
|
||||
|
||||
// iterate through path coords starting from the second
|
||||
for coord in coords.iter().skip(1) {
|
||||
let index = board.add_poly_fixed_dot_infringably(
|
||||
let index = board.add_fixed_dot_infringably(
|
||||
recorder,
|
||||
FixedDotWeight(GeneralDotWeight {
|
||||
circle: Circle {
|
||||
|
|
@ -668,26 +673,38 @@ impl SpecctraDesign {
|
|||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
// TODO: This manual retagging shouldn't be necessary, `.into()` should suffice.
|
||||
poly,
|
||||
None,
|
||||
);
|
||||
nodes.push(index.into());
|
||||
|
||||
// add a seg between the current and previous coords
|
||||
let _ = board.add_poly_fixed_seg_infringably(
|
||||
recorder,
|
||||
prev_index,
|
||||
index,
|
||||
FixedSegWeight(GeneralSegWeight {
|
||||
width,
|
||||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
// TODO: This manual retagging shouldn't be necessary, `.into()` should suffice.
|
||||
poly,
|
||||
nodes.push(
|
||||
board
|
||||
.add_fixed_seg_infringably(
|
||||
recorder,
|
||||
prev_index,
|
||||
index,
|
||||
FixedSegWeight(GeneralSegWeight {
|
||||
width,
|
||||
layer,
|
||||
maybe_net,
|
||||
}),
|
||||
None,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
|
||||
prev_index = index;
|
||||
}
|
||||
|
||||
// assumption: the last coord and the first coord are equal
|
||||
|
||||
board.add_poly_with_nodes(
|
||||
recorder,
|
||||
SolidPolyWeight { layer, maybe_net }.into(),
|
||||
maybe_pin,
|
||||
&nodes[..],
|
||||
);
|
||||
}
|
||||
|
||||
fn pos(place: PointWithRotation, pin: PointWithRotation, x: f64, y: f64) -> Point {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ mod common;
|
|||
#[test]
|
||||
fn test_0603_breakout() {
|
||||
let mut autorouter = common::load_design("tests/single_layer/0603_breakout/0603_breakout.dsn");
|
||||
common::assert_navvertex_count(&mut autorouter, "R1-2", "J1-2", 50);
|
||||
common::assert_navvertex_count(&mut autorouter, "R1-2", "J1-2", 54);
|
||||
let mut invoker = common::create_invoker_and_assert(autorouter);
|
||||
common::replay_and_assert(
|
||||
&mut invoker,
|
||||
|
|
@ -35,7 +35,7 @@ fn test_tht_diode_bridge_rectifier() {
|
|||
let mut autorouter = common::load_design(
|
||||
"tests/single_layer/tht_diode_bridge_rectifier/tht_diode_bridge_rectifier.dsn",
|
||||
);
|
||||
common::assert_navvertex_count(&mut autorouter, "J2-2", "D4-2", 56);
|
||||
common::assert_navvertex_count(&mut autorouter, "J2-2", "D4-2", 68);
|
||||
let mut invoker = common::create_invoker_and_assert(autorouter);
|
||||
common::replay_and_assert(
|
||||
&mut invoker,
|
||||
|
|
@ -46,7 +46,7 @@ fn test_tht_diode_bridge_rectifier() {
|
|||
|
||||
common::assert_single_layer_groundless_autoroute(&mut autorouter, "F.Cu");
|
||||
//common::assert_number_of_conncomps(&mut autorouter, 4);
|
||||
common::assert_band_length(autorouter.board(), "J2-2", "D4-2", 15900.0, 0.01);
|
||||
common::assert_band_length(autorouter.board(), "J2-2", "D4-2", 15906.760439007436, 0.01);
|
||||
|
||||
let mut invoker = Invoker::new(autorouter);
|
||||
let result = invoker.execute(Command::PlaceVia(ViaWeight {
|
||||
|
|
@ -71,7 +71,7 @@ fn test_4x_3rd_order_smd_lc_filters() {
|
|||
let mut autorouter = common::load_design(
|
||||
"tests/single_layer/4x_3rd_order_smd_lc_filters/4x_3rd_order_smd_lc_filters.dsn",
|
||||
);
|
||||
common::assert_navvertex_count(&mut autorouter, "J1-1", "L1-1", 2026);
|
||||
common::assert_navvertex_count(&mut autorouter, "J1-1", "L1-1", 2062);
|
||||
let mut invoker = common::create_invoker_and_assert(autorouter);
|
||||
common::replay_and_assert(
|
||||
&mut invoker,
|
||||
|
|
|
|||
Loading…
Reference in New Issue