mirror of https://codeberg.org/topola/topola.git
refactor(specctra/design): Place fillet circles, netless for now
This commit is contained in:
parent
4a057d3499
commit
521bb0598a
|
|
@ -105,6 +105,8 @@ impl Ratsnest {
|
||||||
|
|
||||||
for node in layout.drawing().layer_primitive_nodes(layer) {
|
for node in layout.drawing().layer_primitive_nodes(layer) {
|
||||||
if let PrimitiveIndex::FixedDot(dot) = node {
|
if let PrimitiveIndex::FixedDot(dot) = node {
|
||||||
|
// Dots that are parts of polys are ignored because ratlines
|
||||||
|
// should only go to their centerpoints.
|
||||||
if layout.drawing().compounds(dot).next().is_none() {
|
if layout.drawing().compounds(dot).next().is_none() {
|
||||||
handle_rvw(
|
handle_rvw(
|
||||||
layout.drawing().primitive(dot).maybe_net(),
|
layout.drawing().primitive(dot).maybe_net(),
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@
|
||||||
|
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
|
|
||||||
use geo::{point, Distance, Euclidean, Line, Point};
|
use geo::{point, Distance, Euclidean, Length, Line, Point};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::math;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct Circle {
|
pub struct Circle {
|
||||||
pub pos: Point,
|
pub pos: Point,
|
||||||
|
|
@ -129,3 +131,36 @@ pub fn intersect_circle_segment(circle: &Circle, segment: &Line) -> Vec<Point> {
|
||||||
|
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the filleting circle of line segments `segment1` and `segment2`.
|
||||||
|
pub fn fillet_circle(segment1: &Line, segment2: &Line) -> Circle {
|
||||||
|
// Turn segment1 delta vector counterclockwisely by 90 degrees.
|
||||||
|
let diameter_ray = Line::new(
|
||||||
|
segment1.end_point(),
|
||||||
|
point! {x: segment1.end_point().x() - segment1.delta().y, y: segment1.end_point().y() + segment1.delta().x},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Radius is the distance from the diameter line to segment2.start_point().
|
||||||
|
let radius = (diameter_ray.delta().y * segment2.start_point().x()
|
||||||
|
- diameter_ray.delta().x * segment2.start_point().y()
|
||||||
|
+ diameter_ray.end_point().x() * diameter_ray.start_point().y()
|
||||||
|
- diameter_ray.end_point().y() * diameter_ray.start_point().x())
|
||||||
|
.abs()
|
||||||
|
/ diameter_ray.length::<Euclidean>();
|
||||||
|
|
||||||
|
let center =
|
||||||
|
if math::perp_dot_product(Point::from(segment1.delta()), Point::from(segment2.delta()))
|
||||||
|
>= 0.0
|
||||||
|
{
|
||||||
|
segment1.end_point()
|
||||||
|
+ (diameter_ray.delta() / diameter_ray.length::<Euclidean>() * radius).into()
|
||||||
|
} else {
|
||||||
|
segment1.end_point()
|
||||||
|
- (diameter_ray.delta() / diameter_ray.length::<Euclidean>() * radius).into()
|
||||||
|
};
|
||||||
|
|
||||||
|
Circle {
|
||||||
|
pos: center,
|
||||||
|
r: radius,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@
|
||||||
|
|
||||||
use std::collections::{btree_map::Entry as BTreeMapEntry, BTreeMap};
|
use std::collections::{btree_map::Entry as BTreeMapEntry, BTreeMap};
|
||||||
|
|
||||||
use geo::{Point, Rotate};
|
use geo::{Euclidean, Length, Line, Point, Rotate};
|
||||||
|
use itertools::Itertools;
|
||||||
use specctra_core::math::PointWithRotation;
|
use specctra_core::math::PointWithRotation;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -22,7 +23,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
geometry::{primitive::PrimitiveShape, GetLayer, GetWidth},
|
geometry::{primitive::PrimitiveShape, GetLayer, GetWidth},
|
||||||
layout::{poly::SolidPolyWeight, Layout},
|
layout::{poly::SolidPolyWeight, Layout},
|
||||||
math::Circle,
|
math::{self, Circle},
|
||||||
specctra::{
|
specctra::{
|
||||||
mesadata::SpecctraMesadata,
|
mesadata::SpecctraMesadata,
|
||||||
read::ListTokenizer,
|
read::ListTokenizer,
|
||||||
|
|
@ -733,6 +734,78 @@ impl SpecctraDesign {
|
||||||
maybe_pin,
|
maybe_pin,
|
||||||
&nodes[..],
|
&nodes[..],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Self::add_polygon_fillet_circles(
|
||||||
|
recorder, board, place, pin, coords, width, layer, maybe_net, None, flip,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_polygon_fillet_circles(
|
||||||
|
recorder: &mut BoardEdit,
|
||||||
|
board: &mut Board<SpecctraMesadata>,
|
||||||
|
place: PointWithRotation,
|
||||||
|
pin: PointWithRotation,
|
||||||
|
coords: &[structure::Point],
|
||||||
|
_width: f64,
|
||||||
|
layer: usize,
|
||||||
|
maybe_net: Option<usize>,
|
||||||
|
_maybe_pin: Option<String>,
|
||||||
|
flip: bool,
|
||||||
|
) {
|
||||||
|
let MIN_FIRST_CHAIN_ELEMENT_LENGTH = 100.0;
|
||||||
|
let mut maybe_first_chain_segment = None;
|
||||||
|
|
||||||
|
let first_pos = Self::pos(place, pin, coords[0].x, coords[0].y, flip);
|
||||||
|
let last_pos = Self::pos(
|
||||||
|
place,
|
||||||
|
pin,
|
||||||
|
coords.last().unwrap().x,
|
||||||
|
coords.last().unwrap().y,
|
||||||
|
flip,
|
||||||
|
);
|
||||||
|
|
||||||
|
let last_first_segment = Line::new(last_pos, first_pos);
|
||||||
|
|
||||||
|
if last_first_segment.length::<Euclidean>() >= MIN_FIRST_CHAIN_ELEMENT_LENGTH {
|
||||||
|
maybe_first_chain_segment = Some((Line::new(last_pos, first_pos), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index, coord_triple) in coords
|
||||||
|
.iter()
|
||||||
|
.circular_tuple_windows::<(_, _, _)>()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
let curr_pos0 = Self::pos(place, pin, coord_triple.0.x, coord_triple.0.y, flip);
|
||||||
|
let curr_pos1 = Self::pos(place, pin, coord_triple.1.x, coord_triple.1.y, flip);
|
||||||
|
let curr_pos2 = Self::pos(place, pin, coord_triple.2.x, coord_triple.2.y, flip);
|
||||||
|
let curr_segment01 = Line::new(curr_pos0, curr_pos1);
|
||||||
|
let curr_segment12 = Line::new(curr_pos1, curr_pos2);
|
||||||
|
|
||||||
|
if math::angle_between(curr_segment01.delta().into(), curr_segment12.delta().into())
|
||||||
|
.abs()
|
||||||
|
> 30.0_f64.to_radians()
|
||||||
|
|| curr_segment12.length::<Euclidean>() >= MIN_FIRST_CHAIN_ELEMENT_LENGTH
|
||||||
|
{
|
||||||
|
if let Some((first_chain_segment, first_chain_index)) = maybe_first_chain_segment {
|
||||||
|
if index - first_chain_index >= 3 {
|
||||||
|
let circle = math::fillet_circle(&first_chain_segment, &curr_segment12);
|
||||||
|
|
||||||
|
board.add_fixed_dot_infringably(
|
||||||
|
recorder,
|
||||||
|
FixedDotWeight(GeneralDotWeight {
|
||||||
|
circle,
|
||||||
|
layer,
|
||||||
|
maybe_net: None, // TODO.
|
||||||
|
//maybe_net,
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
maybe_first_chain_segment = Some((Line::new(curr_pos1, curr_pos2), index));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pos(place: PointWithRotation, pin: PointWithRotation, x: f64, y: f64, flip: bool) -> Point {
|
fn pos(place: PointWithRotation, pin: PointWithRotation, x: f64, y: f64, flip: bool) -> Point {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue