mirror of https://codeberg.org/topola/topola.git
Display repulsions and attractions of selected pins and components
This commit is contained in:
parent
4c6f5b4c43
commit
05108e964d
|
|
@ -3,8 +3,8 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{viewport::Viewport, workspace::GuiWorkspace};
|
||||
use topola::Workspace;
|
||||
use topola::primitives::{Joint, Polygon, Segment, Via};
|
||||
use topola::{Orientation, Vector2, Workspace};
|
||||
|
||||
pub struct Display {}
|
||||
|
||||
|
|
@ -22,6 +22,8 @@ impl Display {
|
|||
workspace: &GuiWorkspace,
|
||||
) {
|
||||
self.display_layout(ctx, ui, /*menu_bar,*/ viewport, workspace);
|
||||
self.display_repulsions(ui, viewport, workspace);
|
||||
self.display_attractions(ui, viewport, workspace);
|
||||
self.display_bboxes(ctx, ui, viewport, workspace);
|
||||
self.display_navmeshes(ctx, ui, viewport, workspace);
|
||||
self.display_ratsnest(ctx, ui, viewport, workspace);
|
||||
|
|
@ -156,6 +158,109 @@ impl Display {
|
|||
);
|
||||
}
|
||||
|
||||
fn display_repulsions(&mut self, ui: &egui::Ui, viewport: &Viewport, workspace: &GuiWorkspace) {
|
||||
let board = workspace.workspace.board();
|
||||
let stroke = egui::Stroke::new(150.0 / viewport.scale_factor(), egui::Color32::YELLOW);
|
||||
|
||||
for selector in &workspace.workspace.selection().components.0 {
|
||||
let Some(component_id) = board.component_id(&selector.component) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(bbox) = board.layout().component_bbox2(component_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let origin = Vector2::new((bbox.min.x + bbox.max.x) / 2, (bbox.min.y + bbox.max.y) / 2);
|
||||
|
||||
Self::paint_arrows(
|
||||
ui,
|
||||
origin,
|
||||
board
|
||||
.layout()
|
||||
.locate_component_repulsions(component_id, Orientation::Oblique),
|
||||
stroke,
|
||||
);
|
||||
}
|
||||
|
||||
for selector in &workspace.workspace.selection().pins.0 {
|
||||
let Some(pin_id) = board.pin_id(&selector.pin) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
Self::paint_arrows(
|
||||
ui,
|
||||
board.layout().pin_centroid(pin_id),
|
||||
board
|
||||
.layout()
|
||||
.locate_pin_repulsions(pin_id, Orientation::Oblique),
|
||||
stroke,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn display_attractions(
|
||||
&mut self,
|
||||
ui: &egui::Ui,
|
||||
viewport: &Viewport,
|
||||
workspace: &GuiWorkspace,
|
||||
) {
|
||||
let board = workspace.workspace.board();
|
||||
let layout = board.layout();
|
||||
let stroke = egui::Stroke::new(150.0 / viewport.scale_factor(), egui::Color32::BLUE);
|
||||
|
||||
for selector in &workspace.workspace.selection().components.0 {
|
||||
let Some(component_id) = board.component_id(&selector.component) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(bbox) = layout.component_bbox2(component_id) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let origin = Vector2::new((bbox.min.x + bbox.max.x) / 2, (bbox.min.y + bbox.max.y) / 2);
|
||||
|
||||
Self::paint_arrows(
|
||||
ui,
|
||||
origin,
|
||||
layout.component_attractions(component_id),
|
||||
stroke,
|
||||
);
|
||||
}
|
||||
|
||||
for selector in &workspace.workspace.selection().pins.0 {
|
||||
let Some(pin_id) = board.pin_id(&selector.pin) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
Self::paint_arrows(
|
||||
ui,
|
||||
layout.pin_centroid(pin_id),
|
||||
layout.pin_attractions(pin_id),
|
||||
stroke,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_arrows(
|
||||
ui: &egui::Ui,
|
||||
origin: Vector2<i64>,
|
||||
repulsions: impl IntoIterator<Item = Vector2<i64>>,
|
||||
stroke: egui::Stroke,
|
||||
) {
|
||||
for repulsion in repulsions {
|
||||
if repulsion.x == 0 && repulsion.y == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
ui.painter().arrow(
|
||||
egui::pos2(origin.x as f32, origin.y as f32),
|
||||
egui::vec2(repulsion.x as f32, repulsion.y as f32),
|
||||
stroke,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_joint(
|
||||
&mut self,
|
||||
ctx: &egui::Context,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
compounds::{ComponentId, NetId},
|
||||
primitives::{JointId, PolygonId, SegmentId, ViaId},
|
||||
},
|
||||
primitives::PrimitiveId,
|
||||
};
|
||||
|
||||
#[derive(
|
||||
|
|
@ -61,6 +62,23 @@ impl Pin {
|
|||
polygons: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn primitives(&self) -> impl Iterator<Item = PrimitiveId> + '_ {
|
||||
self.joints
|
||||
.iter()
|
||||
.map(|&joint_id| PrimitiveId::Joint(joint_id))
|
||||
.chain(
|
||||
self.segments
|
||||
.iter()
|
||||
.map(|&segment_id| PrimitiveId::Segment(segment_id)),
|
||||
)
|
||||
.chain(self.vias.iter().map(|&via_id| PrimitiveId::Via(via_id)))
|
||||
.chain(
|
||||
self.polygons
|
||||
.iter()
|
||||
.map(|&polygon_id| PrimitiveId::Polygon(polygon_id)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
|
|||
use crate::primitives::PrimitiveId;
|
||||
|
||||
use super::Layout;
|
||||
use super::compounds::{ComponentId, NetId};
|
||||
use super::compounds::{ComponentId, NetId, PinId};
|
||||
use super::primitives::{JointId, PolygonId, SegmentId, ViaId};
|
||||
|
||||
#[derive(
|
||||
|
|
@ -140,6 +140,60 @@ impl Layout {
|
|||
.chain(polygon_infringements)
|
||||
}
|
||||
|
||||
pub fn locate_pin_infringements(
|
||||
&self,
|
||||
infringer: PinId,
|
||||
) -> impl Iterator<Item = Infringement<PinId, PinId>> + '_ {
|
||||
let mut infringee_pins = BTreeSet::new();
|
||||
|
||||
for infringement in self.locate_pin_primitive_infringements(infringer) {
|
||||
let Some(infringee_pin) = self.primitive_pin(infringement.infringee()) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if infringee_pin == infringer {
|
||||
continue;
|
||||
}
|
||||
|
||||
infringee_pins.insert(infringee_pin);
|
||||
}
|
||||
|
||||
infringee_pins
|
||||
.into_iter()
|
||||
.map(move |infringee| Infringement {
|
||||
infringer,
|
||||
infringee,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn locate_pin_primitive_infringements(
|
||||
&self,
|
||||
infringer: PinId,
|
||||
) -> impl Iterator<Item = Infringement> + '_ {
|
||||
let pin = self.pin(infringer);
|
||||
|
||||
pin.joints
|
||||
.iter()
|
||||
.copied()
|
||||
.flat_map(|joint_id| self.locate_joint_infringements(joint_id).map(Into::into))
|
||||
.chain(
|
||||
pin.segments.iter().copied().flat_map(|segment_id| {
|
||||
self.locate_segment_infringements(segment_id)
|
||||
.map(Into::into)
|
||||
}),
|
||||
)
|
||||
.chain(
|
||||
pin.vias
|
||||
.iter()
|
||||
.copied()
|
||||
.flat_map(|via_id| self.locate_via_infringements(via_id).map(Into::into)),
|
||||
)
|
||||
.chain(pin.polygons.iter().copied().flat_map(|polygon_id| {
|
||||
self.locate_polygon_infringements(polygon_id)
|
||||
.map(Into::into)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn locate_joint_infringements(
|
||||
&self,
|
||||
infringer: JointId,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@
|
|||
use crate::{
|
||||
Rect2, Vector2,
|
||||
compass::CompassDirection,
|
||||
layout::{Layout, compounds::ComponentId},
|
||||
layout::{
|
||||
Layout,
|
||||
compounds::{ComponentId, PinId},
|
||||
},
|
||||
orientation::Orientation,
|
||||
primitives::{JointId, PolygonId, PrimitiveId, SegmentId, ViaId},
|
||||
};
|
||||
|
|
@ -35,8 +38,47 @@ impl Layout {
|
|||
let mut max_repulsion = Vector2::new(0, 0);
|
||||
let mut max_repulsion_magnitude = 0;
|
||||
|
||||
for infringer_primitive in self.component(infringer).primitives() {
|
||||
for infringee_primitive in self.component(infringee).primitives() {
|
||||
for &infringer_pin in self.component(infringer).pins.iter() {
|
||||
for &infringee_pin in self.component(infringee).pins.iter() {
|
||||
let repulsion = self.pin_pin_repulsion(infringer_pin, infringee_pin, orientation);
|
||||
let repulsion_magnitude = repulsion.x.abs() + repulsion.y.abs();
|
||||
|
||||
if repulsion_magnitude > max_repulsion_magnitude {
|
||||
max_repulsion = repulsion;
|
||||
max_repulsion_magnitude = repulsion_magnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
max_repulsion
|
||||
}
|
||||
|
||||
pub fn locate_pin_repulsions(
|
||||
&self,
|
||||
infringer: PinId,
|
||||
orientation: Orientation,
|
||||
) -> impl Iterator<Item = Vector2<i64>> + '_ {
|
||||
self.locate_pin_infringements(infringer)
|
||||
.map(move |infringement| {
|
||||
self.pin_pin_repulsion(
|
||||
infringement.infringer(),
|
||||
infringement.infringee(),
|
||||
orientation,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pin_pin_repulsion(
|
||||
&self,
|
||||
infringer: PinId,
|
||||
infringee: PinId,
|
||||
orientation: Orientation,
|
||||
) -> Vector2<i64> {
|
||||
let mut max_repulsion = Vector2::new(0, 0);
|
||||
let mut max_repulsion_magnitude = 0;
|
||||
|
||||
for infringer_primitive in self.pin(infringer).primitives() {
|
||||
for infringee_primitive in self.pin(infringee).primitives() {
|
||||
let repulsion = self.primitive_primitive_repulsion(
|
||||
infringer_primitive,
|
||||
infringee_primitive,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ 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::orientation::Orientation;
|
||||
pub use crate::ratsnest::{Ratline, Ratsnest};
|
||||
pub use crate::rect::{Rect2, Rect3};
|
||||
pub use crate::vector::{Vector2, Vector3};
|
||||
|
|
|
|||
Loading…
Reference in New Issue