mirror of https://codeberg.org/topola/topola.git
feat(autorouter/anterouter): Don't anteroute fanout vias inside polys
This commit is contained in:
parent
901d6010c2
commit
8095c3a89a
|
|
@ -70,6 +70,7 @@ allowed_scopes = [
|
|||
"layout/collect_bands",
|
||||
"layout/layout",
|
||||
"layout/poly",
|
||||
"layout/query",
|
||||
"layout/via",
|
||||
"math/circle",
|
||||
"math/cyclic_search",
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ use crate::{
|
|||
permutator::PlanarAutorouteExecutionPermutator, planner::Planner,
|
||||
},
|
||||
board::{AccessMesadata, Board},
|
||||
drawing::{band::BandTermsegIndex, Infringement},
|
||||
drawing::band::BandTermsegIndex,
|
||||
graph::MakeRef,
|
||||
layout::{via::ViaWeight, LayoutEdit},
|
||||
layout::{via::ViaWeight, LayoutEdit, LayoutException},
|
||||
router::{navmesh::NavmeshError, ng, thetastar::ThetastarError, RouterOptions},
|
||||
triangulation::GetTrianvertexNodeIndex,
|
||||
};
|
||||
|
|
@ -59,7 +59,7 @@ pub enum AutorouterError {
|
|||
#[error("TopoNavmesh generation failed: {0}")]
|
||||
TopoNavmeshGeneration(#[from] ng::NavmeshCalculationError),
|
||||
#[error("could not place via")]
|
||||
CouldNotPlaceVia(#[from] Infringement),
|
||||
CouldNotPlaceVia(#[from] LayoutException),
|
||||
#[error("could not remove band")]
|
||||
CouldNotRemoveBand(BandTermsegIndex),
|
||||
#[error("need exactly two ratlines")]
|
||||
|
|
|
|||
|
|
@ -21,11 +21,13 @@ use crate::{
|
|||
dot::{FixedDotIndex, FixedDotWeight},
|
||||
graph::PrimitiveIndex,
|
||||
seg::{FixedSegIndex, FixedSegWeight},
|
||||
DrawingException, Infringement,
|
||||
DrawingException,
|
||||
},
|
||||
geometry::{edit::ApplyGeometryEdit, GenericNode, GetLayer},
|
||||
graph::{GenericIndex, MakeRef},
|
||||
layout::{poly::PolyWeight, via::ViaWeight, CompoundWeight, Layout, NodeIndex},
|
||||
layout::{
|
||||
poly::PolyWeight, via::ViaWeight, CompoundWeight, Layout, LayoutException, NodeIndex,
|
||||
},
|
||||
router::ng::EtchedPath,
|
||||
};
|
||||
|
||||
|
|
@ -110,7 +112,7 @@ impl<M: AccessMesadata> Board<M> {
|
|||
recorder: &mut BoardEdit,
|
||||
weight: ViaWeight,
|
||||
maybe_pin: Option<String>,
|
||||
) -> Result<(GenericIndex<ViaWeight>, Vec<FixedDotIndex>), Infringement> {
|
||||
) -> Result<(GenericIndex<ViaWeight>, Vec<FixedDotIndex>), LayoutException> {
|
||||
let (weight, dots) = self.layout.add_via(&mut recorder.layout_edit, weight)?;
|
||||
|
||||
if let Some(pin) = maybe_pin {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
use contracts_try::debug_ensures;
|
||||
use derive_getters::Getters;
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use geo::Point;
|
||||
use geo::{Point, Polygon};
|
||||
use rstar::AABB;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
drawing::{
|
||||
|
|
@ -40,13 +41,23 @@ use crate::{
|
|||
math::RotationSense,
|
||||
};
|
||||
|
||||
/// Represents a weight for various compounds
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum LayoutException {
|
||||
#[error(transparent)]
|
||||
HasPointInPoly(#[from] HasPointInPoly),
|
||||
#[error(transparent)]
|
||||
Infringement(#[from] Infringement),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("(0:?) has point in {1:?}")]
|
||||
pub struct HasPointInPoly(pub Polygon, pub Point);
|
||||
|
||||
/// Represents a weight for various compounds.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[enum_dispatch(GetMaybeNet, IsInLayer)]
|
||||
pub enum CompoundWeight {
|
||||
/// Represents the weight of a polygon compound, includes its basic [`Layout`] information
|
||||
Poly(PolyWeight),
|
||||
/// Represents Via weight properties, containing its [`Layout`] properties
|
||||
Via(ViaWeight),
|
||||
}
|
||||
|
||||
|
|
@ -57,12 +68,12 @@ pub enum CompoundEntryLabel {
|
|||
Fillet,
|
||||
}
|
||||
|
||||
/// The alias to differ node types
|
||||
/// The alias to differentiate node types.
|
||||
pub type NodeIndex = GenericNode<PrimitiveIndex, GenericIndex<CompoundWeight>>;
|
||||
pub type LayoutEdit = DrawingEdit<CompoundWeight, CompoundEntryLabel>;
|
||||
|
||||
#[derive(Clone, Debug, Getters)]
|
||||
/// Structure for managing the Layout design
|
||||
/// Structure for managing the Layout design.
|
||||
pub struct Layout<R> {
|
||||
pub(super) drawing: Drawing<CompoundWeight, CompoundEntryLabel, R>,
|
||||
}
|
||||
|
|
@ -144,7 +155,7 @@ impl<R: AccessRules> Layout<R> {
|
|||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
weight: ViaWeight,
|
||||
) -> Result<(GenericIndex<ViaWeight>, Vec<FixedDotIndex>), Infringement> {
|
||||
) -> Result<(GenericIndex<ViaWeight>, Vec<FixedDotIndex>), LayoutException> {
|
||||
let compound = self.drawing.add_compound(recorder, weight.into());
|
||||
let mut dots = vec![];
|
||||
|
||||
|
|
@ -158,23 +169,34 @@ impl<R: AccessRules> Layout<R> {
|
|||
}),
|
||||
) {
|
||||
Ok(dot) => {
|
||||
dots.push(dot);
|
||||
|
||||
let maybe_enclosing_poly = self
|
||||
.polys_enclosing_point_on_layers(weight.circle.pos, layer)
|
||||
.next();
|
||||
|
||||
if let Some(enclosing_poly) = maybe_enclosing_poly {
|
||||
// If a via is inside poly, it may not necessarily
|
||||
// trigger an infringement on its primitives. To take
|
||||
// this situation into account, we also check if the
|
||||
// via's center is inside the poly's polygon.
|
||||
self.remove_failed_via(recorder, compound, dots);
|
||||
return Err(LayoutException::HasPointInPoly(HasPointInPoly(
|
||||
enclosing_poly.ref_(self).shape(),
|
||||
weight.circle.pos,
|
||||
)));
|
||||
}
|
||||
|
||||
self.drawing.add_to_compound(
|
||||
recorder,
|
||||
dot,
|
||||
CompoundEntryLabel::Normal,
|
||||
compound,
|
||||
);
|
||||
dots.push(dot);
|
||||
}
|
||||
Err(err) => {
|
||||
// Remove inserted dots.
|
||||
self.drawing.remove_compound(recorder, compound);
|
||||
|
||||
for dot in dots.iter().rev() {
|
||||
self.drawing.remove_fixed_dot(recorder, *dot);
|
||||
}
|
||||
|
||||
return Err(err);
|
||||
self.remove_failed_via(recorder, compound, dots);
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -182,6 +204,20 @@ impl<R: AccessRules> Layout<R> {
|
|||
Ok((GenericIndex::<ViaWeight>::new(compound.index()), dots))
|
||||
}
|
||||
|
||||
fn remove_failed_via(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
compound: GenericIndex<CompoundWeight>,
|
||||
dots: Vec<FixedDotIndex>,
|
||||
) {
|
||||
self.drawing.remove_compound(recorder, compound);
|
||||
|
||||
// Remove inserted dots.
|
||||
for dot in dots.iter().rev() {
|
||||
self.drawing.remove_fixed_dot(recorder, *dot);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_fixed_dot(
|
||||
&mut self,
|
||||
recorder: &mut LayoutEdit,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
mod collect_bands;
|
||||
mod layout;
|
||||
pub mod poly;
|
||||
pub mod query;
|
||||
pub mod via;
|
||||
|
||||
pub use layout::*;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
// SPDX-FileCopyrightText: 2025 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use geo::Point;
|
||||
use rstar::AABB;
|
||||
use specctra_core::rules::AccessRules;
|
||||
|
||||
use crate::{
|
||||
drawing::graph::IsInLayer,
|
||||
geometry::{shape::AccessShape, GenericNode},
|
||||
graph::{GenericIndex, GetIndex},
|
||||
layout::{poly::PolyWeight, CompoundWeight, Layout},
|
||||
};
|
||||
|
||||
impl<R: AccessRules> Layout<R> {
|
||||
pub fn polys_enclosing_point_on_layers(
|
||||
&self,
|
||||
point: Point,
|
||||
layer: usize,
|
||||
) -> impl Iterator<Item = GenericIndex<PolyWeight>> + '_ {
|
||||
self.drawing()
|
||||
.rtree()
|
||||
.locate_in_envelope_intersecting(&AABB::<[f64; 3]>::from_corners(
|
||||
[point.x(), point.y(), -f64::INFINITY],
|
||||
[point.x(), point.y(), f64::INFINITY],
|
||||
))
|
||||
.filter_map(move |geom| {
|
||||
let node = geom.data;
|
||||
|
||||
let GenericNode::Compound(compound) = node else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let CompoundWeight::Poly(_) = self.drawing.compound_weight(compound) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if !self.drawing.compound_weight(compound).is_in_layer(layer)
|
||||
|| !self.node_shape(node).contains_point(point)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(GenericIndex::<PolyWeight>::new(compound.index()))
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue