Add methods to obtain pin and component attractions

This commit is contained in:
Mikolaj Wielgus 2026-06-03 01:40:26 +02:00
parent 6cebbb2816
commit 4c6f5b4c43
10 changed files with 157 additions and 24 deletions

View File

@ -22,7 +22,7 @@ use undoredo::{Delta, Recorder};
use crate::{
layout::{
LayerId, Layout, LayoutHalfDelta,
compounds::{ComponentId, NetId, PinId},
compounds::{ComponentId, NetId, PinId, PinSpec},
},
vector::Vector2,
};
@ -43,7 +43,11 @@ pub struct Board {
impl Board {
/*pub fn new(boundary: Vec<Vector2<i64>>, layer_count: usize) -> Self {
Self {
layout: Layout::new(boundary.into_iter().map(Into::into).collect(), layer_count),
layout: Layout::new(
boundary.into_iter().map(Into::into).collect(),
layer_count,
0,
),
component_names: Recorder::new(BiBTreeMap::new()),
pin_names: Recorder::new(BiBTreeMap::new()),
layer_descs: Recorder::new(BiBTreeMap::new()),
@ -60,6 +64,7 @@ impl Board {
layout: Layout::new(
boundary.into_iter().map(Into::into).collect(),
layer_descs.len(),
net_names.len(),
),
component_names: Recorder::new(BiBTreeMap::new()),
pin_names: Recorder::new(BiBTreeMap::new()),
@ -79,12 +84,12 @@ impl Board {
component_id
}
pub fn ensure_named_pin(&mut self, pin_name: String, net_id: Option<NetId>) -> PinId {
pub fn ensure_named_pin(&mut self, pin_name: String, pin_spec: PinSpec) -> PinId {
if let Some(pin) = self.pin_names.get_by_right(&pin_name) {
return *pin;
};
let pin_id = self.layout.insert_pin(net_id);
let pin_id = self.layout.insert_pin(pin_spec);
self.pin_names.insert(pin_id, pin_name);
pin_id

View File

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2026 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{
Layout, Vector2,
layout::compounds::{ComponentId, PinId},
};
impl Layout {
pub fn component_attractions(
&self,
attractee: ComponentId,
) -> impl Iterator<Item = Vector2<i64>> + '_ {
self.component(attractee)
.pins
.iter()
.flat_map(move |&pin_id| self.pin_attractions(pin_id))
}
pub fn pin_attractions(&self, attractee: PinId) -> impl Iterator<Item = Vector2<i64>> + '_ {
self.pin(attractee)
.spec
.net
.into_iter()
.flat_map(move |net_id| {
self.nets[net_id.index()]
.pins
.iter()
.copied()
.filter(move |&attractor| attractor != attractee)
.map(move |attractor| self.pin_pin_attraction(attractee, attractor))
})
}
pub fn pin_pin_attraction(&self, attractee: PinId, attractor: PinId) -> Vector2<i64> {
self.pin_centroid(attractor) - self.pin_centroid(attractee)
}
}

View File

@ -6,6 +6,7 @@ use derive_more::{Constructor, From};
use serde::{Deserialize, Serialize};
use crate::{
PinId,
layout::primitives::{JointId, PolygonId, SegmentId, ViaId},
primitives::PrimitiveId,
};
@ -35,6 +36,7 @@ impl ComponentId {
#[derive(Clone, Debug, Default)]
pub struct Component {
pub pins: Vec<PinId>,
pub joints: Vec<JointId>,
pub segments: Vec<SegmentId>,
pub vias: Vec<ViaId>,

View File

@ -5,7 +5,13 @@
use derive_more::{Constructor, From};
use serde::{Deserialize, Serialize};
use crate::layout::primitives::{JointId, PolygonId, SegmentId, ViaId};
use crate::{
Layout, Vector2,
layout::{
compounds::{ComponentId, NetId},
primitives::{JointId, PolygonId, SegmentId, ViaId},
},
};
#[derive(
Clone,
@ -30,8 +36,15 @@ impl PinId {
}
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Copy, Debug)]
pub struct PinSpec {
pub component: Option<ComponentId>,
pub net: Option<NetId>,
}
#[derive(Clone, Debug)]
pub struct Pin {
pub spec: PinSpec,
pub joints: Vec<JointId>,
pub segments: Vec<SegmentId>,
pub vias: Vec<ViaId>,
@ -39,7 +52,45 @@ pub struct Pin {
}
impl Pin {
pub fn new() -> Self {
Default::default()
pub fn new(spec: PinSpec) -> Self {
Pin {
spec,
joints: Vec::new(),
segments: Vec::new(),
vias: Vec::new(),
polygons: Vec::new(),
}
}
}
impl Layout {
pub fn pin_centroid(&self, pin_id: PinId) -> Vector2<i64> {
let pin = self.pin(pin_id);
let mut sum = Vector2::new(0, 0);
let mut count = 0;
for &joint_id in &pin.joints {
sum = sum + self.joint(joint_id).center();
count += 1;
}
for &segment_id in &pin.segments {
sum = sum + self.segment(segment_id).center();
count += 1;
}
for &via_id in &pin.vias {
sum = sum + self.via(via_id).position;
count += 1;
}
for &polygon_id in &pin.polygons {
sum = sum + self.polygon(polygon_id).center();
count += 1;
}
if count == 0 {
return Vector2::new(0, 0);
}
let count = count as i64;
Vector2::new(sum.x / count, sum.y / count)
}
}

View File

@ -392,7 +392,7 @@ impl Layout {
}
}
fn primitive_net(&self, primitive: PrimitiveId) -> Option<NetId> {
pub fn primitive_net(&self, primitive: PrimitiveId) -> Option<NetId> {
match primitive {
PrimitiveId::Joint(joint_id) => self.joint(joint_id).spec.net,
PrimitiveId::Segment(segment_id) => self.segment(segment_id).net,

View File

@ -5,10 +5,9 @@
use rstar::primitives::GeomWithData;
use crate::{
Pin, PinId,
layout::{
Layout,
compounds::{Component, ComponentId, NetId},
compounds::{Component, ComponentId, Pin, PinId, PinSpec},
},
primitives::{
Joint, JointId, JointSpec, Polygon, PolygonId, Segment, SegmentId, SegmentSpec, Via, ViaId,
@ -21,10 +20,16 @@ impl Layout {
ComponentId::new(self.components.push(Component::new()))
}
pub fn insert_pin(&mut self, net_id: Option<NetId>) -> PinId {
let pin_id = PinId::new(self.pins.push(Pin::new()));
pub fn insert_pin(&mut self, spec: PinSpec) -> PinId {
let pin_id = PinId::new(self.pins.push(Pin::new(spec)));
if let Some(net_id) = net_id {
if let Some(component_id) = spec.component {
self.components.modify(component_id.index(), |component| {
component.pins.push(pin_id)
});
}
if let Some(net_id) = spec.net {
self.nets
.modify(net_id.index(), |net| net.pins.push(pin_id));
}
@ -33,11 +38,7 @@ impl Layout {
}
pub fn insert_joint(&mut self, spec: JointSpec) -> JointId {
let joint = Joint {
spec,
segments: Vec::new(),
vias: Vec::new(),
};
let joint = Joint::new(spec);
let bbox = joint.bbox();
let component_id = joint.spec.component;
let pin_id = joint.spec.pin;

View File

@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
mod attraction;
mod bbox;
pub mod compounds;
mod delete;
@ -90,14 +91,19 @@ pub struct Layout {
}
impl Layout {
pub fn new(boundary: Vec<[i64; 2]>, layer_count: usize) -> Self {
pub fn new(boundary: Vec<[i64; 2]>, layer_count: usize, net_count: usize) -> Self {
let mut nets = StableVec::new();
for _ in 0..net_count {
nets.push(Net::default());
}
Self {
boundary: boundary.clone(),
place_boundary: boundary,
layer_count,
components: Recorder::new(StableVec::new()),
nets: Recorder::new(StableVec::new()),
nets: Recorder::new(nets),
pins: Recorder::new(StableVec::new()),
joints: Recorder::new(StableVec::new()),

View File

@ -52,6 +52,14 @@ pub struct Joint {
}
impl Joint {
pub fn new(spec: JointSpec) -> Self {
Joint {
spec,
segments: Vec::new(),
vias: Vec::new(),
}
}
pub fn center(&self) -> Vector2<i64> {
self.spec.position
}

View File

@ -15,6 +15,8 @@ pub use polygon::*;
pub use segment::*;
pub use via::*;
use crate::{Layout, PinId};
#[derive(Clone, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize)]
pub enum PrimitiveId {
Joint(JointId),
@ -22,3 +24,14 @@ pub enum PrimitiveId {
Via(ViaId),
Polygon(PolygonId),
}
impl Layout {
pub fn primitive_pin(&self, primitive: PrimitiveId) -> Option<PinId> {
match primitive {
PrimitiveId::Joint(joint_id) => self.joint(joint_id).spec.pin,
PrimitiveId::Segment(segment_id) => self.segment(segment_id).spec.pin,
PrimitiveId::Via(via_id) => self.via(via_id).spec.pin,
PrimitiveId::Polygon(polygon_id) => self.polygon(polygon_id).pin,
}
}
}

View File

@ -12,8 +12,10 @@ use specctra::{
use crate::{
board::{Board, LayerDesc, LayerSide, LayerType},
layout::LayerId,
layout::compounds::{ComponentId, NetId, PinId},
layout::{
LayerId,
compounds::{ComponentId, NetId, PinId, PinSpec},
},
primitives::{JointSpec, Polygon, Segment, SegmentSpec},
vector::Vector2,
};
@ -161,7 +163,13 @@ impl Board {
let pin_name = format!("{}-{}", place.name, pin.id);
let net_id = pin_nets.get(&pin_name).copied();
let pin_id = board.ensure_named_pin(pin_name.clone(), net_id);
let pin_id = board.ensure_named_pin(
pin_name.clone(),
PinSpec {
component: Some(component_id),
net: net_id,
},
);
let padstack = dsn.pcb.library.find_padstack_by_name(&pin.name).unwrap();
for shape in padstack.shapes.iter() {