mirror of https://codeberg.org/topola/topola.git
Make drag selection interactor take selection modes as input
This commit is contained in:
parent
739bdafea2
commit
51005bb97c
|
|
@ -3,7 +3,10 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use egui::Pos2;
|
||||
use topola::{CrossingDragSelectionInteractor, InteractiveInput, Vector2};
|
||||
use topola::{
|
||||
DragSelectionInteractor, InteractiveInput, SelectionCombineMode, SelectionContainMode,
|
||||
SelectionOptions, Vector2, Vector3,
|
||||
};
|
||||
|
||||
use crate::{display::Display, workspace::Workspace};
|
||||
|
||||
|
|
@ -11,7 +14,7 @@ pub struct Viewport {
|
|||
pub scene_rect: egui::Rect,
|
||||
pub ref_scene_rect: egui::Rect,
|
||||
pub scheduled_zoom_to_fit: bool,
|
||||
crossing_drag_selection_interactor: Option<CrossingDragSelectionInteractor>,
|
||||
drag_selection_interactor: Option<DragSelectionInteractor>,
|
||||
}
|
||||
|
||||
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)),
|
||||
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,
|
||||
crossing_drag_selection_interactor: None,
|
||||
drag_selection_interactor: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +55,7 @@ impl Viewport {
|
|||
|
||||
if let Some(workspace) = workspace {
|
||||
if ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
|
||||
self.crossing_drag_selection_interactor = None;
|
||||
self.drag_selection_interactor = None;
|
||||
}
|
||||
|
||||
let primary_pressed =
|
||||
|
|
@ -68,15 +71,21 @@ impl Viewport {
|
|||
Vector2::new(pointer_scene_pos.x as i64, pointer_scene_pos.y as i64);
|
||||
|
||||
if primary_pressed && response.hovered() {
|
||||
self.crossing_drag_selection_interactor =
|
||||
Some(CrossingDragSelectionInteractor::new(pointer_scene));
|
||||
self.drag_selection_interactor = Some(DragSelectionInteractor::new(
|
||||
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 {
|
||||
interactor.update(
|
||||
let _ = interactor.update(
|
||||
workspace.autorouter.router().navmesher_board().board(),
|
||||
InteractiveInput::new(pointer_scene),
|
||||
InteractiveInput::new(pointer_scene, false),
|
||||
);
|
||||
}
|
||||
} else if response.clicked() {
|
||||
|
|
@ -85,18 +94,19 @@ impl Viewport {
|
|||
.router()
|
||||
.navmesher_board()
|
||||
.board()
|
||||
.locate_pin_at_point(
|
||||
workspace.appearance_panel.active,
|
||||
pointer_scene,
|
||||
)
|
||||
.locate_pin_at_point(Vector3::new(
|
||||
pointer_scene.x,
|
||||
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 let Some(interactor) = self.crossing_drag_selection_interactor.take() {
|
||||
if let Some(interactor) = self.drag_selection_interactor.take() {
|
||||
workspace.selection = interactor.selection().clone();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,73 +5,115 @@
|
|||
use derive_getters::Getters;
|
||||
|
||||
use crate::{
|
||||
Rect2, Vector2,
|
||||
board::{Board, interactors::InteractiveInput, selections::PersistableSelection},
|
||||
layout::LayerId,
|
||||
Rect3, Vector2, Vector3,
|
||||
board::{
|
||||
Board,
|
||||
interactors::{
|
||||
InteractiveInput, SelectionCombineMode, SelectionContainMode, SelectionOptions,
|
||||
},
|
||||
selections::PersistableSelection,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Eq, Getters, Ord, PartialEq, PartialOrd)]
|
||||
pub struct CrossingDragSelectionInteractor {
|
||||
pub struct DragSelectionInteractor {
|
||||
origin: Vector2<i64>,
|
||||
original_selection: PersistableSelection,
|
||||
selection: PersistableSelection,
|
||||
options: SelectionOptions,
|
||||
}
|
||||
|
||||
impl CrossingDragSelectionInteractor {
|
||||
pub fn new(origin: Vector2<i64>) -> Self {
|
||||
impl DragSelectionInteractor {
|
||||
pub fn new(
|
||||
origin: Vector2<i64>,
|
||||
original_selection: PersistableSelection,
|
||||
options: SelectionOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
origin,
|
||||
original_selection,
|
||||
selection: PersistableSelection::new(),
|
||||
options,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, board: &Board, input: InteractiveInput) {
|
||||
let rect = Rect2::new(self.origin, input.pointer);
|
||||
pub fn update(
|
||||
&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();
|
||||
|
||||
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) {
|
||||
self.selection.components.0.insert(selector);
|
||||
match self.options.contain {
|
||||
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) {
|
||||
self.selection.pins.0.insert(selector);
|
||||
match self.options.contain {
|
||||
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)]
|
||||
pub struct WindowDragSelectionInteractor {
|
||||
origin: Vector2<i64>,
|
||||
selection: PersistableSelection,
|
||||
}
|
||||
|
||||
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);
|
||||
// TODO: There's no need to clone on each update.
|
||||
let mut combined_selection = self.original_selection.clone();
|
||||
match self.options.combine {
|
||||
SelectionCombineMode::Replace => {
|
||||
combined_selection.components = self.selection.components.clone();
|
||||
combined_selection.pins = self.selection.pins.clone();
|
||||
}
|
||||
|
||||
for selector in board.locate_pins_inside_rect(layer, rect) {
|
||||
self.selection.pins.0.insert(selector);
|
||||
SelectionCombineMode::Additive => {
|
||||
combined_selection
|
||||
.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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,40 @@
|
|||
|
||||
mod drag_selection;
|
||||
|
||||
pub use drag_selection::CrossingDragSelectionInteractor;
|
||||
use derive_more::Constructor;
|
||||
pub use drag_selection::DragSelectionInteractor;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::Vector2;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
pub struct InteractiveInput {
|
||||
pointer: Vector2<i64>,
|
||||
cancel: bool,
|
||||
}
|
||||
|
||||
impl InteractiveInput {
|
||||
pub fn new(pointer: Vector2<i64>) -> Self {
|
||||
Self { pointer }
|
||||
pub fn new(pointer: Vector2<i64>, cancel: bool) -> Self {
|
||||
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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,31 +3,26 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{
|
||||
Rect2, Vector2,
|
||||
Rect3, Vector3,
|
||||
board::Board,
|
||||
layout::LayerId,
|
||||
selections::{ComponentSelector, PinSelector},
|
||||
selections::{ComponentSelector, NetSelector, PinSelector},
|
||||
};
|
||||
|
||||
impl Board {
|
||||
pub fn locate_component_at_point(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
point: Vector2<i64>,
|
||||
) -> Option<ComponentSelector> {
|
||||
if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() {
|
||||
pub fn locate_component_at_point(&self, point: Vector3<i64>) -> Option<ComponentSelector> {
|
||||
if let Some(joint_id) = self.layout.locate_joints_at_point(point).next() {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -36,68 +31,66 @@ impl Board {
|
|||
|
||||
pub fn locate_components_intersecting_rect(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
rect: Rect3<i64>,
|
||||
) -> impl Iterator<Item = ComponentSelector> + '_ {
|
||||
self.layout
|
||||
.locate_joints_intersecting_rect(layer, rect)
|
||||
.locate_joints_intersecting_rect(rect)
|
||||
.filter_map(|joint_id| self.joint_component_selector(joint_id))
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_segments_intersecting_rect(layer, rect)
|
||||
.locate_segments_intersecting_rect(rect)
|
||||
.filter_map(|segment_id| self.segment_component_selector(segment_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_vias_intersecting_rect(layer, rect)
|
||||
.locate_vias_intersecting_rect(rect)
|
||||
.filter_map(|via_id| self.via_component_selector(via_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_polygons_intersecting_rect(layer, rect)
|
||||
.locate_polygons_intersecting_rect(rect)
|
||||
.filter_map(|polygon_id| self.polygon_component_selector(polygon_id)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn locate_components_inside_rect(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
rect: Rect3<i64>,
|
||||
) -> impl Iterator<Item = ComponentSelector> + '_ {
|
||||
self.layout
|
||||
.locate_joints_inside_rect(layer, rect)
|
||||
.locate_joints_inside_rect(rect)
|
||||
.filter_map(|joint_id| self.joint_component_selector(joint_id))
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_segments_inside_rect(layer, rect)
|
||||
.locate_segments_inside_rect(rect)
|
||||
.filter_map(|segment_id| self.segment_component_selector(segment_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_vias_inside_rect(layer, rect)
|
||||
.locate_vias_inside_rect(rect)
|
||||
.filter_map(|via_id| self.via_component_selector(via_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_polygons_inside_rect(layer, rect)
|
||||
.locate_polygons_inside_rect(rect)
|
||||
.filter_map(|polygon_id| self.polygon_component_selector(polygon_id)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn locate_pin_at_point(&self, layer: LayerId, point: Vector2<i64>) -> Option<PinSelector> {
|
||||
if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -106,51 +99,73 @@ impl Board {
|
|||
|
||||
pub fn locate_pins_intersecting_rect(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
rect: Rect3<i64>,
|
||||
) -> impl Iterator<Item = PinSelector> + '_ {
|
||||
self.layout
|
||||
.locate_joints_intersecting_rect(layer, rect)
|
||||
.locate_joints_intersecting_rect(rect)
|
||||
.filter_map(|joint_id| self.joint_pin_selector(joint_id))
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_segments_intersecting_rect(layer, rect)
|
||||
.locate_segments_intersecting_rect(rect)
|
||||
.filter_map(|segment_id| self.segment_pin_selector(segment_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_vias_intersecting_rect(layer, rect)
|
||||
.locate_vias_intersecting_rect(rect)
|
||||
.filter_map(|via_id| self.via_pin_selector(via_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_polygons_intersecting_rect(layer, rect)
|
||||
.locate_polygons_intersecting_rect(rect)
|
||||
.filter_map(|polygon_id| self.polygon_pin_selector(polygon_id)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn locate_pins_inside_rect(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
rect: Rect3<i64>,
|
||||
) -> impl Iterator<Item = PinSelector> + '_ {
|
||||
self.layout
|
||||
.locate_joints_inside_rect(layer, rect)
|
||||
.locate_joints_inside_rect(rect)
|
||||
.filter_map(|joint_id| self.joint_pin_selector(joint_id))
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_segments_inside_rect(layer, rect)
|
||||
.locate_segments_inside_rect(rect)
|
||||
.filter_map(|segment_id| self.segment_pin_selector(segment_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_vias_inside_rect(layer, rect)
|
||||
.locate_vias_inside_rect(rect)
|
||||
.filter_map(|via_id| self.via_pin_selector(via_id)),
|
||||
)
|
||||
.chain(
|
||||
self.layout
|
||||
.locate_polygons_inside_rect(layer, rect)
|
||||
.locate_polygons_inside_rect(rect)
|
||||
.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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,23 @@ impl ComponentSelection {
|
|||
Default::default()
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self, selector: ComponentSelector) {
|
||||
if self.0.contains(&selector) {
|
||||
pub fn add(&mut self, selectors: impl IntoIterator<Item = ComponentSelector>) {
|
||||
self.0.extend(selectors);
|
||||
}
|
||||
|
||||
pub fn sub(&mut self, selectors: impl IntoIterator<Item = ComponentSelector>) {
|
||||
for selector in selectors {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,11 +25,23 @@ impl NetSelection {
|
|||
Default::default()
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self, selector: NetSelector) {
|
||||
if self.0.contains(&selector) {
|
||||
pub fn add(&mut self, selectors: impl IntoIterator<Item = NetSelector>) {
|
||||
self.0.extend(selectors);
|
||||
}
|
||||
|
||||
pub fn sub(&mut self, selectors: impl IntoIterator<Item = NetSelector>) {
|
||||
for selector in selectors {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,23 @@ impl PinSelection {
|
|||
Default::default()
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self, selector: PinSelector) {
|
||||
if self.0.contains(&selector) {
|
||||
pub fn add(&mut self, selectors: impl IntoIterator<Item = PinSelector>) {
|
||||
self.0.extend(selectors);
|
||||
}
|
||||
|
||||
pub fn sub(&mut self, selectors: impl IntoIterator<Item = PinSelector>) {
|
||||
for selector in selectors {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,157 +3,116 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{
|
||||
Rect2, Vector2,
|
||||
Rect3, Vector3,
|
||||
layout::{LayerId, Layout},
|
||||
primitives::{JointId, PolygonId, SegmentId, ViaId},
|
||||
};
|
||||
|
||||
impl Layout {
|
||||
pub fn locate_joints_at_point(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
point: Vector2<i64>,
|
||||
) -> impl Iterator<Item = JointId> {
|
||||
pub fn locate_joints_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = JointId> {
|
||||
let point2 = point.xy();
|
||||
self.joints_rtree
|
||||
.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)
|
||||
.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(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
rect: Rect3<i64>,
|
||||
) -> impl Iterator<Item = JointId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
let rect_aabb = rect.aabb3();
|
||||
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<i64>,
|
||||
) -> impl Iterator<Item = JointId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
pub fn locate_joints_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = JointId> {
|
||||
let rect_aabb = rect.aabb3();
|
||||
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,
|
||||
point: Vector2<i64>,
|
||||
) -> impl Iterator<Item = SegmentId> {
|
||||
pub fn locate_segments_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = SegmentId> {
|
||||
let point2 = point.xy();
|
||||
self.segments_rtree
|
||||
.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)
|
||||
.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(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
rect: Rect3<i64>,
|
||||
) -> impl Iterator<Item = SegmentId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
let rect_aabb = rect.aabb3();
|
||||
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<i64>,
|
||||
) -> impl Iterator<Item = SegmentId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
pub fn locate_segments_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = SegmentId> {
|
||||
let rect_aabb = rect.aabb3();
|
||||
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,
|
||||
point: Vector2<i64>,
|
||||
) -> impl Iterator<Item = ViaId> {
|
||||
pub fn locate_vias_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = ViaId> {
|
||||
let layer = LayerId::new(point.z as usize);
|
||||
let point2 = point.xy();
|
||||
self.vias_rtree
|
||||
.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)
|
||||
.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(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
) -> impl Iterator<Item = ViaId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
pub fn locate_vias_intersecting_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = ViaId> {
|
||||
let rect_aabb = rect.aabb3();
|
||||
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<i64>,
|
||||
) -> impl Iterator<Item = ViaId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
pub fn locate_vias_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = ViaId> {
|
||||
let rect_aabb = rect.aabb3();
|
||||
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,
|
||||
point: Vector2<i64>,
|
||||
) -> impl Iterator<Item = PolygonId> {
|
||||
pub fn locate_polygons_at_point(&self, point: Vector3<i64>) -> impl Iterator<Item = PolygonId> {
|
||||
let point2 = point.xy();
|
||||
self.polygons_rtree
|
||||
.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)
|
||||
.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(
|
||||
&self,
|
||||
layer: LayerId,
|
||||
rect: Rect2<i64>,
|
||||
rect: Rect3<i64>,
|
||||
) -> impl Iterator<Item = PolygonId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
let rect_aabb = rect.aabb3();
|
||||
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<i64>,
|
||||
) -> impl Iterator<Item = PolygonId> {
|
||||
let rect_aabb = rect.aabb3(layer.index() as i64);
|
||||
pub fn locate_polygons_inside_rect(&self, rect: Rect3<i64>) -> impl Iterator<Item = PolygonId> {
|
||||
let rect_aabb = rect.aabb3();
|
||||
self.polygons_rtree
|
||||
.as_ref()
|
||||
.locate_in_envelope(&rect_aabb)
|
||||
|
|
|
|||
|
|
@ -18,11 +18,14 @@ pub use crate::board::Board;
|
|||
pub use crate::board::LayerDesc;
|
||||
pub use crate::board::LayerSide;
|
||||
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::layout::LayerId;
|
||||
pub use crate::layout::Layout;
|
||||
pub use crate::layout::compounds::{Pin, PinId};
|
||||
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};
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
Add,
|
||||
AddAssign,
|
||||
|
|
@ -58,6 +90,40 @@ pub struct Vector2<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> {
|
||||
fn from(from: [T; 2]) -> Self {
|
||||
Self {
|
||||
|
|
|
|||
Loading…
Reference in New Issue