feat(geometry/geometry): Create outward bend walker, use it for R-tree updates

Drawing and above abstraction layers do not use it yet, but this will
change soon.
This commit is contained in:
Mikolaj Wielgus 2025-07-21 14:02:21 +02:00 committed by mikolaj
parent 8cf26d1799
commit 6317d8b08a
3 changed files with 63 additions and 26 deletions

View File

@ -488,7 +488,8 @@ impl<CW, Cel, R> LooseBend<'_, CW, Cel, R> {
pub fn outer(&self) -> Option<LooseBendIndex> { pub fn outer(&self) -> Option<LooseBendIndex> {
self.drawing() self.drawing()
.geometry() .geometry()
.outer(self.bend_index()) .outers(self.bend_index())
.map(|ni| LooseBendIndex::new(ni.petgraph_index())) .next()
.map(|node| LooseBendIndex::new(node.petgraph_index()))
} }
} }

View File

@ -7,10 +7,11 @@ use enum_dispatch::enum_dispatch;
use geo::Point; use geo::Point;
use petgraph::{ use petgraph::{
stable_graph::{NodeIndex, StableDiGraph}, stable_graph::{NodeIndex, StableDiGraph},
visit::EdgeRef, visit::{EdgeRef, Walker},
Direction::{Incoming, Outgoing}, Direction::{Incoming, Outgoing},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
use crate::{ use crate::{
drawing::{ drawing::{
@ -520,6 +521,45 @@ impl<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW, Cel, PI, DI, SI, BI>
} }
} }
pub struct OutwardWalker<BI> {
frontier: VecDeque<BI>,
}
impl<BI: GetPetgraphIndex> OutwardWalker<BI> {
pub fn new(initial_frontier: impl Iterator<Item = BI>) -> Self {
let mut frontier = VecDeque::new();
frontier.extend(initial_frontier);
Self { frontier }
}
}
impl<
PW: Copy + Retag<Index = PI>,
DW,
SW,
BW,
CW,
Cel,
PI: TryInto<DI> + TryInto<SI> + TryInto<BI>,
DI,
SI,
BI: Copy + GetPetgraphIndex,
> Walker<&Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>> for OutwardWalker<BI>
{
type Item = BI;
fn walk_next(
&mut self,
geometry: &Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>,
) -> Option<Self::Item> {
let front = self.frontier.pop_front()?;
self.frontier.extend(geometry.outers(front));
Some(front)
}
}
impl< impl<
PW: Copy + Retag<Index = PI>, PW: Copy + Retag<Index = PI>,
DW, DW,
@ -576,16 +616,20 @@ impl<
}) })
} }
pub fn outer(&self, bend: BI) -> Option<BI> { pub fn outers(&self, bend: BI) -> impl Iterator<Item = BI> + '_ {
self.graph self.graph
.edges_directed(bend.petgraph_index(), Outgoing) .edges_directed(bend.petgraph_index(), Outgoing)
.find(|edge| matches!(edge.weight(), GeometryLabel::Outer)) .filter(|edge| matches!(edge.weight(), GeometryLabel::Outer))
.map(|edge| { .map(|edge| {
self.primitive_index(edge.target()) self.primitive_index(edge.target())
.try_into() .try_into()
.unwrap_or_else(|_| unreachable!()) .unwrap_or_else(|_| unreachable!())
}) })
} }
pub fn outwards(&self, bend: BI) -> OutwardWalker<BI> {
OutwardWalker::new(self.outers(bend))
}
} }
impl<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW: Clone, Cel: Copy, PI: Copy, DI, SI, BI> impl<PW: Copy + Retag<Index = PI>, DW, SW, BW, CW: Clone, Cel: Copy, PI: Copy, DI, SI, BI>

View File

@ -5,7 +5,7 @@
use contracts_try::debug_invariant; use contracts_try::debug_invariant;
use derive_getters::Getters; use derive_getters::Getters;
use geo::Point; use geo::Point;
use petgraph::stable_graph::StableDiGraph; use petgraph::{stable_graph::StableDiGraph, visit::Walker};
use rstar::{primitives::GeomWithData, Envelope, RTree, RTreeObject, AABB}; use rstar::{primitives::GeomWithData, Envelope, RTree, RTreeObject, AABB};
use crate::{ use crate::{
@ -194,21 +194,17 @@ impl<
// here because it starts iteration from the bend we currently operate // here because it starts iteration from the bend we currently operate
// on, which obviously does not exist after deletion. // on, which obviously does not exist after deletion.
let mut rail = bend; let mut outwards = self.geometry.outwards(bend);
while let Some(next) = outwards.walk_next(&self.geometry) {
while let Some(outer) = self.geometry.outer(rail) { Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(next)));
Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(outer)));
rail = outer;
} }
let mut maybe_rail = self.geometry.outer(bend);
Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(bend))); Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(bend)));
self.geometry.remove_primitive(bend.into()); self.geometry.remove_primitive(bend.into());
while let Some(outer) = maybe_rail { let mut outwards = self.geometry.outwards(bend);
self.rtree.insert(self.make_bend_bbox(outer)); while let Some(next) = outwards.walk_next(&self.geometry) {
maybe_rail = Some(outer); self.rtree.insert(self.make_bend_bbox(next));
} }
} }
@ -273,11 +269,9 @@ impl<
where where
F: FnOnce(&mut Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>, BI), F: FnOnce(&mut Geometry<PW, DW, SW, BW, CW, Cel, PI, DI, SI, BI>, BI),
{ {
let mut rail = bend; let mut outwards = self.geometry.outwards(bend);
while let Some(next) = outwards.walk_next(&self.geometry) {
while let Some(outer) = self.geometry.outer(rail) { Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(next)));
Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(outer)));
rail = outer;
} }
Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(bend))); Self::rtree_remove_must_be_successful(self.rtree.remove(&self.make_bend_bbox(bend)));
@ -286,11 +280,9 @@ impl<
self.rtree.insert(self.make_bend_bbox(bend)); self.rtree.insert(self.make_bend_bbox(bend));
rail = bend; let mut outwards = self.geometry.outwards(bend);
while let Some(next) = outwards.walk_next(&self.geometry) {
while let Some(outer) = self.geometry.outer(rail) { self.rtree.insert(self.make_bend_bbox(next));
self.rtree.insert(self.make_bend_bbox(outer));
rail = outer;
} }
} }