mirror of https://codeberg.org/topola/topola.git
feat(drawing/gear): Implement finding next and previous gear in chain for fixed dots
This commit is contained in:
parent
310e983b1d
commit
41438eeccc
|
|
@ -53,7 +53,7 @@ impl From<BendIndex> for GearIndex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch(WalkOutwards, GetOuterGears, GetDrawing, GetPetgraphIndex)]
|
#[enum_dispatch(GetOuterGears, WalkOutwards, GetDrawing, GetPetgraphIndex)]
|
||||||
pub enum GearRef<'a, CW, Cel, R> {
|
pub enum GearRef<'a, CW, Cel, R> {
|
||||||
FixedDot(FixedDot<'a, CW, Cel, R>),
|
FixedDot(FixedDot<'a, CW, Cel, R>),
|
||||||
FixedBend(FixedBend<'a, CW, Cel, R>),
|
FixedBend(FixedBend<'a, CW, Cel, R>),
|
||||||
|
|
@ -83,6 +83,29 @@ pub trait WalkOutwards {
|
||||||
fn outwards(&self) -> DrawingOutwardWalker;
|
fn outwards(&self) -> DrawingOutwardWalker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#[enum_dispatch]
|
||||||
|
pub trait GetPrevNextInChain {
|
||||||
|
fn next_in_chain(&self, maybe_prev: Option<GearIndex>) -> Option<GearIndex>;
|
||||||
|
|
||||||
|
fn prev_in_chain(&self, maybe_next: Option<GearIndex>) -> Option<GearIndex> {
|
||||||
|
// Just as in the `GetPrevNextLoose` trait.
|
||||||
|
let maybe_prev = maybe_next.or_else(|| self.next_in_chain(None));
|
||||||
|
self.next_in_chain(maybe_prev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because types have trait bounds, we cannot use enum_dispatch and instead we
|
||||||
|
// implement `GetPrevNextInChain` explicitly.
|
||||||
|
impl<'a, CW: Clone, Cel: Copy, R: AccessRules> GetPrevNextInChain for GearRef<'a, CW, Cel, R> {
|
||||||
|
fn next_in_chain(&self, maybe_prev: Option<GearIndex>) -> Option<GearIndex> {
|
||||||
|
match self {
|
||||||
|
GearRef::FixedDot(dot) => dot.next_in_chain(maybe_prev),
|
||||||
|
GearRef::FixedBend(bend) => bend.next_in_chain(maybe_prev),
|
||||||
|
GearRef::LooseBend(bend) => bend.next_in_chain(maybe_prev),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// I found it easier to just duplicate `OutwardWalker<BI>` for `Drawing<...>`.
|
/// I found it easier to just duplicate `OutwardWalker<BI>` for `Drawing<...>`.
|
||||||
pub struct DrawingOutwardWalker {
|
pub struct DrawingOutwardWalker {
|
||||||
frontier: VecDeque<LooseBendIndex>,
|
frontier: VecDeque<LooseBendIndex>,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
drawing::{
|
drawing::{
|
||||||
bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
bend::{BendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
||||||
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
|
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
|
||||||
|
gear::{GearIndex, GetPrevNextInChain},
|
||||||
graph::{GetMaybeNet, PrimitiveIndex, PrimitiveWeight},
|
graph::{GetMaybeNet, PrimitiveIndex, PrimitiveWeight},
|
||||||
rules::{AccessRules, Conditions, GetConditions},
|
rules::{AccessRules, Conditions, GetConditions},
|
||||||
seg::{FixedSegWeight, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight},
|
seg::{FixedSegWeight, LoneLooseSegWeight, SegIndex, SeqLooseSegIndex, SeqLooseSegWeight},
|
||||||
|
|
@ -291,6 +292,24 @@ impl<CW, Cel, R> GetOuterGears 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> {
|
||||||
|
self.drawing
|
||||||
|
.clearance_intersectors(self.index.into())
|
||||||
|
.find_map(|infringement| {
|
||||||
|
let PrimitiveIndex::FixedDot(intersectee) = infringement.1 else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(prev) = maybe_prev {
|
||||||
|
(infringement.1 == prev.into()).then_some(intersectee.into())
|
||||||
|
} else {
|
||||||
|
Some(intersectee.into())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<CW, Cel, R> WalkOutwards for FixedDot<'_, CW, Cel, R> {
|
impl<CW, Cel, R> WalkOutwards for FixedDot<'_, CW, Cel, R> {
|
||||||
fn outwards(&self) -> DrawingOutwardWalker {
|
fn outwards(&self) -> DrawingOutwardWalker {
|
||||||
DrawingOutwardWalker::new(self.lowest_gears().into_iter())
|
DrawingOutwardWalker::new(self.lowest_gears().into_iter())
|
||||||
|
|
@ -457,6 +476,12 @@ impl<CW, Cel, R> GetOuterGears for FixedBend<'_, CW, Cel, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<CW, Cel, R> GetPrevNextInChain for FixedBend<'_, CW, Cel, R> {
|
||||||
|
fn next_in_chain(&self, _maybe_prev: Option<GearIndex>) -> Option<GearIndex> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<CW, Cel, R> WalkOutwards for FixedBend<'_, CW, Cel, R> {
|
impl<CW, Cel, R> WalkOutwards for FixedBend<'_, CW, Cel, R> {
|
||||||
fn outwards(&self) -> DrawingOutwardWalker {
|
fn outwards(&self) -> DrawingOutwardWalker {
|
||||||
DrawingOutwardWalker::new(self.lowest_gears().into_iter())
|
DrawingOutwardWalker::new(self.lowest_gears().into_iter())
|
||||||
|
|
@ -510,6 +535,12 @@ impl<CW, Cel, R> GetOuterGears for LooseBend<'_, CW, Cel, R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<CW, Cel, R> GetPrevNextInChain for LooseBend<'_, CW, Cel, R> {
|
||||||
|
fn next_in_chain(&self, _maybe_prev: Option<GearIndex>) -> Option<GearIndex> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<CW, Cel, R> WalkOutwards for LooseBend<'_, CW, Cel, R> {
|
impl<CW, Cel, R> WalkOutwards for LooseBend<'_, CW, Cel, R> {
|
||||||
fn outwards(&self) -> DrawingOutwardWalker {
|
fn outwards(&self) -> DrawingOutwardWalker {
|
||||||
DrawingOutwardWalker::new(self.outers())
|
DrawingOutwardWalker::new(self.outers())
|
||||||
|
|
|
||||||
|
|
@ -112,24 +112,38 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn find_infringement_except(
|
pub(super) fn find_infringement_except<'a>(
|
||||||
&self,
|
&'a self,
|
||||||
infringer: PrimitiveIndex,
|
infringer: PrimitiveIndex,
|
||||||
predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
predicate: &'a impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||||
) -> Option<Infringement> {
|
) -> Option<Infringement> {
|
||||||
|
self.infringements_except(infringer, predicate).next()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*pub(super) fn infringements<'a>(
|
||||||
|
&'a self,
|
||||||
|
infringer: PrimitiveIndex,
|
||||||
|
) -> impl Iterator<Item = Infringement> + 'a {
|
||||||
|
self.infringements_except(infringer, &|_, _, _| true)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
fn infringements_except<'a>(
|
||||||
|
&'a self,
|
||||||
|
infringer: PrimitiveIndex,
|
||||||
|
predicate: &'a impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
|
||||||
|
) -> impl Iterator<Item = Infringement> + 'a {
|
||||||
self.infringements_among(
|
self.infringements_among(
|
||||||
infringer,
|
infringer,
|
||||||
self.locate_possible_infringees(infringer)
|
self.locate_possible_infringees(infringer)
|
||||||
.filter_map(|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(|infringee| predicate(&self, infringer, *infringee)),
|
.filter(move |infringee| predicate(&self, infringer, *infringee)),
|
||||||
)
|
)
|
||||||
.next()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn infringements_among<'a>(
|
pub(super) fn infringements_among<'a>(
|
||||||
|
|
@ -137,21 +151,45 @@ 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 {
|
||||||
let mut inflated_shape = infringer.primitive(self).shape(); // Unused temporary value just for initialization.
|
self.clearance_intersectors_among(infringer, it)
|
||||||
let conditions = infringer.primitive(self).conditions();
|
.filter(move |infringement| {
|
||||||
|
|
||||||
it.filter(move |infringee| {
|
|
||||||
// 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.
|
||||||
!matches!(infringer, PrimitiveIndex::LooseDot(..))
|
!matches!(infringer, PrimitiveIndex::LooseDot(..))
|
||||||
&& !matches!(infringee, PrimitiveIndex::LooseDot(..))
|
&& !matches!(infringement.1, PrimitiveIndex::LooseDot(..))
|
||||||
})
|
})
|
||||||
.filter(move |infringee| !self.are_connectable(infringer, *infringee))
|
.filter(move |infringement| !self.are_connectable(infringer, infringement.1))
|
||||||
.filter_map(move |primitive_node| {
|
}
|
||||||
|
|
||||||
|
pub(super) fn clearance_intersectors<'a>(
|
||||||
|
&'a self,
|
||||||
|
intersector: PrimitiveIndex,
|
||||||
|
) -> impl Iterator<Item = Infringement> + 'a {
|
||||||
|
self.clearance_intersectors_among(
|
||||||
|
intersector,
|
||||||
|
self.locate_possible_infringees(intersector)
|
||||||
|
.filter_map(move |infringee_node| {
|
||||||
|
if let GenericNode::Primitive(primitive_node) = infringee_node {
|
||||||
|
Some(primitive_node)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn clearance_intersectors_among<'a>(
|
||||||
|
&'a self,
|
||||||
|
intersector: PrimitiveIndex,
|
||||||
|
it: impl Iterator<Item = PrimitiveIndex> + 'a,
|
||||||
|
) -> impl Iterator<Item = Infringement> + 'a {
|
||||||
|
let conditions = intersector.primitive(self).conditions();
|
||||||
|
|
||||||
|
it.filter_map(move |primitive_node| {
|
||||||
let infringee_conditions = primitive_node.primitive(self).conditions();
|
let infringee_conditions = primitive_node.primitive(self).conditions();
|
||||||
|
|
||||||
let epsilon = 1.0;
|
let epsilon = 1.0;
|
||||||
inflated_shape = infringer.primitive(self).shape().inflate(
|
let inflated_shape = intersector.primitive(self).shape().inflate(
|
||||||
match (&conditions, infringee_conditions) {
|
match (&conditions, infringee_conditions) {
|
||||||
(None, _) | (_, None) => 0.0,
|
(None, _) | (_, None) => 0.0,
|
||||||
(Some(lhs), Some(rhs)) => {
|
(Some(lhs), Some(rhs)) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue