From c927ad281f79f2ca3daac9b04ee21a2ffa60fdd9 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 10 Mar 2026 13:13:38 +0100 Subject: [PATCH] Add polygon insertion --- topola/src/board.rs | 7 ++++++- topola/src/layout.rs | 44 +++++++++++++++++++++++++++++++++++++---- topola/src/math.rs | 40 +++++++++++++++++++++++++++++++++++++ topola/src/navmesher.rs | 7 ++++++- topola/src/specctra.rs | 34 +++++++++++++++++++++++++------ 5 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 topola/src/math.rs diff --git a/topola/src/board.rs b/topola/src/board.rs index b7e2034..47689db 100644 --- a/topola/src/board.rs +++ b/topola/src/board.rs @@ -6,7 +6,8 @@ use derive_getters::{Dissolve, Getters}; use undoredo::{ApplyDelta, Delta, FlushDelta}; use crate::layout::{ - Arc, ArcId, Joint, JointId, Layout, LayoutHalfDelta, Segment, SegmentId, Via, ViaId, + Arc, ArcId, Joint, JointId, Layout, LayoutHalfDelta, Polygon, PolygonId, Segment, SegmentId, + Via, ViaId, }; struct Layer { @@ -41,6 +42,10 @@ impl Board { pub fn add_via(&mut self, via: Via) -> ViaId { self.layout.add_via(via) } + + pub fn add_polygon(&mut self, polygon: Polygon) -> PolygonId { + self.layout.add_polygon(polygon) + } } #[derive(Clone, Debug, Dissolve)] diff --git a/topola/src/layout.rs b/topola/src/layout.rs index 1ab1533..39639e9 100644 --- a/topola/src/layout.rs +++ b/topola/src/layout.rs @@ -12,7 +12,7 @@ use undoredo::{ApplyDelta, Delta, FlushDelta, Recorder}; pub struct JointId(usize); impl JointId { - /// Wrap a vertex index in a newtype struct. + /// Wrap a joint index in a newtype struct. #[inline] pub fn new(id: usize) -> Self { Self(id) @@ -36,7 +36,7 @@ pub struct Joint { pub struct SegmentId(usize); impl SegmentId { - /// Wrap a vertex index in a newtype struct. + /// Wrap a segment index in a newtype struct. #[inline] pub fn new(id: usize) -> Self { Self(id) @@ -60,7 +60,7 @@ pub struct Segment { pub struct ArcId(usize); impl ArcId { - /// Wrap a vertex index in a newtype struct. + /// Wrap an arc index in a newtype struct. #[inline] pub fn new(id: usize) -> Self { Self(id) @@ -85,7 +85,7 @@ pub struct Arc { pub struct ViaId(usize); impl ViaId { - /// Wrap a vertex index in a newtype struct. + /// Wrap a via index in a newtype struct. #[inline] pub fn new(id: usize) -> Self { Self(id) @@ -105,6 +105,29 @@ pub struct Via { pub radius: u64, } +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct PolygonId(usize); + +impl PolygonId { + /// Wrap a polygon index in a newtype struct. + #[inline] + pub fn new(id: usize) -> Self { + Self(id) + } + + /// Returns the underlying index. + #[inline] + pub fn id(self) -> usize { + self.0 + } +} + +#[derive(Clone, Debug)] +pub struct Polygon { + pub vertices: Vec<[i64; 2]>, + pub layer: usize, +} + #[derive(Clone, Debug, Getters)] pub struct Layout { boundary: Vec<[i64; 2]>, @@ -113,6 +136,7 @@ pub struct Layout { segments: Recorder>, arcs: Recorder>, vias: Recorder>, + polygons: Recorder>, } impl Layout { @@ -124,6 +148,7 @@ impl Layout { segments: Recorder::new(StableVec::new()), arcs: Recorder::new(StableVec::new()), vias: Recorder::new(StableVec::new()), + polygons: Recorder::new(StableVec::new()), } } @@ -142,6 +167,10 @@ impl Layout { pub fn add_via(&mut self, via: Via) -> ViaId { ViaId::new(self.vias.push(via)) } + + pub fn add_polygon(&mut self, polygon: Polygon) -> PolygonId { + PolygonId::new(self.polygons.push(polygon)) + } } #[derive(Clone, Debug, Dissolve)] @@ -150,6 +179,7 @@ pub struct LayoutHalfDelta { segments: BTreeMap, arcs: BTreeMap, vias: BTreeMap, + polygons: BTreeMap, } impl ApplyDelta for Layout { @@ -167,6 +197,9 @@ impl ApplyDelta for Layout { let vias_delta = Delta::with_removed_inserted(removed.vias, inserted.vias); self.vias.apply_delta(&vias_delta); + + let polygons_delta = Delta::with_removed_inserted(removed.polygons, inserted.polygons); + self.polygons.apply_delta(&polygons_delta); } } @@ -176,6 +209,7 @@ impl FlushDelta for Layout { let (removed_segments, inserted_segments) = self.segments.flush_delta().dissolve(); let (removed_arcs, inserted_arcs) = self.arcs.flush_delta().dissolve(); let (removed_vias, inserted_vias) = self.vias.flush_delta().dissolve(); + let (removed_polygons, inserted_polygons) = self.polygons.flush_delta().dissolve(); Delta::with_removed_inserted( LayoutHalfDelta { @@ -183,12 +217,14 @@ impl FlushDelta for Layout { segments: removed_segments, arcs: removed_arcs, vias: removed_vias, + polygons: removed_polygons, }, LayoutHalfDelta { joints: inserted_joints, segments: inserted_segments, arcs: inserted_arcs, vias: inserted_vias, + polygons: inserted_polygons, }, ) } diff --git a/topola/src/math.rs b/topola/src/math.rs new file mode 100644 index 0000000..262a40d --- /dev/null +++ b/topola/src/math.rs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2026 Topola contributors +// +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use derive_more::{Add, Constructor, From, Into, Sub}; + +#[derive(Add, Clone, Constructor, Copy, Debug, From, Into, Sub)] +pub struct Vector2 { + pub x: T, + pub y: T, +} + +macro_rules! impl_rotate_around_point { + ($t:ty) => { + impl Vector2<$t> { + pub fn rotate_around_point(&mut self, angle: $t, origin: Vector2<$t>) -> Self { + let sin = angle.sin(); + let cos = angle.cos(); + + let tx = self.x - origin.x; + let ty = self.y - origin.y; + + let rx = tx * cos - ty * sin; + let ry = tx * sin + ty * cos; + + self.x = rx + origin.x; + self.y = ry + origin.y; + + *self + } + + pub fn rotate_around_point_degrees(&mut self, angle: $t, origin: Vector2<$t>) -> Self { + self.rotate_around_point(angle.to_radians(), origin) + } + } + }; +} + +impl_rotate_around_point!(f32); +impl_rotate_around_point!(f64); diff --git a/topola/src/navmesher.rs b/topola/src/navmesher.rs index 7cb9890..4e3aab9 100644 --- a/topola/src/navmesher.rs +++ b/topola/src/navmesher.rs @@ -7,7 +7,7 @@ use derive_getters::Getters; use crate::{ Board, - layout::{Arc, ArcId, Joint, JointId, Segment, SegmentId, Via, ViaId}, + layout::{Arc, ArcId, Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId}, }; #[derive(Clone, Debug, Getters)] @@ -123,4 +123,9 @@ impl NavmesherBoard { // TODO: Insert into navmesh. self.board.add_via(via) } + + pub fn insert_polygon(&mut self, polygon: Polygon) -> PolygonId { + // TODO: Insert into navmesh. + self.board.add_polygon(polygon) + } } diff --git a/topola/src/specctra.rs b/topola/src/specctra.rs index 5a661c0..6de81f5 100644 --- a/topola/src/specctra.rs +++ b/topola/src/specctra.rs @@ -47,6 +47,7 @@ impl Board { &mut board, place.point_with_rotation(), pin.point_with_rotation(), + 0, (circle.diameter / 2.0) as u64, false, ), @@ -64,31 +65,52 @@ impl Board { board: &mut Board, place: PointWithRotation, pin: PointWithRotation, + layer: usize, radius: u64, flip: bool, ) { - let pos = Self::pos(place, pin, 0.0, 0.0, flip); - board.add_joint(Joint { - position: [pos.x, pos.y], - layer: 0, + position: Self::pos(place, pin, 0.0, 0.0, flip), + layer, radius, }); } + /*pub fn place_rect( + board: &mut Board, + place: PointWithRotation, + pin: PointWithRotation, + x1: f64, + y1: f64, + x2: f64, + y2: f64, + layer: usize, + flip: bool, + ) { + board.add_polygon(Polygon { + vertices: [ + Self::pos(place, pin, x1, y1, flip), + Self::pos(place, pin, x2, y1, flip), + Self::pos(place, pin, x2, y2, flip), + Self::pos(place, pin, x1, y2, flip), + ], + layer, + }) + }*/ + fn pos( place: PointWithRotation, pin: PointWithRotation, x: f64, y: f64, flip: bool, - ) -> Vector2 { + ) -> [i64; 2] { let pos = (Vector2::new(x, y) + Vector2::new(pin.pos.x(), pin.pos.y())) .rotate_around_point_degrees(pin.rot, Vector2::new(pin.pos.x(), pin.pos.y())); let pos = (Vector2::new(place.pos.x(), place.pos.y()) + flip.then_some(Vector2::new(-pos.x, pos.y)).unwrap_or(pos)) .rotate_around_point_degrees(place.rot, Vector2::new(place.pos.x(), place.pos.y())); - Vector2::new(pos.x as i64, pos.y as i64) + [pos.x as i64, pos.y as i64] } }