Load layers to primitives

This commit is contained in:
Mikolaj Wielgus 2026-03-10 22:18:15 +01:00
parent 5e6ddac19f
commit 8a50e70a6a
3 changed files with 151 additions and 46 deletions

View File

@ -9,6 +9,7 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
bimap = "0.6"
dearcut = { version = "0.1", features = ["undoredo"] } dearcut = { version = "0.1", features = ["undoredo"] }
derive-getters.workspace = true derive-getters.workspace = true
derive_more.workspace = true derive_more.workspace = true

View File

@ -2,6 +2,7 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use bimap::BiBTreeMap;
use derive_getters::{Dissolve, Getters}; use derive_getters::{Dissolve, Getters};
use undoredo::{ApplyDelta, Delta, FlushDelta}; use undoredo::{ApplyDelta, Delta, FlushDelta};
@ -18,12 +19,30 @@ struct Layer {
#[derive(Clone, Debug, Getters)] #[derive(Clone, Debug, Getters)]
pub struct Board { pub struct Board {
layout: Layout, layout: Layout,
#[getter(skip)]
layer_names: BiBTreeMap<usize, String>,
#[getter(skip)]
net_names: BiBTreeMap<usize, String>,
} }
impl Board { impl Board {
pub fn new(boundary: Vec<[i64; 2]>) -> Self { pub fn new(boundary: Vec<[i64; 2]>) -> Self {
Self { Self {
layout: Layout::new(boundary), layout: Layout::new(boundary),
layer_names: BiBTreeMap::new(),
net_names: BiBTreeMap::new(),
}
}
pub fn with_names(
boundary: Vec<[i64; 2]>,
layer_names: BiBTreeMap<usize, String>,
net_names: BiBTreeMap<usize, String>,
) -> Self {
Self {
layout: Layout::new(boundary),
layer_names,
net_names,
} }
} }
@ -46,6 +65,22 @@ impl Board {
pub fn add_polygon(&mut self, polygon: Polygon) -> PolygonId { pub fn add_polygon(&mut self, polygon: Polygon) -> PolygonId {
self.layout.add_polygon(polygon) self.layout.add_polygon(polygon)
} }
pub fn layer_name(&self, layer: usize) -> &str {
&self.layer_names.get_by_left(&layer).unwrap()
}
pub fn layer_id(&self, name: &str) -> usize {
*self.layer_names.get_by_right(name).unwrap()
}
pub fn net_name(&self, net: usize) -> &str {
&self.net_names.get_by_left(&net).unwrap()
}
pub fn net_id(&self, name: &str) -> usize {
*self.net_names.get_by_right(name).unwrap()
}
} }
#[derive(Clone, Debug, Dissolve)] #[derive(Clone, Debug, Dissolve)]

View File

@ -2,9 +2,10 @@
// //
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use bimap::BiBTreeMap;
use specctra::{ use specctra::{
math::PointWithRotation, math::PointWithRotation,
structure::{DsnFile, Point, Shape}, structure::{DsnFile, Layer, Point, Shape},
}; };
use crate::{ use crate::{
@ -16,7 +17,33 @@ use crate::{
impl Board { impl Board {
pub fn from_specctra(dsn: DsnFile) -> Self { pub fn from_specctra(dsn: DsnFile) -> Self {
let mut board = Board::new( let layer_names = BiBTreeMap::from_iter(
dsn.pcb
.structure
.layers
.iter()
.enumerate()
.map(|(index, layer)| (index, layer.name.clone())),
);
// assign IDs to all nets named in pcb.network
let net_names = {
let mut tmp: Vec<_> = dsn
.pcb
.network
.classes
.iter()
.flat_map(|class| &class.nets)
.chain(dsn.pcb.network.nets.iter().map(|net| &net.name))
.collect();
// deduplicate net names
tmp.sort_unstable();
tmp.dedup();
BiBTreeMap::from_iter(tmp.into_iter().cloned().enumerate())
};
let mut board = Board::with_names(
dsn.pcb dsn.pcb
.structure .structure
.boundary .boundary
@ -25,8 +52,29 @@ impl Board {
.into_iter() .into_iter()
.map(|p| [p.x as i64, p.y as i64]) .map(|p| [p.x as i64, p.y as i64])
.collect(), .collect(),
layer_names,
net_names,
); );
// Mapping of pin -> net prepared for adding pins.
let pin_nets = dsn
.pcb
.network
.nets
.iter()
.filter_map(|net_pin_assignments| {
// Resolve the id so we don't work with strings.
let net = board.net_id(&net_pin_assignments.name);
net_pin_assignments.pins.as_ref().map(|pins| {
// Take the list of pins
// and for each pin output (pin name, net id).
pins.names.iter().map(move |pinname| (pinname.clone(), net))
})
})
// Flatten the nested iters into a single stream of tuples.
.flatten();
// Add pins from components. // Add pins from components.
for component in &dsn.pcb.placement.components { for component in &dsn.pcb.placement.components {
let image = dsn let image = dsn
@ -38,54 +86,65 @@ impl Board {
.unwrap(); .unwrap();
for place in &component.places { for place in &component.places {
/*let place_side_is_front = place.side == "front"; let place_side_is_front = place.side == "front";
let get_layer = |board: &Board, name: &str| { let get_layer = |board: &Board, name: &str| {
Self::layer(board, &dsn.pcb.structure.layers, name, place_side_is_front) Self::layer(board, &dsn.pcb.structure.layers, name, place_side_is_front)
};*/ };
for pin in &image.pins { for pin in &image.pins {
let padstack = dsn.pcb.library.find_padstack_by_name(&pin.name).unwrap(); let padstack = dsn.pcb.library.find_padstack_by_name(&pin.name).unwrap();
for shape in padstack.shapes.iter() { for shape in padstack.shapes.iter() {
match shape { match shape {
Shape::Circle(circle) => Self::place_circle( Shape::Circle(circle) => {
&mut board, let layer = get_layer(&board, &circle.layer);
place.point_with_rotation(), Self::place_circle(
pin.point_with_rotation(), &mut board,
0, place.point_with_rotation(),
(circle.diameter / 2.0) as u64, pin.point_with_rotation(),
false, layer,
), (circle.diameter / 2.0) as u64,
Shape::Rect(rect) => Self::place_rect( false,
&mut board, )
place.point_with_rotation(), }
pin.point_with_rotation(), Shape::Rect(rect) => {
rect.x1, let layer = get_layer(&board, &rect.layer);
rect.y1, Self::place_rect(
rect.x2, &mut board,
rect.y2, place.point_with_rotation(),
0, pin.point_with_rotation(),
false, rect.x1,
), rect.y1,
Shape::Path(path) => Self::place_path( rect.x2,
&mut board, rect.y2,
place.point_with_rotation(), layer,
pin.point_with_rotation(), false,
&path.coords, )
path.width, }
0, Shape::Path(path) => {
false, let layer = get_layer(&board, &path.layer);
), Self::place_path(
Shape::Polygon(polygon) => Self::place_polygon( &mut board,
&mut board, place.point_with_rotation(),
place.point_with_rotation(), pin.point_with_rotation(),
pin.point_with_rotation(), &path.coords,
&polygon.coords, path.width,
polygon.width, layer,
0, false,
false, )
), }
_ => (), Shape::Polygon(polygon) => {
let layer = get_layer(&board, &polygon.layer);
Self::place_polygon(
&mut board,
place.point_with_rotation(),
pin.point_with_rotation(),
&polygon.coords,
polygon.width,
layer,
false,
)
}
} }
} }
} }
@ -95,7 +154,7 @@ impl Board {
board board
} }
pub fn place_circle( fn place_circle(
board: &mut Board, board: &mut Board,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -110,7 +169,7 @@ impl Board {
}); });
} }
pub fn place_rect( fn place_rect(
board: &mut Board, board: &mut Board,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -132,7 +191,7 @@ impl Board {
}); });
} }
pub fn place_path( fn place_path(
board: &mut Board, board: &mut Board,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -175,7 +234,7 @@ impl Board {
} }
} }
pub fn place_polygon( fn place_polygon(
board: &mut Board, board: &mut Board,
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,
@ -191,6 +250,16 @@ impl Board {
board.add_polygon(Polygon { vertices, layer }); board.add_polygon(Polygon { vertices, layer });
} }
fn layer(board: &Board, layers: &[Layer], name: &str, front: bool) -> usize {
let image_layer = board.layer_id(name);
if front {
image_layer
} else {
layers.len() - image_layer - 1
}
}
fn pos( fn pos(
place: PointWithRotation, place: PointWithRotation,
pin: PointWithRotation, pin: PointWithRotation,