From d9a4c7a11f6b8d05c182a2ecaf277cee29a85e52 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Mon, 25 May 2026 23:32:39 +0200 Subject: [PATCH] Add missing code for vias --- topola-egui/src/display.rs | 47 ++++++++++++++++++++++-- topola/src/board/locate.rs | 8 +++-- topola/src/board/select.rs | 55 +++++++++++++++++++++++++---- topola/src/layout/locate.rs | 14 ++++++-- topola/src/layout/mod.rs | 16 +++++++++ topola/src/layout/primitives/via.rs | 9 +++++ 6 files changed, 135 insertions(+), 14 deletions(-) diff --git a/topola-egui/src/display.rs b/topola-egui/src/display.rs index 97097f3..be53cfa 100644 --- a/topola-egui/src/display.rs +++ b/topola-egui/src/display.rs @@ -4,7 +4,7 @@ use crate::{viewport::Viewport, workspace::Workspace}; use topola::LayerId; -use topola::primitives::{Joint, Polygon, Segment}; +use topola::primitives::{Joint, Polygon, Segment, Via}; pub struct Display {} @@ -74,7 +74,20 @@ impl Display { ); } - // TODO: Vias. + for via_id in layout.layer_vias(layer) { + let via = layout.via(via_id); + self.paint_via( + ctx, + ui, + viewport, + via, + workspace.appearance_panel.layer_color( + ctx, + board.layer_desc(layer), + board.pin_selection_contains_via(&workspace.selection.pins, via_id), + ), + ); + } for polygon_id in layout.layer_polygons(layer) { let polygon = layout.polygon(polygon_id); @@ -137,6 +150,21 @@ impl Display { ); } + fn paint_via( + &mut self, + ctx: &egui::Context, + ui: &egui::Ui, + viewport: &Viewport, + via: &Via, + color: egui::Color32, + ) { + ui.painter().circle_filled( + egui::pos2(via.position.x as f32, via.position.y as f32), + via.spec.radius as f32, + color, + ); + } + fn paint_polygon( &mut self, ctx: &egui::Context, @@ -206,7 +234,20 @@ impl Display { ); } - // TODO: vias. + for via_id in layout.layer_vias(layer) { + let via = layout.via(via_id); + let bbox = via.bbox(); + + ui.painter().rect_stroke( + egui::Rect { + min: egui::pos2(bbox.lower()[0] as f32, bbox.lower()[1] as f32), + max: egui::pos2(bbox.upper()[0] as f32, bbox.upper()[1] as f32), + }, + egui::CornerRadius::ZERO, + egui::Stroke::new(5.0, egui::Color32::GRAY), + egui::StrokeKind::Middle, + ); + } for polygon_id in layout.layer_polygons(layer) { let polygon = layout.polygon(polygon_id); diff --git a/topola/src/board/locate.rs b/topola/src/board/locate.rs index b852b77..47357f7 100644 --- a/topola/src/board/locate.rs +++ b/topola/src/board/locate.rs @@ -23,7 +23,9 @@ impl Board { return self.segment_component_selector(segment_id); } - // TODO: Vias. + if let Some(via_id) = self.layout.locate_vias_at_point(layer, point).next() { + return self.via_component_selector(via_id); + } if let Some(polygon_id) = self.layout.locate_polygons_at_point(layer, point).next() { return self.polygon_component_selector(polygon_id); @@ -41,7 +43,9 @@ impl Board { return self.segment_pin_selector(segment_id); } - // TODO: Vias. + if let Some(via_id) = self.layout.locate_vias_at_point(layer, point).next() { + return self.via_pin_selector(via_id); + } if let Some(polygon_id) = self.layout.locate_polygons_at_point(layer, point).next() { return self.polygon_pin_selector(polygon_id); diff --git a/topola/src/board/select.rs b/topola/src/board/select.rs index e25241c..b771eab 100644 --- a/topola/src/board/select.rs +++ b/topola/src/board/select.rs @@ -9,7 +9,7 @@ use crate::{ }, layout::LayerId, math::Vector2, - primitives::{JointId, PolygonId, SegmentId}, + primitives::{JointId, PolygonId, SegmentId, ViaId}, }; impl Board { @@ -40,7 +40,17 @@ impl Board { component_selection.0.insert(component_selector); } - // TODO: Vias. + for via_id in self.layout.layer_vias(layer_id) { + if self.layout.via(via_id).spec.pin != Some(pin_id) { + continue; + } + + let Some(component_selector) = self.via_component_selector(via_id) else { + continue; + }; + + component_selection.0.insert(component_selector); + } for segment_id in self.layout.layer_segments(layer_id) { if self.layout.segment(segment_id).spec.pin != Some(pin_id) { @@ -94,7 +104,17 @@ impl Board { selection.0.contains(&selector) } - // TODO: Vias. + pub fn component_selection_contains_via( + &self, + selection: &ComponentSelection, + id: ViaId, + ) -> bool { + let Some(selector) = self.via_component_selector(id) else { + return false; + }; + + selection.0.contains(&selector) + } pub fn component_selection_contains_polygon( &self, @@ -124,7 +144,13 @@ impl Board { }) } - // TODO: Vias. + pub fn via_component_selector(&self, id: ViaId) -> Option { + let via = self.layout.via(id); + + Some(ComponentSelector { + component: self.component_name(via.spec.component?)?.to_string(), + }) + } pub fn polygon_component_selector(&self, id: PolygonId) -> Option { let polygon = self.layout.polygon(id); @@ -150,7 +176,13 @@ impl Board { selection.0.contains(&selector) } - // TODO: Vias. + pub fn pin_selection_contains_via(&self, selection: &PinSelection, id: ViaId) -> bool { + let Some(selector) = self.via_pin_selector(id) else { + return false; + }; + + selection.0.contains(&selector) + } pub fn pin_selection_contains_polygon(&self, selection: &PinSelection, id: PolygonId) -> bool { let Some(selector) = self.polygon_pin_selector(id) else { @@ -169,7 +201,9 @@ impl Board { return self.segment_pin_selector(segment_id); } - // TODO: Vias. + if let Some(via_id) = self.layout.locate_vias_at_point(layer, point).next() { + return self.via_pin_selector(via_id); + } if let Some(polygon_id) = self.layout.locate_polygons_at_point(layer, point).next() { return self.polygon_pin_selector(polygon_id); @@ -196,7 +230,14 @@ impl Board { }) } - // TODO: Vias. + pub fn via_pin_selector(&self, id: ViaId) -> Option { + let via = self.layout.via(id); + + Some(PinSelector { + pin: self.pin_name(via.spec.pin?)?.to_string(), + layer: self.layer_name(via.min_layer)?, + }) + } pub fn polygon_pin_selector(&self, id: PolygonId) -> Option { let polygon = self.layout.polygon(id); diff --git a/topola/src/layout/locate.rs b/topola/src/layout/locate.rs index b76ed86..db1832d 100644 --- a/topola/src/layout/locate.rs +++ b/topola/src/layout/locate.rs @@ -5,7 +5,7 @@ use crate::{ Vector2, layout::{LayerId, Layout}, - primitives::{JointId, PolygonId, SegmentId}, + primitives::{JointId, PolygonId, SegmentId, ViaId}, }; impl Layout { @@ -33,7 +33,17 @@ impl Layout { .filter(move |&segment_id| self.segment(segment_id).contains_point(point)) } - // TODO: vias. + pub fn locate_vias_at_point( + &self, + layer: LayerId, + point: Vector2, + ) -> impl Iterator { + self.vias_rtree + .as_ref() + .locate_all_at_point(&[point.x, point.y, layer.index() as i64]) + .map(|geom_with_data| geom_with_data.data) + .filter(move |&via_id| self.vias[via_id.index()].contains_point(layer, point)) + } pub fn locate_polygons_at_point( &self, diff --git a/topola/src/layout/mod.rs b/topola/src/layout/mod.rs index 7d5b139..753f1e4 100644 --- a/topola/src/layout/mod.rs +++ b/topola/src/layout/mod.rs @@ -388,6 +388,18 @@ impl Layout { .filter(move |&id| self.segment(id).layer == layer) } + pub fn layer_vias(&self, layer: LayerId) -> impl Iterator + '_ { + let envelope = Self::whole_layer_aabb(layer); + self.vias_rtree + .as_ref() + .locate_in_envelope_intersecting(&envelope) + .map(|geom_with_data| geom_with_data.data) + .filter(move |&id| { + let via = self.via(id); + via.min_layer <= layer && layer <= via.max_layer + }) + } + pub fn layer_polygons(&self, layer: LayerId) -> impl Iterator + '_ { let envelope = Self::whole_layer_aabb(layer); self.polygons_rtree @@ -412,6 +424,10 @@ impl Layout { &self.segments[segment_id.index()] } + pub fn via(&self, via_id: ViaId) -> &Via { + &self.vias[via_id.index()] + } + pub fn polygon(&self, polygon_id: PolygonId) -> &Polygon { &self.polygons[polygon_id.index()] } diff --git a/topola/src/layout/primitives/via.rs b/topola/src/layout/primitives/via.rs index 4239324..6790c5a 100644 --- a/topola/src/layout/primitives/via.rs +++ b/topola/src/layout/primitives/via.rs @@ -54,6 +54,15 @@ pub struct Via { } impl Via { + pub fn contains_point(&self, layer: LayerId, point: Vector2) -> bool { + if layer < self.min_layer || layer > self.max_layer { + return false; + } + + (point.x - self.position.x).pow(2) as u64 + (point.y - self.position.y).pow(2) as u64 + <= self.spec.radius.pow(2) + } + pub fn bbox(&self) -> Rectangle<[i64; 3]> { let radius = self.spec.radius as i64;