From 1b4bb49a8924795e672d65a36a4ec2a42b9572fd Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 26 May 2026 01:27:06 +0200 Subject: [PATCH] Add location methods for inside rect and intersecting rect I did some renames while at it. --- topola-egui/src/display.rs | 8 +-- topola-egui/src/layers_panel.rs | 10 +-- topola/src/board/layer.rs | 20 +++--- topola/src/board/locate.rs | 102 ++++++++++++++++++++++++++++++- topola/src/board/mod.rs | 2 +- topola/src/board/select.rs | 51 +++------------- topola/src/layout/locate.rs | 105 +++++++++++++++++++++++++++++++- topola/src/lib.rs | 4 +- topola/src/math.rs | 23 +++++++ topola/src/specctra.rs | 12 ++-- 10 files changed, 265 insertions(+), 72 deletions(-) diff --git a/topola-egui/src/display.rs b/topola-egui/src/display.rs index be53cfa..a24df58 100644 --- a/topola-egui/src/display.rs +++ b/topola-egui/src/display.rs @@ -54,7 +54,7 @@ impl Display { workspace.appearance_panel.layer_color( ctx, board.layer_desc(joint.spec.layer), - board.pin_selection_contains_joint(&workspace.selection.pins, joint_id), + board.pins_contain_joint(&workspace.selection.pins, joint_id), ), ); } @@ -69,7 +69,7 @@ impl Display { workspace.appearance_panel.layer_color( ctx, board.layer_desc(segment.layer), - board.pin_selection_contains_segment(&workspace.selection.pins, segment_id), + board.pins_contain_segment(&workspace.selection.pins, segment_id), ), ); } @@ -84,7 +84,7 @@ impl Display { workspace.appearance_panel.layer_color( ctx, board.layer_desc(layer), - board.pin_selection_contains_via(&workspace.selection.pins, via_id), + board.pins_contain_via(&workspace.selection.pins, via_id), ), ); } @@ -99,7 +99,7 @@ impl Display { workspace.appearance_panel.layer_color( ctx, board.layer_desc(polygon.layer), - board.pin_selection_contains_polygon(&workspace.selection.pins, polygon_id), + board.pins_contain_polygon(&workspace.selection.pins, polygon_id), ), ); } diff --git a/topola-egui/src/layers_panel.rs b/topola-egui/src/layers_panel.rs index 865bea6..3393d23 100644 --- a/topola-egui/src/layers_panel.rs +++ b/topola-egui/src/layers_panel.rs @@ -6,7 +6,7 @@ use std::collections::BTreeMap; use egui::{Context, Grid, ScrollArea, SidePanel, widget_text::WidgetText}; use serde::{Deserialize, Serialize}; -use topola::{Board, LayerDesc, LayerId, LayerTier, LayerType}; +use topola::{Board, LayerDesc, LayerId, LayerSide, LayerType}; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Colors { @@ -59,8 +59,8 @@ impl LayersPanel { }; let color = match layer_desc.typ { - LayerType::Copper => match layer_desc.tier { - LayerTier::Top => Some(( + LayerType::Copper => match layer_desc.side { + LayerSide::Top => Some(( LayerColors { normal: egui::Color32::from_rgb(255, 52, 52), highlighted: egui::Color32::from_rgb(255, 100, 100), @@ -70,7 +70,7 @@ impl LayersPanel { highlighted: egui::Color32::from_rgb(255, 52, 52), }, )), - LayerTier::Bottom => Some(( + LayerSide::Bottom => Some(( LayerColors { normal: egui::Color32::from_rgb(52, 52, 255), highlighted: egui::Color32::from_rgb(100, 100, 255), @@ -80,7 +80,7 @@ impl LayersPanel { highlighted: egui::Color32::from_rgb(52, 52, 255), }, )), - LayerTier::Inner => (layer_desc.index % 2 == 0) + LayerSide::Inner => (layer_desc.index % 2 == 0) .then_some(( LayerColors { normal: egui::Color32::from_rgb(127, 200, 127), diff --git a/topola/src/board/layer.rs b/topola/src/board/layer.rs index a593b2c..a2f2cbb 100644 --- a/topola/src/board/layer.rs +++ b/topola/src/board/layer.rs @@ -14,7 +14,7 @@ pub enum LayerType { } #[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] -pub enum LayerTier { +pub enum LayerSide { Top, Inner, Bottom, @@ -23,22 +23,22 @@ pub enum LayerTier { #[derive(Clone, Constructor, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] pub struct LayerDesc { pub typ: LayerType, - pub tier: LayerTier, + pub side: LayerSide, pub index: usize, } impl Display for LayerDesc { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self.typ { - LayerType::Copper => match self.tier { - LayerTier::Top => write!(f, "F.Cu"), - LayerTier::Bottom => write!(f, "B.Cu"), - LayerTier::Inner => write!(f, "In{}.Cu", self.index.saturating_sub(1)), + LayerType::Copper => match self.side { + LayerSide::Top => write!(f, "F.Cu"), + LayerSide::Bottom => write!(f, "B.Cu"), + LayerSide::Inner => write!(f, "In{}.Cu", self.index.saturating_sub(1)), }, - LayerType::Outline => match self.tier { - LayerTier::Top => write!(f, "outlines.top"), - LayerTier::Bottom => write!(f, "outlines.bottom"), - LayerTier::Inner => write!(f, "outlines.{}", self.index), + LayerType::Outline => match self.side { + LayerSide::Top => write!(f, "F.Outl"), + LayerSide::Bottom => write!(f, "B.Outl"), + LayerSide::Inner => write!(f, "In{}.Outl", self.index), }, } } diff --git a/topola/src/board/locate.rs b/topola/src/board/locate.rs index 47357f7..7438d90 100644 --- a/topola/src/board/locate.rs +++ b/topola/src/board/locate.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::{ - Vector2, + Rect2, Vector2, board::Board, layout::LayerId, selections::{ComponentSelector, PinSelector}, @@ -34,6 +34,56 @@ impl Board { None } + pub fn locate_component_intersecting_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator + '_ { + self.layout + .locate_joints_intersecting_rect(layer, rect) + .filter_map(|joint_id| self.joint_component_selector(joint_id)) + .chain( + self.layout + .locate_segments_intersecting_rect(layer, rect) + .filter_map(|segment_id| self.segment_component_selector(segment_id)), + ) + .chain( + self.layout + .locate_vias_intersecting_rect(layer, rect) + .filter_map(|via_id| self.via_component_selector(via_id)), + ) + .chain( + self.layout + .locate_polygons_intersecting_rect(layer, rect) + .filter_map(|polygon_id| self.polygon_component_selector(polygon_id)), + ) + } + + pub fn locate_component_inside_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator + '_ { + self.layout + .locate_joints_inside_rect(layer, rect) + .filter_map(|joint_id| self.joint_component_selector(joint_id)) + .chain( + self.layout + .locate_segments_inside_rect(layer, rect) + .filter_map(|segment_id| self.segment_component_selector(segment_id)), + ) + .chain( + self.layout + .locate_vias_inside_rect(layer, rect) + .filter_map(|via_id| self.via_component_selector(via_id)), + ) + .chain( + self.layout + .locate_polygons_inside_rect(layer, rect) + .filter_map(|polygon_id| self.polygon_component_selector(polygon_id)), + ) + } + pub fn locate_pin_at_point(&self, layer: LayerId, point: Vector2) -> Option { if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() { return self.joint_pin_selector(joint_id); @@ -53,4 +103,54 @@ impl Board { None } + + pub fn locate_pin_intersecting_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator + '_ { + self.layout + .locate_joints_intersecting_rect(layer, rect) + .filter_map(|joint_id| self.joint_pin_selector(joint_id)) + .chain( + self.layout + .locate_segments_intersecting_rect(layer, rect) + .filter_map(|segment_id| self.segment_pin_selector(segment_id)), + ) + .chain( + self.layout + .locate_vias_intersecting_rect(layer, rect) + .filter_map(|via_id| self.via_pin_selector(via_id)), + ) + .chain( + self.layout + .locate_polygons_intersecting_rect(layer, rect) + .filter_map(|polygon_id| self.polygon_pin_selector(polygon_id)), + ) + } + + pub fn locate_pin_inside_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator + '_ { + self.layout + .locate_joints_inside_rect(layer, rect) + .filter_map(|joint_id| self.joint_pin_selector(joint_id)) + .chain( + self.layout + .locate_segments_inside_rect(layer, rect) + .filter_map(|segment_id| self.segment_pin_selector(segment_id)), + ) + .chain( + self.layout + .locate_vias_inside_rect(layer, rect) + .filter_map(|via_id| self.via_pin_selector(via_id)), + ) + .chain( + self.layout + .locate_polygons_inside_rect(layer, rect) + .filter_map(|polygon_id| self.polygon_pin_selector(polygon_id)), + ) + } } diff --git a/topola/src/board/mod.rs b/topola/src/board/mod.rs index 024b512..9e38cb7 100644 --- a/topola/src/board/mod.rs +++ b/topola/src/board/mod.rs @@ -9,7 +9,7 @@ mod select; pub mod selections; mod transforms; -pub use crate::board::layer::{LayerDesc, LayerTier, LayerType}; +pub use crate::board::layer::{LayerDesc, LayerSide, LayerType}; use bidimap::BiBTreeMap; use derive_getters::Getters; diff --git a/topola/src/board/select.rs b/topola/src/board/select.rs index b771eab..84dc33a 100644 --- a/topola/src/board/select.rs +++ b/topola/src/board/select.rs @@ -7,16 +7,11 @@ use crate::{ Board, selections::{ComponentSelection, ComponentSelector, PinSelection, PinSelector}, }, - layout::LayerId, - math::Vector2, primitives::{JointId, PolygonId, SegmentId, ViaId}, }; impl Board { - pub fn pin_selection_to_component_selection( - &mut self, - pin_selection: PinSelection, - ) -> ComponentSelection { + pub fn pins_to_components(&mut self, pin_selection: PinSelection) -> ComponentSelection { let mut component_selection = ComponentSelection::new(); for selector in pin_selection.0 { @@ -80,11 +75,7 @@ impl Board { component_selection } - pub fn component_selection_contains_joint( - &self, - selection: &ComponentSelection, - id: JointId, - ) -> bool { + pub fn components_contain_joint(&self, selection: &ComponentSelection, id: JointId) -> bool { let Some(selector) = self.joint_component_selector(id) else { return false; }; @@ -92,7 +83,7 @@ impl Board { selection.0.contains(&selector) } - pub fn component_selection_contains_segment( + pub fn components_contain_segment( &self, selection: &ComponentSelection, id: SegmentId, @@ -104,11 +95,7 @@ impl Board { selection.0.contains(&selector) } - pub fn component_selection_contains_via( - &self, - selection: &ComponentSelection, - id: ViaId, - ) -> bool { + pub fn components_contain_via(&self, selection: &ComponentSelection, id: ViaId) -> bool { let Some(selector) = self.via_component_selector(id) else { return false; }; @@ -116,7 +103,7 @@ impl Board { selection.0.contains(&selector) } - pub fn component_selection_contains_polygon( + pub fn components_contain_polygon( &self, selection: &ComponentSelection, id: PolygonId, @@ -160,7 +147,7 @@ impl Board { }) } - pub fn pin_selection_contains_joint(&self, selection: &PinSelection, id: JointId) -> bool { + pub fn pins_contain_joint(&self, selection: &PinSelection, id: JointId) -> bool { let Some(selector) = self.joint_pin_selector(id) else { return false; }; @@ -168,7 +155,7 @@ impl Board { selection.0.contains(&selector) } - pub fn pin_selection_contains_segment(&self, selection: &PinSelection, id: SegmentId) -> bool { + pub fn pins_contain_segment(&self, selection: &PinSelection, id: SegmentId) -> bool { let Some(selector) = self.segment_pin_selector(id) else { return false; }; @@ -176,7 +163,7 @@ impl Board { selection.0.contains(&selector) } - pub fn pin_selection_contains_via(&self, selection: &PinSelection, id: ViaId) -> bool { + pub fn pins_contain_via(&self, selection: &PinSelection, id: ViaId) -> bool { let Some(selector) = self.via_pin_selector(id) else { return false; }; @@ -184,7 +171,7 @@ impl Board { selection.0.contains(&selector) } - pub fn pin_selection_contains_polygon(&self, selection: &PinSelection, id: PolygonId) -> bool { + pub fn pins_contain_polygon(&self, selection: &PinSelection, id: PolygonId) -> bool { let Some(selector) = self.polygon_pin_selector(id) else { return false; }; @@ -192,26 +179,6 @@ impl Board { selection.0.contains(&selector) } - pub fn point_pin_selector(&self, layer: LayerId, point: Vector2) -> Option { - if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() { - return self.joint_pin_selector(joint_id); - } - - if let Some(segment_id) = self.layout.locate_segments_at_point(layer, point).next() { - return self.segment_pin_selector(segment_id); - } - - 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); - } - - None - } - pub fn joint_pin_selector(&self, id: JointId) -> Option { let joint = self.layout.joint(id); diff --git a/topola/src/layout/locate.rs b/topola/src/layout/locate.rs index db1832d..5770880 100644 --- a/topola/src/layout/locate.rs +++ b/topola/src/layout/locate.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::{ - Vector2, + Rect2, Vector2, layout::{LayerId, Layout}, primitives::{JointId, PolygonId, SegmentId, ViaId}, }; @@ -21,6 +21,31 @@ impl Layout { .filter(move |&joint_id| self.joints[joint_id.index()].contains_point(point)) } + pub fn locate_joints_intersecting_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.joints_rtree + .as_ref() + .locate_in_envelope_intersecting(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + .filter(move |&joint_id| self.joint(joint_id).spec.layer == layer) + } + + pub fn locate_joints_inside_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.joints_rtree + .as_ref() + .locate_in_envelope(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + } + pub fn locate_segments_at_point( &self, layer: LayerId, @@ -33,6 +58,31 @@ impl Layout { .filter(move |&segment_id| self.segment(segment_id).contains_point(point)) } + pub fn locate_segments_intersecting_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.segments_rtree + .as_ref() + .locate_in_envelope_intersecting(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + .filter(move |&segment_id| self.segment(segment_id).layer == layer) + } + + pub fn locate_segments_inside_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.segments_rtree + .as_ref() + .locate_in_envelope(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + } + pub fn locate_vias_at_point( &self, layer: LayerId, @@ -45,6 +95,34 @@ impl Layout { .filter(move |&via_id| self.vias[via_id.index()].contains_point(layer, point)) } + pub fn locate_vias_intersecting_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.vias_rtree + .as_ref() + .locate_in_envelope_intersecting(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + .filter(move |&via_id| { + let via = self.via(via_id); + via.min_layer <= layer && layer <= via.max_layer + }) + } + + pub fn locate_vias_inside_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.vias_rtree + .as_ref() + .locate_in_envelope(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + } + pub fn locate_polygons_at_point( &self, layer: LayerId, @@ -56,4 +134,29 @@ impl Layout { .map(|geom_with_data| geom_with_data.data) .filter(move |&polygon_id| self.polygons[polygon_id.index()].contains_point(point)) } + + pub fn locate_polygons_intersecting_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.polygons_rtree + .as_ref() + .locate_in_envelope_intersecting(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + .filter(move |&polygon_id| self.polygon(polygon_id).layer == layer) + } + + pub fn locate_polygons_inside_rect( + &self, + layer: LayerId, + rect: Rect2, + ) -> impl Iterator { + let rect_aabb = rect.aabb3(layer.index() as i64); + self.polygons_rtree + .as_ref() + .locate_in_envelope(&rect_aabb) + .map(|geom_with_data| geom_with_data.data) + } } diff --git a/topola/src/lib.rs b/topola/src/lib.rs index fa6185b..c1d7739 100644 --- a/topola/src/lib.rs +++ b/topola/src/lib.rs @@ -16,12 +16,12 @@ mod specctra; pub use crate::autorouter::Autorouter; pub use crate::board::Board; pub use crate::board::LayerDesc; -pub use crate::board::LayerTier; +pub use crate::board::LayerSide; pub use crate::board::LayerType; pub use crate::board::selections; pub use crate::layout::LayerId; pub use crate::layout::Layout; pub use crate::layout::compounds::{Pin, PinId}; pub use crate::layout::primitives; -pub use crate::math::Vector2; +pub use crate::math::{Rect2, Vector2}; pub use crate::ratsnest::{Ratline, Ratsnest}; diff --git a/topola/src/math.rs b/topola/src/math.rs index c6bc9d8..171d1ff 100644 --- a/topola/src/math.rs +++ b/topola/src/math.rs @@ -2,12 +2,35 @@ // // SPDX-License-Identifier: MIT OR Apache-2.0 +use derive_getters::Getters; use derive_more::{ Add, AddAssign, Constructor, Div, DivAssign, From, Into, Mul, MulAssign, Sub, SubAssign, }; use polygon_unionfind::UnionFind; +use rstar::AABB; use serde::{Deserialize, Serialize}; +#[derive(Clone, Copy, Debug, Deserialize, Eq, Getters, Ord, PartialEq, PartialOrd, Serialize)] +pub struct Rect2 { + min: Vector2, + max: Vector2, +} + +impl Rect2 { + pub fn new(from: Vector2, to: Vector2) -> Self { + Self { + min: Vector2::new(std::cmp::min(from.x, to.x), std::cmp::min(from.y, to.y)), + max: Vector2::new(std::cmp::max(from.x, to.x), std::cmp::max(from.y, to.y)), + } + } +} + +impl Rect2 { + pub fn aabb3(self, z: i64) -> AABB<[i64; 3]> { + AABB::from_corners([self.min.x, self.min.y, z], [self.max.x, self.max.y, z]) + } +} + #[derive( Add, AddAssign, diff --git a/topola/src/specctra.rs b/topola/src/specctra.rs index 5d9ff11..193dbd5 100644 --- a/topola/src/specctra.rs +++ b/topola/src/specctra.rs @@ -11,7 +11,7 @@ use specctra::{ }; use crate::{ - board::{Board, LayerDesc, LayerTier, LayerType}, + board::{Board, LayerDesc, LayerSide, LayerType}, layout::LayerId, layout::compounds::{ComponentId, NetId, PinId}, math::Vector2, @@ -31,11 +31,11 @@ impl Board { BiBTreeMap::from_iter(dsn.pcb.structure.layers.iter().enumerate().map( |(index, _layer)| { let tier = if index == 0 { - LayerTier::Top + LayerSide::Top } else if index + 1 == dsn.pcb.structure.layers.len() { - LayerTier::Bottom + LayerSide::Bottom } else { - LayerTier::Inner + LayerSide::Inner }; ( LayerId::new(index + pcb_layer_offset), @@ -48,7 +48,7 @@ impl Board { top_outline_layer_id, LayerDesc::new( LayerType::Outline, - LayerTier::Top, + LayerSide::Top, top_outline_layer_id.index(), ), ); @@ -56,7 +56,7 @@ impl Board { bottom_outline_layer_id, LayerDesc::new( LayerType::Outline, - LayerTier::Bottom, + LayerSide::Bottom, bottom_outline_layer_id.index(), ), );