Implement selection of nets

This commit is contained in:
Mikolaj Wielgus 2026-05-27 00:45:30 +02:00
parent 51005bb97c
commit 15a7bc65f1
6 changed files with 215 additions and 38 deletions

View File

@ -46,6 +46,8 @@ impl Display {
for joint_id in layout.layer_joints(layer) {
let joint = layout.joint(joint_id);
let pin_selected = board.pins_contain_joint(&workspace.selection.pins, joint_id);
let net_selected = board.nets_contain_joint(&workspace.selection.nets, joint_id);
self.paint_joint(
ctx,
ui,
@ -54,13 +56,17 @@ impl Display {
workspace.appearance_panel.layer_color(
ctx,
board.layer_desc(joint.spec.layer),
board.pins_contain_joint(&workspace.selection.pins, joint_id),
pin_selected || (joint.spec.pin.is_none() && net_selected),
),
);
}
for segment_id in layout.layer_segments(layer) {
let segment = layout.segment(segment_id);
let pin_selected =
board.pins_contain_segment(&workspace.selection.pins, segment_id);
let net_selected =
board.nets_contain_segment(&workspace.selection.nets, segment_id);
self.paint_segment(
ctx,
ui,
@ -69,13 +75,15 @@ impl Display {
workspace.appearance_panel.layer_color(
ctx,
board.layer_desc(segment.layer),
board.pins_contain_segment(&workspace.selection.pins, segment_id),
pin_selected || (segment.spec.pin.is_none() && net_selected),
),
);
}
for via_id in layout.layer_vias(layer) {
let via = layout.via(via_id);
let pin_selected = board.pins_contain_via(&workspace.selection.pins, via_id);
let net_selected = board.nets_contain_via(&workspace.selection.nets, via_id);
self.paint_via(
ctx,
ui,
@ -84,13 +92,17 @@ impl Display {
workspace.appearance_panel.layer_color(
ctx,
board.layer_desc(layer),
board.pins_contain_via(&workspace.selection.pins, via_id),
pin_selected || (via.spec.pin.is_none() && net_selected),
),
);
}
for polygon_id in layout.layer_polygons(layer) {
let polygon = layout.polygon(polygon_id);
let pin_selected =
board.pins_contain_polygon(&workspace.selection.pins, polygon_id);
let net_selected =
board.nets_contain_polygon(&workspace.selection.nets, polygon_id);
self.paint_polygon(
ctx,
ui,
@ -99,7 +111,7 @@ impl Display {
workspace.appearance_panel.layer_color(
ctx,
board.layer_desc(polygon.layer),
board.pins_contain_polygon(&workspace.selection.pins, polygon_id),
pin_selected || (polygon.pin.is_none() && net_selected),
),
);
}

View File

@ -81,14 +81,7 @@ impl Viewport {
));
}
if let Some(interactor) = self.drag_selection_interactor.as_mut() {
if primary_down || primary_released {
let _ = interactor.update(
workspace.autorouter.router().navmesher_board().board(),
InteractiveInput::new(pointer_scene, false),
);
}
} else if response.clicked() {
if response.clicked() {
if let Some(pin_selector) = workspace
.autorouter
.router()
@ -102,6 +95,13 @@ impl Viewport {
{
workspace.selection.pins.xor(std::iter::once(pin_selector));
}
} else if let Some(interactor) = self.drag_selection_interactor.as_mut() {
if primary_down || primary_released {
let _ = interactor.update(
workspace.autorouter.router().navmesher_board().board(),
InteractiveInput::new(pointer_scene, false),
);
}
}
}

View File

@ -68,6 +68,17 @@ impl DragSelectionInteractor {
}
}
match self.options.contain {
SelectionContainMode::Crossing => {
self.selection
.nets
.add(board.locate_nets_intersecting_rect(rect));
}
SelectionContainMode::Window => {
self.selection.nets.add(board.locate_nets_inside_rect(rect));
}
}
match self.options.contain {
SelectionContainMode::Crossing => {
self.selection
@ -85,12 +96,16 @@ impl DragSelectionInteractor {
match self.options.combine {
SelectionCombineMode::Replace => {
combined_selection.components = self.selection.components.clone();
combined_selection.nets = self.selection.nets.clone();
combined_selection.pins = self.selection.pins.clone();
}
SelectionCombineMode::Additive => {
combined_selection
.pins
.add(self.selection.pins.0.iter().cloned());
combined_selection
.nets
.add(self.selection.nets.0.iter().cloned());
combined_selection
.components
.add(self.selection.components.0.iter().cloned());
@ -99,6 +114,9 @@ impl DragSelectionInteractor {
combined_selection
.pins
.sub(self.selection.pins.0.iter().cloned());
combined_selection
.nets
.sub(self.selection.nets.0.iter().cloned());
combined_selection
.components
.sub(self.selection.components.0.iter().cloned());
@ -107,6 +125,9 @@ impl DragSelectionInteractor {
combined_selection
.components
.xor(self.selection.components.0.iter().cloned());
combined_selection
.nets
.xor(self.selection.nets.0.iter().cloned());
combined_selection
.pins
.xor(self.selection.pins.0.iter().cloned());

View File

@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::collections::BTreeSet;
use crate::{
Rect3, Vector3,
board::Board,
@ -77,6 +79,57 @@ impl Board {
)
}
pub fn locate_nets_at_point(
&self,
point: Vector3<i64>,
) -> impl Iterator<Item = NetSelector> + '_ {
let mut selectors = BTreeSet::new();
for net_id in self.layout.locate_nets_at_point(point) {
let Some(net_name) = self.net_name(net_id) else {
continue;
};
selectors.insert(NetSelector::new(net_name.to_string()));
}
selectors.into_iter()
}
pub fn locate_nets_intersecting_rect(
&self,
rect: Rect3<i64>,
) -> impl Iterator<Item = NetSelector> + '_ {
let mut selectors = BTreeSet::new();
for net_id in self.layout.locate_nets_intersecting_rect(rect) {
let Some(net_name) = self.net_name(net_id) else {
continue;
};
selectors.insert(NetSelector::new(net_name.to_string()));
}
selectors.into_iter()
}
pub fn locate_nets_inside_rect(
&self,
rect: Rect3<i64>,
) -> impl Iterator<Item = NetSelector> + '_ {
let mut selectors = BTreeSet::new();
for net_id in self.layout.locate_nets_inside_rect(rect) {
let Some(net_name) = self.net_name(net_id) else {
continue;
};
selectors.insert(NetSelector::new(net_name.to_string()));
}
selectors.into_iter()
}
pub fn locate_pin_at_point(&self, point: Vector3<i64>) -> Option<PinSelector> {
if let Some(joint_id) = self.layout.locate_joints_at_point(point).next() {
return self.joint_pin_selector(joint_id);
@ -144,28 +197,4 @@ impl Board {
.filter_map(|polygon_id| self.polygon_pin_selector(polygon_id)),
)
}
pub fn locate_nets_at_point(
&self,
_point: Vector3<i64>,
) -> impl Iterator<Item = NetSelector> + '_ {
// TODO
std::iter::empty()
}
pub fn locate_nets_intersecting_rect(
&self,
_rect: Rect3<i64>,
) -> impl Iterator<Item = NetSelector> + '_ {
// TODO
std::iter::empty()
}
pub fn locate_nets_inside_rect(
&self,
_rect: Rect3<i64>,
) -> impl Iterator<Item = NetSelector> + '_ {
// TODO
std::iter::empty()
}
}

View File

@ -5,7 +5,10 @@
use crate::{
board::{
Board,
selections::{ComponentSelection, ComponentSelector, PinSelection, PinSelector},
selections::{
ComponentSelection, ComponentSelector, NetSelection, NetSelector, PinSelection,
PinSelector,
},
},
primitives::{JointId, PolygonId, SegmentId, ViaId},
};
@ -147,6 +150,50 @@ impl Board {
})
}
pub fn nets_contain_joint(&self, selection: &NetSelection, id: JointId) -> bool {
let joint = self.layout.joint(id);
let Some(net_name) = self.net_name(joint.spec.net) else {
return false;
};
selection
.0
.contains(&NetSelector::new(net_name.to_string()))
}
pub fn nets_contain_segment(&self, selection: &NetSelection, id: SegmentId) -> bool {
let segment = self.layout.segment(id);
let Some(net_name) = self.net_name(segment.net) else {
return false;
};
selection
.0
.contains(&NetSelector::new(net_name.to_string()))
}
pub fn nets_contain_via(&self, selection: &NetSelection, id: ViaId) -> bool {
let via = self.layout.via(id);
let Some(net_name) = self.net_name(via.net) else {
return false;
};
selection
.0
.contains(&NetSelector::new(net_name.to_string()))
}
pub fn nets_contain_polygon(&self, selection: &NetSelection, id: PolygonId) -> bool {
let polygon = self.layout.polygon(id);
let Some(net_name) = self.net_name(polygon.net) else {
return false;
};
selection
.0
.contains(&NetSelector::new(net_name.to_string()))
}
pub fn pins_contain_joint(&self, selection: &PinSelection, id: JointId) -> bool {
let Some(selector) = self.joint_pin_selector(id) else {
return false;

View File

@ -2,9 +2,11 @@
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use std::collections::BTreeSet;
use crate::{
Rect3, Vector3,
layout::{LayerId, Layout},
layout::{LayerId, Layout, compounds::NetId},
primitives::{JointId, PolygonId, SegmentId, ViaId},
};
@ -118,4 +120,70 @@ impl Layout {
.locate_in_envelope(&rect_aabb)
.map(|geom_with_data| geom_with_data.data)
}
pub fn locate_nets_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = NetId> {
let mut nets = BTreeSet::new();
for joint_id in self.locate_joints_at_point(point) {
nets.insert(self.joint(joint_id).spec.net);
}
for segment_id in self.locate_segments_at_point(point) {
nets.insert(self.segment(segment_id).net);
}
for via_id in self.locate_vias_at_point(point) {
nets.insert(self.via(via_id).net);
}
for polygon_id in self.locate_polygons_at_point(point) {
nets.insert(self.polygon(polygon_id).net);
}
nets.into_iter()
}
pub fn locate_nets_intersecting_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = NetId> {
let mut nets = BTreeSet::new();
for joint_id in self.locate_joints_intersecting_rect(rect) {
nets.insert(self.joint(joint_id).spec.net);
}
for segment_id in self.locate_segments_intersecting_rect(rect) {
nets.insert(self.segment(segment_id).net);
}
for via_id in self.locate_vias_intersecting_rect(rect) {
nets.insert(self.via(via_id).net);
}
for polygon_id in self.locate_polygons_intersecting_rect(rect) {
nets.insert(self.polygon(polygon_id).net);
}
nets.into_iter()
}
pub fn locate_nets_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = NetId> {
let mut nets = BTreeSet::new();
for joint_id in self.locate_joints_inside_rect(rect) {
nets.insert(self.joint(joint_id).spec.net);
}
for segment_id in self.locate_segments_inside_rect(rect) {
nets.insert(self.segment(segment_id).net);
}
for via_id in self.locate_vias_inside_rect(rect) {
nets.insert(self.via(via_id).net);
}
for polygon_id in self.locate_polygons_inside_rect(rect) {
nets.insert(self.polygon(polygon_id).net);
}
nets.into_iter()
}
}