feat(drawing/drawing): Make it possible to have multiple outers for each gear

This commit is contained in:
Mikolaj Wielgus 2025-07-22 01:38:03 +02:00 committed by mikolaj
parent 6317d8b08a
commit 83285dde6d
6 changed files with 206 additions and 170 deletions

View File

@ -2,12 +2,12 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::graph::MakeRef; use petgraph::visit::Walker;
use super::{ use super::{
band::{BandTermsegIndex, BandUid}, band::{BandTermsegIndex, BandUid},
bend::LooseBendIndex, bend::LooseBendIndex,
gear::{GearIndex, GetNextGear}, gear::WalkOutwards,
graph::PrimitiveIndex, graph::PrimitiveIndex,
loose::{GetPrevNextLoose, LooseIndex}, loose::{GetPrevNextLoose, LooseIndex},
primitive::GetJoints, primitive::GetJoints,
@ -26,9 +26,7 @@ pub trait Collect {
fn bend_bow(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex>; fn bend_bow(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex>;
fn bend_outer_bows(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex>; fn bend_outward_bows(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex>;
fn wraparounded_bows(&self, around: GearIndex) -> Vec<PrimitiveIndex>;
} }
impl<CW: Clone, Cel: Copy, R: AccessRules> Collect for Drawing<CW, Cel, R> { impl<CW: Clone, Cel: Copy, R: AccessRules> Collect for Drawing<CW, Cel, R> {
@ -62,35 +60,12 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Collect for Drawing<CW, Cel, R> {
v v
} }
fn bend_outer_bows(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex> { fn bend_outward_bows(&self, bend: LooseBendIndex) -> Vec<PrimitiveIndex> {
let mut v = vec![]; let mut v = vec![];
let mut gear = bend;
while let Some(outer) = self.primitive(gear).outer() { let mut outwards = self.primitive(bend).outwards();
v.append(&mut self.bend_bow(outer)); while let Some(next) = outwards.walk_next(self) {
gear = outer; v.append(&mut self.bend_bow(next));
}
v
}
fn wraparounded_bows(&self, around: GearIndex) -> Vec<PrimitiveIndex> {
let mut v = vec![];
let mut gear = around;
while let Some(bend) = gear.ref_(self).next_gear() {
let primitive = self.primitive(bend);
v.push(bend.into());
let joints = primitive.joints();
v.push(joints.0.into());
v.push(joints.1.into());
v.push(self.primitive(joints.0).seg().unwrap().into());
v.push(self.primitive(joints.1).seg().unwrap().into());
gear = bend.into();
} }
v v

View File

@ -5,6 +5,7 @@
use contracts_try::{debug_ensures, debug_invariant}; use contracts_try::{debug_ensures, debug_invariant};
use derive_getters::Getters; use derive_getters::Getters;
use geo::{Point, Polygon}; use geo::{Point, Polygon};
use petgraph::visit::Walker;
use core::fmt; use core::fmt;
use rstar::{RTree, AABB}; use rstar::{RTree, AABB};
@ -17,7 +18,7 @@ use crate::{
cane::Cane, cane::Cane,
collect::Collect, collect::Collect,
dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, dot::{DotIndex, DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
gear::{GearIndex, GetNextGear}, gear::GearIndex,
graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight}, graph::{GetMaybeNet, IsInLayer, MakePrimitive, PrimitiveIndex, PrimitiveWeight},
guide::Guide, guide::Guide,
loose::{GetPrevNextLoose, Loose, LooseIndex}, loose::{GetPrevNextLoose, Loose, LooseIndex},
@ -44,6 +45,8 @@ use crate::{
math::RotationSense, math::RotationSense,
}; };
use super::gear::{GetOuterGears, WalkOutwards};
#[derive(Clone, Copy, Error)] #[derive(Clone, Copy, Error)]
pub enum DrawingException { pub enum DrawingException {
#[error(transparent)] #[error(transparent)]
@ -255,7 +258,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
LooseIndex::Bend(bend) => { LooseIndex::Bend(bend) => {
bends.push(bend); bends.push(bend);
if let Some(outer) = self.primitive(bend).outer() { for outer in self.primitive(bend).outers().collect::<Vec<_>>() {
outers.push(outer); outers.push(outer);
self.reattach_bend(recorder, outer, self.primitive(bend).inner()); self.reattach_bend(recorder, outer, self.primitive(bend).inner());
} }
@ -509,10 +512,11 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
} }
} }
// //
if let Some(next_gear) = around.ref_(self).next_gear() { let mut outwards = around.ref_(self).outwards();
if let Some(next_gear_net) = next_gear.primitive(self).maybe_net() { while let Some(gear) = outwards.walk_next(self) {
if let Some(next_gear_net) = gear.primitive(self).maybe_net() {
if net == next_gear_net { if net == next_gear_net {
return Err(AlreadyConnected(net, next_gear.into()).into()); return Err(AlreadyConnected(net, gear.into()).into());
} }
} }
} }
@ -666,7 +670,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
bend_weight: LooseBendWeight, bend_weight: LooseBendWeight,
sense: RotationSense, sense: RotationSense,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
let maybe_next_gear = around.ref_(self).next_gear(); let outer_gears = around.ref_(self).outer_gears();
let cane = self.add_cane_with_infringement_filtering( let cane = self.add_cane_with_infringement_filtering(
recorder, recorder,
from, from,
@ -678,11 +682,11 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
&|_drawing, _infringer, _infringee| true, &|_drawing, _infringer, _infringee| true,
)?; )?;
if let Some(next_gear) = maybe_next_gear { for gear in outer_gears {
self.reattach_bend(recorder, next_gear, Some(cane.bend)); self.reattach_bend(recorder, gear, Some(cane.bend));
} }
if let Some(outer) = self.primitive(cane.bend).outer() { for outer in self.primitive(cane.bend).outers().collect::<Vec<_>>() {
self.update_this_and_outward_bows(recorder, outer) self.update_this_and_outward_bows(recorder, outer)
.inspect_err(|_| { .inspect_err(|_| {
let joint = self.primitive(cane.bend).other_joint(cane.dot); let joint = self.primitive(cane.bend).other_joint(cane.dot);
@ -700,81 +704,88 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
around: LooseBendIndex, around: LooseBendIndex,
) -> Result<(), DrawingException> { ) -> Result<(), DrawingException> {
let mut maybe_rail = Some(around); self.update_bow(recorder, around)?;
while let Some(rail) = maybe_rail { let mut outwards = self.primitive(around).outwards();
let rail_primitive = self.primitive(rail); while let Some(rail) = outwards.walk_next(self) {
let joints = rail_primitive.joints(); self.update_bow(recorder, rail)?;
let width = rail_primitive.width();
let from_head = self.rear_head(joints.1);
let to_head = self.rear_head(joints.0);
let (from, to, offset) = if let Some(inner) = rail_primitive.inner() {
let inner = inner.into();
let from = self.guide_for_head_around_bend_segment(
&from_head,
inner,
RotationSense::Counterclockwise,
width,
)?;
let to = self.guide_for_head_around_bend_segment(
&to_head,
inner,
RotationSense::Clockwise,
width,
)?;
let offset = self.guide_for_head_around_bend_offset(&from_head, inner, width);
(from, to, offset)
} else {
let core = rail_primitive.core().into();
let from = self.guide_for_head_around_dot_segment(
&from_head,
core,
RotationSense::Counterclockwise,
width,
)?;
let to = self.guide_for_head_around_dot_segment(
&to_head,
core,
RotationSense::Clockwise,
width,
)?;
let offset = self.guide_for_head_around_dot_offset(&from_head, core, width);
(from, to, offset)
};
let rail_outer_bows = self.bend_outer_bows(rail);
// Commenting out these two makes the crash go away.
self.move_dot_with_infringement_filtering(
recorder,
joints.0.into(),
from.end_point(),
&|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?;
self.move_dot_with_infringement_filtering(
recorder,
joints.1.into(),
to.end_point(),
&|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?;
self.shift_bend_with_infringement_filtering(
recorder,
rail.into(),
offset,
&|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?;
// Update offsets in case the rule conditions changed.
maybe_rail = self.primitive(rail).outer();
} }
Ok(()) Ok(())
} }
fn update_bow(
&mut self,
recorder: &mut DrawingEdit<CW, Cel>,
rail: LooseBendIndex,
) -> Result<(), DrawingException> {
let rail_primitive = self.primitive(rail);
let joints = rail_primitive.joints();
let width = rail_primitive.width();
let from_head = self.rear_head(joints.1);
let to_head = self.rear_head(joints.0);
let (from, to, offset) = if let Some(inner) = rail_primitive.inner() {
let inner = inner.into();
let from = self.guide_for_head_around_bend_segment(
&from_head,
inner,
RotationSense::Counterclockwise,
width,
)?;
let to = self.guide_for_head_around_bend_segment(
&to_head,
inner,
RotationSense::Clockwise,
width,
)?;
let offset = self.guide_for_head_around_bend_offset(&from_head, inner, width);
(from, to, offset)
} else {
let core = rail_primitive.core().into();
let from = self.guide_for_head_around_dot_segment(
&from_head,
core,
RotationSense::Counterclockwise,
width,
)?;
let to = self.guide_for_head_around_dot_segment(
&to_head,
core,
RotationSense::Clockwise,
width,
)?;
let offset = self.guide_for_head_around_dot_offset(&from_head, core, width);
(from, to, offset)
};
let rail_outer_bows = self.bend_outward_bows(rail);
// Commenting out these two makes the crash go away.
self.move_dot_with_infringement_filtering(
recorder,
joints.0.into(),
from.end_point(),
&|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?;
self.move_dot_with_infringement_filtering(
recorder,
joints.1.into(),
to.end_point(),
&|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?;
self.shift_bend_with_infringement_filtering(
recorder,
rail.into(),
offset,
&|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?;
Ok(())
}
#[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 4))] #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 4))]
#[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().edge_count() >= old(self.recording_geometry_with_rtree.graph().edge_count() + 5))] #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().edge_count() >= old(self.recording_geometry_with_rtree.graph().edge_count() + 5))]
#[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))]
@ -877,11 +888,11 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
cane: &Cane, cane: &Cane,
face: LooseDotIndex, face: LooseDotIndex,
) { ) {
let maybe_outer = self.primitive(cane.bend).outer(); let outers = self.primitive(cane.bend).outers().collect::<Vec<_>>();
// Removing a loose bend affects its outer bends. // Removing a loose bend affects its outer bends.
if let Some(outer) = maybe_outer { for outer in &outers {
self.reattach_bend(recorder, outer, self.primitive(cane.bend).inner()); self.reattach_bend(recorder, *outer, self.primitive(cane.bend).inner());
} }
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
@ -897,7 +908,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.remove_dot(recorder, cane.dot.into()); .remove_dot(recorder, cane.dot.into());
if let Some(outer) = maybe_outer { for outer in outers {
self.update_this_and_outward_bows(recorder, outer).unwrap(); // Must never fail. self.update_this_and_outward_bows(recorder, outer).unwrap(); // Must never fail.
} }
} }

View File

@ -2,26 +2,23 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use std::collections::VecDeque;
use enum_dispatch::enum_dispatch; use enum_dispatch::enum_dispatch;
use petgraph::stable_graph::NodeIndex; use petgraph::{stable_graph::NodeIndex, visit::Walker};
use crate::{ use crate::{
drawing::{ drawing::{
bend::{BendIndex, FixedBendIndex, LooseBendIndex}, bend::{BendIndex, FixedBendIndex, LooseBendIndex},
dot::FixedDotIndex, dot::FixedDotIndex,
graph::{MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
primitive::{FixedBend, FixedDot, GetFirstGear, LooseBend, Primitive}, primitive::{FixedBend, FixedDot, LooseBend, Primitive},
rules::AccessRules, rules::AccessRules,
Drawing, Drawing,
}, },
graph::{GetPetgraphIndex, MakeRef}, graph::{GetPetgraphIndex, MakeRef},
}; };
#[enum_dispatch]
pub trait GetNextGear: GetPetgraphIndex {
fn next_gear(&self) -> Option<LooseBendIndex>;
}
#[enum_dispatch(GetPetgraphIndex, MakePrimitive)] #[enum_dispatch(GetPetgraphIndex, MakePrimitive)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum GearIndex { pub enum GearIndex {
@ -56,7 +53,7 @@ impl From<BendIndex> for GearIndex {
} }
} }
#[enum_dispatch(GetNextGear, GetDrawing, GetPetgraphIndex)] #[enum_dispatch(WalkOutwards, GetOuterGears, 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>),
@ -73,20 +70,40 @@ impl<'a, CW, Cel, R> GearRef<'a, CW, Cel, R> {
} }
} }
impl<CW, Cel, R> GetNextGear for FixedDot<'_, CW, Cel, R> { #[enum_dispatch]
fn next_gear(&self) -> Option<LooseBendIndex> { pub trait GetOuterGears {
self.first_gear() // TODO: This duplicates `.outers()` methods in some other places, we need
// to merge them with this.
// TODO: Use iterator instead of vec.
fn outer_gears(&self) -> Vec<LooseBendIndex>;
}
#[enum_dispatch]
pub trait WalkOutwards {
fn outwards(&self) -> DrawingOutwardWalker;
}
/// I found it easier to just duplicate `OutwardWalker<BI>` for `Drawing<...>`.
pub struct DrawingOutwardWalker {
frontier: VecDeque<LooseBendIndex>,
}
impl DrawingOutwardWalker {
pub fn new(initial_frontier: impl Iterator<Item = LooseBendIndex>) -> Self {
let mut frontier = VecDeque::new();
frontier.extend(initial_frontier);
Self { frontier }
} }
} }
impl<CW, Cel, R> GetNextGear for LooseBend<'_, CW, Cel, R> { impl<CW: Clone, Cel: Copy, R: AccessRules> Walker<&Drawing<CW, Cel, R>> for DrawingOutwardWalker {
fn next_gear(&self) -> Option<LooseBendIndex> { type Item = LooseBendIndex;
self.outer()
}
}
impl<CW, Cel, R> GetNextGear for FixedBend<'_, CW, Cel, R> { fn walk_next(&mut self, drawing: &Drawing<CW, Cel, R>) -> Option<Self::Item> {
fn next_gear(&self) -> Option<LooseBendIndex> { let front = self.frontier.pop_front()?;
self.first_gear() self.frontier.extend(drawing.primitive(front).outers());
Some(front)
} }
} }

View File

@ -18,6 +18,8 @@ use crate::{
graph::{GenericIndex, GetPetgraphIndex}, graph::{GenericIndex, GetPetgraphIndex},
}; };
use super::gear::{DrawingOutwardWalker, GetOuterGears, WalkOutwards};
pub trait GetDrawing { pub trait GetDrawing {
type CompoundWeight; type CompoundWeight;
type CompoundEntryLabel; type CompoundEntryLabel;
@ -86,12 +88,14 @@ pub trait GetJoints {
fn joints(&self) -> (Self::F, Self::T); fn joints(&self) -> (Self::F, Self::T);
} }
pub trait GetFirstGear: GetDrawing + GetPetgraphIndex { pub trait GetLowestGears: GetDrawing + GetPetgraphIndex {
fn first_gear(&self) -> Option<LooseBendIndex> { // TODO: Make it return an iterator instead of a vec.
fn lowest_gears(&self) -> Vec<LooseBendIndex> {
self.drawing() self.drawing()
.geometry() .geometry()
.first_rail(self.petgraph_index()) .all_rails(self.petgraph_index())
.map(|ni| LooseBendIndex::new(ni.petgraph_index())) .map(|ni| LooseBendIndex::new(ni.petgraph_index()))
.collect()
} }
} }
@ -279,7 +283,19 @@ impl<CW, Cel, R> GetLimbs for FixedDot<'_, CW, Cel, R> {
} }
} }
impl<CW, Cel, R> GetFirstGear for FixedDot<'_, CW, Cel, R> {} impl<CW, Cel, R> GetLowestGears for FixedDot<'_, CW, Cel, R> {}
impl<CW, Cel, R> GetOuterGears for FixedDot<'_, CW, Cel, R> {
fn outer_gears(&self) -> Vec<LooseBendIndex> {
self.lowest_gears()
}
}
impl<CW, Cel, R> WalkOutwards for FixedDot<'_, CW, Cel, R> {
fn outwards(&self) -> DrawingOutwardWalker {
DrawingOutwardWalker::new(self.lowest_gears().into_iter())
}
}
pub type LooseDot<'a, CW, Cel, R> = GenericPrimitive<'a, LooseDotWeight, CW, Cel, R>; pub type LooseDot<'a, CW, Cel, R> = GenericPrimitive<'a, LooseDotWeight, CW, Cel, R>;
impl_loose_primitive!(LooseDot, LooseDotWeight); impl_loose_primitive!(LooseDot, LooseDotWeight);
@ -433,8 +449,19 @@ impl<CW, Cel, R> GetJoints for FixedBend<'_, CW, Cel, R> {
} }
} }
impl<CW, Cel, R> GetFirstGear for FixedBend<'_, CW, Cel, R> {} impl<CW, Cel, R> GetLowestGears for FixedBend<'_, CW, Cel, R> {}
//impl<'a, R: QueryRules> GetInnerOuter for FixedBend<'a, CW, Cel, R> {}
impl<CW, Cel, R> GetOuterGears for FixedBend<'_, CW, Cel, R> {
fn outer_gears(&self) -> Vec<LooseBendIndex> {
self.lowest_gears()
}
}
impl<CW, Cel, R> WalkOutwards for FixedBend<'_, CW, Cel, R> {
fn outwards(&self) -> DrawingOutwardWalker {
DrawingOutwardWalker::new(self.lowest_gears().into_iter())
}
}
pub type LooseBend<'a, CW, Cel, R> = GenericPrimitive<'a, LooseBendWeight, CW, Cel, R>; pub type LooseBend<'a, CW, Cel, R> = GenericPrimitive<'a, LooseBendWeight, CW, Cel, R>;
impl_loose_primitive!(LooseBend, LooseBendWeight); impl_loose_primitive!(LooseBend, LooseBendWeight);
@ -477,6 +504,18 @@ impl<CW, Cel, R> GetJoints for LooseBend<'_, CW, Cel, R> {
} }
} }
impl<CW, Cel, R> GetOuterGears for LooseBend<'_, CW, Cel, R> {
fn outer_gears(&self) -> Vec<LooseBendIndex> {
self.outers().collect()
}
}
impl<CW, Cel, R> WalkOutwards for LooseBend<'_, CW, Cel, R> {
fn outwards(&self) -> DrawingOutwardWalker {
DrawingOutwardWalker::new(self.outers())
}
}
impl<CW, Cel, R> LooseBend<'_, CW, Cel, R> { impl<CW, Cel, R> LooseBend<'_, CW, Cel, R> {
pub fn inner(&self) -> Option<LooseBendIndex> { pub fn inner(&self) -> Option<LooseBendIndex> {
self.drawing() self.drawing()
@ -485,11 +524,10 @@ impl<CW, Cel, R> LooseBend<'_, CW, Cel, R> {
.map(|ni| LooseBendIndex::new(ni.petgraph_index())) .map(|ni| LooseBendIndex::new(ni.petgraph_index()))
} }
pub fn outer(&self) -> Option<LooseBendIndex> { pub fn outers(&self) -> impl Iterator<Item = LooseBendIndex> + '_ {
self.drawing() self.drawing()
.geometry() .geometry()
.outers(self.bend_index()) .outers(self.bend_index())
.next()
.map(|node| LooseBendIndex::new(node.petgraph_index())) .map(|node| LooseBendIndex::new(node.petgraph_index()))
} }
} }

