From f4a8bee711abbe04aec7ab176464410306f023e1 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 10 Mar 2026 01:48:11 +0100 Subject: [PATCH] feat(topola-egui): Implement import of circular pads --- Cargo.toml | 2 +- topola-egui/src/displayer.rs | 8 ++++ topola-egui/src/viewport.rs | 2 +- topola/src/lib.rs | 1 + topola/src/specctra.rs | 80 ++++++++++++++++++++++++++++++++++-- 5 files changed, 87 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 71e2dd8..314395e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ resolver = "2" [workspace.dependencies] derive-getters = "0.5" -derive_more = { version = "2.1", features = ["from"] } +derive_more = { version = "2.1", features = ["add", "constructor", "from", "into"] } serde = { version = "1", features = ["derive", "rc"] } thiserror = "2.0" undoredo = { version = "0.8", features = ["stable-vec"] } diff --git a/topola-egui/src/displayer.rs b/topola-egui/src/displayer.rs index 0414ef7..b051bcc 100644 --- a/topola-egui/src/displayer.rs +++ b/topola-egui/src/displayer.rs @@ -45,5 +45,13 @@ impl Displayer { .collect::>(), egui::Stroke::new(5.0 / viewport.scale_factor(), egui::Color32::WHITE), ); + + for (_, joint) in workspace.board.layout().joints().collection() { + ui.painter().circle_filled( + egui::Pos2::new(joint.position[0] as f32, joint.position[1] as f32), + joint.radius as f32, + egui::Color32::RED, + ); + } } } diff --git a/topola-egui/src/viewport.rs b/topola-egui/src/viewport.rs index ad65713..a7f1088 100644 --- a/topola-egui/src/viewport.rs +++ b/topola-egui/src/viewport.rs @@ -26,7 +26,7 @@ impl Viewport { let mut scene_rect = self.scene_rect.clone(); egui::Scene::new() - .zoom_range(0.0001..=10000.0) + .zoom_range(0.00001..=10000.0) .show(ui, &mut scene_rect, |ui| { if let Some(ref workspace) = workspace { let mut displayer = Displayer::new(); diff --git a/topola/src/lib.rs b/topola/src/lib.rs index 072bb67..8e19d70 100644 --- a/topola/src/lib.rs +++ b/topola/src/lib.rs @@ -4,6 +4,7 @@ mod board; mod layout; +mod math; mod navmesher; mod specctra; diff --git a/topola/src/specctra.rs b/topola/src/specctra.rs index c03afad..5a661c0 100644 --- a/topola/src/specctra.rs +++ b/topola/src/specctra.rs @@ -2,13 +2,16 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 -use specctra::structure::DsnFile; +use specctra::{ + math::PointWithRotation, + structure::{DsnFile, Shape}, +}; -use crate::board::Board; +use crate::{board::Board, layout::Joint, math::Vector2}; impl Board { pub fn from_specctra(dsn: DsnFile) -> Self { - Board::new( + let mut board = Board::new( dsn.pcb .structure .boundary @@ -17,6 +20,75 @@ impl Board { .into_iter() .map(|p| [p.x as i64, p.y as i64]) .collect(), - ) + ); + + // add pins from components + for component in &dsn.pcb.placement.components { + let image = dsn + .pcb + .library + .images + .iter() + .find(|image| image.name == component.name) + .unwrap(); + + for place in &component.places { + /*let place_side_is_front = place.side == "front"; + let get_layer = |board: &Board, name: &str| { + Self::layer(board, &dsn.pcb.structure.layers, name, place_side_is_front) + };*/ + + for pin in &image.pins { + let padstack = dsn.pcb.library.find_padstack_by_name(&pin.name).unwrap(); + + for shape in padstack.shapes.iter() { + match shape { + Shape::Circle(circle) => Self::place_circle( + &mut board, + place.point_with_rotation(), + pin.point_with_rotation(), + (circle.diameter / 2.0) as u64, + false, + ), + _ => (), + } + } + } + } + } + + board + } + + pub fn place_circle( + board: &mut Board, + place: PointWithRotation, + pin: PointWithRotation, + radius: u64, + flip: bool, + ) { + let pos = Self::pos(place, pin, 0.0, 0.0, flip); + + board.add_joint(Joint { + position: [pos.x, pos.y], + layer: 0, + radius, + }); + } + + fn pos( + place: PointWithRotation, + pin: PointWithRotation, + x: f64, + y: f64, + flip: bool, + ) -> Vector2 { + let pos = (Vector2::new(x, y) + Vector2::new(pin.pos.x(), pin.pos.y())) + .rotate_around_point_degrees(pin.rot, Vector2::new(pin.pos.x(), pin.pos.y())); + let pos = (Vector2::new(place.pos.x(), place.pos.y()) + + flip.then_some(Vector2::new(-pos.x, pos.y)).unwrap_or(pos)) + .rotate_around_point_degrees(place.rot, Vector2::new(place.pos.x(), place.pos.y())); + + Vector2::new(pos.x as i64, pos.y as i64) } }