Add ratsnest generation (not used yet)

This commit is contained in:
Mikolaj Wielgus 2026-03-19 21:43:51 +01:00
parent f351728762
commit 7f4d3eb420
4 changed files with 142 additions and 2 deletions

View File

@ -164,6 +164,12 @@ impl Layout {
polygon_id
}
pub fn segment_center(&self, segment_id: SegmentId) -> Vector2<i64> {
let endpoints = self.segment_endpoints(segment_id);
(endpoints[0] + endpoints[1]) / 2
}
pub fn segment_endpoints(&self, segment_id: SegmentId) -> [Vector2<i64>; 2] {
let endjoints = self.segments.get(&segment_id.index()).unwrap().endjoints;
[

View File

@ -7,7 +7,7 @@ mod layout;
mod math;
mod navmesher;
mod primitives;
//mod ratsnests;
mod ratsnest;
mod selection;
mod specctra;
@ -15,5 +15,8 @@ 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};
pub use crate::primitives::{
Joint, JointId, Polygon, PolygonId, PrimitiveId, Segment, SegmentId, Via, ViaId,
};
pub use crate::ratsnest::{Ratline, Ratsnest};
pub use crate::selection::{PinSelection, PinSelector};

View File

@ -56,6 +56,10 @@ impl Joint {
))
}
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)
@ -145,6 +149,10 @@ impl Polygon {
)
}
pub fn center(&self) -> Vector2<i64> {
Vector2::<i64>::polygon_centroid(&self.vertices)
}
pub fn contains_point(&self, point: Vector2<i64>) -> bool {
point.inside_polygon(&self.vertices)
}

123
topola/src/ratsnest.rs Normal file
View File

@ -0,0 +1,123 @@
// SPDX-FileCopyrightText: 2026 Topola contributors
//
// SPDX-License-Identifier: MIT OR Apache-2.0
use derive_getters::Getters;
use serde::{Deserialize, Serialize};
use spade::{DelaunayTriangulation, HasPosition, Triangulation, handles::FixedVertexHandle};
use crate::{Board, JointId, PolygonId, SegmentId, Vector2, primitives::PrimitiveId};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Getters, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Ratline {
endpoint_primitive_ids: [PrimitiveId; 2],
endpoint_layers: [usize; 2],
endpoints: [Vector2<i64>; 2],
}
struct DelaunayVertex {
pub layer: usize,
pub center: Vector2<i64>,
pub position: spade::Point2<f64>,
pub primitive_id: PrimitiveId,
}
impl HasPosition for DelaunayVertex {
type Scalar = f64;
fn position(&self) -> spade::Point2<f64> {
self.position
}
}
#[derive(Clone, Debug, Deserialize, Getters, Serialize)]
pub struct Ratsnest {
ratlines: Vec<Ratline>,
}
impl Ratsnest {
pub fn new(board: &Board) -> Self {
let mut ratlines = Vec::new();
for layer in 0..*board.layout().layer_count() {
let mut triangulation: DelaunayTriangulation<DelaunayVertex> =
DelaunayTriangulation::new();
for layer in 0..*board.layout().layer_count() {
for (i, joint) in board.layout().joints().collection() {
if joint.layer == layer {
triangulation.insert(DelaunayVertex {
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)),
});
}
}
for (i, segment) in board.layout().segments().collection() {
if segment.layer == layer {
let segment_center = board.layout().segment_center(SegmentId::new(i));
triangulation.insert(DelaunayVertex {
layer,
center: segment_center,
position: spade::Point2::new(
segment_center.x as f64,
segment_center.y as f64,
),
primitive_id: PrimitiveId::Segment(SegmentId::new(i)),
});
}
}
for (i, polygon) in board.layout().polygons().collection() {
if polygon.layer == layer {
triangulation.insert(DelaunayVertex {
layer,
center: polygon.center(),
position: spade::Point2::new(
polygon.center().x as f64,
polygon.center().y as f64,
),
primitive_id: PrimitiveId::Polygon(PolygonId::new(i)),
});
}
}
}
let mut weighted_edges: Vec<(u64, [usize; 2])> = Vec::new();
for edge in triangulation.undirected_edges() {
let vertices = edge.vertices();
weighted_edges.push((
edge.length_2() as u64,
[vertices[0].index(), vertices[1].index()],
));
}
for [index0, index1] in
crate::math::kruskal_mst(triangulation.num_vertices(), &weighted_edges)
{
let vertex0 = triangulation
.get_vertex(FixedVertexHandle::from_index(index0))
.unwrap();
let vertex0 = vertex0.data();
let vertex1 = triangulation
.get_vertex(FixedVertexHandle::from_index(index1))
.unwrap();
let vertex1 = vertex1.data();
ratlines.push(Ratline {
endpoint_primitive_ids: [vertex0.primitive_id, vertex1.primitive_id],
endpoint_layers: [vertex0.layer, vertex1.layer],
endpoints: [vertex0.center, vertex1.center],
});
}
}
Self { ratlines }
}
}