View File

@ -573,15 +573,6 @@ impl<
BI: GetPetgraphIndex, BI: GetPetgraphIndex,
> Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI> > Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
{ {
pub fn first_rail(&self, node: NodeIndex<usize>) -> Option<BI> {
self.all_rails(node).find(|bend| {
!self
.graph
.edges_directed(bend.petgraph_index(), Incoming)
.any(|edge| matches!(edge.weight(), GeometryLabel::Outer))
})
}
pub fn all_rails(&self, node: NodeIndex<usize>) -> impl Iterator<Item = BI> + '_ { pub fn all_rails(&self, node: NodeIndex<usize>) -> impl Iterator<Item = BI> + '_ {
self.graph self.graph
.edges_directed(node, Incoming) .edges_directed(node, Incoming)

View File

@ -11,7 +11,8 @@ use petgraph::{
graph::UnGraph, graph::UnGraph,
stable_graph::NodeIndex, stable_graph::NodeIndex,
visit::{ visit::{
Data, EdgeRef, GraphBase, IntoEdgeReferences, IntoEdges, IntoNeighbors, IntoNodeIdentifiers, Data, EdgeRef, GraphBase, IntoEdgeReferences, IntoEdges, IntoNeighbors,
IntoNodeIdentifiers, Walker,
}, },
}; };
use spade::InsertionError; use spade::InsertionError;
@ -21,7 +22,7 @@ use crate::{
drawing::{ drawing::{
bend::{FixedBendIndex, LooseBendIndex}, bend::{FixedBendIndex, LooseBendIndex},
dot::FixedDotIndex, dot::FixedDotIndex,
gear::{GearIndex, GetNextGear}, gear::{GearIndex, GetOuterGears, WalkOutwards},
graph::{MakePrimitive, PrimitiveIndex}, graph::{MakePrimitive, PrimitiveIndex},
primitive::Primitive, primitive::Primitive,
rules::AccessRules, rules::AccessRules,
@ -183,8 +184,7 @@ impl Navmesh {
} else { } else {
map.insert(trianvertex, vec![]); map.insert(trianvertex, vec![]);
let mut gear = let gear = Into::<GearIndex>::into(Into::<BinavnodeNodeIndex>::into(trianvertex));
Into::<GearIndex>::into(Into::<BinavnodeNodeIndex>::into(trianvertex));
if options.squeeze_through_under_bends { if options.squeeze_through_under_bends {
Self::add_trianvertex_to_graph_and_map_as_binavnode( Self::add_trianvertex_to_graph_and_map_as_binavnode(
@ -195,30 +195,34 @@ impl Navmesh {
); );
if options.wrap_around_bands { if options.wrap_around_bands {
while let Some(bend) = gear.ref_(layout.drawing()).next_gear() { let mut outwards = gear.ref_(layout.drawing()).outwards();
while let Some(outward) = outwards.walk_next(layout.drawing()) {
Self::add_trianvertex_to_graph_and_map_as_binavnode( Self::add_trianvertex_to_graph_and_map_as_binavnode(
&mut graph, &mut graph,
&mut map, &mut map,
trianvertex, trianvertex,
bend.into(), outward.into(),
); );
gear = bend.into();
} }
} }
} else if let Some(first_bend) = gear.ref_(layout.drawing()).next_gear() { } else if !gear.ref_(layout.drawing()).outer_gears().is_empty() {
let mut bend = first_bend; let mut outwards = gear.ref_(layout.drawing()).outwards();
while let Some(outward) = outwards.walk_next(layout.drawing()) {
while let Some(next_bend) = gear.ref_(layout.drawing()).next_gear() { if layout
bend = next_bend; .drawing()
gear = bend.into(); .primitive(outward)
.outers()
.collect::<Vec<_>>()
.is_empty()
{
Self::add_trianvertex_to_graph_and_map_as_binavnode(
&mut graph,
&mut map,
trianvertex,
outward.into(),
);
}
} }
Self::add_trianvertex_to_graph_and_map_as_binavnode(
&mut graph,
&mut map,
trianvertex,
bend.into(),
);
} else { } else {
Self::add_trianvertex_to_graph_and_map_as_binavnode( Self::add_trianvertex_to_graph_and_map_as_binavnode(
&mut graph, &mut graph,