Encapsulate layer indices in new `LayerId` type

This commit is contained in:
Mikolaj Wielgus 2026-05-23 20:28:57 +02:00
parent 1b9673e3e7
commit a947a72a02
16 changed files with 209 additions and 83 deletions

View File

@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use crate::{viewport::Viewport, workspace::Workspace}; use crate::{viewport::Viewport, workspace::Workspace};
use topola::LayerId;
use topola::primitives::{Joint, Polygon, Segment}; use topola::primitives::{Joint, Polygon, Segment};
pub struct Display {} pub struct Display {}
@ -38,8 +39,8 @@ impl Display {
let layout = board.layout(); let layout = board.layout();
// Start from the bottom layer so that top layers are drawn on top. // Start from the bottom layer so that top layers are drawn on top.
for layer in (0..*layout.layer_count()).rev() { for layer in (0..*layout.layer_count()).rev().map(LayerId::new) {
if !workspace.appearance_panel.visible[layer] { if !workspace.appearance_panel.visible[layer.index()] {
continue; continue;
} }
@ -167,8 +168,8 @@ impl Display {
let board = workspace.autorouter.router().navmesher_board().board(); let board = workspace.autorouter.router().navmesher_board().board();
let layout = board.layout(); let layout = board.layout();
for layer in (0..*layout.layer_count()).rev() { for layer in (0..*layout.layer_count()).rev().map(LayerId::new) {
if !workspace.appearance_panel.visible[layer] { if !workspace.appearance_panel.visible[layer.index()] {
continue; continue;
} }
@ -231,22 +232,23 @@ impl Display {
viewport: &Viewport, viewport: &Viewport,
workspace: &Workspace, workspace: &Workspace,
) { ) {
for layer in 0..*workspace for layer in (0..*workspace
.autorouter .autorouter
.router() .router()
.navmesher_board() .navmesher_board()
.board() .board()
.layout() .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 for navmesh in workspace
.autorouter .autorouter
.router() .router()
.navmesher_board() .navmesher_board()
.navmesher() .navmesher()
.layer_navmeshers()[layer] .layer_navmeshers()[layer.index()]
.navmeshes() .navmeshes()
{ {
for edge_geom in navmesh for edge_geom in navmesh
.triangulation() .triangulation()
@ -305,8 +307,8 @@ impl Display {
let layers = *ratline.endpoint_layers(); let layers = *ratline.endpoint_layers();
let endpoints = *ratline.endpoints(); let endpoints = *ratline.endpoints();
if !workspace.appearance_panel.visible[layers[0]] if !workspace.appearance_panel.visible[layers[0].index()]
|| !workspace.appearance_panel.visible[layers[1]] || !workspace.appearance_panel.visible[layers[1].index()]
{ {
continue; continue;
} }

View File

@ -6,7 +6,7 @@ use std::collections::BTreeMap;
use egui::{Context, Grid, ScrollArea, SidePanel, widget_text::WidgetText}; use egui::{Context, Grid, ScrollArea, SidePanel, widget_text::WidgetText};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use topola::Board; use topola::{Board, LayerId};
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Colors { pub struct Colors {
@ -42,7 +42,7 @@ pub struct LayersPanel {
light_colors: Colors, light_colors: Colors,
#[serde(skip)] #[serde(skip)]
pub active: usize, pub active: LayerId,
#[serde(skip)] #[serde(skip)]
pub visible: Box<[bool]>, pub visible: Box<[bool]>,
} }
@ -161,7 +161,7 @@ impl LayersPanel {
Self { Self {
dark_colors, dark_colors,
light_colors, light_colors,
active: 0, active: LayerId::new(0),
visible, visible,
} }
} }
@ -181,17 +181,16 @@ impl LayersPanel {
.num_columns(3) .num_columns(3)
.start_row(start_row) .start_row(start_row)
.show(ui, |ui| { .show(ui, |ui| {
for layer in row_range { for layer_index in row_range {
let visible = &mut self.visible[layer]; let layer = LayerId::new(layer_index);
let visible = &mut self.visible[layer.index()];
let layer_name = board.layer_name(layer); let layer_name = board.layer_name(layer);
ui.radio_value(&mut self.active, layer, WidgetText::default()); ui.radio_value(&mut self.active, layer, WidgetText::default());
ui.checkbox(visible, WidgetText::default()); ui.checkbox(visible, WidgetText::default());
ui.label( ui.label(layer_name.map(|i| i.to_string()).unwrap_or_else(|| {
layer_name format!("{} - Unnamed layer", layer.index())
.map(|i| i.to_string()) }));
.unwrap_or_else(|| format!("{} - Unnamed layer", layer)),
);
ui.end_row(); ui.end_row();
} }
}) })

View File

@ -13,6 +13,7 @@ use undoredo::{Delta, Recorder};
use crate::{ use crate::{
compounds::{ComponentId, NetId, PinId}, compounds::{ComponentId, NetId, PinId},
layout::LayerId,
layout::{ layout::{
Layout, LayoutHalfDelta, Layout, LayoutHalfDelta,
primitives::{ primitives::{
@ -31,7 +32,7 @@ pub struct Board {
#[getter(skip)] #[getter(skip)]
pin_names: Recorder<BiBTreeMap<PinId, String>>, pin_names: Recorder<BiBTreeMap<PinId, String>>,
#[getter(skip)] #[getter(skip)]
layer_names: Recorder<BiBTreeMap<usize, String>>, layer_names: Recorder<BiBTreeMap<LayerId, String>>,
#[getter(skip)] #[getter(skip)]
net_names: Recorder<BiBTreeMap<NetId, String>>, net_names: Recorder<BiBTreeMap<NetId, String>>,
} }
@ -50,7 +51,7 @@ impl Board {
pub fn with_names( pub fn with_names(
boundary: Vec<Vector2<i64>>, boundary: Vec<Vector2<i64>>,
layer_count: usize, layer_count: usize,
layer_names: BiBTreeMap<usize, String>, layer_names: BiBTreeMap<LayerId, String>,
net_names: BiBTreeMap<NetId, String>, net_names: BiBTreeMap<NetId, String>,
) -> Self { ) -> Self {
Self { Self {
@ -131,11 +132,11 @@ impl Board {
self.pin_names.as_ref().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) self.layer_names.get_by_left(&layer).map(String::as_str)
} }
pub fn layer_id(&self, layer_name: &str) -> Option<usize> { pub fn layer_id(&self, layer_name: &str) -> Option<LayerId> {
self.layer_names.as_ref().get_by_right(layer_name).copied() self.layer_names.as_ref().get_by_right(layer_name).copied()
} }

View File

@ -7,6 +7,7 @@ use crate::{
Board, Board,
selections::{ComponentSelection, ComponentSelector, PinSelection, PinSelector}, selections::{ComponentSelection, ComponentSelector, PinSelection, PinSelector},
}, },
layout::LayerId,
math::Vector2, math::Vector2,
primitives::{JointId, PolygonId, SegmentId}, primitives::{JointId, PolygonId, SegmentId},
}; };
@ -109,7 +110,7 @@ impl Board {
pub fn point_component_selector( pub fn point_component_selector(
&self, &self,
layer: usize, layer: LayerId,
point: Vector2<i64>, point: Vector2<i64>,
) -> Option<ComponentSelector> { ) -> Option<ComponentSelector> {
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(layer, point).next() {
@ -181,7 +182,7 @@ impl Board {
selection.0.contains(&selector) 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() { if let Some(joint_id) = self.layout.locate_joints_at_point(layer, point).next() {
return self.joint_pin_selector(joint_id); return self.joint_pin_selector(joint_id);
} }

View File

@ -8,7 +8,18 @@ use serde::{Deserialize, Serialize};
use crate::primitives::{JointId, PolygonId, SegmentId, ViaId}; use crate::primitives::{JointId, PolygonId, SegmentId, ViaId};
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct ComponentId(usize); pub struct ComponentId(usize);

View File

@ -6,7 +6,18 @@ use derive_more::{Constructor, From};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct NetId(usize); pub struct NetId(usize);

View File

@ -8,7 +8,18 @@ use serde::{Deserialize, Serialize};
use crate::primitives::{JointId, PolygonId, SegmentId, ViaId}; use crate::primitives::{JointId, PolygonId, SegmentId, ViaId};
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct PinId(usize); pub struct PinId(usize);

View File

@ -6,10 +6,12 @@ pub mod primitives;
mod transforms; mod transforms;
use derive_getters::Getters; use derive_getters::Getters;
use derive_more::{Constructor, From};
use rstar::{ use rstar::{
AABB, RTree, AABB, RTree,
primitives::{GeomWithData, Rectangle}, primitives::{GeomWithData, Rectangle},
}; };
use serde::{Deserialize, Serialize};
use stable_vec::StableVec; use stable_vec::StableVec;
use undoredo::aliases::RTreeHalfDelta; use undoredo::aliases::RTreeHalfDelta;
use undoredo::{Delta, Recorder}; use undoredo::{Delta, Recorder};
@ -23,6 +25,29 @@ use crate::{
math::Vector2, 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)] #[derive(Clone, Debug, Delta, Getters)]
pub struct Layout { pub struct Layout {
#[undoredo(skip)] #[undoredo(skip)]
@ -346,24 +371,24 @@ impl Layout {
pub fn locate_joints_at_point( pub fn locate_joints_at_point(
&self, &self,
layer: usize, layer: LayerId,
point: Vector2<i64>, point: Vector2<i64>,
) -> impl Iterator<Item = JointId> { ) -> impl Iterator<Item = JointId> {
self.joints_rtree self.joints_rtree
.as_ref() .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) .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(point))
} }
pub fn locate_segments_at_point( pub fn locate_segments_at_point(
&self, &self,
layer: usize, layer: LayerId,
point: Vector2<i64>, point: Vector2<i64>,
) -> impl Iterator<Item = SegmentId> { ) -> impl Iterator<Item = SegmentId> {
self.segments_rtree self.segments_rtree
.as_ref() .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) .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(point))
} }
@ -372,17 +397,17 @@ impl Layout {
pub fn locate_polygons_at_point( pub fn locate_polygons_at_point(
&self, &self,
layer: usize, layer: LayerId,
point: Vector2<i64>, point: Vector2<i64>,
) -> impl Iterator<Item = PolygonId> { ) -> impl Iterator<Item = PolygonId> {
self.polygons_rtree self.polygons_rtree
.as_ref() .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) .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(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); let envelope = Self::whole_layer_aabb(layer);
self.joints_rtree self.joints_rtree
.as_ref() .as_ref()
@ -391,7 +416,7 @@ impl Layout {
.filter(move |&id| self.joint(id).spec.layer == layer) .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); let envelope = Self::whole_layer_aabb(layer);
self.segments_rtree self.segments_rtree
.as_ref() .as_ref()
@ -400,7 +425,7 @@ impl Layout {
.filter(move |&id| self.segment(id).layer == layer) .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); let envelope = Self::whole_layer_aabb(layer);
self.polygons_rtree self.polygons_rtree
.as_ref() .as_ref()
@ -409,10 +434,10 @@ impl Layout {
.filter(move |&id| self.polygon(id).layer == layer) .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( AABB::from_corners(
[i64::MIN, i64::MIN, layer as i64], [i64::MIN, i64::MIN, layer.index() as i64],
[i64::MAX, i64::MAX, layer as i64], [i64::MAX, i64::MAX, layer.index() as i64],
) )
} }

View File

@ -7,12 +7,24 @@ use rstar::{AABB, primitives::Rectangle};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::compounds::{ComponentId, NetId, PinId}; use crate::compounds::{ComponentId, NetId, PinId};
use crate::layout::LayerId;
use crate::math::Vector2; use crate::math::Vector2;
use super::{SegmentId, ViaId}; use super::{SegmentId, ViaId};
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct JointId(usize); pub struct JointId(usize);
@ -27,7 +39,7 @@ impl JointId {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct JointSpec { pub struct JointSpec {
pub position: Vector2<i64>, pub position: Vector2<i64>,
pub layer: usize, pub layer: LayerId,
pub radius: u64, pub radius: u64,
pub net: NetId, pub net: NetId,
pub component: Option<ComponentId>, pub component: Option<ComponentId>,
@ -51,12 +63,12 @@ impl Joint {
[ [
self.spec.position.x - self.spec.radius as i64, self.spec.position.x - self.spec.radius as i64,
self.spec.position.y - 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.x + self.spec.radius as i64,
self.spec.position.y + 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,
], ],
)) ))
} }

View File

@ -7,10 +7,22 @@ use rstar::{AABB, Envelope, primitives::Rectangle};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::compounds::{ComponentId, NetId, PinId}; use crate::compounds::{ComponentId, NetId, PinId};
use crate::layout::LayerId;
use crate::math::Vector2; use crate::math::Vector2;
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct PolygonId(usize); pub struct PolygonId(usize);
@ -25,7 +37,7 @@ impl PolygonId {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Polygon { pub struct Polygon {
pub vertices: Vec<Vector2<i64>>, pub vertices: Vec<Vector2<i64>>,
pub layer: usize, pub layer: LayerId,
pub net: NetId, pub net: NetId,
pub component: Option<ComponentId>, pub component: Option<ComponentId>,
pub pin: Option<PinId>, pub pin: Option<PinId>,
@ -33,14 +45,16 @@ pub struct Polygon {
impl Polygon { impl Polygon {
pub fn bbox(&self) -> Rectangle<[i64; 3]> { pub fn bbox(&self) -> Rectangle<[i64; 3]> {
Rectangle::from_aabb( Rectangle::from_aabb(self.vertices.clone().into_iter().fold(
self.vertices AABB::new_empty(),
.clone() |aabb, vertex| {
.into_iter() aabb.merged(&AABB::from_point([
.fold(AABB::new_empty(), |aabb, vertex| { vertex.x,
aabb.merged(&AABB::from_point([vertex.x, vertex.y, self.layer as i64])) vertex.y,
}), self.layer.index() as i64,
) ]))
},
))
} }
pub fn center(&self) -> Vector2<i64> { pub fn center(&self) -> Vector2<i64> {

View File

@ -7,12 +7,24 @@ use rstar::primitives::Rectangle;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::compounds::{ComponentId, NetId, PinId}; use crate::compounds::{ComponentId, NetId, PinId};
use crate::layout::LayerId;
use crate::math::Vector2; use crate::math::Vector2;
use super::JointId; use super::JointId;
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct SegmentId(usize); pub struct SegmentId(usize);
@ -36,7 +48,7 @@ pub struct SegmentSpec {
pub struct Segment { pub struct Segment {
pub spec: SegmentSpec, pub spec: SegmentSpec,
pub endpoints: [Vector2<i64>; 2], pub endpoints: [Vector2<i64>; 2],
pub layer: usize, pub layer: LayerId,
pub net: NetId, pub net: NetId,
} }
@ -70,7 +82,7 @@ impl Segment {
pub fn bbox(&self) -> Rectangle<[i64; 3]> { pub fn bbox(&self) -> Rectangle<[i64; 3]> {
let endpoints = self.endpoints; 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 half_width = self.spec.half_width as i64;
let min_x = std::cmp::min(endpoints[0].x, endpoints[1].x) - half_width; let min_x = std::cmp::min(endpoints[0].x, endpoints[1].x) - half_width;

View File

@ -7,12 +7,24 @@ use rstar::{AABB, primitives::Rectangle};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::compounds::{ComponentId, NetId, PinId}; use crate::compounds::{ComponentId, NetId, PinId};
use crate::layout::LayerId;
use crate::math::Vector2; use crate::math::Vector2;
use super::JointId; use super::JointId;
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct ViaId(usize); pub struct ViaId(usize);
@ -36,8 +48,8 @@ pub struct ViaSpec {
pub struct Via { pub struct Via {
pub spec: ViaSpec, pub spec: ViaSpec,
pub position: Vector2<i64>, pub position: Vector2<i64>,
pub min_layer: usize, pub min_layer: LayerId,
pub max_layer: usize, pub max_layer: LayerId,
pub net: NetId, pub net: NetId,
} }
@ -49,12 +61,12 @@ impl Via {
[ [
self.position.x - radius, self.position.x - radius,
self.position.y - radius, self.position.y - radius,
self.min_layer as i64, self.min_layer.index() as i64,
], ],
[ [
self.position.x + radius, self.position.x + radius,
self.position.y + radius, self.position.y + radius,
self.max_layer as i64, self.max_layer.index() as i64,
], ],
)) ))
} }

View File

@ -18,6 +18,7 @@ pub use crate::autorouter::Autorouter;
pub use crate::board::Board; pub use crate::board::Board;
pub use crate::board::selections; pub use crate::board::selections;
pub use crate::compounds::{Pin, PinId}; pub use crate::compounds::{Pin, PinId};
pub use crate::layout::LayerId;
pub use crate::layout::Layout; pub use crate::layout::Layout;
pub use crate::layout::primitives; pub use crate::layout::primitives;
pub use crate::math::Vector2; pub use crate::math::Vector2;

View File

@ -11,22 +11,34 @@ use undoredo::Recorder;
use crate::{ use crate::{
Board, Board,
layout::LayerId,
math::Vector2, math::Vector2,
primitives::{Joint, JointId, JointSpec, Polygon, PolygonId, Segment, SegmentId}, primitives::{Joint, JointId, JointSpec, Polygon, PolygonId, Segment, SegmentId},
}; };
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone,
Constructor,
Copy,
Debug,
Default,
Deserialize,
Eq,
From,
Ord,
PartialEq,
PartialOrd,
Serialize,
)] )]
pub struct MultiObstacleId { pub struct MultiObstacleId {
layer: usize, layer: LayerId,
index: usize, index: usize,
} }
impl MultiObstacleId { impl MultiObstacleId {
/// Layer of the obstacle. /// Layer of the obstacle.
#[inline] #[inline]
pub fn layer(self) -> usize { pub fn layer(self) -> LayerId {
self.layer self.layer
} }
@ -38,17 +50,17 @@ impl MultiObstacleId {
} }
#[derive( #[derive(
Clone, Constructor, Debug, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize, Clone, Constructor, Debug, Default, Deserialize, Eq, From, Ord, PartialEq, PartialOrd, Serialize,
)] )]
pub struct MultiVertexId { pub struct MultiVertexId {
layer: usize, layer: LayerId,
indices: Vec<VertexId>, indices: Vec<VertexId>,
} }
impl MultiVertexId { impl MultiVertexId {
/// Layer of the obstacle. /// Layer of the obstacle.
#[inline] #[inline]
pub fn layer(self) -> usize { pub fn layer(self) -> LayerId {
self.layer self.layer
} }
} }
@ -156,12 +168,12 @@ impl Navmesher {
pub fn insert_multiobstacle( pub fn insert_multiobstacle(
&mut self, &mut self,
layer: usize, layer: LayerId,
multiobstacle: impl IntoIterator<Item = Vector2<i64>>, multiobstacle: impl IntoIterator<Item = Vector2<i64>>,
) -> MultiObstacleId { ) -> MultiObstacleId {
MultiObstacleId::new( MultiObstacleId::new(
layer, layer,
self.layer_navmeshers[layer].insert_multiobstacle(multiobstacle), self.layer_navmeshers[layer.index()].insert_multiobstacle(multiobstacle),
) )
} }
@ -172,7 +184,7 @@ impl Navmesher {
) -> MultiVertexId { ) -> MultiVertexId {
MultiVertexId { MultiVertexId {
layer: multiobstacle_id.layer, 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), .insert_free_multivertex_in_multiobstacle(multiobstacle_id.index, position),
} }
} }

View File

@ -11,6 +11,7 @@ use spade::{DelaunayTriangulation, HasPosition, Triangulation, handles::FixedVer
use crate::{ use crate::{
Board, Board,
compounds::NetId, compounds::NetId,
layout::LayerId,
math::Vector2, math::Vector2,
primitives::{JointId, PolygonId, PrimitiveId, SegmentId}, primitives::{JointId, PolygonId, PrimitiveId, SegmentId},
}; };
@ -18,12 +19,12 @@ use crate::{
#[derive(Clone, Copy, Debug, Deserialize, Eq, Getters, Ord, PartialEq, PartialOrd, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Getters, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Ratline { pub struct Ratline {
endpoint_primitive_ids: [PrimitiveId; 2], endpoint_primitive_ids: [PrimitiveId; 2],
endpoint_layers: [usize; 2], endpoint_layers: [LayerId; 2],
endpoints: [Vector2<i64>; 2], endpoints: [Vector2<i64>; 2],
} }
struct DelaunayVertex { struct DelaunayVertex {
pub layer: usize, pub layer: LayerId,
pub center: Vector2<i64>, pub center: Vector2<i64>,
pub position: spade::Point2<f64>, pub position: spade::Point2<f64>,
pub primitive_id: PrimitiveId, pub primitive_id: PrimitiveId,
@ -46,7 +47,7 @@ impl Ratsnest {
pub fn new(board: &Board) -> Self { pub fn new(board: &Board) -> Self {
let mut ratlines = Vec::new(); let mut ratlines = Vec::new();
let mut triangulations: BTreeMap<(NetId, usize), DelaunayTriangulation<DelaunayVertex>> = let mut triangulations: BTreeMap<(NetId, LayerId), DelaunayTriangulation<DelaunayVertex>> =
BTreeMap::new(); BTreeMap::new();
for (i, joint) in board.layout().joints().container().iter() { for (i, joint) in board.layout().joints().container().iter() {

View File

@ -13,6 +13,7 @@ use specctra::{
use crate::{ use crate::{
board::Board, board::Board,
compounds::{ComponentId, NetId, PinId}, compounds::{ComponentId, NetId, PinId},
layout::LayerId,
math::Vector2, math::Vector2,
primitives::{JointSpec, Polygon, Segment, SegmentSpec}, primitives::{JointSpec, Polygon, Segment, SegmentSpec},
}; };
@ -25,7 +26,7 @@ impl Board {
.layers .layers
.iter() .iter()
.enumerate() .enumerate()
.map(|(index, layer)| (index, layer.name.clone())), .map(|(index, layer)| (LayerId::new(index), layer.name.clone())),
); );
// assign IDs to all nets named in pcb.network // assign IDs to all nets named in pcb.network
@ -284,7 +285,7 @@ impl Board {
place: PointWithRotation, place: PointWithRotation,
pin_pos: PointWithRotation, pin_pos: PointWithRotation,
radius: u64, radius: u64,
layer: usize, layer: LayerId,
net: NetId, net: NetId,
component: Option<ComponentId>, component: Option<ComponentId>,
pin: Option<PinId>, pin: Option<PinId>,
@ -308,7 +309,7 @@ impl Board {
y1: f64, y1: f64,
x2: f64, x2: f64,
y2: f64, y2: f64,
layer: usize, layer: LayerId,
net: NetId, net: NetId,
component: Option<ComponentId>, component: Option<ComponentId>,
pin: Option<PinId>, pin: Option<PinId>,
@ -334,7 +335,7 @@ impl Board {
pin_pos: PointWithRotation, pin_pos: PointWithRotation,
coords: &[Point], coords: &[Point],
width: f64, width: f64,
layer: usize, layer: LayerId,
net: NetId, net: NetId,
component: Option<ComponentId>, component: Option<ComponentId>,
pin: Option<PinId>, pin: Option<PinId>,
@ -392,7 +393,7 @@ impl Board {
pin_pos: PointWithRotation, pin_pos: PointWithRotation,
coords: &[Point], coords: &[Point],
_width: f64, _width: f64,
layer: usize, layer: LayerId,
net: NetId, net: NetId,
component: Option<ComponentId>, component: Option<ComponentId>,
pin: Option<PinId>, pin: Option<PinId>,
@ -411,13 +412,13 @@ 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 image_layer = board.layer_id(name).unwrap(); let image_layer = board.layer_id(name).unwrap();
if front { if front {
image_layer image_layer
} else { } else {
layers.len() - image_layer - 1 LayerId::new(layers.len() - image_layer.index() - 1)
} }
} }