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

View File

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

View File

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

View File

@ -9,7 +9,9 @@ use serde::{Deserialize, Serialize};
use stable_vec::StableVec;
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(
Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize,
@ -204,7 +206,7 @@ impl NavmesherBoard {
this.joint_multiobstacles.insert(
i,
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
}
pub fn insert_joint(&mut self, joint: Joint) -> JointId {
let joint_id = self.board.add_joint(joint);
pub fn insert_joint(&mut self, spec: JointSpec) -> JointId {
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(
joint_id.index(),
self.navmesher
.insert_multiobstacle(joint.layer, Self::joint_bounding_octagon(joint)),
self.navmesher.insert_multiobstacle(layer, obstacle),
);
joint_id
}
fn joint_bounding_octagon(joint: Joint) -> [Vector2<i64>; 8] {
let cx = joint.position.x;
let cy = joint.position.y;
let r = joint.radius as i64;
fn joint_bounding_octagon(joint: &Joint) -> [Vector2<i64>; 8] {
let cx = joint.spec.position.x;
let cy = joint.spec.position.y;
let r = joint.spec.radius as i64;
[
Vector2::new(cx + r, cy + r / 2),

View File

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

View File

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

View File

@ -14,7 +14,7 @@ use crate::{
Segment, Vector2,
board::Board,
layout::{NetId, PinId},
primitives::{Joint, Polygon, SegmentSpec},
primitives::{JointSpec, Polygon, SegmentSpec},
};
impl Board {
@ -278,7 +278,7 @@ impl Board {
pin: Option<PinId>,
flip: bool,
) {
board.add_joint(Joint {
board.add_joint(JointSpec {
position: Self::pos(place, pin_pos, 0.0, 0.0, flip),
layer,
net,
@ -326,7 +326,7 @@ impl Board {
) {
// 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_joint = board.add_joint(Joint {
let mut prev_joint = board.add_joint(JointSpec {
position: prev_pos,
layer,
radius: (width / 2.0) as u64,
@ -342,7 +342,7 @@ impl Board {
continue;
}
let joint = board.add_joint(Joint {
let joint = board.add_joint(JointSpec {
position: pos,
layer,
radius: (width / 2.0) as u64,