mirror of https://codeberg.org/topola/topola.git
feat(layout): implement extraction of band-between-nodes information
This commit is contained in:
parent
3c3c1d9b42
commit
e7b120e8ed
|
|
@ -62,13 +62,7 @@ impl<'a> ResolvedSelector<'a> {
|
|||
let (layer, loose) = match node {
|
||||
NodeIndex::Primitive(primitive) => (
|
||||
primitive.primitive(board.layout().drawing()).layer(),
|
||||
match primitive {
|
||||
PrimitiveIndex::LooseDot(dot) => Some(dot.into()),
|
||||
PrimitiveIndex::LoneLooseSeg(seg) => Some(seg.into()),
|
||||
PrimitiveIndex::SeqLooseSeg(seg) => Some(seg.into()),
|
||||
PrimitiveIndex::LooseBend(bend) => Some(bend.into()),
|
||||
_ => None,
|
||||
},
|
||||
primitive.try_into().ok(),
|
||||
),
|
||||
NodeIndex::Compound(compound) => {
|
||||
match board.layout().drawing().compound_weight(compound) {
|
||||
|
|
|
|||
|
|
@ -57,6 +57,19 @@ impl From<LooseIndex> for PrimitiveIndex {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<PrimitiveIndex> for LooseIndex {
|
||||
type Error = ();
|
||||
fn try_from(primitive: PrimitiveIndex) -> Result<LooseIndex, ()> {
|
||||
match primitive {
|
||||
PrimitiveIndex::LooseDot(dot) => Ok(dot.into()),
|
||||
PrimitiveIndex::LoneLooseSeg(seg) => Ok(seg.into()),
|
||||
PrimitiveIndex::SeqLooseSeg(seg) => Ok(seg.into()),
|
||||
PrimitiveIndex::LooseBend(bend) => Ok(bend.into()),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_dispatch(GetPrevNextLoose, GetDrawing, GetPetgraphIndex)]
|
||||
pub enum Loose<'a, CW: Copy, R: AccessRules> {
|
||||
Dot(LooseDot<'a, CW, R>),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rstar::AABB;
|
|||
|
||||
use crate::{
|
||||
drawing::{
|
||||
band::BandTermsegIndex,
|
||||
band::{BandTermsegIndex, BandUid},
|
||||
bend::{BendIndex, BendWeight, LooseBendWeight},
|
||||
dot::{
|
||||
DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, GeneralDotWeight, LooseDotIndex,
|
||||
|
|
@ -18,15 +18,21 @@ use crate::{
|
|||
},
|
||||
gear::GearIndex,
|
||||
graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight},
|
||||
loose::LooseIndex,
|
||||
primitive::MakePrimitiveShape,
|
||||
rules::AccessRules,
|
||||
seg::{
|
||||
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
|
||||
SegWeight, SeqLooseSegIndex, SeqLooseSegWeight,
|
||||
},
|
||||
Cane, Drawing, DrawingEdit, DrawingException, Infringement,
|
||||
Cane, Collect, Drawing, DrawingEdit, DrawingException, Infringement,
|
||||
},
|
||||
geometry::{
|
||||
edit::ApplyGeometryEdit,
|
||||
primitive::{AccessPrimitiveShape, PrimitiveShape, SegShape},
|
||||
shape::{AccessShape, Shape},
|
||||
GenericNode,
|
||||
},
|
||||
geometry::{edit::ApplyGeometryEdit, shape::Shape, GenericNode},
|
||||
graph::{GenericIndex, GetPetgraphIndex},
|
||||
layout::{
|
||||
poly::{MakePolygon, Poly, PolyWeight},
|
||||
|
|
@ -367,6 +373,68 @@ impl<R: AccessRules> Layout<R> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Finds all bands on `layer` between `left` and `right`
|
||||
/// (usually assuming `left` and `right` are neighbors in a Delaunay triangulation)
|
||||
/// and returns them ordered from `left` to `right`.
|
||||
pub fn bands_between_nodes(
|
||||
&self,
|
||||
layer: usize,
|
||||
left: NodeIndex,
|
||||
right: NodeIndex,
|
||||
) -> Vec<BandUid> {
|
||||
assert_ne!(left, right);
|
||||
let left_pos = self.node_shape(left).center();
|
||||
let right_pos = self.node_shape(right).center();
|
||||
let delta = right_pos - left_pos;
|
||||
let delta_len = delta.y().hypot(delta.x());
|
||||
let fake_seg = PrimitiveShape::Seg(SegShape {
|
||||
from: left_pos,
|
||||
to: right_pos,
|
||||
// TODO: being able to use a zero-width segshape here would be optimal
|
||||
// check if that works
|
||||
width: f64::EPSILON,
|
||||
});
|
||||
|
||||
let mut bands: Vec<_> = self
|
||||
.drawing
|
||||
.rtree()
|
||||
.locate_in_envelope_intersecting(&{
|
||||
let aabb_init = AABB::from_corners(
|
||||
[left_pos.x(), left_pos.y()],
|
||||
[right_pos.x(), right_pos.y()],
|
||||
);
|
||||
AABB::from_corners(
|
||||
[aabb_init.lower()[0], aabb_init.lower()[1], layer as f64],
|
||||
[aabb_init.upper()[0], aabb_init.upper()[1], layer as f64],
|
||||
)
|
||||
})
|
||||
// TODO: handle non-loose entries (bends, segs)
|
||||
.filter_map(|geom| match geom.data {
|
||||
NodeIndex::Primitive(prim) => LooseIndex::try_from(prim).ok(),
|
||||
NodeIndex::Compound(_) => None,
|
||||
})
|
||||
.map(|loose| {
|
||||
let prim: PrimitiveIndex = loose.into();
|
||||
let shape = prim.primitive(&self.drawing).shape();
|
||||
(prim, loose, shape)
|
||||
})
|
||||
.filter(|(_, _, shape)| shape.intersects(&fake_seg))
|
||||
.map(|(_, loose, shape)| {
|
||||
let band_uid = self.drawing.loose_band_uid(loose);
|
||||
// TODO: check that the resulting order is correct
|
||||
let location = crate::math::dot_product(delta, shape.center()) / delta_len;
|
||||
(location, band_uid)
|
||||
})
|
||||
.collect();
|
||||
bands.sort_by(|a, b| f64::total_cmp(&a.0, &b.0));
|
||||
|
||||
// TODO: handle "loops" of bands, or multiple primitives from the band crossing the segment
|
||||
// both in the case of "edge" of a primitive/loose, and in case the band actually goes into a segment
|
||||
// and then again out of it.
|
||||
|
||||
bands.into_iter().map(|(_, band_uid)| band_uid).collect()
|
||||
}
|
||||
|
||||
pub fn rules(&self) -> &R {
|
||||
self.drawing.rules()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue