Make drag selection interactor take selection modes as input

This commit is contained in:
Mikolaj Wielgus 2026-05-27 00:21:13 +02:00
parent 739bdafea2
commit 51005bb97c
10 changed files with 345 additions and 190 deletions

View File

@ -3,7 +3,10 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use egui::Pos2; use egui::Pos2;
use topola::{CrossingDragSelectionInteractor, InteractiveInput, Vector2}; use topola::{
DragSelectionInteractor, InteractiveInput, SelectionCombineMode, SelectionContainMode,
SelectionOptions, Vector2, Vector3,
};
use crate::{display::Display, workspace::Workspace}; use crate::{display::Display, workspace::Workspace};
@ -11,7 +14,7 @@ pub struct Viewport {
pub scene_rect: egui::Rect, pub scene_rect: egui::Rect,
pub ref_scene_rect: egui::Rect, pub ref_scene_rect: egui::Rect,
pub scheduled_zoom_to_fit: bool, pub scheduled_zoom_to_fit: bool,
crossing_drag_selection_interactor: Option<CrossingDragSelectionInteractor>, drag_selection_interactor: Option<DragSelectionInteractor>,
} }
impl Viewport { impl Viewport {
@ -20,7 +23,7 @@ impl Viewport {
scene_rect: egui::Rect::from_min_max(egui::pos2(-1.0, -1.0), egui::pos2(1.0, 1.0)), scene_rect: egui::Rect::from_min_max(egui::pos2(-1.0, -1.0), egui::pos2(1.0, 1.0)),
ref_scene_rect: egui::Rect::from_min_max(egui::pos2(-1.0, -1.0), egui::pos2(1.0, 1.0)), ref_scene_rect: egui::Rect::from_min_max(egui::pos2(-1.0, -1.0), egui::pos2(1.0, 1.0)),
scheduled_zoom_to_fit: false, scheduled_zoom_to_fit: false,
crossing_drag_selection_interactor: None, drag_selection_interactor: None,
} }
} }
@ -52,7 +55,7 @@ impl Viewport {
if let Some(workspace) = workspace { if let Some(workspace) = workspace {
if ctx.input(|i| i.key_pressed(egui::Key::Escape)) { if ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
self.crossing_drag_selection_interactor = None; self.drag_selection_interactor = None;
} }
let primary_pressed = let primary_pressed =
@ -68,15 +71,21 @@ impl Viewport {
Vector2::new(pointer_scene_pos.x as i64, pointer_scene_pos.y as i64); Vector2::new(pointer_scene_pos.x as i64, pointer_scene_pos.y as i64);
if primary_pressed && response.hovered() { if primary_pressed && response.hovered() {
self.crossing_drag_selection_interactor = self.drag_selection_interactor = Some(DragSelectionInteractor::new(
Some(CrossingDragSelectionInteractor::new(pointer_scene)); pointer_scene,
workspace.selection.clone(),
SelectionOptions::new(
SelectionCombineMode::Replace,
SelectionContainMode::Crossing,
),
));
} }
if let Some(interactor) = self.crossing_drag_selection_interactor.as_mut() { if let Some(interactor) = self.drag_selection_interactor.as_mut() {
if primary_down || primary_released { if primary_down || primary_released {
interactor.update( let _ = interactor.update(
workspace.autorouter.router().navmesher_board().board(), workspace.autorouter.router().navmesher_board().board(),
InteractiveInput::new(pointer_scene), InteractiveInput::new(pointer_scene, false),
); );
} }
} else if response.clicked() { } else if response.clicked() {
@ -85,18 +94,19 @@ impl Viewport {
.router() .router()
.navmesher_board() .navmesher_board()
.board() .board()
.locate_pin_at_point( .locate_pin_at_point(Vector3::new(
workspace.appearance_panel.active, pointer_scene.x,
pointer_scene, pointer_scene.y,
) workspace.appearance_panel.active.index() as i64,
))
{ {
workspace.selection.pins.toggle(pin_selector); workspace.selection.pins.xor(std::iter::once(pin_selector));
} }
} }
} }
if primary_released { if primary_released {
if let Some(interactor) = self.crossing_drag_selection_interactor.take() { if let Some(interactor) = self.drag_selection_interactor.take() {
workspace.selection = interactor.selection().clone(); workspace.selection = interactor.selection().clone();
} }
} }

View File

@ -5,73 +5,115 @@
use derive_getters::Getters; use derive_getters::Getters;
use crate::{ use crate::{
Rect2, Vector2, Rect3, Vector2, Vector3,
board::{Board, interactors::InteractiveInput, selections::PersistableSelection}, board::{
layout::LayerId, Board,
interactors::{
InteractiveInput, SelectionCombineMode, SelectionContainMode, SelectionOptions,
},
selections::PersistableSelection,
},
}; };
#[derive(Clone, Debug, Eq, Getters, Ord, PartialEq, PartialOrd)] #[derive(Clone, Debug, Eq, Getters, Ord, PartialEq, PartialOrd)]
pub struct CrossingDragSelectionInteractor { pub struct DragSelectionInteractor {
origin: Vector2<i64>, origin: Vector2<i64>,
original_selection: PersistableSelection,
selection: PersistableSelection, selection: PersistableSelection,
options: SelectionOptions,
} }
impl CrossingDragSelectionInteractor { impl DragSelectionInteractor {
pub fn new(origin: Vector2<i64>) -> Self { pub fn new(
origin: Vector2<i64>,
original_selection: PersistableSelection,
options: SelectionOptions,
) -> Self {
Self { Self {
origin, origin,
original_selection,
selection: PersistableSelection::new(), selection: PersistableSelection::new(),
options,
} }
} }
pub fn update(&mut self, board: &Board, input: InteractiveInput) { pub fn update(
let rect = Rect2::new(self.origin, input.pointer); &mut self,
board: &Board,
input: InteractiveInput,
) -> Option<PersistableSelection> {
if input.cancel {
self.selection = self.original_selection.clone();
return Some(self.selection.clone());
}
self.selection = PersistableSelection::new(); self.selection = PersistableSelection::new();
for layer_index in 0..*board.layout().layer_count() { for layer_index in 0..*board.layout().layer_count() {
let layer = LayerId::new(layer_index); let rect = Rect3::new(
Vector3::new(self.origin.x, self.origin.y, layer_index as i64),
Vector3::new(input.pointer.x, input.pointer.y, layer_index as i64),
);
for selector in board.locate_components_intersecting_rect(layer, rect) { match self.options.contain {
self.selection.components.0.insert(selector); SelectionContainMode::Crossing => {
self.selection
.components
.add(board.locate_components_intersecting_rect(rect));
}
SelectionContainMode::Window => {
self.selection
.components
.add(board.locate_components_inside_rect(rect));
}
} }
for selector in board.locate_pins_intersecting_rect(layer, rect) { match self.options.contain {
self.selection.pins.0.insert(selector); SelectionContainMode::Crossing => {
self.selection
.pins
.add(board.locate_pins_intersecting_rect(rect));
}
SelectionContainMode::Window => {
self.selection.pins.add(board.locate_pins_inside_rect(rect));
}
} }
} }
}
}
#[derive(Clone, Debug, Eq, Getters, Ord, PartialEq, PartialOrd)] // TODO: There's no need to clone on each update.
pub struct WindowDragSelectionInteractor { let mut combined_selection = self.original_selection.clone();
origin: Vector2<i64>, match self.options.combine {
selection: PersistableSelection, SelectionCombineMode::Replace => {
} combined_selection.components = self.selection.components.clone();
combined_selection.pins = self.selection.pins.clone();
impl WindowDragSelectionInteractor {
pub fn new(origin: Vector2<i64>) -> Self {
Self {
origin,
selection: PersistableSelection::new(),
}
}
pub fn update(&mut self, board: &Board, input: InteractiveInput) {
let rect = Rect2::new(self.origin, input.pointer);
self.selection = PersistableSelection::new();
for layer_index in 0..*board.layout().layer_count() {
let layer = LayerId::new(layer_index);
for selector in board.locate_components_inside_rect(layer, rect) {
self.selection.components.0.insert(selector);
} }
SelectionCombineMode::Additive => {
for selector in board.locate_pins_inside_rect(layer, rect) { combined_selection
self.selection.pins.0.insert(selector); .pins
.add(self.selection.pins.0.iter().cloned());
combined_selection
.components
.add(self.selection.components.0.iter().cloned());
}
SelectionCombineMode::Subtractive => {
combined_selection
.pins
.sub(self.selection.pins.0.iter().cloned());
combined_selection
.components
.sub(self.selection.components.0.iter().cloned());
}
SelectionCombineMode::Toggle => {
combined_selection
.components
.xor(self.selection.components.0.iter().cloned());
combined_selection
.pins
.xor(self.selection.pins.0.iter().cloned());
} }
} }
self.selection = combined_selection;
Some(self.selection.clone())
} }
} }

View File

@ -4,16 +4,40 @@
mod drag_selection; mod drag_selection;
pub use drag_selection::CrossingDragSelectionInteractor; use derive_more::Constructor;
pub use drag_selection::DragSelectionInteractor;
use serde::{Deserialize, Serialize};
use crate::Vector2; use crate::Vector2;
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct InteractiveInput { pub struct InteractiveInput {
pointer: Vector2<i64>, pointer: Vector2<i64>,
cancel: bool,
} }
impl InteractiveInput { impl InteractiveInput {
pub fn new(pointer: Vector2<i64>) -> Self { pub fn new(pointer: Vector2<i64>, cancel: bool) -> Self {
Self { pointer } Self { pointer, cancel }
} }
} }
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub enum SelectionCombineMode {
Replace,
Additive,
Subtractive,
Toggle,
}
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub enum SelectionContainMode {
Crossing,
Window,
}
#[derive(Clone, Constructor, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct SelectionOptions {
combine: SelectionCombineMode,
contain: SelectionContainMode,
}

View File

@ -3,31 +3,26 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{ use crate::{
Rect2, Vector2, Rect3, Vector3,
board::Board, board::Board,
layout::LayerId, selections::{ComponentSelector, NetSelector, PinSelector},
selections::{ComponentSelector, PinSelector},
}; };
impl Board { impl Board {
pub fn locate_component_at_point( pub fn locate_component_at_point(&self, point: Vector3<i64>) -> Option<ComponentSelector> {
&self, if let Some(joint_id) = self.layout.locate_joints_at_point(point).next() {
layer: LayerId,
point: Vector2<i64>,
) -> Option<ComponentSelector> {
if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() {
return self.joint_component_selector(joint_id); return self.joint_component_selector(joint_id);
} }
if let Some(segment_id) = self.layout.locate_segments_at_point(layer, point).next() { if let Some(segment_id) = self.layout.locate_segments_at_point(point).next() {
return self.segment_component_selector(segment_id); return self.segment_component_selector(segment_id);
} }
if let Some(via_id) = self.layout.locate_vias_at_point(layer, point).next() { if let Some(via_id) = self.layout.locate_vias_at_point(point).next() {
return self.via_component_selector(via_id); return self.via_component_selector(via_id);
} }
if let Some(polygon_id) = self.layout.locate_polygons_at_point(layer, point).next() { if let Some(polygon_id) = self.layout.locate_polygons_at_point(point).next() {
return self.polygon_component_selector(polygon_id); return self.polygon_component_selector(polygon_id);
} }
@ -36,68 +31,66 @@ impl Board {
pub fn locate_components_intersecting_rect( pub fn locate_components_intersecting_rect(
&self, &self,
layer: LayerId, rect: Rect3<i64>,
rect: Rect2<i64>,
) -> impl Iterator<Item = ComponentSelector> + '_ { ) -> impl Iterator<Item = ComponentSelector> + '_ {
self.layout self.layout
.locate_joints_intersecting_rect(layer, rect) .locate_joints_intersecting_rect(rect)
.filter_map(|joint_id| self.joint_component_selector(joint_id)) .filter_map(|joint_id| self.joint_component_selector(joint_id))
.chain( .chain(
self.layout self.layout
.locate_segments_intersecting_rect(layer, rect) .locate_segments_intersecting_rect(rect)
.filter_map(|segment_id| self.segment_component_selector(segment_id)), .filter_map(|segment_id| self.segment_component_selector(segment_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_vias_intersecting_rect(layer, rect) .locate_vias_intersecting_rect(rect)
.filter_map(|via_id| self.via_component_selector(via_id)), .filter_map(|via_id| self.via_component_selector(via_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_polygons_intersecting_rect(layer, rect) .locate_polygons_intersecting_rect(rect)
.filter_map(|polygon_id| self.polygon_component_selector(polygon_id)), .filter_map(|polygon_id| self.polygon_component_selector(polygon_id)),
) )
} }
pub fn locate_components_inside_rect( pub fn locate_components_inside_rect(
&self, &self,
layer: LayerId, rect: Rect3<i64>,
rect: Rect2<i64>,
) -> impl Iterator<Item = ComponentSelector> + '_ { ) -> impl Iterator<Item = ComponentSelector> + '_ {
self.layout self.layout
.locate_joints_inside_rect(layer, rect) .locate_joints_inside_rect(rect)
.filter_map(|joint_id| self.joint_component_selector(joint_id)) .filter_map(|joint_id| self.joint_component_selector(joint_id))
.chain( .chain(
self.layout self.layout
.locate_segments_inside_rect(layer, rect) .locate_segments_inside_rect(rect)
.filter_map(|segment_id| self.segment_component_selector(segment_id)), .filter_map(|segment_id| self.segment_component_selector(segment_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_vias_inside_rect(layer, rect) .locate_vias_inside_rect(rect)
.filter_map(|via_id| self.via_component_selector(via_id)), .filter_map(|via_id| self.via_component_selector(via_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_polygons_inside_rect(layer, rect) .locate_polygons_inside_rect(rect)
.filter_map(|polygon_id| self.polygon_component_selector(polygon_id)), .filter_map(|polygon_id| self.polygon_component_selector(polygon_id)),
) )
} }
pub fn locate_pin_at_point(&self, layer: LayerId, point: Vector2<i64>) -> Option<PinSelector> { pub fn locate_pin_at_point(&self, point: Vector3<i64>) -> Option<PinSelector> {
if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() { if let Some(joint_id) = self.layout.locate_joints_at_point(point).next() {
return self.joint_pin_selector(joint_id); return self.joint_pin_selector(joint_id);
} }
if let Some(segment_id) = self.layout.locate_segments_at_point(layer, point).next() { if let Some(segment_id) = self.layout.locate_segments_at_point(point).next() {
return self.segment_pin_selector(segment_id); return self.segment_pin_selector(segment_id);
} }
if let Some(via_id) = self.layout.locate_vias_at_point(layer, point).next() { if let Some(via_id) = self.layout.locate_vias_at_point(point).next() {
return self.via_pin_selector(via_id); return self.via_pin_selector(via_id);
} }
if let Some(polygon_id) = self.layout.locate_polygons_at_point(layer, point).next() { if let Some(polygon_id) = self.layout.locate_polygons_at_point(point).next() {
return self.polygon_pin_selector(polygon_id); return self.polygon_pin_selector(polygon_id);
} }
@ -106,51 +99,73 @@ impl Board {
pub fn locate_pins_intersecting_rect( pub fn locate_pins_intersecting_rect(
&self, &self,
layer: LayerId, rect: Rect3<i64>,
rect: Rect2<i64>,
) -> impl Iterator<Item = PinSelector> + '_ { ) -> impl Iterator<Item = PinSelector> + '_ {
self.layout self.layout
.locate_joints_intersecting_rect(layer, rect) .locate_joints_intersecting_rect(rect)
.filter_map(|joint_id| self.joint_pin_selector(joint_id)) .filter_map(|joint_id| self.joint_pin_selector(joint_id))
.chain( .chain(
self.layout self.layout
.locate_segments_intersecting_rect(layer, rect) .locate_segments_intersecting_rect(rect)
.filter_map(|segment_id| self.segment_pin_selector(segment_id)), .filter_map(|segment_id| self.segment_pin_selector(segment_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_vias_intersecting_rect(layer, rect) .locate_vias_intersecting_rect(rect)
.filter_map(|via_id| self.via_pin_selector(via_id)), .filter_map(|via_id| self.via_pin_selector(via_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_polygons_intersecting_rect(layer, rect) .locate_polygons_intersecting_rect(rect)
.filter_map(|polygon_id| self.polygon_pin_selector(polygon_id)), .filter_map(|polygon_id| self.polygon_pin_selector(polygon_id)),
) )
} }
pub fn locate_pins_inside_rect( pub fn locate_pins_inside_rect(
&self, &self,
layer: LayerId, rect: Rect3<i64>,
rect: Rect2<i64>,
) -> impl Iterator<Item = PinSelector> + '_ { ) -> impl Iterator<Item = PinSelector> + '_ {
self.layout self.layout
.locate_joints_inside_rect(layer, rect) .locate_joints_inside_rect(rect)
.filter_map(|joint_id| self.joint_pin_selector(joint_id)) .filter_map(|joint_id| self.joint_pin_selector(joint_id))
.chain( .chain(
self.layout self.layout
.locate_segments_inside_rect(layer, rect) .locate_segments_inside_rect(rect)
.filter_map(|segment_id| self.segment_pin_selector(segment_id)), .filter_map(|segment_id| self.segment_pin_selector(segment_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_vias_inside_rect(layer, rect) .locate_vias_inside_rect(rect)
.filter_map(|via_id| self.via_pin_selector(via_id)), .filter_map(|via_id| self.via_pin_selector(via_id)),
) )
.chain( .chain(
self.layout self.layout
.locate_polygons_inside_rect(layer, rect) .locate_polygons_inside_rect(rect)
.filter_map(|polygon_id| self.polygon_pin_selector(polygon_id)), .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

@ -20,11 +20,23 @@ impl ComponentSelection {
Default::default() Default::default()
} }
pub fn toggle(&mut self, selector: ComponentSelector) { pub fn add(&mut self, selectors: impl IntoIterator<Item = ComponentSelector>) {
if self.0.contains(&selector) { self.0.extend(selectors);
}
pub fn sub(&mut self, selectors: impl IntoIterator<Item = ComponentSelector>) {
for selector in selectors {
self.0.remove(&selector); self.0.remove(&selector);
} else { }
self.0.insert(selector); }
pub fn xor(&mut self, selectors: impl IntoIterator<Item = ComponentSelector>) {
for selector in selectors {
if self.0.contains(&selector) {
self.0.remove(&selector);
} else {
self.0.insert(selector);
}
} }
} }
} }

View File

@ -25,11 +25,23 @@ impl NetSelection {
Default::default() Default::default()
} }
pub fn toggle(&mut self, selector: NetSelector) { pub fn add(&mut self, selectors: impl IntoIterator<Item = NetSelector>) {
if self.0.contains(&selector) { self.0.extend(selectors);
}
pub fn sub(&mut self, selectors: impl IntoIterator<Item = NetSelector>) {
for selector in selectors {
self.0.remove(&selector); self.0.remove(&selector);
} else { }
self.0.insert(selector); }
pub fn xor(&mut self, selectors: impl IntoIterator<Item = NetSelector>) {
for selector in selectors {
if self.0.contains(&selector) {
self.0.remove(&selector);
} else {
self.0.insert(selector);
}
} }
} }
} }

View File

@ -23,11 +23,23 @@ impl PinSelection {
Default::default() Default::default()
} }
pub fn toggle(&mut self, selector: PinSelector) { pub fn add(&mut self, selectors: impl IntoIterator<Item = PinSelector>) {
if self.0.contains(&selector) { self.0.extend(selectors);
}
pub fn sub(&mut self, selectors: impl IntoIterator<Item = PinSelector>) {
for selector in selectors {
self.0.remove(&selector); self.0.remove(&selector);
} else { }
self.0.insert(selector); }
pub fn xor(&mut self, selectors: impl IntoIterator<Item = PinSelector>) {
for selector in selectors {
if self.0.contains(&selector) {
self.0.remove(&selector);
} else {
self.0.insert(selector);
}
} }
} }
} }

View File

@ -3,157 +3,116 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{ use crate::{
Rect2, Vector2, Rect3, Vector3,
layout::{LayerId, Layout}, layout::{LayerId, Layout},
primitives::{JointId, PolygonId, SegmentId, ViaId}, primitives::{JointId, PolygonId, SegmentId, ViaId},
}; };
impl Layout { impl Layout {
pub fn locate_joints_at_point( pub fn locate_joints_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = JointId> {
&self, let point2 = point.xy();
layer: LayerId,
point: Vector2<i64>,
) -> impl Iterator<Item = JointId> {
self.joints_rtree self.joints_rtree
.as_ref() .as_ref()
.locate_all_at_point(&[point.x, point.y, layer.index() as i64]) .locate_all_at_point(&[point.x, point.y, point.z])
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
.filter(move |&joint_id| self.joints[joint_id.index()].contains_point(point)) .filter(move |&joint_id| self.joints[joint_id.index()].contains_point(point2))
} }
pub fn locate_joints_intersecting_rect( pub fn locate_joints_intersecting_rect(
&self, &self,
layer: LayerId, rect: Rect3<i64>,
rect: Rect2<i64>,
) -> impl Iterator<Item = JointId> { ) -> impl Iterator<Item = JointId> {
let rect_aabb = rect.aabb3(layer.index() as i64); let rect_aabb = rect.aabb3();
self.joints_rtree self.joints_rtree
.as_ref() .as_ref()
.locate_in_envelope_intersecting(&rect_aabb) .locate_in_envelope_intersecting(&rect_aabb)
.map(|geom_with_data| geom_with_data.data) .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( pub fn locate_joints_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = JointId> {
&self, let rect_aabb = rect.aabb3();
layer: LayerId,
rect: Rect2<i64>,
) -> impl Iterator<Item = JointId> {
let rect_aabb = rect.aabb3(layer.index() as i64);
self.joints_rtree self.joints_rtree
.as_ref() .as_ref()
.locate_in_envelope(&rect_aabb) .locate_in_envelope(&rect_aabb)
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
} }
pub fn locate_segments_at_point( pub fn locate_segments_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = SegmentId> {
&self, let point2 = point.xy();
layer: LayerId,
point: Vector2<i64>,
) -> impl Iterator<Item = SegmentId> {
self.segments_rtree self.segments_rtree
.as_ref() .as_ref()
.locate_all_at_point(&[point.x, point.y, layer.index() as i64]) .locate_all_at_point(&[point.x, point.y, point.z])
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
.filter(move |&segment_id| self.segment(segment_id).contains_point(point)) .filter(move |&segment_id| self.segment(segment_id).contains_point(point2))
} }
pub fn locate_segments_intersecting_rect( pub fn locate_segments_intersecting_rect(
&self, &self,
layer: LayerId, rect: Rect3<i64>,
rect: Rect2<i64>,
) -> impl Iterator<Item = SegmentId> { ) -> impl Iterator<Item = SegmentId> {
let rect_aabb = rect.aabb3(layer.index() as i64); let rect_aabb = rect.aabb3();
self.segments_rtree self.segments_rtree
.as_ref() .as_ref()
.locate_in_envelope_intersecting(&rect_aabb) .locate_in_envelope_intersecting(&rect_aabb)
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
.filter(move |&segment_id| self.segment(segment_id).layer == layer)
} }
pub fn locate_segments_inside_rect( pub fn locate_segments_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = SegmentId> {
&self, let rect_aabb = rect.aabb3();
layer: LayerId,
rect: Rect2<i64>,
) -> impl Iterator<Item = SegmentId> {
let rect_aabb = rect.aabb3(layer.index() as i64);
self.segments_rtree self.segments_rtree
.as_ref() .as_ref()
.locate_in_envelope(&rect_aabb) .locate_in_envelope(&rect_aabb)
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
} }
pub fn locate_vias_at_point( pub fn locate_vias_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = ViaId> {
&self, let layer = LayerId::new(point.z as usize);
layer: LayerId, let point2 = point.xy();
point: Vector2<i64>,
) -> impl Iterator<Item = ViaId> {
self.vias_rtree self.vias_rtree
.as_ref() .as_ref()
.locate_all_at_point(&[point.x, point.y, layer.index() as i64]) .locate_all_at_point(&[point.x, point.y, point.z])
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
.filter(move |&via_id| self.vias[via_id.index()].contains_point(layer, point)) .filter(move |&via_id| self.vias[via_id.index()].contains_point(layer, point2))
} }
pub fn locate_vias_intersecting_rect( pub fn locate_vias_intersecting_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = ViaId> {
&self, let rect_aabb = rect.aabb3();
layer: LayerId,
rect: Rect2<i64>,
) -> impl Iterator<Item = ViaId> {
let rect_aabb = rect.aabb3(layer.index() as i64);
self.vias_rtree self.vias_rtree
.as_ref() .as_ref()
.locate_in_envelope_intersecting(&rect_aabb) .locate_in_envelope_intersecting(&rect_aabb)
.map(|geom_with_data| geom_with_data.data) .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( pub fn locate_vias_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = ViaId> {
&self, let rect_aabb = rect.aabb3();
layer: LayerId,
rect: Rect2<i64>,
) -> impl Iterator<Item = ViaId> {
let rect_aabb = rect.aabb3(layer.index() as i64);
self.vias_rtree self.vias_rtree
.as_ref() .as_ref()
.locate_in_envelope(&rect_aabb) .locate_in_envelope(&rect_aabb)
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
} }
pub fn locate_polygons_at_point( pub fn locate_polygons_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = PolygonId> {
&self, let point2 = point.xy();
layer: LayerId,
point: Vector2<i64>,
) -> impl Iterator<Item = PolygonId> {
self.polygons_rtree self.polygons_rtree
.as_ref() .as_ref()
.locate_all_at_point(&[point.x, point.y, layer.index() as i64]) .locate_all_at_point(&[point.x, point.y, point.z])
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
.filter(move |&polygon_id| self.polygons[polygon_id.index()].contains_point(point)) .filter(move |&polygon_id| self.polygons[polygon_id.index()].contains_point(point2))
} }
pub fn locate_polygons_intersecting_rect( pub fn locate_polygons_intersecting_rect(
&self, &self,
layer: LayerId, rect: Rect3<i64>,
rect: Rect2<i64>,
) -> impl Iterator<Item = PolygonId> { ) -> impl Iterator<Item = PolygonId> {
let rect_aabb = rect.aabb3(layer.index() as i64); let rect_aabb = rect.aabb3();
self.polygons_rtree self.polygons_rtree
.as_ref() .as_ref()
.locate_in_envelope_intersecting(&rect_aabb) .locate_in_envelope_intersecting(&rect_aabb)
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
.filter(move |&polygon_id| self.polygon(polygon_id).layer == layer)
} }
pub fn locate_polygons_inside_rect( pub fn locate_polygons_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = PolygonId> {
&self, let rect_aabb = rect.aabb3();
layer: LayerId,
rect: Rect2<i64>,
) -> impl Iterator<Item = PolygonId> {
let rect_aabb = rect.aabb3(layer.index() as i64);
self.polygons_rtree self.polygons_rtree
.as_ref() .as_ref()
.locate_in_envelope(&rect_aabb) .locate_in_envelope(&rect_aabb)

View File

@ -18,11 +18,14 @@ pub use crate::board::Board;
pub use crate::board::LayerDesc; pub use crate::board::LayerDesc;
pub use crate::board::LayerSide; pub use crate::board::LayerSide;
pub use crate::board::LayerType; pub use crate::board::LayerType;
pub use crate::board::interactors::{CrossingDragSelectionInteractor, InteractiveInput}; pub use crate::board::interactors::{
DragSelectionInteractor, InteractiveInput, SelectionCombineMode, SelectionContainMode,
SelectionOptions,
};
pub use crate::board::selections; pub use crate::board::selections;
pub use crate::layout::LayerId; pub use crate::layout::LayerId;
pub use crate::layout::Layout; pub use crate::layout::Layout;
pub use crate::layout::compounds::{Pin, PinId}; pub use crate::layout::compounds::{Pin, PinId};
pub use crate::layout::primitives; pub use crate::layout::primitives;
pub use crate::math::{Rect2, Vector2}; pub use crate::math::{Rect2, Rect3, Vector2, Vector3};
pub use crate::ratsnest::{Ratline, Ratsnest}; pub use crate::ratsnest::{Ratline, Ratsnest};

View File

@ -31,6 +31,38 @@ impl Rect2<i64> {
} }
} }
#[derive(Clone, Copy, Debug, Deserialize, Eq, Getters, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Rect3<T> {
min: Vector3<T>,
max: Vector3<T>,
}
impl<T: Ord + Copy> Rect3<T> {
pub fn new(from: Vector3<T>, to: Vector3<T>) -> Self {
Self {
min: Vector3::new(
std::cmp::min(from.x, to.x),
std::cmp::min(from.y, to.y),
std::cmp::min(from.z, to.z),
),
max: Vector3::new(
std::cmp::max(from.x, to.x),
std::cmp::max(from.y, to.y),
std::cmp::max(from.z, to.z),
),
}
}
}
impl Rect3<i64> {
pub fn aabb3(self) -> AABB<[i64; 3]> {
AABB::from_corners(
[self.min.x, self.min.y, self.min.z],
[self.max.x, self.max.y, self.max.z],
)
}
}
#[derive( #[derive(
Add, Add,
AddAssign, AddAssign,
@ -58,6 +90,40 @@ pub struct Vector2<T> {
pub y: T, pub y: T,
} }
#[derive(
Add,
AddAssign,
Clone,
Constructor,
Copy,
Debug,
Deserialize,
Div,
DivAssign,
Eq,
From,
Into,
Mul,
MulAssign,
Ord,
PartialEq,
PartialOrd,
Serialize,
Sub,
SubAssign,
)]
pub struct Vector3<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<T: Copy> Vector3<T> {
pub fn xy(self) -> Vector2<T> {
Vector2::new(self.x, self.y)
}
}
impl<T: Copy> From<[T; 2]> for Vector2<T> { impl<T: Copy> From<[T; 2]> for Vector2<T> {
fn from(from: [T; 2]) -> Self { fn from(from: [T; 2]) -> Self {
Self { Self {