fix(geometry/recording_with_rtree): Attach bends applied from edit

This was unimplemented, which made both redo and cane removal not work
correctly.
This commit is contained in:
Mikolaj Wielgus 2025-07-16 15:27:56 +02:00
parent 1f8ace9c77
commit f75bae0666
4 changed files with 43 additions and 7 deletions

View File

@ -27,7 +27,13 @@ pub trait ApplyGeometryEdit<
pub struct GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI> { pub struct GeometryEdit<DW, SW, BW, CW, Cel, PI, DI, SI, BI> {
pub(super) dots: BTreeMap<DI, (Option<DW>, Option<DW>)>, pub(super) dots: BTreeMap<DI, (Option<DW>, Option<DW>)>,
pub(super) segs: BTreeMap<SI, (Option<((DI, DI), SW)>, Option<((DI, DI), SW)>)>, pub(super) segs: BTreeMap<SI, (Option<((DI, DI), SW)>, Option<((DI, DI), SW)>)>,
pub(super) bends: BTreeMap<BI, (Option<((DI, DI, DI), BW)>, Option<((DI, DI, DI), BW)>)>, pub(super) bends: BTreeMap<
BI,
(
Option<((DI, DI, DI, Option<BI>), BW)>,
Option<((DI, DI, DI, Option<BI>), BW)>,
),
>,
pub(super) compounds: pub(super) compounds:
BTreeMap<GenericIndex<CW>, (Option<(Vec<(Cel, PI)>, CW)>, Option<(Vec<(Cel, PI)>, CW)>)>, BTreeMap<GenericIndex<CW>, (Option<(Vec<(Cel, PI)>, CW)>, Option<(Vec<(Cel, PI)>, CW)>)>,
} }

View File

@ -302,6 +302,18 @@ impl<
); );
} }
pub(super) fn init_bend_inner<W: AccessBendWeight + Into<PW>>(
&mut self,
bend: GenericIndex<W>,
inner: BI,
) {
self.graph.update_edge(
inner.petgraph_index(),
bend.petgraph_index(),
GeometryLabel::Outer,
);
}
pub fn remove_primitive(&mut self, primitive: PI) { pub fn remove_primitive(&mut self, primitive: PI) {
self.graph.remove_node(primitive.petgraph_index()); self.graph.remove_node(primitive.petgraph_index());
} }

View File

@ -138,7 +138,7 @@ impl<
( (
None, None,
Some(( Some((
(from, to, core), (from, to, core, None),
weight.into().try_into().unwrap_or_else(|_| unreachable!()), weight.into().try_into().unwrap_or_else(|_| unreachable!()),
)), )),
), ),
@ -215,11 +215,13 @@ impl<
let weight = geometry.bend_weight(bend); let weight = geometry.bend_weight(bend);
let joints = geometry.bend_joints(bend); let joints = geometry.bend_joints(bend);
let core = geometry.core(bend); let core = geometry.core(bend);
let maybe_inner = geometry.inner(bend);
self.geometry_with_rtree.remove_bend(bend); self.geometry_with_rtree.remove_bend(bend);
edit_remove_from_map( edit_remove_from_map(
&mut recorder.bends, &mut recorder.bends,
bend, bend,
((joints.0, joints.1, core), weight), ((joints.0, joints.1, core, maybe_inner), weight),
); );
} }
@ -263,6 +265,7 @@ impl<
let geometry = self.geometry_with_rtree.geometry(); let geometry = self.geometry_with_rtree.geometry();
let old_joints = geometry.bend_joints(bend); let old_joints = geometry.bend_joints(bend);
let old_core = geometry.core(bend); let old_core = geometry.core(bend);
let old_maybe_inner = geometry.inner(bend);
let old_weight = geometry.bend_weight(bend); let old_weight = geometry.bend_weight(bend);
f(&mut self.geometry_with_rtree, bend); f(&mut self.geometry_with_rtree, bend);
@ -270,16 +273,23 @@ impl<
let geometry = self.geometry_with_rtree.geometry(); let geometry = self.geometry_with_rtree.geometry();
let new_joints = geometry.bend_joints(bend); let new_joints = geometry.bend_joints(bend);
let new_core = geometry.core(bend); let new_core = geometry.core(bend);
let new_maybe_inner = geometry.inner(bend);
let new_weight = geometry.bend_weight(bend); let new_weight = geometry.bend_weight(bend);
recorder recorder
.bends .bends
.entry(bend) .entry(bend)
.or_insert(( .or_insert((
Some(((old_joints.0, old_joints.1, old_core), old_weight)), Some((
(old_joints.0, old_joints.1, old_core, old_maybe_inner),
old_weight,
)),
None, None,
)) ))
.1 = Some(((new_joints.0, new_joints.1, new_core), new_weight)); .1 = Some((
(new_joints.0, new_joints.1, new_core, new_maybe_inner),
new_weight,
));
} }
pub fn shift_bend( pub fn shift_bend(

View File

@ -508,7 +508,6 @@ impl<
// Because removal of a bend will invalidate bboxes of the bends wrapped // Because removal of a bend will invalidate bboxes of the bends wrapped
// around it, we first remove the bends from the R-tree, and their nodes // around it, we first remove the bends from the R-tree, and their nodes
// from the graph only afterwards. // from the graph only afterwards.
for (bend, (maybe_old_data, ..)) in &edit.bends { for (bend, (maybe_old_data, ..)) in &edit.bends {
if maybe_old_data.is_some() { if maybe_old_data.is_some() {
Self::rtree_remove_must_be_successful( Self::rtree_remove_must_be_successful(
@ -556,7 +555,7 @@ impl<
// separately to prevent failures from inadvertent bbox invalidation. // separately to prevent failures from inadvertent bbox invalidation.
for (bend, (.., maybe_new_data)) in &edit.bends { for (bend, (.., maybe_new_data)) in &edit.bends {
if let Some(((from, to, core), weight)) = maybe_new_data { if let Some(((from, to, core, ..), weight)) = maybe_new_data {
self.geometry.add_bend_at_index( self.geometry.add_bend_at_index(
GenericIndex::<BW>::new(bend.petgraph_index()), GenericIndex::<BW>::new(bend.petgraph_index()),
*from, *from,
@ -567,6 +566,15 @@ impl<
} }
} }
// We attach bends to other bends only after all bends have been
// created, since we cannot guarantee that their inner bends will exist,
// and attaching to an inexistent bend will result in a crash.
for (bend, (.., maybe_new_data)) in &edit.bends {
if let Some(((.., maybe_inner), ..)) = maybe_new_data {
self.geometry.reattach_bend(*bend, *maybe_inner);
}
}
for (bend, (.., maybe_new_data)) in &edit.bends { for (bend, (.., maybe_new_data)) in &edit.bends {
if let Some(..) = maybe_new_data { if let Some(..) = maybe_new_data {
self.init_bend_bbox(*bend); self.init_bend_bbox(*bend);