diff --git a/topola-egui/src/display.rs b/topola-egui/src/display.rs index 138ec85..aa6f7eb 100644 --- a/topola-egui/src/display.rs +++ b/topola-egui/src/display.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use crate::{viewport::Viewport, workspace::Workspace}; -use topola::{Joint, Polygon, Segment, SegmentId}; +use topola::{Joint, Polygon, Segment, SegmentId, Vector2}; pub struct Display {} @@ -132,7 +132,7 @@ impl Display { color: egui::Color32, ) { ui.painter().circle_filled( - egui::pos2(joint.position[0] as f32, joint.position[1] as f32), + egui::pos2(joint.position.x as f32, joint.position.y as f32), joint.radius as f32, color, ); @@ -144,13 +144,13 @@ impl Display { ui: &egui::Ui, viewport: &Viewport, segment: &Segment, - endpoints: [[i64; 2]; 2], + endpoints: [Vector2; 2], color: egui::Color32, ) { ui.painter().line_segment( [ - egui::pos2(endpoints[0][0] as f32, endpoints[0][1] as f32), - egui::pos2(endpoints[1][0] as f32, endpoints[1][1] as f32), + egui::pos2(endpoints[0].x as f32, endpoints[0].y as f32), + egui::pos2(endpoints[1].x as f32, endpoints[1].y as f32), ], egui::Stroke::new(segment.half_width as f32 * 2.0, color), ); @@ -167,7 +167,7 @@ impl Display { let points: Vec = polygon .vertices .iter() - .map(|v| egui::pos2(v[0] as f32, v[1] as f32)) + .map(|v| egui::pos2(v.x as f32, v.y as f32)) .collect(); ui.painter().add(egui::Shape::convex_polygon( @@ -226,8 +226,8 @@ impl Display { ui.painter().rect_stroke( egui::Rect::from_two_pos( - egui::pos2(endpoints[0][0] as f32, endpoints[0][1] as f32), - egui::pos2(endpoints[1][0] as f32, endpoints[1][1] as f32), + egui::pos2(endpoints[0].x as f32, endpoints[0].y as f32), + egui::pos2(endpoints[1].x as f32, endpoints[1].y as f32), ), egui::CornerRadius::ZERO, egui::Stroke::new(5.0, egui::Color32::GRAY), diff --git a/topola/src/layout.rs b/topola/src/layout.rs index 110bc62..67df45a 100644 --- a/topola/src/layout.rs +++ b/topola/src/layout.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use stable_vec::StableVec; use undoredo::{ApplyDelta, Delta, FlushDelta, Recorder}; -use crate::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId}; +use crate::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId, Vector2}; #[derive( Clone, Constructor, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, @@ -164,7 +164,7 @@ impl Layout { polygon_id } - pub fn segment_endpoints(&self, segment_id: SegmentId) -> [[i64; 2]; 2] { + pub fn segment_endpoints(&self, segment_id: SegmentId) -> [Vector2; 2] { let endjoints = self.segments.get(&segment_id.id()).unwrap().endjoints; [ self.joints.get(&endjoints[0].id()).unwrap().position, @@ -177,10 +177,10 @@ impl Layout { let layer = self.segments.get(&segment_id.id()).unwrap().layer as i64; let half_width = self.segments.get(&segment_id.id()).unwrap().half_width as i64; - let min_x = std::cmp::min(endpoints[0][0], endpoints[1][0]) - half_width; - let min_y = std::cmp::min(endpoints[0][1], endpoints[1][1]) - half_width; - let max_x = std::cmp::max(endpoints[0][0], endpoints[1][0]) + half_width; - let max_y = std::cmp::max(endpoints[0][1], endpoints[1][1]) + half_width; + let min_x = std::cmp::min(endpoints[0].x, endpoints[1].x) - half_width; + let min_y = std::cmp::min(endpoints[0].y, endpoints[1].y) - half_width; + let max_x = std::cmp::max(endpoints[0].x, endpoints[1].x) + half_width; + let max_y = std::cmp::max(endpoints[0].y, endpoints[1].y) + half_width; Rectangle::from_corners([min_x, min_y, layer], [max_x, max_y, layer]) } diff --git a/topola/src/lib.rs b/topola/src/lib.rs index f4a5caf..3ad740e 100644 --- a/topola/src/lib.rs +++ b/topola/src/lib.rs @@ -12,5 +12,6 @@ mod specctra; pub use crate::board::Board; pub use crate::layout::Layout; +pub use crate::math::Vector2; pub use crate::navmesher::NavmesherBoard; pub use crate::primitives::{Joint, JointId, Polygon, PolygonId, Segment, SegmentId, Via, ViaId}; diff --git a/topola/src/math.rs b/topola/src/math.rs index 262a40d..63351c0 100644 --- a/topola/src/math.rs +++ b/topola/src/math.rs @@ -4,12 +4,59 @@ use derive_more::{Add, Constructor, From, Into, Sub}; -#[derive(Add, Clone, Constructor, Copy, Debug, From, Into, Sub)] +#[derive(Add, Clone, Constructor, Copy, Debug, Eq, From, Into, PartialEq, Sub)] pub struct Vector2 { pub x: T, pub y: T, } +impl From<[T; 2]> for Vector2 { + fn from(from: [T; 2]) -> Self { + Self { + x: from[0], + y: from[1], + } + } +} + +impl From> for [T; 2] { + fn from(from: Vector2) -> Self { + [from.x, from.y] + } +} + +// Check if the point (px, py) is inside the polygon using the ray-casting +// algorithm. +macro_rules! impl_inside_polygon { + ($type:ty) => { + impl Vector2<$type> { + pub fn inside_polygon(&self, polygon: &[Vector2<$type>]) -> bool { + let mut inside = false; + let n = polygon.len(); + let px = &self.x; + let py = &self.y; + + let mut p1 = &polygon[n - 1]; + for p2 in polygon.iter() { + if (*py > p1.y) != (*py > p2.y) { + if *px < (p2.x - p1.x) * (*py - p1.y) / (p2.y - p1.y) + p1.x { + inside = !inside; + } + } + p1 = p2; + } + + inside + } + } + }; +} + +impl_inside_polygon!(f32); +impl_inside_polygon!(f64); +impl_inside_polygon!(i32); +impl_inside_polygon!(i64); + macro_rules! impl_rotate_around_point { ($t:ty) => { impl Vector2<$t> { diff --git a/topola/src/navmesher.rs b/topola/src/navmesher.rs index eb7ba32..f9959f8 100644 --- a/topola/src/navmesher.rs +++ b/topola/src/navmesher.rs @@ -129,8 +129,8 @@ impl NavmesherBoard { } fn joint_circumscribed_octagon(joint: Joint) -> [[i64; 2]; 8] { - let cx = joint.position[0]; - let cy = joint.position[1]; + let cx = joint.position.x; + let cy = joint.position.y; let r = joint.radius as i64; [ @@ -163,10 +163,10 @@ impl NavmesherBoard { navmesher.insert_polygon( segment.layer, Self::inflated_segment( - endpoints[0][0], - endpoints[0][1], - endpoints[1][0], - endpoints[1][1], + endpoints[0].x, + endpoints[0].y, + endpoints[1].x, + endpoints[1].y, segment.half_width, ), ) @@ -202,6 +202,9 @@ impl NavmesherBoard { } fn insert_polygon_in_navmesher(navmesher: &mut Navmesher, polygon: Polygon) { - navmesher.insert_polygon(polygon.layer, polygon.vertices); + navmesher.insert_polygon( + polygon.layer, + polygon.vertices.into_iter().map(Into::into), + ); } } diff --git a/topola/src/primitives.rs b/topola/src/primitives.rs index 21d5d4b..e4e4094 100644 --- a/topola/src/primitives.rs +++ b/topola/src/primitives.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::{ layout::{NetId, PinId}, selection::PinSelector, + Vector2, }; #[derive( @@ -26,7 +27,7 @@ impl JointId { #[derive(Clone, Copy, Debug)] pub struct Joint { - pub position: [i64; 2], + pub position: Vector2, pub layer: usize, pub radius: u64, pub net: NetId, @@ -37,18 +38,23 @@ impl Joint { pub fn bbox(&self) -> Rectangle<[i64; 3]> { Rectangle::from_aabb(AABB::from_corners( [ - self.position[0] - self.radius as i64, - self.position[1] - self.radius as i64, + self.position.x - self.radius as i64, + self.position.y - self.radius as i64, self.layer as i64, ], [ - self.position[0] + self.radius as i64, - self.position[1] + self.radius as i64, + self.position.x + self.radius as i64, + self.position.y + self.radius as i64, self.layer as i64, ], )) } + pub fn contains_point(&self, point: Vector2) -> bool { + (point.x - self.position.x).pow(2) as u64 + (point.y - self.position.y).pow(2) as u64 + <= self.radius.pow(2) + } + pub fn pin_selector(&self) -> Option { Some(PinSelector { pin: self.pin?, @@ -138,7 +144,7 @@ impl PolygonId { #[derive(Clone, Debug)] pub struct Polygon { - pub vertices: Vec<[i64; 2]>, + pub vertices: Vec>, pub layer: usize, pub net: NetId, pub pin: Option, @@ -149,11 +155,17 @@ impl Polygon { Rectangle::from_aabb(self.vertices.clone().into_iter().fold( AABB::new_empty(), |aabb, vertex| { - aabb.merged(&AABB::from_point([vertex[0], vertex[1], self.layer as i64])) + aabb.merged(&AABB::from_point([vertex.x, vertex.y, self.layer as i64])) }, )) } + pub fn contains_point(&self, point: Vector2) -> bool { + /*Vector2::from(point) + .inside_polygon(&self.vertices.iter().map(Into::into).collect::>())*/ + false + } + pub fn pin_selector(&self) -> Option { Some(PinSelector { pin: self.pin?, diff --git a/topola/src/specctra.rs b/topola/src/specctra.rs index 2e9be73..904a3ed 100644 --- a/topola/src/specctra.rs +++ b/topola/src/specctra.rs @@ -14,8 +14,8 @@ use crate::{ Segment, board::Board, layout::{NetId, PinId}, - math::Vector2, primitives::{Joint, Polygon}, + Vector2, }; impl Board { @@ -322,7 +322,7 @@ impl Board { flip: bool, ) { // Add the first coordinate in the wire path as a dot and save its index. - let mut prev_pos = Self::pos(place, pin_pos, coords[0].x, coords[0].y, flip); + let mut prev_pos: Vector2 = Self::pos(place, pin_pos, coords[0].x, coords[0].y, flip); let mut prev_joint = board.add_joint(Joint { position: prev_pos, layer, @@ -372,7 +372,7 @@ impl Board { pin: Option, flip: bool, ) { - let vertices: Vec<[i64; 2]> = coords + let vertices: Vec> = coords .iter() .map(|coord| Self::pos(place, pin_pos, coord.x, coord.y, flip)) .collect(); @@ -400,13 +400,13 @@ impl Board { x: f64, y: f64, flip: bool, - ) -> [i64; 2] { + ) -> Vector2 { 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())); - [pos.x as i64, pos.y as i64] + Vector2::new(pos.x as i64, pos.y as i64) } }