mirror of https://codeberg.org/topola/topola.git
feat(router/prenavmesh): Have fillets as prenavnodes instead of long vertex chains
This commit is contained in:
parent
521bb0598a
commit
3e466960fa
|
|
@ -158,10 +158,11 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
weight: PolyWeight,
|
weight: PolyWeight,
|
||||||
maybe_pin: Option<String>,
|
maybe_pin: Option<String>,
|
||||||
nodes: &[PrimitiveIndex],
|
nodes: &[PrimitiveIndex],
|
||||||
|
fillets: &[FixedDotIndex],
|
||||||
) -> GenericIndex<PolyWeight> {
|
) -> GenericIndex<PolyWeight> {
|
||||||
let (poly, apex) =
|
let (poly, apex) =
|
||||||
self.layout
|
self.layout
|
||||||
.add_poly_with_nodes(&mut recorder.layout_edit, weight, nodes);
|
.add_poly_with_nodes(&mut recorder.layout_edit, weight, nodes, fillets);
|
||||||
|
|
||||||
if let Some(pin) = maybe_pin {
|
if let Some(pin) = maybe_pin {
|
||||||
for i in nodes {
|
for i in nodes {
|
||||||
|
|
|
||||||
|
|
@ -295,7 +295,7 @@ impl<CW, Cel, R> GetOuterGears for FixedDot<'_, CW, Cel, R> {
|
||||||
impl<CW: Clone, Cel: Copy, R: AccessRules> GetPrevNextInChain for FixedDot<'_, CW, Cel, R> {
|
impl<CW: Clone, Cel: Copy, R: AccessRules> GetPrevNextInChain for FixedDot<'_, CW, Cel, R> {
|
||||||
fn next_in_chain(&self, maybe_prev: Option<GearIndex>) -> Option<GearIndex> {
|
fn next_in_chain(&self, maybe_prev: Option<GearIndex>) -> Option<GearIndex> {
|
||||||
self.drawing
|
self.drawing
|
||||||
.clearance_intersectors(self.index.into())
|
.overlapees(self.index.into())
|
||||||
.find_map(|infringement| {
|
.find_map(|infringement| {
|
||||||
let PrimitiveIndex::FixedDot(intersectee) = infringement.1 else {
|
let PrimitiveIndex::FixedDot(intersectee) = infringement.1 else {
|
||||||
return None;
|
return None;
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
||||||
infringer: PrimitiveIndex,
|
infringer: PrimitiveIndex,
|
||||||
it: impl Iterator<Item = PrimitiveIndex> + 'a,
|
it: impl Iterator<Item = PrimitiveIndex> + 'a,
|
||||||
) -> impl Iterator<Item = Infringement> + 'a {
|
) -> impl Iterator<Item = Infringement> + 'a {
|
||||||
self.clearance_intersectors_among(infringer, it)
|
self.overlapees_among(infringer, it)
|
||||||
.filter(move |infringement| {
|
.filter(move |infringement| {
|
||||||
// Infringement with loose dots resulted in false positives for
|
// Infringement with loose dots resulted in false positives for
|
||||||
// line-of-sight paths.
|
// line-of-sight paths.
|
||||||
|
|
@ -161,24 +161,25 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
||||||
.filter(move |infringement| !self.are_connectable(infringer, infringement.1))
|
.filter(move |infringement| !self.are_connectable(infringer, infringement.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clearance_intersectors<'a>(
|
pub fn overlapees<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
intersector: PrimitiveIndex,
|
overlapper: PrimitiveIndex,
|
||||||
) -> impl Iterator<Item = Infringement> + 'a {
|
) -> impl Iterator<Item = Infringement> + 'a {
|
||||||
self.clearance_intersectors_among(
|
self.overlapees_among(
|
||||||
intersector,
|
overlapper,
|
||||||
self.locate_possible_infringees(intersector)
|
self.locate_possible_infringees(overlapper)
|
||||||
.filter_map(move |infringee_node| {
|
.filter_map(move |infringee_node| {
|
||||||
if let GenericNode::Primitive(primitive_node) = infringee_node {
|
if let GenericNode::Primitive(primitive_node) = infringee_node {
|
||||||
Some(primitive_node)
|
Some(primitive_node)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
|
.filter(move |&overlapee| overlapper != overlapee),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn clearance_intersectors_among<'a>(
|
pub(super) fn overlapees_among<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
intersector: PrimitiveIndex,
|
intersector: PrimitiveIndex,
|
||||||
it: impl Iterator<Item = PrimitiveIndex> + 'a,
|
it: impl Iterator<Item = PrimitiveIndex> + 'a,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,8 @@ pub enum CompoundWeight {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum CompoundEntryLabel {
|
pub enum CompoundEntryLabel {
|
||||||
Normal,
|
Normal,
|
||||||
NotInConvexHull,
|
Apex,
|
||||||
|
Fillet,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The alias to differ node types
|
/// The alias to differ node types
|
||||||
|
|
@ -254,13 +255,14 @@ impl<R: AccessRules> Layout<R> {
|
||||||
recorder: &mut LayoutEdit,
|
recorder: &mut LayoutEdit,
|
||||||
weight: PolyWeight,
|
weight: PolyWeight,
|
||||||
nodes: &[PrimitiveIndex],
|
nodes: &[PrimitiveIndex],
|
||||||
|
fillets: &[FixedDotIndex],
|
||||||
) -> (GenericIndex<PolyWeight>, FixedDotIndex) {
|
) -> (GenericIndex<PolyWeight>, FixedDotIndex) {
|
||||||
let layer = weight.layer();
|
let layer = weight.layer();
|
||||||
let maybe_net = weight.maybe_net();
|
let maybe_net = weight.maybe_net();
|
||||||
let poly = self.add_poly(recorder, weight);
|
let poly = self.add_poly(recorder, weight);
|
||||||
(
|
(
|
||||||
poly,
|
poly,
|
||||||
add_poly_with_nodes_intern(self, recorder, poly, nodes, layer, maybe_net),
|
add_poly_with_nodes_intern(self, recorder, poly, nodes, fillets, layer, maybe_net),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -361,6 +363,7 @@ impl<R: AccessRules> Layout<R> {
|
||||||
if self
|
if self
|
||||||
.drawing()
|
.drawing()
|
||||||
.geometry()
|
.geometry()
|
||||||
|
// TODO: Add `.compounds()` method working on `PrimitiveIndex`.
|
||||||
.compounds(GenericIndex::<()>::new(primitive.petgraph_index()))
|
.compounds(GenericIndex::<()>::new(primitive.petgraph_index()))
|
||||||
.next()
|
.next()
|
||||||
.is_some()
|
.is_some()
|
||||||
|
|
@ -380,7 +383,7 @@ impl<R: AccessRules> Layout<R> {
|
||||||
let apex = loop {
|
let apex = loop {
|
||||||
// this returns None if the via is not present on this layer
|
// this returns None if the via is not present on this layer
|
||||||
let (entry_label, dot) = dots.next()?;
|
let (entry_label, dot) = dots.next()?;
|
||||||
if entry_label == CompoundEntryLabel::NotInConvexHull {
|
if entry_label == CompoundEntryLabel::Apex {
|
||||||
if let Some((dot, weight)) = handle_fixed_dot(&self.drawing, dot) {
|
if let Some((dot, weight)) = handle_fixed_dot(&self.drawing, dot) {
|
||||||
if weight.layer() == active_layer {
|
if weight.layer() == active_layer {
|
||||||
break dot;
|
break dot;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ pub(super) fn add_poly_with_nodes_intern<R: AccessRules>(
|
||||||
recorder: &mut LayoutEdit,
|
recorder: &mut LayoutEdit,
|
||||||
poly: GenericIndex<PolyWeight>,
|
poly: GenericIndex<PolyWeight>,
|
||||||
nodes: &[PrimitiveIndex],
|
nodes: &[PrimitiveIndex],
|
||||||
|
fillets: &[FixedDotIndex],
|
||||||
layer: usize,
|
layer: usize,
|
||||||
maybe_net: Option<usize>,
|
maybe_net: Option<usize>,
|
||||||
) -> FixedDotIndex {
|
) -> FixedDotIndex {
|
||||||
|
|
@ -123,19 +124,22 @@ pub(super) fn add_poly_with_nodes_intern<R: AccessRules>(
|
||||||
layout.drawing.add_to_compound(
|
layout.drawing.add_to_compound(
|
||||||
recorder,
|
recorder,
|
||||||
GenericIndex::<()>::new(idx.petgraph_index()),
|
GenericIndex::<()>::new(idx.petgraph_index()),
|
||||||
CompoundEntryLabel::NotInConvexHull,
|
CompoundEntryLabel::Apex,
|
||||||
poly_compound,
|
poly_compound,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for fillet in fillets {
|
||||||
|
layout
|
||||||
|
.drawing
|
||||||
|
.add_to_compound(recorder, *fillet, CompoundEntryLabel::Fillet, poly_compound)
|
||||||
|
}
|
||||||
|
|
||||||
// maybe this should be a different edge label
|
// maybe this should be a different edge label
|
||||||
layout.drawing.add_to_compound(
|
layout
|
||||||
recorder,
|
.drawing
|
||||||
apex,
|
.add_to_compound(recorder, apex, CompoundEntryLabel::Apex, poly_compound);
|
||||||
CompoundEntryLabel::NotInConvexHull,
|
|
||||||
poly_compound,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(is_apex(&layout.drawing, apex));
|
assert!(is_apex(&layout.drawing, apex));
|
||||||
apex
|
apex
|
||||||
|
|
@ -166,7 +170,7 @@ impl<'a, R> PolyRef<'a, R> {
|
||||||
.geometry()
|
.geometry()
|
||||||
.compound_members(self.index.into())
|
.compound_members(self.index.into())
|
||||||
.find_map(|(label, primitive_node)| {
|
.find_map(|(label, primitive_node)| {
|
||||||
if label == CompoundEntryLabel::NotInConvexHull {
|
if label == CompoundEntryLabel::Apex {
|
||||||
if let PrimitiveIndex::FixedDot(dot) = primitive_node {
|
if let PrimitiveIndex::FixedDot(dot) = primitive_node {
|
||||||
if is_apex(self.drawing, dot) {
|
if is_apex(self.drawing, dot) {
|
||||||
return Some(dot);
|
return Some(dot);
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ impl Navmesh {
|
||||||
|
|
||||||
// The existence of a constraint edge does not (!) guarantee that this
|
// The existence of a constraint edge does not (!) guarantee that this
|
||||||
// edge exactly will be present in the triangulation. It appears that
|
// edge exactly will be present in the triangulation. It appears that
|
||||||
// Spade splits a constraint edge into two if an endpoint of another
|
// Spade splits a constraint edge in two if an endpoint of another
|
||||||
// constraint lies on it.
|
// constraint lies on it.
|
||||||
//
|
//
|
||||||
// So now we go over all the constraints and make sure that
|
// So now we go over all the constraints and make sure that
|
||||||
|
|
@ -324,7 +324,7 @@ impl Navmesh {
|
||||||
overlapping_prenavnodes_unions: &mut UnionFind<NodeIndex<usize>>,
|
overlapping_prenavnodes_unions: &mut UnionFind<NodeIndex<usize>>,
|
||||||
prenavnode: PrenavmeshNodeIndex,
|
prenavnode: PrenavmeshNodeIndex,
|
||||||
) {
|
) {
|
||||||
for overlap in layout.drawing().clearance_intersectors(prenavnode.into()) {
|
for overlap in layout.drawing().overlapees(prenavnode.into()) {
|
||||||
let PrimitiveIndex::FixedDot(overlapee) = overlap.1 else {
|
let PrimitiveIndex::FixedDot(overlapee) = overlap.1 else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ use crate::{
|
||||||
Drawing,
|
Drawing,
|
||||||
},
|
},
|
||||||
geometry::{shape::AccessShape, GetLayer},
|
geometry::{shape::AccessShape, GetLayer},
|
||||||
graph::GetPetgraphIndex,
|
graph::{GenericIndex, GetPetgraphIndex},
|
||||||
layout::Layout,
|
layout::{CompoundEntryLabel, Layout},
|
||||||
triangulation::{GetTrianvertexNodeIndex, Triangulation},
|
triangulation::{GetTrianvertexNodeIndex, Triangulation},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -153,32 +153,51 @@ impl Prenavmesh {
|
||||||
for node in layout.drawing().layer_primitive_nodes(layer) {
|
for node in layout.drawing().layer_primitive_nodes(layer) {
|
||||||
let primitive = node.primitive(layout.drawing());
|
let primitive = node.primitive(layout.drawing());
|
||||||
|
|
||||||
if let Some(primitive_net) = primitive.maybe_net() {
|
let Some(primitive_net) = primitive.maybe_net() else {
|
||||||
if node == origin.into()
|
continue;
|
||||||
|| node == destination.into()
|
};
|
||||||
|| Some(primitive_net) != maybe_net
|
|
||||||
{
|
if node == origin.into()
|
||||||
match node {
|
|| node == destination.into()
|
||||||
PrimitiveIndex::FixedDot(dot) => {
|
|| Some(primitive_net) != maybe_net
|
||||||
this.triangulation
|
{
|
||||||
.add_vertex(PrenavmeshWeight::new_from_fixed_dot(layout, dot))?;
|
match node {
|
||||||
|
PrimitiveIndex::FixedDot(dot) => {
|
||||||
|
layout
|
||||||
|
.drawing()
|
||||||
|
// TODO: Add `.compounds()` method working on `PrimitiveIndex`.
|
||||||
|
.compounds(GenericIndex::<()>::new(dot.petgraph_index()))
|
||||||
|
.find(|(label, _)| *label == CompoundEntryLabel::Fillet)
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
// Do not add prenavnodes for primitives that have been filleted.
|
||||||
|
// For now, we do this by detecting if the primitive overlaps
|
||||||
|
// a fillet.
|
||||||
|
// TODO: This method is simplistic and will obviously result in
|
||||||
|
// false positives in some cases, so in the future, instead of this,
|
||||||
|
// create a fillet compound type and check for compound membership.
|
||||||
|
if Self::is_fixed_dot_filleted(layout, dot) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
PrimitiveIndex::LoneLooseSeg(seg) => {
|
|
||||||
this.add_constraint(PrenavmeshConstraint::new_from_lone_loose_seg(
|
this.triangulation
|
||||||
layout, seg,
|
.add_vertex(PrenavmeshWeight::new_from_fixed_dot(layout, dot))?;
|
||||||
))?;
|
|
||||||
}
|
|
||||||
PrimitiveIndex::SeqLooseSeg(seg) => {
|
|
||||||
this.add_constraint(PrenavmeshConstraint::new_from_seq_loose_seg(
|
|
||||||
layout, seg,
|
|
||||||
))?;
|
|
||||||
}
|
|
||||||
PrimitiveIndex::FixedBend(bend) => {
|
|
||||||
this.triangulation
|
|
||||||
.add_vertex(PrenavmeshWeight::new_from_fixed_bend(layout, bend))?;
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
PrimitiveIndex::LoneLooseSeg(seg) => {
|
||||||
|
this.add_constraint(PrenavmeshConstraint::new_from_lone_loose_seg(
|
||||||
|
layout, seg,
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
PrimitiveIndex::SeqLooseSeg(seg) => {
|
||||||
|
this.add_constraint(PrenavmeshConstraint::new_from_seq_loose_seg(
|
||||||
|
layout, seg,
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
PrimitiveIndex::FixedBend(bend) => {
|
||||||
|
this.triangulation
|
||||||
|
.add_vertex(PrenavmeshWeight::new_from_fixed_bend(layout, bend))?;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -186,36 +205,46 @@ impl Prenavmesh {
|
||||||
for node in layout.drawing().layer_primitive_nodes(layer) {
|
for node in layout.drawing().layer_primitive_nodes(layer) {
|
||||||
let primitive = node.primitive(layout.drawing());
|
let primitive = node.primitive(layout.drawing());
|
||||||
|
|
||||||
if let Some(primitive_net) = primitive.maybe_net() {
|
let Some(primitive_net) = primitive.maybe_net() else {
|
||||||
if node == origin.into()
|
continue;
|
||||||
|| node == destination.into()
|
};
|
||||||
|| Some(primitive_net) != maybe_net
|
|
||||||
{
|
|
||||||
// If you have a band that was routed from a polygonal pad,
|
|
||||||
// when you will start a new routing some of the constraint
|
|
||||||
// edges created from the loose segs of a band will
|
|
||||||
// intersect some of the constraint edges created from the
|
|
||||||
// fixed segs constituting the pad boundary.
|
|
||||||
//
|
|
||||||
// Such constraint intersections are erroneous and cause
|
|
||||||
// Spade to throw a panic at runtime. So, to prevent this
|
|
||||||
// from occuring, we iterate over the layout for the second
|
|
||||||
// time, after all the constraint edges from bands have been
|
|
||||||
// placed, and only then add constraint edges created from
|
|
||||||
// fixed segs that do not cause an intersection.
|
|
||||||
match node {
|
|
||||||
PrimitiveIndex::FixedSeg(seg) => {
|
|
||||||
let constraint = PrenavmeshConstraint::new_from_fixed_seg(layout, seg);
|
|
||||||
|
|
||||||
if !this
|
if node == origin.into()
|
||||||
.triangulation
|
|| node == destination.into()
|
||||||
.intersects_constraint(&constraint.0, &constraint.1)
|
|| Some(primitive_net) != maybe_net
|
||||||
{
|
{
|
||||||
this.add_constraint(constraint);
|
// If you have a band that was routed from a polygonal pad,
|
||||||
}
|
// when you will start a new routing some of the constraint
|
||||||
|
// edges created from the loose segs of a band will
|
||||||
|
// intersect some of the constraint edges created from the
|
||||||
|
// fixed segs constituting the pad boundary.
|
||||||
|
//
|
||||||
|
// Such constraint intersections are erroneous and cause
|
||||||
|
// Spade to throw a panic at runtime. So, to prevent this
|
||||||
|
// from occuring, we iterate over the layout for the second
|
||||||
|
// time, after all the constraint edges from bands have been
|
||||||
|
// placed, and only then add constraint edges created from
|
||||||
|
// fixed segs that do not cause an intersection.
|
||||||
|
match node {
|
||||||
|
PrimitiveIndex::FixedSeg(seg) => {
|
||||||
|
let (from_dot, to_dot) = layout.drawing().primitive(seg).joints();
|
||||||
|
|
||||||
|
if Self::is_fixed_dot_filleted(layout, from_dot)
|
||||||
|
&& Self::is_fixed_dot_filleted(layout, to_dot)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let constraint = PrenavmeshConstraint::new_from_fixed_seg(layout, seg);
|
||||||
|
|
||||||
|
if !this
|
||||||
|
.triangulation
|
||||||
|
.intersects_constraint(&constraint.0, &constraint.1)
|
||||||
|
{
|
||||||
|
this.add_constraint(constraint);
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,6 +252,31 @@ impl Prenavmesh {
|
||||||
Ok(this)
|
Ok(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_fixed_dot_filleted(layout: &Layout<impl AccessRules>, dot: FixedDotIndex) -> bool {
|
||||||
|
layout
|
||||||
|
.drawing()
|
||||||
|
.compounds(GenericIndex::<()>::new(dot.petgraph_index()))
|
||||||
|
.find(|(label, _)|
|
||||||
|
// Fillets fail this test for some reason that I did not investigate, so
|
||||||
|
// I added this condition.
|
||||||
|
*label == CompoundEntryLabel::Fillet
|
||||||
|
// Exclude apices because they may overlap fillets.
|
||||||
|
|| *label == CompoundEntryLabel::Apex)
|
||||||
|
.is_none()
|
||||||
|
&& layout
|
||||||
|
.drawing()
|
||||||
|
.overlapees(dot.into())
|
||||||
|
.find(|overlapee| {
|
||||||
|
layout
|
||||||
|
.drawing()
|
||||||
|
// TODO: Add `.compounds()` method working on `PrimitiveIndex`.
|
||||||
|
.compounds(GenericIndex::<()>::new(overlapee.1.petgraph_index()))
|
||||||
|
.find(|(label, _)| *label == CompoundEntryLabel::Fillet)
|
||||||
|
.is_some()
|
||||||
|
})
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
fn add_constraint(&mut self, constraint: PrenavmeshConstraint) -> Result<(), InsertionError> {
|
fn add_constraint(&mut self, constraint: PrenavmeshConstraint) -> Result<(), InsertionError> {
|
||||||
self.triangulation
|
self.triangulation
|
||||||
.add_constraint_edge(constraint.0, constraint.1)?;
|
.add_constraint_edge(constraint.0, constraint.1)?;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use specctra_core::math::PointWithRotation;
|
||||||
use crate::{
|
use crate::{
|
||||||
board::{edit::BoardEdit, AccessMesadata, Board},
|
board::{edit::BoardEdit, AccessMesadata, Board},
|
||||||
drawing::{
|
drawing::{
|
||||||
dot::{FixedDotWeight, GeneralDotWeight},
|
dot::{FixedDotIndex, FixedDotWeight, GeneralDotWeight},
|
||||||
graph::{GetMaybeNet, MakePrimitive},
|
graph::{GetMaybeNet, MakePrimitive},
|
||||||
primitive::MakePrimitiveShape,
|
primitive::MakePrimitiveShape,
|
||||||
seg::{FixedSegWeight, GeneralSegWeight},
|
seg::{FixedSegWeight, GeneralSegWeight},
|
||||||
|
|
@ -584,6 +584,7 @@ impl SpecctraDesign {
|
||||||
seg3.into(),
|
seg3.into(),
|
||||||
seg4.into(),
|
seg4.into(),
|
||||||
],
|
],
|
||||||
|
&[],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -728,15 +729,16 @@ impl SpecctraDesign {
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let fillets = Self::add_polygon_fillet_circles(
|
||||||
|
recorder, board, place, pin, coords, width, layer, maybe_net, None, flip,
|
||||||
|
);
|
||||||
|
|
||||||
board.add_poly_with_nodes(
|
board.add_poly_with_nodes(
|
||||||
recorder,
|
recorder,
|
||||||
SolidPolyWeight { layer, maybe_net }.into(),
|
SolidPolyWeight { layer, maybe_net }.into(),
|
||||||
maybe_pin,
|
maybe_pin,
|
||||||
&nodes[..],
|
&nodes[..],
|
||||||
);
|
&fillets[..],
|
||||||
|
|
||||||
Self::add_polygon_fillet_circles(
|
|
||||||
recorder, board, place, pin, coords, width, layer, maybe_net, None, flip,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -751,9 +753,10 @@ impl SpecctraDesign {
|
||||||
maybe_net: Option<usize>,
|
maybe_net: Option<usize>,
|
||||||
_maybe_pin: Option<String>,
|
_maybe_pin: Option<String>,
|
||||||
flip: bool,
|
flip: bool,
|
||||||
) {
|
) -> Vec<FixedDotIndex> {
|
||||||
let MIN_FIRST_CHAIN_ELEMENT_LENGTH = 100.0;
|
let MIN_FIRST_CHAIN_ELEMENT_LENGTH = 100.0;
|
||||||
let mut maybe_first_chain_segment = None;
|
let mut maybe_first_chain_segment = None;
|
||||||
|
let mut fillets = vec![];
|
||||||
|
|
||||||
let first_pos = Self::pos(place, pin, coords[0].x, coords[0].y, flip);
|
let first_pos = Self::pos(place, pin, coords[0].x, coords[0].y, flip);
|
||||||
let last_pos = Self::pos(
|
let last_pos = Self::pos(
|
||||||
|
|
@ -790,22 +793,23 @@ impl SpecctraDesign {
|
||||||
if index - first_chain_index >= 3 {
|
if index - first_chain_index >= 3 {
|
||||||
let circle = math::fillet_circle(&first_chain_segment, &curr_segment12);
|
let circle = math::fillet_circle(&first_chain_segment, &curr_segment12);
|
||||||
|
|
||||||
board.add_fixed_dot_infringably(
|
fillets.push(board.add_fixed_dot_infringably(
|
||||||
recorder,
|
recorder,
|
||||||
FixedDotWeight(GeneralDotWeight {
|
FixedDotWeight(GeneralDotWeight {
|
||||||
circle,
|
circle,
|
||||||
layer,
|
layer,
|
||||||
maybe_net: None, // TODO.
|
maybe_net,
|
||||||
//maybe_net,
|
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_first_chain_segment = Some((Line::new(curr_pos1, curr_pos2), index));
|
maybe_first_chain_segment = Some((Line::new(curr_pos1, curr_pos2), index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fillets
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ fn test_tht_de9_to_tht_de9() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_0603_breakout() {
|
fn test_0603_breakout() {
|
||||||
let mut autorouter = common::load_design("tests/single_layer/0603_breakout/0603_breakout.dsn");
|
let mut autorouter = common::load_design("tests/single_layer/0603_breakout/0603_breakout.dsn");
|
||||||
common::assert_navnode_count(&mut autorouter, "R1-2", "J1-2", 54);
|
common::assert_navnode_count(&mut autorouter, "R1-2", "J1-2", 22);
|
||||||
let mut invoker = common::create_invoker_and_assert(autorouter);
|
let mut invoker = common::create_invoker_and_assert(autorouter);
|
||||||
common::replay_and_assert(
|
common::replay_and_assert(
|
||||||
&mut invoker,
|
&mut invoker,
|
||||||
|
|
@ -93,7 +93,7 @@ fn test_4x_3rd_order_smd_lc_filters() {
|
||||||
let mut autorouter = common::load_design(
|
let mut autorouter = common::load_design(
|
||||||
"tests/single_layer/4x_3rd_order_smd_lc_filters/4x_3rd_order_smd_lc_filters.dsn",
|
"tests/single_layer/4x_3rd_order_smd_lc_filters/4x_3rd_order_smd_lc_filters.dsn",
|
||||||
);
|
);
|
||||||
common::assert_navnode_count(&mut autorouter, "J1-1", "L1-1", 2062);
|
common::assert_navnode_count(&mut autorouter, "J1-1", "L1-1", 558);
|
||||||
let mut invoker = common::create_invoker_and_assert(autorouter);
|
let mut invoker = common::create_invoker_and_assert(autorouter);
|
||||||
common::replay_and_assert(
|
common::replay_and_assert(
|
||||||
&mut invoker,
|
&mut invoker,
|
||||||
|
|
@ -130,7 +130,7 @@ fn test_tht_3pin_xlr_to_tht_3pin_xlr() {
|
||||||
fn test_vga_dac_breakout() {
|
fn test_vga_dac_breakout() {
|
||||||
let mut autorouter =
|
let mut autorouter =
|
||||||
common::load_design("tests/single_layer/vga_dac_breakout/vga_dac_breakout.dsn");
|
common::load_design("tests/single_layer/vga_dac_breakout/vga_dac_breakout.dsn");
|
||||||
common::assert_navnode_count(&mut autorouter, "J1-2", "R4-1", 944);
|
common::assert_navnode_count(&mut autorouter, "J1-2", "R4-1", 272);
|
||||||
let mut invoker = common::create_invoker_and_assert(autorouter);
|
let mut invoker = common::create_invoker_and_assert(autorouter);
|
||||||
common::replay_and_assert(
|
common::replay_and_assert(
|
||||||
&mut invoker,
|
&mut invoker,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue