mirror of https://codeberg.org/topola/topola.git
refactor(drawing/drawing): Move infringement and collision detection to drawing/query
This commit is contained in:
parent
ca4a2d1cbf
commit
310e983b1d
|
|
@ -188,7 +188,7 @@ impl<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, AutorouteContinue
|
|||
.board
|
||||
.layout()
|
||||
.drawing()
|
||||
.loose_band_uid(band_termseg.into())
|
||||
.find_loose_band_uid(band_termseg.into())
|
||||
.expect("a completely routed band should've Seg's as ends");
|
||||
|
||||
autorouter.ratsnest.assign_band_termseg_to_ratline(
|
||||
|
|
|
|||
|
|
@ -122,7 +122,10 @@ impl BandSelector {
|
|||
_ => return None,
|
||||
};
|
||||
|
||||
Self::try_from_uid(board, &board.layout().drawing().loose_band_uid(loose).ok()?)
|
||||
Self::try_from_uid(
|
||||
board,
|
||||
&board.layout().drawing().find_loose_band_uid(loose).ok()?,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn try_from_uid(
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ impl<'a> ResolvedSelector<'a> {
|
|||
} else {
|
||||
loose.and_then(|loose| {
|
||||
Some(ResolvedSelector::Band {
|
||||
band_uid: board.layout().drawing().loose_band_uid(loose).ok()?,
|
||||
band_uid: board.layout().drawing().find_loose_band_uid(loose).ok()?,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use crate::{
|
|||
primitive::{
|
||||
GenericPrimitive, GetCore, GetJoints, GetLimbs, GetOtherJoint, MakePrimitiveShape,
|
||||
},
|
||||
rules::{AccessRules, GetConditions},
|
||||
rules::AccessRules,
|
||||
seg::{
|
||||
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
|
||||
SegWeight, SeqLooseSegIndex, SeqLooseSegWeight,
|
||||
|
|
@ -31,7 +31,7 @@ use crate::{
|
|||
},
|
||||
geometry::{
|
||||
edit::{ApplyGeometryEdit, GeometryEdit},
|
||||
primitive::{AccessPrimitiveShape, PrimitiveShape},
|
||||
primitive::PrimitiveShape,
|
||||
recording_with_rtree::RecordingGeometryWithRtree,
|
||||
with_rtree::BboxedIndex,
|
||||
AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel,
|
||||
|
|
@ -751,7 +751,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
(from, to, offset)
|
||||
};
|
||||
|
||||
let rail_outer_bows = self.bend_outward_bows(rail);
|
||||
let rail_outer_bows = self.collect_bend_outward_bows(rail);
|
||||
|
||||
// Commenting out these two makes the crash go away.
|
||||
self.move_dot_with_infringement_filtering(
|
||||
|
|
@ -950,7 +950,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
.move_dot(recorder, dot, to);
|
||||
|
||||
for limb in dot.primitive(self).limbs() {
|
||||
if let Some(infringement) = self.detect_infringement_except(limb, predicate) {
|
||||
if let Some(infringement) = self.find_infringement_except(limb, predicate) {
|
||||
// Restore previous state.
|
||||
self.recording_geometry_with_rtree
|
||||
.move_dot(recorder, dot, old_pos);
|
||||
|
|
@ -958,7 +958,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(infringement) = self.detect_infringement_except(dot.into(), predicate) {
|
||||
if let Some(infringement) = self.find_infringement_except(dot.into(), predicate) {
|
||||
// Restore previous state.
|
||||
self.recording_geometry_with_rtree
|
||||
.move_dot(recorder, dot, old_pos);
|
||||
|
|
@ -985,7 +985,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
self.recording_geometry_with_rtree
|
||||
.shift_bend(recorder, bend, offset);
|
||||
|
||||
if let Some(infringement) = self.detect_infringement_except(bend.into(), predicate) {
|
||||
if let Some(infringement) = self.find_infringement_except(bend.into(), predicate) {
|
||||
// Restore previous state.
|
||||
self.recording_geometry_with_rtree
|
||||
.shift_bend(recorder, bend, old_offset);
|
||||
|
|
@ -1068,7 +1068,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
node: PrimitiveIndex,
|
||||
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||
) -> Result<(), Infringement> {
|
||||
if let Some(infringement) = self.detect_infringement_except(node, predicate) {
|
||||
if let Some(infringement) = self.find_infringement_except(node, predicate) {
|
||||
if let Ok(dot) = node.try_into() {
|
||||
self.recording_geometry_with_rtree.remove_dot(recorder, dot);
|
||||
} else if let Ok(seg) = node.try_into() {
|
||||
|
|
@ -1082,114 +1082,6 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn detect_infringement_except(
|
||||
&self,
|
||||
infringer: PrimitiveIndex,
|
||||
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||
) -> Option<Infringement> {
|
||||
self.find_infringement(
|
||||
infringer,
|
||||
self.locate_possible_infringees(infringer)
|
||||
.filter_map(|infringee_node| {
|
||||
if let GenericNode::Primitive(primitive_node) = infringee_node {
|
||||
Some(primitive_node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|infringee| predicate(&self, infringer, *infringee)),
|
||||
)
|
||||
}
|
||||
|
||||
fn locate_possible_infringees(
|
||||
&self,
|
||||
node: PrimitiveIndex,
|
||||
) -> impl Iterator<Item = GenericNode<PrimitiveIndex, GenericIndex<CW>>> + '_ {
|
||||
let limiting_shape = node.primitive(self).shape().inflate(
|
||||
node.primitive(self)
|
||||
.maybe_net()
|
||||
.map(|net| self.rules.largest_clearance(Some(net)))
|
||||
.unwrap_or(0.0),
|
||||
);
|
||||
|
||||
self.recording_geometry_with_rtree
|
||||
.rtree()
|
||||
.locate_in_envelope_intersecting(
|
||||
&limiting_shape.envelope_3d(0.0, node.primitive(self).layer()),
|
||||
)
|
||||
.map(|wrapper| wrapper.data)
|
||||
}
|
||||
|
||||
fn find_infringement(
|
||||
&self,
|
||||
infringer: PrimitiveIndex,
|
||||
it: impl Iterator<Item = PrimitiveIndex>,
|
||||
) -> Option<Infringement> {
|
||||
let mut inflated_shape = infringer.primitive(self).shape(); // Unused temporary value just for initialization.
|
||||
let conditions = infringer.primitive(self).conditions();
|
||||
|
||||
it.filter(|infringee| {
|
||||
// Infringement with loose dots resulted in false positives for
|
||||
// line-of-sight paths.
|
||||
!matches!(infringer, PrimitiveIndex::LooseDot(..))
|
||||
&& !matches!(infringee, PrimitiveIndex::LooseDot(..))
|
||||
})
|
||||
.filter(|infringee| !self.are_connectable(infringer, *infringee))
|
||||
.find_map(|primitive_node| {
|
||||
let infringee_conditions = primitive_node.primitive(self).conditions();
|
||||
|
||||
let epsilon = 1.0;
|
||||
inflated_shape = infringer.primitive(self).shape().inflate(
|
||||
match (&conditions, infringee_conditions) {
|
||||
(None, _) | (_, None) => 0.0,
|
||||
(Some(lhs), Some(rhs)) => {
|
||||
// Note the epsilon comparison.
|
||||
// XXX: Epsilon is probably too large. But what should
|
||||
// it be exactly then?
|
||||
(self.rules.clearance(lhs, &rhs) - epsilon).clamp(0.0, f64::INFINITY)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
inflated_shape
|
||||
.intersects(&primitive_node.primitive(self).shape())
|
||||
.then_some(Infringement(inflated_shape, primitive_node))
|
||||
})
|
||||
}
|
||||
|
||||
fn detect_collision_except(
|
||||
&self,
|
||||
collider: PrimitiveIndex,
|
||||
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||
) -> Option<Collision> {
|
||||
let shape = collider.primitive(self).shape();
|
||||
|
||||
self.recording_geometry_with_rtree
|
||||
.rtree()
|
||||
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
|
||||
.filter_map(|wrapper| {
|
||||
if let GenericNode::Primitive(collidee) = wrapper.data {
|
||||
Some(collidee)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
// NOTE: Collisions can happen between two same-net loose
|
||||
// segs, so these cases in particular are not filtered out
|
||||
// here, unlike what is done in infringement code.
|
||||
.filter(|&collidee| collider != collidee)
|
||||
.filter(|&collidee| {
|
||||
!self.are_connectable(collider, collidee)
|
||||
|| ((matches!(collider, PrimitiveIndex::LoneLooseSeg(..))
|
||||
|| matches!(collider, PrimitiveIndex::SeqLooseSeg(..)))
|
||||
&& (matches!(collidee, PrimitiveIndex::LoneLooseSeg(..))
|
||||
|| matches!(collidee, PrimitiveIndex::SeqLooseSeg(..))))
|
||||
})
|
||||
.filter(|collidee| predicate(&self, collider, *collidee))
|
||||
.find(|collidee| shape.intersects(&collidee.primitive(self).shape()))
|
||||
.map(|collidee| Collision(shape, collidee))
|
||||
}
|
||||
|
||||
pub fn primitive_nodes(&self) -> impl Iterator<Item = PrimitiveIndex> + '_ {
|
||||
self.recording_geometry_with_rtree
|
||||
.rtree()
|
||||
|
|
@ -1253,17 +1145,6 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
}
|
||||
}
|
||||
|
||||
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
|
||||
if let (Some(node1_net), Some(node2_net)) = (
|
||||
node1.primitive(self).maybe_net(),
|
||||
node2.primitive(self).maybe_net(),
|
||||
) {
|
||||
node1_net == node2_net
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn test_if_looses_dont_infringe_each_other(&self) -> bool {
|
||||
!self
|
||||
.primitive_nodes()
|
||||
|
|
@ -1277,7 +1158,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
)
|
||||
})
|
||||
.any(|node| {
|
||||
self.find_infringement(
|
||||
self.infringements_among(
|
||||
node,
|
||||
self.locate_possible_infringees(node)
|
||||
.filter_map(|n| {
|
||||
|
|
@ -1297,6 +1178,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
)
|
||||
}),
|
||||
)
|
||||
.next()
|
||||
.is_some()
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,17 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use petgraph::visit::Walker;
|
||||
use specctra_core::rules::GetConditions;
|
||||
|
||||
use crate::{
|
||||
drawing::{
|
||||
graph::{GetMaybeNet, MakePrimitive},
|
||||
primitive::MakePrimitiveShape,
|
||||
Collision, Infringement,
|
||||
},
|
||||
geometry::{primitive::AccessPrimitiveShape, GenericNode, GetLayer},
|
||||
graph::GenericIndex,
|
||||
};
|
||||
|
||||
use super::{
|
||||
band::{BandTermsegIndex, BandUid},
|
||||
|
|
@ -24,10 +35,10 @@ pub struct BandUidError {
|
|||
/// Routines implementing various queries on drawing. A query is a routine that
|
||||
/// returns indices of one or more primitives.
|
||||
impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
||||
pub fn loose_band_uid(&self, start_loose: LooseIndex) -> Result<BandUid, BandUidError> {
|
||||
pub fn find_loose_band_uid(&self, start_loose: LooseIndex) -> Result<BandUid, BandUidError> {
|
||||
match (
|
||||
self.loose_band_first_seg(start_loose),
|
||||
self.loose_band_last_seg(start_loose),
|
||||
self.find_loose_band_first_seg(start_loose),
|
||||
self.find_loose_band_last_seg(start_loose),
|
||||
) {
|
||||
(Some(first), Some(last)) => Ok(BandUid::from((first, last))),
|
||||
(Some(x), None) | (None, Some(x)) => Err(BandUidError { maybe_end: Some(x) }),
|
||||
|
|
@ -35,18 +46,54 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn bend_outward_bows(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex> {
|
||||
fn find_loose_band_first_seg(&self, start_loose: LooseIndex) -> Option<BandTermsegIndex> {
|
||||
if let LooseIndex::LoneSeg(seg) = start_loose {
|
||||
return Some(BandTermsegIndex::Lone(seg));
|
||||
}
|
||||
|
||||
let mut loose = start_loose;
|
||||
let mut prev = None;
|
||||
|
||||
loop {
|
||||
if let Some(next_loose) = self.loose(loose).prev_loose(prev) {
|
||||
prev = Some(loose);
|
||||
loose = next_loose;
|
||||
} else {
|
||||
return loose.try_into().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_loose_band_last_seg(&self, start_loose: LooseIndex) -> Option<BandTermsegIndex> {
|
||||
if let LooseIndex::LoneSeg(seg) = start_loose {
|
||||
return Some(BandTermsegIndex::Lone(seg));
|
||||
}
|
||||
|
||||
let mut loose = start_loose;
|
||||
let mut next = None;
|
||||
|
||||
loop {
|
||||
if let Some(prev_loose) = self.loose(loose).next_loose(next) {
|
||||
next = Some(loose);
|
||||
loose = prev_loose;
|
||||
} else {
|
||||
return loose.try_into().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_bend_outward_bows(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex> {
|
||||
let mut v = vec![];
|
||||
|
||||
let mut outwards = self.primitive(bend).outwards();
|
||||
while let Some(next) = outwards.walk_next(self) {
|
||||
v.append(&mut self.bend_bow(next));
|
||||
v.append(&mut self.collect_bend_bow(next));
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
fn bend_bow(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex> {
|
||||
fn collect_bend_bow(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex> {
|
||||
let mut v: Vec<PrimitiveIndex> = vec![];
|
||||
v.push(bend.into());
|
||||
|
||||
|
|
@ -65,39 +112,123 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
|||
v
|
||||
}
|
||||
|
||||
fn loose_band_first_seg(&self, start_loose: LooseIndex) -> Option<BandTermsegIndex> {
|
||||
if let LooseIndex::LoneSeg(seg) = start_loose {
|
||||
return Some(BandTermsegIndex::Lone(seg));
|
||||
}
|
||||
|
||||
let mut loose = start_loose;
|
||||
let mut prev = None;
|
||||
|
||||
loop {
|
||||
if let Some(next_loose) = self.loose(loose).prev_loose(prev) {
|
||||
prev = Some(loose);
|
||||
loose = next_loose;
|
||||
pub(super) fn find_infringement_except(
|
||||
&self,
|
||||
infringer: PrimitiveIndex,
|
||||
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||
) -> Option<Infringement> {
|
||||
self.infringements_among(
|
||||
infringer,
|
||||
self.locate_possible_infringees(infringer)
|
||||
.filter_map(|infringee_node| {
|
||||
if let GenericNode::Primitive(primitive_node) = infringee_node {
|
||||
Some(primitive_node)
|
||||
} else {
|
||||
return loose.try_into().ok();
|
||||
}
|
||||
None
|
||||
}
|
||||
})
|
||||
.filter(|infringee| predicate(&self, infringer, *infringee)),
|
||||
)
|
||||
.next()
|
||||
}
|
||||
|
||||
fn loose_band_last_seg(&self, start_loose: LooseIndex) -> Option<BandTermsegIndex> {
|
||||
if let LooseIndex::LoneSeg(seg) = start_loose {
|
||||
return Some(BandTermsegIndex::Lone(seg));
|
||||
pub(super) fn infringements_among<'a>(
|
||||
&'a self,
|
||||
infringer: PrimitiveIndex,
|
||||
it: impl Iterator<Item = PrimitiveIndex> + 'a,
|
||||
) -> impl Iterator<Item = Infringement> + 'a {
|
||||
let mut inflated_shape = infringer.primitive(self).shape(); // Unused temporary value just for initialization.
|
||||
let conditions = infringer.primitive(self).conditions();
|
||||
|
||||
it.filter(move |infringee| {
|
||||
// Infringement with loose dots resulted in false positives for
|
||||
// line-of-sight paths.
|
||||
!matches!(infringer, PrimitiveIndex::LooseDot(..))
|
||||
&& !matches!(infringee, PrimitiveIndex::LooseDot(..))
|
||||
})
|
||||
.filter(move |infringee| !self.are_connectable(infringer, *infringee))
|
||||
.filter_map(move |primitive_node| {
|
||||
let infringee_conditions = primitive_node.primitive(self).conditions();
|
||||
|
||||
let epsilon = 1.0;
|
||||
inflated_shape = infringer.primitive(self).shape().inflate(
|
||||
match (&conditions, infringee_conditions) {
|
||||
(None, _) | (_, None) => 0.0,
|
||||
(Some(lhs), Some(rhs)) => {
|
||||
// Note the epsilon comparison.
|
||||
// XXX: Epsilon is probably too large. But what should
|
||||
// it be exactly then?
|
||||
(self.rules().clearance(lhs, &rhs) - epsilon).clamp(0.0, f64::INFINITY)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
inflated_shape
|
||||
.intersects(&primitive_node.primitive(self).shape())
|
||||
.then_some(Infringement(inflated_shape, primitive_node))
|
||||
})
|
||||
}
|
||||
|
||||
let mut loose = start_loose;
|
||||
let mut next = None;
|
||||
pub(super) fn locate_possible_infringees(
|
||||
&self,
|
||||
node: PrimitiveIndex,
|
||||
) -> impl Iterator<Item = GenericNode<PrimitiveIndex, GenericIndex<CW>>> + '_ {
|
||||
let limiting_shape = node.primitive(self).shape().inflate(
|
||||
node.primitive(self)
|
||||
.maybe_net()
|
||||
.map(|net| self.rules().largest_clearance(Some(net)))
|
||||
.unwrap_or(0.0),
|
||||
);
|
||||
|
||||
loop {
|
||||
if let Some(prev_loose) = self.loose(loose).next_loose(next) {
|
||||
next = Some(loose);
|
||||
loose = prev_loose;
|
||||
self.recording_geometry_with_rtree()
|
||||
.rtree()
|
||||
.locate_in_envelope_intersecting(
|
||||
&limiting_shape.envelope_3d(0.0, node.primitive(self).layer()),
|
||||
)
|
||||
.map(|wrapper| wrapper.data)
|
||||
}
|
||||
|
||||
pub(super) fn detect_collision_except(
|
||||
&self,
|
||||
collider: PrimitiveIndex,
|
||||
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||
) -> Option<Collision> {
|
||||
let shape = collider.primitive(self).shape();
|
||||
|
||||
self.recording_geometry_with_rtree()
|
||||
.rtree()
|
||||
.locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2))
|
||||
.filter_map(|wrapper| {
|
||||
if let GenericNode::Primitive(collidee) = wrapper.data {
|
||||
Some(collidee)
|
||||
} else {
|
||||
return loose.try_into().ok();
|
||||
}
|
||||
None
|
||||
}
|
||||
})
|
||||
// NOTE: Collisions can happen between two same-net loose
|
||||
// segs, so these cases in particular are not filtered out
|
||||
// here, unlike what is done in infringement code.
|
||||
.filter(|&collidee| collider != collidee)
|
||||
.filter(|&collidee| {
|
||||
!self.are_connectable(collider, collidee)
|
||||
|| ((matches!(collider, PrimitiveIndex::LoneLooseSeg(..))
|
||||
|| matches!(collider, PrimitiveIndex::SeqLooseSeg(..)))
|
||||
&& (matches!(collidee, PrimitiveIndex::LoneLooseSeg(..))
|
||||
|| matches!(collidee, PrimitiveIndex::SeqLooseSeg(..))))
|
||||
})
|
||||
.filter(|collidee| predicate(&self, collider, *collidee))
|
||||
.find(|collidee| shape.intersects(&collidee.primitive(self).shape()))
|
||||
.map(|collidee| Collision(shape, collidee))
|
||||
}
|
||||
|
||||
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
|
||||
if let (Some(node1_net), Some(node2_net)) = (
|
||||
node1.primitive(self).maybe_net(),
|
||||
node2.primitive(self).maybe_net(),
|
||||
) {
|
||||
node1_net == node2_net
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ impl<R: AccessRules> Layout<R> {
|
|||
(loose, shape)
|
||||
})
|
||||
.filter_map(move |(loose, shape)| {
|
||||
let band_uid = self.drawing.loose_band_uid(loose).ok()?;
|
||||
let band_uid = self.drawing.find_loose_band_uid(loose).ok()?;
|
||||
let loose_hline = orig_hline.orthogonal_through(&match shape {
|
||||
PrimitiveShape::Seg(seg) => {
|
||||
let seg_hline = LineInGeneralForm::from(seg.middle_line());
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ impl AstarContext {
|
|||
sub.label.clone(),
|
||||
layout
|
||||
.drawing()
|
||||
.loose_band_uid(fin.into())
|
||||
.find_loose_band_uid(fin.into())
|
||||
.expect("a completely routed band should've Seg's as ends"),
|
||||
);
|
||||
Ok((
|
||||
|
|
|
|||
|
|
@ -583,7 +583,7 @@ fn cane_around<R: AccessRules>(
|
|||
.all_rails(core.petgraph_index())
|
||||
.filter_map(|bi| {
|
||||
if let BendIndex::Loose(lbi) = bi {
|
||||
if layout.drawing().loose_band_uid(lbi.into()).ok() == Some(inner) {
|
||||
if layout.drawing().find_loose_band_uid(lbi.into()).ok() == Some(inner) {
|
||||
Some(lbi)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
Loading…
Reference in New Issue