mirror of https://codeberg.org/topola/topola.git
Compare commits
7 Commits
24af694c6b
...
f9ea3940d2
| Author | SHA1 | Date |
|---|---|---|
|
|
f9ea3940d2 | |
|
|
ca517f62bd | |
|
|
58be28cc8b | |
|
|
a947a72a02 | |
|
|
1b9673e3e7 | |
|
|
c525af7fca | |
|
|
459c4b41ee |
|
|
@ -12,7 +12,7 @@ derive-getters = "0.5"
|
|||
derive_more = { version = "2.1", features = ["full"] }
|
||||
serde = { version = "1", features = ["derive", "rc"] }
|
||||
thiserror = "2.0"
|
||||
undoredo = { version = "0.10", features = ["derive", "stable-vec", "rstar"] }
|
||||
undoredo = { version = "0.10", features = ["derive", "bidimap", "stable-vec", "rstar"] }
|
||||
|
||||
[profile.release]
|
||||
opt-level = 2 # Fast and small WASM.
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{viewport::Viewport, workspace::Workspace};
|
||||
use topola::LayerId;
|
||||
use topola::primitives::{Joint, Polygon, Segment};
|
||||
|
||||
pub struct Display {}
|
||||
|
|
@ -38,8 +39,8 @@ impl Display {
|
|||
let layout = board.layout();
|
||||
|
||||
// Start from the bottom layer so that top layers are drawn on top.
|
||||
for layer in (0..*layout.layer_count()).rev() {
|
||||
if !workspace.appearance_panel.visible[layer] {
|
||||
for layer in (0..*layout.layer_count()).rev().map(LayerId::new) {
|
||||
if !workspace.appearance_panel.visible[layer.index()] {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -167,8 +168,8 @@ impl Display {
|
|||
let board = workspace.autorouter.router().navmesher_board().board();
|
||||
let layout = board.layout();
|
||||
|
||||
for layer in (0..*layout.layer_count()).rev() {
|
||||
if !workspace.appearance_panel.visible[layer] {
|
||||
for layer in (0..*layout.layer_count()).rev().map(LayerId::new) {
|
||||
if !workspace.appearance_panel.visible[layer.index()] {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -231,22 +232,23 @@ impl Display {
|
|||
viewport: &Viewport,
|
||||
workspace: &Workspace,
|
||||
) {
|
||||
for layer in 0..*workspace
|
||||
for layer in (0..*workspace
|
||||
.autorouter
|
||||
.router()
|
||||
.navmesher_board()
|
||||
.board()
|
||||
.layout()
|
||||
.layer_count()
|
||||
.layer_count())
|
||||
.map(LayerId::new)
|
||||
{
|
||||
if workspace.appearance_panel.visible[layer] {
|
||||
if workspace.appearance_panel.visible[layer.index()] {
|
||||
for navmesh in workspace
|
||||
.autorouter
|
||||
.router()
|
||||
.navmesher_board()
|
||||
.navmesher()
|
||||
.layer_navmeshers()[layer]
|
||||
.navmeshes()
|
||||
.layer_navmeshers()[layer.index()]
|
||||
.navmeshes()
|
||||
{
|
||||
for edge_geom in navmesh
|
||||
.triangulation()
|
||||
|
|
@ -305,8 +307,8 @@ impl Display {
|
|||
let layers = *ratline.endpoint_layers();
|
||||
let endpoints = *ratline.endpoints();
|
||||
|
||||
if !workspace.appearance_panel.visible[layers[0]]
|
||||
|| !workspace.appearance_panel.visible[layers[1]]
|
||||
if !workspace.appearance_panel.visible[layers[0].index()]
|
||||
|| !workspace.appearance_panel.visible[layers[1].index()]
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::collections::BTreeMap;
|
|||
|
||||
use egui::{Context, Grid, ScrollArea, SidePanel, widget_text::WidgetText};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use topola::Board;
|
||||
use topola::{Board, LayerId};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Colors {
|
||||
|
|
@ -42,7 +42,7 @@ pub struct LayersPanel {
|
|||
light_colors: Colors,
|
||||
|
||||
#[serde(skip)]
|
||||
pub active: usize,
|
||||
pub active: LayerId,
|
||||
#[serde(skip)]
|
||||
pub visible: Box<[bool]>,
|
||||
}
|
||||
|
|
@ -161,7 +161,7 @@ impl LayersPanel {
|
|||
Self {
|
||||
dark_colors,
|
||||
light_colors,
|
||||
active: 0,
|
||||
active: LayerId::new(0),
|
||||
visible,
|
||||
}
|
||||
}
|
||||
|
|
@ -181,17 +181,16 @@ impl LayersPanel {
|
|||
.num_columns(3)
|
||||
.start_row(start_row)
|
||||
.show(ui, |ui| {
|
||||
for layer in row_range {
|
||||
let visible = &mut self.visible[layer];
|
||||
for layer_index in row_range {
|
||||
let layer = LayerId::new(layer_index);
|
||||
let visible = &mut self.visible[layer.index()];
|
||||
let layer_name = board.layer_name(layer);
|
||||
|
||||
ui.radio_value(&mut self.active, layer, WidgetText::default());
|
||||
ui.checkbox(visible, WidgetText::default());
|
||||
ui.label(
|
||||
layer_name
|
||||
.map(|i| i.to_string())
|
||||
.unwrap_or_else(|| format!("{} - Unnamed layer", layer)),
|
||||
);
|
||||
ui.label(layer_name.map(|i| i.to_string()).unwrap_or_else(|| {
|
||||
format!("{} - Unnamed layer", layer.index())
|
||||
}));
|
||||
ui.end_row();
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ version = "0.1.0"
|
|||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bimap = "0.6"
|
||||
bidimap = "0.7"
|
||||
dearcut = { version = "0.3", features = ["serde", "undoredo"] }
|
||||
derive-getters.workspace = true
|
||||
derive_more.workspace = true
|
||||
|
|
|
|||
|
|
@ -2,17 +2,21 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
mod resolve;
|
||||
mod select;
|
||||
pub mod selections;
|
||||
mod transforms;
|
||||
|
||||
use bimap::BiBTreeMap;
|
||||
use derive_getters::{Dissolve, Getters};
|
||||
use undoredo::{ApplyDelta, Delta, FlushDelta};
|
||||
use bidimap::BiBTreeMap;
|
||||
use derive_getters::Getters;
|
||||
use derive_more::{Constructor, From};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use undoredo::{Delta, Recorder};
|
||||
|
||||
use crate::{
|
||||
compounds::{ComponentId, NetId, PinId},
|
||||
layout::{
|
||||
Layout, LayoutHalfDelta,
|
||||
LayerId, Layout, LayoutHalfDelta,
|
||||
compounds::{ComponentId, NetId, PinId},
|
||||
primitives::{
|
||||
JointId, JointSpec, Polygon, PolygonId, Segment, SegmentId, SegmentSpec, Via, ViaId,
|
||||
ViaSpec,
|
||||
|
|
@ -21,42 +25,71 @@ use crate::{
|
|||
math::Vector2,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Getters)]
|
||||
#[derive(
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct LayerGroupId(usize);
|
||||
|
||||
impl LayerGroupId {
|
||||
#[inline]
|
||||
pub fn index(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Getters, Delta)]
|
||||
pub struct Board {
|
||||
layout: Layout,
|
||||
#[getter(skip)]
|
||||
component_names: BiBTreeMap<ComponentId, String>,
|
||||
layer_groups: Recorder<Vec<LayerGroupId>>,
|
||||
#[getter(skip)]
|
||||
pin_names: BiBTreeMap<PinId, String>,
|
||||
component_names: Recorder<BiBTreeMap<ComponentId, String>>,
|
||||
#[getter(skip)]
|
||||
layer_names: BiBTreeMap<usize, String>,
|
||||
pin_names: Recorder<BiBTreeMap<PinId, String>>,
|
||||
#[getter(skip)]
|
||||
net_names: BiBTreeMap<NetId, String>,
|
||||
layer_names: Recorder<BiBTreeMap<LayerId, String>>,
|
||||
#[getter(skip)]
|
||||
net_names: Recorder<BiBTreeMap<NetId, String>>,
|
||||
}
|
||||
|
||||
impl Board {
|
||||
pub fn new(boundary: Vec<Vector2<i64>>, layer_count: usize) -> Self {
|
||||
/*pub fn new(boundary: Vec<Vector2<i64>>, layer_count: usize) -> Self {
|
||||
Self {
|
||||
layout: Layout::new(boundary.into_iter().map(Into::into).collect(), layer_count),
|
||||
component_names: BiBTreeMap::new(),
|
||||
pin_names: BiBTreeMap::new(),
|
||||
layer_names: BiBTreeMap::new(),
|
||||
net_names: BiBTreeMap::new(),
|
||||
component_names: Recorder::new(BiBTreeMap::new()),
|
||||
pin_names: Recorder::new(BiBTreeMap::new()),
|
||||
layer_names: Recorder::new(BiBTreeMap::new()),
|
||||
net_names: Recorder::new(BiBTreeMap::new()),
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
pub fn with_names(
|
||||
boundary: Vec<Vector2<i64>>,
|
||||
layer_count: usize,
|
||||
layer_names: BiBTreeMap<usize, String>,
|
||||
layer_groups: Vec<LayerGroupId>,
|
||||
layer_names: BiBTreeMap<LayerId, String>,
|
||||
net_names: BiBTreeMap<NetId, String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
layout: Layout::new(boundary.into_iter().map(Into::into).collect(), layer_count),
|
||||
component_names: BiBTreeMap::new(),
|
||||
pin_names: BiBTreeMap::new(),
|
||||
layer_names,
|
||||
net_names,
|
||||
layout: Layout::new(
|
||||
boundary.into_iter().map(Into::into).collect(),
|
||||
layer_groups.len(),
|
||||
),
|
||||
layer_groups: Recorder::new(layer_groups),
|
||||
component_names: Recorder::new(BiBTreeMap::new()),
|
||||
pin_names: Recorder::new(BiBTreeMap::new()),
|
||||
layer_names: Recorder::new(layer_names),
|
||||
net_names: Recorder::new(net_names),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,7 +148,10 @@ impl Board {
|
|||
}
|
||||
|
||||
pub fn component_id(&self, component_name: &str) -> Option<ComponentId> {
|
||||
self.component_names.get_by_right(component_name).copied()
|
||||
self.component_names
|
||||
.as_ref()
|
||||
.get_by_right(component_name)
|
||||
.copied()
|
||||
}
|
||||
|
||||
pub fn pin_name(&self, id: PinId) -> Option<&str> {
|
||||
|
|
@ -123,15 +159,19 @@ impl Board {
|
|||
}
|
||||
|
||||
pub fn pin_id(&self, pin_name: &str) -> Option<PinId> {
|
||||
self.pin_names.get_by_right(pin_name).copied()
|
||||
self.pin_names.as_ref().get_by_right(pin_name).copied()
|
||||
}
|
||||
|
||||
pub fn layer_name(&self, layer: usize) -> Option<&str> {
|
||||
pub fn layer_name(&self, layer: LayerId) -> Option<&str> {
|
||||
self.layer_names.get_by_left(&layer).map(String::as_str)
|
||||
}
|
||||
|
||||
pub fn layer_id(&self, layer_name: &str) -> Option<usize> {
|
||||
self.layer_names.get_by_right(layer_name).copied()
|
||||
pub fn layer_id(&self, layer_name: &str) -> Option<LayerId> {
|
||||
self.layer_names.as_ref().get_by_right(layer_name).copied()
|
||||
}
|
||||
|
||||
pub fn layer_group(&self, layer: LayerId) -> LayerGroupId {
|
||||
self.layer_groups[layer.index()]
|
||||
}
|
||||
|
||||
pub fn net_name(&self, id: NetId) -> Option<&str> {
|
||||
|
|
@ -139,35 +179,6 @@ impl Board {
|
|||
}
|
||||
|
||||
pub fn net_id(&self, net_name: &str) -> Option<NetId> {
|
||||
self.net_names.get_by_right(net_name).copied()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Dissolve)]
|
||||
pub struct BoardHalfDelta {
|
||||
layout: LayoutHalfDelta,
|
||||
}
|
||||
|
||||
impl ApplyDelta<BoardHalfDelta> for Board {
|
||||
fn apply_delta(&mut self, delta: Delta<BoardHalfDelta>) {
|
||||
let (removed, inserted) = delta.dissolve();
|
||||
|
||||
let layout_delta = Delta::with_removed_inserted(removed.layout, inserted.layout);
|
||||
self.layout.apply_delta(layout_delta);
|
||||
}
|
||||
}
|
||||
|
||||
impl FlushDelta<BoardHalfDelta> for Board {
|
||||
fn flush_delta(&mut self) -> Delta<BoardHalfDelta> {
|
||||
let (removed_layout, inserted_layout) = self.layout.flush_delta().dissolve();
|
||||
|
||||
Delta::with_removed_inserted(
|
||||
BoardHalfDelta {
|
||||
layout: removed_layout,
|
||||
},
|
||||
BoardHalfDelta {
|
||||
layout: inserted_layout,
|
||||
},
|
||||
)
|
||||
self.net_names.as_ref().get_by_right(net_name).copied()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// SPDX-FileCopyrightText: 2026 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{
|
||||
board::{Board, selections::ComponentSelection},
|
||||
layout::compounds::ComponentId,
|
||||
};
|
||||
|
||||
impl Board {
|
||||
pub fn resolve_components(&self, selection: ComponentSelection) -> Vec<ComponentId> {
|
||||
selection
|
||||
.0
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter_map(|selector| self.component_id(&selector.component))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
Board,
|
||||
selections::{ComponentSelection, ComponentSelector, PinSelection, PinSelector},
|
||||
},
|
||||
layout::LayerId,
|
||||
math::Vector2,
|
||||
primitives::{JointId, PolygonId, SegmentId},
|
||||
};
|
||||
|
|
@ -109,7 +110,7 @@ impl Board {
|
|||
|
||||
pub fn point_component_selector(
|
||||
&self,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
point: Vector2<i64>,
|
||||
) -> Option<ComponentSelector> {
|
||||
if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() {
|
||||
|
|
@ -181,7 +182,7 @@ impl Board {
|
|||
selection.0.contains(&selector)
|
||||
}
|
||||
|
||||
pub fn point_pin_selector(&self, layer: usize, point: Vector2<i64>) -> Option<PinSelector> {
|
||||
pub fn point_pin_selector(&self, layer: LayerId, point: Vector2<i64>) -> Option<PinSelector> {
|
||||
if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() {
|
||||
return self.joint_pin_selector(joint_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
// SPDX-FileCopyrightText: 2026 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
mod move_by;
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// SPDX-FileCopyrightText: 2026 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{Board, Vector2, layout::compounds::ComponentId, selections::ComponentSelection};
|
||||
|
||||
impl Board {
|
||||
pub fn move_components_by(
|
||||
&mut self,
|
||||
selection: &ComponentSelection,
|
||||
translation: Vector2<i64>,
|
||||
) {
|
||||
self.move_resolved_components_by(&self.resolve_components(selection.clone()), translation);
|
||||
}
|
||||
|
||||
pub fn move_resolved_components_by(
|
||||
&mut self,
|
||||
selection: &[ComponentId],
|
||||
translation: Vector2<i64>,
|
||||
) {
|
||||
self.layout.move_components_by(selection, translation);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,13 +2,24 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::primitives::{JointId, PolygonId, SegmentId, ViaId};
|
||||
use crate::layout::primitives::{JointId, PolygonId, SegmentId, ViaId};
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct ComponentId(usize);
|
||||
|
||||
|
|
@ -2,11 +2,22 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct NetId(usize);
|
||||
|
||||
|
|
@ -2,13 +2,24 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::primitives::{JointId, PolygonId, SegmentId, ViaId};
|
||||
use crate::layout::primitives::{JointId, PolygonId, SegmentId, ViaId};
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct PinId(usize);
|
||||
|
||||
|
|
@ -2,19 +2,23 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
pub mod compounds;
|
||||
pub mod primitives;
|
||||
mod transforms;
|
||||
|
||||
use derive_getters::Getters;
|
||||
use derive_more::{Constructor, From};
|
||||
use rstar::{
|
||||
AABB, RTree,
|
||||
primitives::{GeomWithData, Rectangle},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stable_vec::StableVec;
|
||||
use undoredo::aliases::RTreeHalfDelta;
|
||||
use undoredo::{Delta, Recorder};
|
||||
|
||||
use crate::{
|
||||
compounds::{Component, ComponentId, Pin, PinId},
|
||||
layout::compounds::{Component, ComponentId, Pin, PinId},
|
||||
layout::primitives::{
|
||||
Joint, JointId, JointSpec, Polygon, PolygonId, Segment, SegmentId, SegmentSpec, Via, ViaId,
|
||||
ViaSpec,
|
||||
|
|
@ -22,6 +26,29 @@ use crate::{
|
|||
math::Vector2,
|
||||
};
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct LayerId(usize);
|
||||
|
||||
impl LayerId {
|
||||
#[inline]
|
||||
pub fn index(self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Delta, Getters)]
|
||||
pub struct Layout {
|
||||
#[undoredo(skip)]
|
||||
|
|
@ -122,12 +149,12 @@ impl Layout {
|
|||
self.modify_joint_raw(id, |joint| f(&mut joint.spec));
|
||||
let new_joint = self.joints[id.index()].clone();
|
||||
|
||||
for &segment in &new_joint.segments {
|
||||
self.update_segment(segment);
|
||||
for &segment_id in &new_joint.segments {
|
||||
self.update_segment(segment_id);
|
||||
}
|
||||
|
||||
for &via in &new_joint.vias {
|
||||
self.update_via(via);
|
||||
for &via_id in &new_joint.vias {
|
||||
self.update_via(via_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -345,24 +372,24 @@ impl Layout {
|
|||
|
||||
pub fn locate_joints_at_point(
|
||||
&self,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
point: Vector2<i64>,
|
||||
) -> impl Iterator<Item = JointId> {
|
||||
self.joints_rtree
|
||||
.as_ref()
|
||||
.locate_all_at_point(&[point.x, point.y, layer as i64])
|
||||
.locate_all_at_point(&[point.x, point.y, layer.index() as i64])
|
||||
.map(|geom_with_data| geom_with_data.data)
|
||||
.filter(move |&joint_id| self.joints[joint_id.index()].contains_point(point))
|
||||
}
|
||||
|
||||
pub fn locate_segments_at_point(
|
||||
&self,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
point: Vector2<i64>,
|
||||
) -> impl Iterator<Item = SegmentId> {
|
||||
self.segments_rtree
|
||||
.as_ref()
|
||||
.locate_all_at_point(&[point.x, point.y, layer as i64])
|
||||
.locate_all_at_point(&[point.x, point.y, layer.index() as i64])
|
||||
.map(|geom_with_data| geom_with_data.data)
|
||||
.filter(move |&segment_id| self.segment(segment_id).contains_point(point))
|
||||
}
|
||||
|
|
@ -371,17 +398,17 @@ impl Layout {
|
|||
|
||||
pub fn locate_polygons_at_point(
|
||||
&self,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
point: Vector2<i64>,
|
||||
) -> impl Iterator<Item = PolygonId> {
|
||||
self.polygons_rtree
|
||||
.as_ref()
|
||||
.locate_all_at_point(&[point.x, point.y, layer as i64])
|
||||
.locate_all_at_point(&[point.x, point.y, layer.index() as i64])
|
||||
.map(|geom_with_data| geom_with_data.data)
|
||||
.filter(move |&polygon_id| self.polygons[polygon_id.index()].contains_point(point))
|
||||
}
|
||||
|
||||
pub fn layer_joints(&self, layer: usize) -> impl Iterator<Item = JointId> + '_ {
|
||||
pub fn layer_joints(&self, layer: LayerId) -> impl Iterator<Item = JointId> + '_ {
|
||||
let envelope = Self::whole_layer_aabb(layer);
|
||||
self.joints_rtree
|
||||
.as_ref()
|
||||
|
|
@ -390,7 +417,7 @@ impl Layout {
|
|||
.filter(move |&id| self.joint(id).spec.layer == layer)
|
||||
}
|
||||
|
||||
pub fn layer_segments(&self, layer: usize) -> impl Iterator<Item = SegmentId> + '_ {
|
||||
pub fn layer_segments(&self, layer: LayerId) -> impl Iterator<Item = SegmentId> + '_ {
|
||||
let envelope = Self::whole_layer_aabb(layer);
|
||||
self.segments_rtree
|
||||
.as_ref()
|
||||
|
|
@ -399,7 +426,7 @@ impl Layout {
|
|||
.filter(move |&id| self.segment(id).layer == layer)
|
||||
}
|
||||
|
||||
pub fn layer_polygons(&self, layer: usize) -> impl Iterator<Item = PolygonId> + '_ {
|
||||
pub fn layer_polygons(&self, layer: LayerId) -> impl Iterator<Item = PolygonId> + '_ {
|
||||
let envelope = Self::whole_layer_aabb(layer);
|
||||
self.polygons_rtree
|
||||
.as_ref()
|
||||
|
|
@ -408,10 +435,10 @@ impl Layout {
|
|||
.filter(move |&id| self.polygon(id).layer == layer)
|
||||
}
|
||||
|
||||
fn whole_layer_aabb(layer: usize) -> AABB<[i64; 3]> {
|
||||
fn whole_layer_aabb(layer: LayerId) -> AABB<[i64; 3]> {
|
||||
AABB::from_corners(
|
||||
[i64::MIN, i64::MIN, layer as i64],
|
||||
[i64::MAX, i64::MAX, layer as i64],
|
||||
[i64::MIN, i64::MIN, layer.index() as i64],
|
||||
[i64::MAX, i64::MAX, layer.index() as i64],
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,29 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use rstar::{AABB, primitives::Rectangle};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::layout::LayerId;
|
||||
use crate::layout::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::math::Vector2;
|
||||
|
||||
use super::{SegmentId, ViaId};
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct JointId(usize);
|
||||
|
||||
|
|
@ -27,7 +39,7 @@ impl JointId {
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct JointSpec {
|
||||
pub position: Vector2<i64>,
|
||||
pub layer: usize,
|
||||
pub layer: LayerId,
|
||||
pub radius: u64,
|
||||
pub net: NetId,
|
||||
pub component: Option<ComponentId>,
|
||||
|
|
@ -51,12 +63,12 @@ impl Joint {
|
|||
[
|
||||
self.spec.position.x - self.spec.radius as i64,
|
||||
self.spec.position.y - self.spec.radius as i64,
|
||||
self.spec.layer as i64,
|
||||
self.spec.layer.index() as i64,
|
||||
],
|
||||
[
|
||||
self.spec.position.x + self.spec.radius as i64,
|
||||
self.spec.position.y + self.spec.radius as i64,
|
||||
self.spec.layer as i64,
|
||||
self.spec.layer.index() as i64,
|
||||
],
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,27 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use rstar::{AABB, Envelope, primitives::Rectangle};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::layout::LayerId;
|
||||
use crate::layout::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::math::Vector2;
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct PolygonId(usize);
|
||||
|
||||
|
|
@ -25,7 +37,7 @@ impl PolygonId {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct Polygon {
|
||||
pub vertices: Vec<Vector2<i64>>,
|
||||
pub layer: usize,
|
||||
pub layer: LayerId,
|
||||
pub net: NetId,
|
||||
pub component: Option<ComponentId>,
|
||||
pub pin: Option<PinId>,
|
||||
|
|
@ -33,14 +45,16 @@ pub struct Polygon {
|
|||
|
||||
impl Polygon {
|
||||
pub fn bbox(&self) -> Rectangle<[i64; 3]> {
|
||||
Rectangle::from_aabb(
|
||||
self.vertices
|
||||
.clone()
|
||||
.into_iter()
|
||||
.fold(AABB::new_empty(), |aabb, vertex| {
|
||||
aabb.merged(&AABB::from_point([vertex.x, vertex.y, self.layer as i64]))
|
||||
}),
|
||||
)
|
||||
Rectangle::from_aabb(self.vertices.clone().into_iter().fold(
|
||||
AABB::new_empty(),
|
||||
|aabb, vertex| {
|
||||
aabb.merged(&AABB::from_point([
|
||||
vertex.x,
|
||||
vertex.y,
|
||||
self.layer.index() as i64,
|
||||
]))
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn center(&self) -> Vector2<i64> {
|
||||
|
|
|
|||
|
|
@ -2,17 +2,29 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use rstar::primitives::Rectangle;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::layout::LayerId;
|
||||
use crate::layout::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::math::Vector2;
|
||||
|
||||
use super::JointId;
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct SegmentId(usize);
|
||||
|
||||
|
|
@ -36,7 +48,7 @@ pub struct SegmentSpec {
|
|||
pub struct Segment {
|
||||
pub spec: SegmentSpec,
|
||||
pub endpoints: [Vector2<i64>; 2],
|
||||
pub layer: usize,
|
||||
pub layer: LayerId,
|
||||
pub net: NetId,
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +82,7 @@ impl Segment {
|
|||
|
||||
pub fn bbox(&self) -> Rectangle<[i64; 3]> {
|
||||
let endpoints = self.endpoints;
|
||||
let layer = self.layer as i64;
|
||||
let layer = self.layer.index() as i64;
|
||||
let half_width = self.spec.half_width as i64;
|
||||
|
||||
let min_x = std::cmp::min(endpoints[0].x, endpoints[1].x) - half_width;
|
||||
|
|
|
|||
|
|
@ -2,17 +2,29 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use rstar::{AABB, primitives::Rectangle};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::layout::LayerId;
|
||||
use crate::layout::compounds::{ComponentId, NetId, PinId};
|
||||
use crate::math::Vector2;
|
||||
|
||||
use super::JointId;
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct ViaId(usize);
|
||||
|
||||
|
|
@ -36,8 +48,8 @@ pub struct ViaSpec {
|
|||
pub struct Via {
|
||||
pub spec: ViaSpec,
|
||||
pub position: Vector2<i64>,
|
||||
pub min_layer: usize,
|
||||
pub max_layer: usize,
|
||||
pub min_layer: LayerId,
|
||||
pub max_layer: LayerId,
|
||||
pub net: NetId,
|
||||
}
|
||||
|
||||
|
|
@ -49,12 +61,12 @@ impl Via {
|
|||
[
|
||||
self.position.x - radius,
|
||||
self.position.y - radius,
|
||||
self.min_layer as i64,
|
||||
self.min_layer.index() as i64,
|
||||
],
|
||||
[
|
||||
self.position.x + radius,
|
||||
self.position.y + radius,
|
||||
self.max_layer as i64,
|
||||
self.max_layer.index() as i64,
|
||||
],
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
// SPDX-FileCopyrightText: 2026 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
mod move_by;
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: 2026 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
|
||||
use crate::{Layout, layout::compounds::ComponentId, math::Vector2};
|
||||
|
||||
impl Layout {
|
||||
pub fn move_component_by(&mut self, id: ComponentId, translation: Vector2<i64>) {
|
||||
self.move_components_by(&[id], translation);
|
||||
}
|
||||
|
||||
pub fn move_components_by(&mut self, ids: &[ComponentId], translation: Vector2<i64>) {
|
||||
for id in ids {
|
||||
let component = self.components[id.index()].clone();
|
||||
|
||||
for &joint_id in &component.joints {
|
||||
self.modify_joint_raw(joint_id, |joint| joint.spec.position += translation);
|
||||
}
|
||||
|
||||
for &segment_id in &component.segments {
|
||||
self.update_segment(segment_id);
|
||||
}
|
||||
|
||||
for &via_id in &component.vias {
|
||||
self.update_via(via_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
mod autorouter;
|
||||
mod board;
|
||||
mod compounds;
|
||||
mod drawer;
|
||||
mod layout;
|
||||
mod math;
|
||||
|
|
@ -17,8 +16,9 @@ mod specctra;
|
|||
pub use crate::autorouter::Autorouter;
|
||||
pub use crate::board::Board;
|
||||
pub use crate::board::selections;
|
||||
pub use crate::compounds::{Pin, PinId};
|
||||
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::ratsnest::{Ratline, Ratsnest};
|
||||
|
|
|
|||
|
|
@ -4,29 +4,41 @@
|
|||
|
||||
use dearcut::{RecordingTriangulator, VertexId};
|
||||
use derive_getters::Getters;
|
||||
use derive_more::Constructor;
|
||||
use derive_more::{Constructor, From};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stable_vec::StableVec;
|
||||
use undoredo::Recorder;
|
||||
|
||||
use crate::{
|
||||
Board,
|
||||
layout::LayerId,
|
||||
math::Vector2,
|
||||
primitives::{Joint, JointId, JointSpec, Polygon, PolygonId, Segment, SegmentId},
|
||||
};
|
||||
|
||||
#[derive(
|
||||
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Constructor,
|
||||
Copy,
|
||||
Debug,
|
||||
Default,
|
||||
Deserialize,
|
||||
Eq,
|
||||
From,
|
||||
Ord,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
pub struct MultiObstacleId {
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl MultiObstacleId {
|
||||
/// Layer of the obstacle.
|
||||
#[inline]
|
||||
pub fn layer(self) -> usize {
|
||||
pub fn layer(self) -> LayerId {
|
||||
self.layer
|
||||
}
|
||||
|
||||
|
|
@ -37,16 +49,18 @@ impl MultiObstacleId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Constructor, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
#[derive(
|
||||
Clone, Constructor, Debug, Default, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize,
|
||||
)]
|
||||
pub struct MultiVertexId {
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
indices: Vec<VertexId>,
|
||||
}
|
||||
|
||||
impl MultiVertexId {
|
||||
/// Layer of the obstacle.
|
||||
#[inline]
|
||||
pub fn layer(self) -> usize {
|
||||
pub fn layer(self) -> LayerId {
|
||||
self.layer
|
||||
}
|
||||
}
|
||||
|
|
@ -154,12 +168,12 @@ impl Navmesher {
|
|||
|
||||
pub fn insert_multiobstacle(
|
||||
&mut self,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
multiobstacle: impl IntoIterator<Item = Vector2<i64>>,
|
||||
) -> MultiObstacleId {
|
||||
MultiObstacleId::new(
|
||||
layer,
|
||||
self.layer_navmeshers[layer].insert_multiobstacle(multiobstacle),
|
||||
self.layer_navmeshers[layer.index()].insert_multiobstacle(multiobstacle),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +184,7 @@ impl Navmesher {
|
|||
) -> MultiVertexId {
|
||||
MultiVertexId {
|
||||
layer: multiobstacle_id.layer,
|
||||
indices: self.layer_navmeshers[multiobstacle_id.layer]
|
||||
indices: self.layer_navmeshers[multiobstacle_id.layer.index()]
|
||||
.insert_free_multivertex_in_multiobstacle(multiobstacle_id.index, position),
|
||||
}
|
||||
}
|
||||
|
|
@ -204,7 +218,7 @@ impl NavmesherBoard {
|
|||
polygon_multiobstacles: Recorder::new(StableVec::new()),
|
||||
};
|
||||
|
||||
for (i, joint) in this.board.layout().joints().container().iter() {
|
||||
/*for (i, joint) in this.board.layout().joints().container().iter() {
|
||||
this.joint_multiobstacles.insert(
|
||||
i,
|
||||
this.navmesher
|
||||
|
|
@ -226,7 +240,7 @@ impl NavmesherBoard {
|
|||
this.navmesher
|
||||
.insert_multiobstacle(polygon.layer, polygon.vertices.clone()),
|
||||
);
|
||||
}
|
||||
}*/
|
||||
|
||||
this
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ use spade::{DelaunayTriangulation, HasPosition, Triangulation, handles::FixedVer
|
|||
|
||||
use crate::{
|
||||
Board,
|
||||
compounds::NetId,
|
||||
layout::LayerId,
|
||||
layout::compounds::NetId,
|
||||
math::Vector2,
|
||||
primitives::{JointId, PolygonId, PrimitiveId, SegmentId},
|
||||
};
|
||||
|
|
@ -18,12 +19,12 @@ use crate::{
|
|||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Getters, Ord, PartialEq, PartialOrd, Serialize)]
|
||||
pub struct Ratline {
|
||||
endpoint_primitive_ids: [PrimitiveId; 2],
|
||||
endpoint_layers: [usize; 2],
|
||||
endpoint_layers: [LayerId; 2],
|
||||
endpoints: [Vector2<i64>; 2],
|
||||
}
|
||||
|
||||
struct DelaunayVertex {
|
||||
pub layer: usize,
|
||||
pub layer: LayerId,
|
||||
pub center: Vector2<i64>,
|
||||
pub position: spade::Point2<f64>,
|
||||
pub primitive_id: PrimitiveId,
|
||||
|
|
@ -46,7 +47,7 @@ impl Ratsnest {
|
|||
pub fn new(board: &Board) -> Self {
|
||||
let mut ratlines = Vec::new();
|
||||
|
||||
let mut triangulations: BTreeMap<(NetId, usize), DelaunayTriangulation<DelaunayVertex>> =
|
||||
let mut triangulations: BTreeMap<(NetId, LayerId), DelaunayTriangulation<DelaunayVertex>> =
|
||||
BTreeMap::new();
|
||||
|
||||
for (i, joint) in board.layout().joints().container().iter() {
|
||||
|
|
|
|||
|
|
@ -4,52 +4,59 @@
|
|||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use bimap::BiBTreeMap;
|
||||
use bidimap::BiBTreeMap;
|
||||
use specctra::{
|
||||
math::PointWithRotation,
|
||||
structure::{DsnFile, Layer, Point, Shape},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
board::Board,
|
||||
compounds::{ComponentId, NetId, PinId},
|
||||
board::{Board, LayerGroupId},
|
||||
layout::LayerId,
|
||||
layout::compounds::{ComponentId, NetId, PinId},
|
||||
math::Vector2,
|
||||
primitives::{JointSpec, Polygon, Segment, SegmentSpec},
|
||||
};
|
||||
|
||||
impl Board {
|
||||
pub fn from_specctra(dsn: DsnFile) -> Self {
|
||||
let layer_names = BiBTreeMap::from_iter(
|
||||
dsn.pcb
|
||||
.structure
|
||||
.layers
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, layer)| (index, layer.name.clone())),
|
||||
);
|
||||
let top_outline_layer_id = LayerId::new(0);
|
||||
let pcb_layer_offset = 1;
|
||||
let bottom_outline_layer_id =
|
||||
LayerId::new(dsn.pcb.structure.layers.len() + pcb_layer_offset);
|
||||
let mut layer_names =
|
||||
BiBTreeMap::from_iter(dsn.pcb.structure.layers.iter().enumerate().map(
|
||||
|(index, layer)| (LayerId::new(index + pcb_layer_offset), layer.name.clone()),
|
||||
));
|
||||
layer_names.insert(top_outline_layer_id, "outlines.top".to_string());
|
||||
layer_names.insert(bottom_outline_layer_id, "outlines.bottom".to_string());
|
||||
|
||||
// assign IDs to all nets named in pcb.network
|
||||
let net_names = {
|
||||
let mut tmp: Vec<_> = dsn
|
||||
let mut tmp: Vec<String> = dsn
|
||||
.pcb
|
||||
.network
|
||||
.classes
|
||||
.iter()
|
||||
.flat_map(|class| &class.nets)
|
||||
.chain(dsn.pcb.network.nets.iter().map(|net| &net.name))
|
||||
.cloned()
|
||||
.collect();
|
||||
// deduplicate net names
|
||||
tmp.push("outlines".to_string());
|
||||
tmp.sort_unstable();
|
||||
tmp.dedup();
|
||||
|
||||
BiBTreeMap::from_iter(
|
||||
tmp.into_iter()
|
||||
.cloned()
|
||||
.enumerate()
|
||||
.map(|(i, v)| (NetId::new(i), v)),
|
||||
)
|
||||
BiBTreeMap::from_iter(tmp.into_iter().enumerate().map(|(i, v)| (NetId::new(i), v)))
|
||||
};
|
||||
|
||||
let mut layer_groups = vec![LayerGroupId::new(1)];
|
||||
layer_groups.extend(std::iter::repeat_n(
|
||||
LayerGroupId::new(0),
|
||||
dsn.pcb.structure.layers.len(),
|
||||
));
|
||||
layer_groups.push(LayerGroupId::new(1));
|
||||
|
||||
let mut board = Board::with_names(
|
||||
dsn.pcb
|
||||
.structure
|
||||
|
|
@ -61,10 +68,11 @@ impl Board {
|
|||
.rev()
|
||||
.map(|p| Vector2::new(p.x as i64, p.y as i64))
|
||||
.collect(),
|
||||
dsn.pcb.structure.layers.len(),
|
||||
layer_groups,
|
||||
layer_names,
|
||||
net_names,
|
||||
);
|
||||
let outline_net = board.net_id("outlines").unwrap();
|
||||
|
||||
// Mapping of pin -> net prepared for adding pins.
|
||||
let pin_nets: BTreeMap<String, NetId> = dsn
|
||||
|
|
@ -104,6 +112,26 @@ impl Board {
|
|||
Self::layer(board, &dsn.pcb.structure.layers, name, place_side_is_front)
|
||||
};
|
||||
|
||||
for outline in &image.outlines {
|
||||
let outline_layer_id = if place_side_is_front {
|
||||
top_outline_layer_id
|
||||
} else {
|
||||
bottom_outline_layer_id
|
||||
};
|
||||
Self::place_path(
|
||||
&mut board,
|
||||
place.point_with_rotation(),
|
||||
PointWithRotation::default(),
|
||||
&outline.path.coords,
|
||||
outline.path.width,
|
||||
outline_layer_id,
|
||||
outline_net,
|
||||
Some(component_id),
|
||||
None,
|
||||
!place_side_is_front,
|
||||
);
|
||||
}
|
||||
|
||||
for pin in &image.pins {
|
||||
let pin_name = format!("{}-{}", place.name, pin.id);
|
||||
|
||||
|
|
@ -284,7 +312,7 @@ impl Board {
|
|||
place: PointWithRotation,
|
||||
pin_pos: PointWithRotation,
|
||||
radius: u64,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
net: NetId,
|
||||
component: Option<ComponentId>,
|
||||
pin: Option<PinId>,
|
||||
|
|
@ -308,7 +336,7 @@ impl Board {
|
|||
y1: f64,
|
||||
x2: f64,
|
||||
y2: f64,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
net: NetId,
|
||||
component: Option<ComponentId>,
|
||||
pin: Option<PinId>,
|
||||
|
|
@ -334,7 +362,7 @@ impl Board {
|
|||
pin_pos: PointWithRotation,
|
||||
coords: &[Point],
|
||||
width: f64,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
net: NetId,
|
||||
component: Option<ComponentId>,
|
||||
pin: Option<PinId>,
|
||||
|
|
@ -392,7 +420,7 @@ impl Board {
|
|||
pin_pos: PointWithRotation,
|
||||
coords: &[Point],
|
||||
_width: f64,
|
||||
layer: usize,
|
||||
layer: LayerId,
|
||||
net: NetId,
|
||||
component: Option<ComponentId>,
|
||||
pin: Option<PinId>,
|
||||
|
|
@ -411,13 +439,15 @@ impl Board {
|
|||
});
|
||||
}
|
||||
|
||||
fn layer(board: &Board, layers: &[Layer], name: &str, front: bool) -> usize {
|
||||
fn layer(board: &Board, layers: &[Layer], name: &str, front: bool) -> LayerId {
|
||||
let pcb_layer_offset = 1;
|
||||
let image_layer = board.layer_id(name).unwrap();
|
||||
let image_layer_index = image_layer.index() - pcb_layer_offset;
|
||||
|
||||
if front {
|
||||
image_layer
|
||||
} else {
|
||||
layers.len() - image_layer - 1
|
||||
LayerId::new(layers.len() - image_layer_index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue