Split `Joint` into input `JointSpec` and actually stored `Joint`

This commit is contained in:
Mikolaj Wielgus 2026-05-18 15:02:44 +02:00
parent 7f67a24808
commit b2a75fd520
8 changed files with 88 additions and 50 deletions

View File

@ -52,7 +52,7 @@ impl Display {
joint, joint,
workspace.appearance_panel.layer_color( workspace.appearance_panel.layer_color(
ctx, ctx,
board.layer_name(joint.layer), board.layer_name(joint.spec.layer),
board.pin_selection_contains_joint(&workspace.pin_selection, joint_id), board.pin_selection_contains_joint(&workspace.pin_selection, joint_id),
), ),
); );
@ -113,8 +113,8 @@ impl Display {
color: egui::Color32, color: egui::Color32,
) { ) {
ui.painter().circle_filled( ui.painter().circle_filled(
egui::pos2(joint.position.x as f32, joint.position.y as f32), egui::pos2(joint.spec.position.x as f32, joint.spec.position.y as f32),
joint.radius as f32, joint.spec.radius as f32,
color, color,
); );
} }

View File

@ -10,7 +10,8 @@ use crate::{
layout::{Layout, LayoutHalfDelta, NetId, PinId}, layout::{Layout, LayoutHalfDelta, NetId, PinId},
math::Vector2, math::Vector2,
primitives::{ primitives::{
Joint, JointId, Polygon, PolygonId, Segment, SegmentId, SegmentSpec, Via, ViaId, ViaSpec, JointId, JointSpec, Polygon, PolygonId, Segment, SegmentId, SegmentSpec, Via, ViaId,
ViaSpec,
}, },
selection::{PinSelection, PinSelector}, selection::{PinSelection, PinSelector},
}; };
@ -61,8 +62,8 @@ impl Board {
pin_id pin_id
} }
pub fn add_joint(&mut self, joint: Joint) -> JointId { pub fn add_joint(&mut self, spec: JointSpec) -> JointId {
self.layout.add_joint(joint) self.layout.add_joint(spec)
} }
pub fn add_segment(&mut self, spec: SegmentSpec) -> SegmentId { pub fn add_segment(&mut self, spec: SegmentSpec) -> SegmentId {
@ -89,8 +90,8 @@ impl Board {
let joint = self.layout.joint(joint_id); let joint = self.layout.joint(joint_id);
Some(PinSelector { Some(PinSelector {
pin: self.pin_name(joint.pin?)?.to_string(), pin: self.pin_name(joint.spec.pin?)?.to_string(),
layer: self.layer_name(joint.layer)?.to_string(), layer: self.layer_name(joint.spec.layer)?.to_string(),
}) })
} }

View File

@ -15,7 +15,7 @@ use undoredo::{Delta, Recorder};
use crate::{ use crate::{
Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Vector2, Via, ViaId, Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Vector2, Via, ViaId,
primitives::{SegmentSpec, ViaSpec}, primitives::{JointSpec, SegmentSpec, ViaSpec},
}; };
#[derive( #[derive(
@ -123,9 +123,14 @@ impl Layout {
PinId::new(self.pins.push(Pin::new())) PinId::new(self.pins.push(Pin::new()))
} }
pub fn add_joint(&mut self, joint: Joint) -> JointId { pub fn add_joint(&mut self, spec: JointSpec) -> JointId {
let joint = Joint {
spec,
segments: Vec::new(),
vias: Vec::new(),
};
let bbox = joint.bbox(); let bbox = joint.bbox();
let pin_id = joint.pin; let pin_id = joint.spec.pin;
let joint_id = JointId::new(self.joints.push(joint)); let joint_id = JointId::new(self.joints.push(joint));
self.joints_rtree self.joints_rtree
@ -142,11 +147,11 @@ impl Layout {
self.add_segment_raw(Segment { self.add_segment_raw(Segment {
spec, spec,
endpoints: [ endpoints: [
self.joint(spec.endjoints[0]).position, self.joint(spec.endjoints[0]).spec.position,
self.joint(spec.endjoints[1]).position, self.joint(spec.endjoints[1]).spec.position,
], ],
layer: self.joint(spec.endjoints[0]).layer, layer: self.joint(spec.endjoints[0]).spec.layer,
net: self.joint(spec.endjoints[0]).net, net: self.joint(spec.endjoints[0]).spec.net,
}) })
} }
@ -155,6 +160,15 @@ impl Layout {
let bbox = segment.bbox(); let bbox = segment.bbox();
let segment_id = SegmentId::new(self.segments.push(segment)); let segment_id = SegmentId::new(self.segments.push(segment));
self.joints
.modify(segment.spec.endjoints[0].index(), |joint| {
joint.segments.push(segment_id)
});
self.joints
.modify(segment.spec.endjoints[1].index(), |joint| {
joint.segments.push(segment_id)
});
self.segments_rtree self.segments_rtree
.insert(GeomWithData::new(bbox, segment_id), ()); .insert(GeomWithData::new(bbox, segment_id), ());
@ -171,10 +185,10 @@ impl Layout {
self.add_via_raw(Via { self.add_via_raw(Via {
spec, spec,
min_layer: std::cmp::min(joint0.layer, joint1.layer), min_layer: std::cmp::min(joint0.spec.layer, joint1.spec.layer),
max_layer: std::cmp::max(joint0.layer, joint1.layer), max_layer: std::cmp::max(joint0.spec.layer, joint1.spec.layer),
net: joint0.net, net: joint0.spec.net,
position: (joint0.position + joint1.position) / 2, position: (joint0.spec.position + joint1.spec.position) / 2,
}) })
} }
@ -183,6 +197,13 @@ impl Layout {
let pin_id = via.spec.pin; let pin_id = via.spec.pin;
let via_id = ViaId::new(self.vias.push(via)); let via_id = ViaId::new(self.vias.push(via));
self.joints.modify(via.spec.endjoints[0].index(), |joint| {
joint.vias.push(via_id)
});
self.joints.modify(via.spec.endjoints[1].index(), |joint| {
joint.vias.push(via_id)
});
self.vias_rtree.insert(GeomWithData::new(bbox, via_id), ()); self.vias_rtree.insert(GeomWithData::new(bbox, via_id), ());
if let Some(pin_id) = pin_id { if let Some(pin_id) = pin_id {
@ -261,7 +282,7 @@ impl Layout {
.as_ref() .as_ref()
.locate_in_envelope_intersecting(&envelope) .locate_in_envelope_intersecting(&envelope)
.map(|geom_with_data| geom_with_data.data) .map(|geom_with_data| geom_with_data.data)
.filter(move |&id| self.joint(id).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: usize) -> impl Iterator<Item = SegmentId> + '_ {

View File

@ -9,7 +9,9 @@ use serde::{Deserialize, Serialize};
use stable_vec::StableVec; use stable_vec::StableVec;
use undoredo::Recorder; use undoredo::Recorder;
use crate::{Board, Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Vector2}; use crate::{
Board, Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Vector2, primitives::JointSpec,
};
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
@ -204,7 +206,7 @@ impl NavmesherBoard {
this.joint_multiobstacles.insert( this.joint_multiobstacles.insert(
i, i,
this.navmesher this.navmesher
.insert_multiobstacle(joint.layer, Self::joint_bounding_octagon(*joint)), .insert_multiobstacle(joint.spec.layer, Self::joint_bounding_octagon(joint)),
); );
} }
@ -227,21 +229,26 @@ impl NavmesherBoard {
this this
} }
pub fn insert_joint(&mut self, joint: Joint) -> JointId { pub fn insert_joint(&mut self, spec: JointSpec) -> JointId {
let joint_id = self.board.add_joint(joint); let layer = spec.layer;
let obstacle = Self::joint_bounding_octagon(&Joint {
spec,
segments: Vec::new(),
vias: Vec::new(),
});
let joint_id = self.board.add_joint(spec);
self.joint_multiobstacles.insert( self.joint_multiobstacles.insert(
joint_id.index(), joint_id.index(),
self.navmesher self.navmesher.insert_multiobstacle(layer, obstacle),
.insert_multiobstacle(joint.layer, Self::joint_bounding_octagon(joint)),
); );
joint_id joint_id
} }
fn joint_bounding_octagon(joint: Joint) -> [Vector2<i64>; 8] { fn joint_bounding_octagon(joint: &Joint) -> [Vector2<i64>; 8] {
let cx = joint.position.x; let cx = joint.spec.position.x;
let cy = joint.position.y; let cy = joint.spec.position.y;
let r = joint.radius as i64; let r = joint.spec.radius as i64;
[ [
Vector2::new(cx + r, cy + r / 2), Vector2::new(cx + r, cy + r / 2),

View File

@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::layout::{NetId, PinId}; use crate::layout::{NetId, PinId};
use crate::math::Vector2; use crate::math::Vector2;
use crate::primitives::{SegmentId, ViaId};
#[derive( #[derive(
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
@ -23,7 +24,7 @@ impl JointId {
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct Joint { pub struct JointSpec {
pub position: Vector2<i64>, pub position: Vector2<i64>,
pub layer: usize, pub layer: usize,
pub radius: u64, pub radius: u64,
@ -31,28 +32,36 @@ pub struct Joint {
pub pin: Option<PinId>, pub pin: Option<PinId>,
} }
#[derive(Clone, Debug)]
pub struct Joint {
pub spec: JointSpec,
pub segments: Vec<SegmentId>,
pub vias: Vec<ViaId>,
}
impl Joint { impl Joint {
pub fn center(&self) -> Vector2<i64> {
self.spec.position
}
pub fn bbox(&self) -> Rectangle<[i64; 3]> { pub fn bbox(&self) -> Rectangle<[i64; 3]> {
Rectangle::from_aabb(AABB::from_corners( Rectangle::from_aabb(AABB::from_corners(
[ [
self.position.x - self.radius as i64, self.spec.position.x - self.spec.radius as i64,
self.position.y - self.radius as i64, self.spec.position.y - self.spec.radius as i64,
self.layer as i64, self.spec.layer as i64,
], ],
[ [
self.position.x + self.radius as i64, self.spec.position.x + self.spec.radius as i64,
self.position.y + self.radius as i64, self.spec.position.y + self.spec.radius as i64,
self.layer as i64, self.spec.layer as i64,
], ],
)) ))
} }
pub fn center(&self) -> Vector2<i64> {
self.position
}
pub fn contains_point(&self, point: Vector2<i64>) -> bool { pub fn contains_point(&self, point: Vector2<i64>) -> bool {
(point.x - self.position.x).pow(2) as u64 + (point.y - self.position.y).pow(2) as u64 (point.x - self.spec.position.x).pow(2) as u64
<= self.radius.pow(2) + (point.y - self.spec.position.y).pow(2) as u64
<= self.spec.radius.pow(2)
} }
} }

View File

@ -9,7 +9,7 @@ mod polygon;
mod segment; mod segment;
mod via; mod via;
pub use joint::{Joint, JointId}; pub use joint::{Joint, JointId, JointSpec};
pub use polygon::{Polygon, PolygonId}; pub use polygon::{Polygon, PolygonId};
pub use segment::{Segment, SegmentId, SegmentSpec}; pub use segment::{Segment, SegmentId, SegmentSpec};
pub use via::{Via, ViaId, ViaSpec}; pub use via::{Via, ViaId, ViaSpec};

View File

@ -48,10 +48,10 @@ impl Ratsnest {
for (i, joint) in board.layout().joints().container().iter() { for (i, joint) in board.layout().joints().container().iter() {
let _ = triangulations let _ = triangulations
.entry((joint.net, joint.layer)) .entry((joint.spec.net, joint.spec.layer))
.or_insert_with(DelaunayTriangulation::new) .or_insert_with(DelaunayTriangulation::new)
.insert(DelaunayVertex { .insert(DelaunayVertex {
layer: joint.layer, layer: joint.spec.layer,
center: joint.center(), center: joint.center(),
position: spade::Point2::new(joint.center().x as f64, joint.center().y as f64), position: spade::Point2::new(joint.center().x as f64, joint.center().y as f64),
primitive_id: PrimitiveId::Joint(JointId::new(i)), primitive_id: PrimitiveId::Joint(JointId::new(i)),

View File

@ -14,7 +14,7 @@ use crate::{
Segment, Vector2, Segment, Vector2,
board::Board, board::Board,
layout::{NetId, PinId}, layout::{NetId, PinId},
primitives::{Joint, Polygon, SegmentSpec}, primitives::{JointSpec, Polygon, SegmentSpec},
}; };
impl Board { impl Board {
@ -278,7 +278,7 @@ impl Board {
pin: Option<PinId>, pin: Option<PinId>,
flip: bool, flip: bool,
) { ) {
board.add_joint(Joint { board.add_joint(JointSpec {
position: Self::pos(place, pin_pos, 0.0, 0.0, flip), position: Self::pos(place, pin_pos, 0.0, 0.0, flip),
layer, layer,
net, net,
@ -326,7 +326,7 @@ impl Board {
) { ) {
// Add the first coordinate in the wire path as a dot and save its index. // Add the first coordinate in the wire path as a dot and save its index.
let mut prev_pos: Vector2<i64> = Self::pos(place, pin_pos, coords[0].x, coords[0].y, flip); let mut prev_pos: Vector2<i64> = Self::pos(place, pin_pos, coords[0].x, coords[0].y, flip);
let mut prev_joint = board.add_joint(Joint { let mut prev_joint = board.add_joint(JointSpec {
position: prev_pos, position: prev_pos,
layer, layer,
radius: (width / 2.0) as u64, radius: (width / 2.0) as u64,
@ -342,7 +342,7 @@ impl Board {
continue; continue;
} }
let joint = board.add_joint(Joint { let joint = board.add_joint(JointSpec {
position: pos, position: pos,
layer, layer,
radius: (width / 2.0) as u64, radius: (width / 2.0) as u64,