// SPDX-FileCopyrightText: 2024 Topola contributors // // SPDX-License-Identifier: MIT use std::collections::btree_map::Entry as BTreeMapEntry; use geo::Point; use petgraph::stable_graph::StableDiGraph; use rstar::RTree; use crate::{ drawing::graph::{GetLayer, Retag}, graph::{GenericIndex, GetPetgraphIndex}, }; use super::{ compound::ManageCompounds, edit::{ApplyGeometryEdit, GeometryEdit}, with_rtree::{BboxedIndex, GeometryWithRtree}, AccessBendWeight, AccessDotWeight, AccessSegWeight, GenericNode, Geometry, GeometryLabel, GetWidth, }; #[derive(Debug)] pub struct RecordingGeometryWithRtree { geometry_with_rtree: GeometryWithRtree, } impl< PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, DW: AccessDotWeight + GetLayer, SW: AccessSegWeight + GetLayer, BW: AccessBendWeight + GetLayer, CW: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, DI: GetPetgraphIndex + Into + Eq + Ord + Copy, SI: GetPetgraphIndex + Into + Eq + Ord + Copy, BI: GetPetgraphIndex + Into + Eq + Ord + Copy, > RecordingGeometryWithRtree { pub fn new(layer_count: usize) -> Self { Self { geometry_with_rtree: GeometryWithRtree::::new( layer_count, ), } } pub fn add_dot + GetLayer>( &mut self, recorder: &mut GeometryEdit, weight: W, ) -> GenericIndex where GenericIndex: Into, { let dot = self.geometry_with_rtree.add_dot(weight); recorder.dots.insert( Into::::into(dot) .try_into() .unwrap_or_else(|_| unreachable!()), ( None, Some(weight.into().try_into().unwrap_or_else(|_| unreachable!())), ), ); dot } pub fn add_seg + GetLayer>( &mut self, recorder: &mut GeometryEdit, from: DI, to: DI, weight: W, ) -> GenericIndex where GenericIndex: Into, { let seg = self.geometry_with_rtree.add_seg(from, to, weight); recorder.segs.insert( Into::::into(seg) .try_into() .unwrap_or_else(|_| unreachable!()), ( None, Some(( (from, to), weight.into().try_into().unwrap_or_else(|_| unreachable!()), )), ), ); seg } pub fn add_bend + GetLayer>( &mut self, recorder: &mut GeometryEdit, from: DI, to: DI, core: DI, weight: W, ) -> GenericIndex where GenericIndex: Into, { let bend = self.geometry_with_rtree.add_bend(from, to, core, weight); recorder.bends.insert( Into::::into(bend) .try_into() .unwrap_or_else(|_| unreachable!()), ( None, Some(( (from, to, core), weight.into().try_into().unwrap_or_else(|_| unreachable!()), )), ), ); bend } pub fn add_compound( &mut self, recorder: &mut GeometryEdit, weight: CW, ) -> GenericIndex { let compound = self.geometry_with_rtree.add_compound(weight); recorder .compounds .insert(compound, (None, Some((vec![], weight)))); compound } pub fn add_to_compound( &mut self, recorder: &mut GeometryEdit, primitive: GenericIndex, compound: GenericIndex, ) { let geometry = self.geometry_with_rtree.geometry(); let old_members = geometry.compound_members(compound).collect(); let old_weight = geometry.compound_weight(compound); self.geometry_with_rtree .add_to_compound(primitive, compound); let geometry = self.geometry_with_rtree.geometry(); let new_members = geometry.compound_members(compound).collect(); let new_weight = geometry.compound_weight(compound); recorder .compounds .entry(compound) .or_insert((Some((old_members, old_weight)), None)) .1 = Some((new_members, new_weight)); } pub fn remove_dot( &mut self, recorder: &mut GeometryEdit, dot: DI, ) -> Result<(), ()> { let weight = self.geometry_with_rtree.geometry().dot_weight(dot); self.geometry_with_rtree.remove_dot(dot)?; edit_remove_from_map(&mut recorder.dots, dot, weight); Ok(()) } pub fn remove_seg( &mut self, recorder: &mut GeometryEdit, seg: SI, ) { let geometry = self.geometry_with_rtree.geometry(); let weight = geometry.seg_weight(seg); let joints = geometry.seg_joints(seg); self.geometry_with_rtree.remove_seg(seg); edit_remove_from_map(&mut recorder.segs, seg, (joints, weight)); } pub fn remove_bend( &mut self, recorder: &mut GeometryEdit, bend: BI, ) { let geometry = self.geometry_with_rtree.geometry(); let weight = geometry.bend_weight(bend); let joints = geometry.bend_joints(bend); let core = geometry.core(bend); self.geometry_with_rtree.remove_bend(bend); edit_remove_from_map( &mut recorder.bends, bend, ((joints.0, joints.1, core), weight), ); } pub fn remove_compound( &mut self, recorder: &mut GeometryEdit, compound: GenericIndex, ) { let geometry = self.geometry_with_rtree.geometry(); let weight = geometry.compound_weight(compound); let members = geometry.compound_members(compound).collect(); self.geometry_with_rtree.remove_compound(compound); edit_remove_from_map(&mut recorder.compounds, compound, (members, weight)); } pub fn move_dot( &mut self, recorder: &mut GeometryEdit, dot: DI, to: Point, ) { let old_weight = self.geometry_with_rtree.geometry().dot_weight(dot); self.geometry_with_rtree.move_dot(dot, to); let new_weight = self.geometry_with_rtree.geometry().dot_weight(dot); recorder .dots .entry(dot) .or_insert((Some(old_weight), None)) .1 = Some(new_weight); } fn modify_bend( &mut self, recorder: &mut GeometryEdit, bend: BI, f: F, ) where F: FnOnce(&mut GeometryWithRtree, BI), { let geometry = self.geometry_with_rtree.geometry(); let old_joints = geometry.bend_joints(bend); let old_core = geometry.core(bend); let old_weight = geometry.bend_weight(bend); f(&mut self.geometry_with_rtree, bend); let geometry = self.geometry_with_rtree.geometry(); let new_joints = geometry.bend_joints(bend); let new_core = geometry.core(bend); let new_weight = geometry.bend_weight(bend); recorder .bends .entry(bend) .or_insert(( Some(((old_joints.0, old_joints.1, old_core), old_weight)), None, )) .1 = Some(((new_joints.0, new_joints.1, new_core), new_weight)); } pub fn shift_bend( &mut self, recorder: &mut GeometryEdit, bend: BI, offset: f64, ) { self.modify_bend(recorder, bend, |geometry_with_rtree, bend| { geometry_with_rtree.shift_bend(bend, offset) }); } pub fn flip_bend( &mut self, recorder: &mut GeometryEdit, bend: BI, ) { self.modify_bend(recorder, bend, |geometry_with_rtree, bend| { geometry_with_rtree.flip_bend(bend) }); } pub fn reattach_bend( &mut self, recorder: &mut GeometryEdit, bend: BI, maybe_new_inner: Option, ) { self.modify_bend(recorder, bend, |geometry_with_rtree, bend| { geometry_with_rtree.reattach_bend(bend, maybe_new_inner) }); } pub fn compound_weight(&self, compound: GenericIndex) -> CW { self.geometry_with_rtree.compound_weight(compound) } pub fn compounds<'a, W: 'a>( &'a self, node: GenericIndex, ) -> impl Iterator> + 'a { self.geometry_with_rtree.compounds(node) } pub fn geometry(&self) -> &Geometry { self.geometry_with_rtree.geometry() } pub fn rtree(&self) -> &RTree>>> { self.geometry_with_rtree.rtree() } pub fn layer_count(&self) -> usize { *self.geometry_with_rtree.layer_count() } pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { self.geometry_with_rtree.graph() } } fn edit_remove_from_map( map: &mut std::collections::BTreeMap, Option)>, index: I, data: T, ) where I: core::cmp::Eq + Ord, { let to_be_inserted = (Some(data), None); match map.entry(index) { BTreeMapEntry::Occupied(mut occ) => { if let (None, Some(_)) = occ.get() { occ.remove(); } else { *occ.get_mut() = to_be_inserted; } } BTreeMapEntry::Vacant(vac) => { vac.insert(to_be_inserted); } } } impl< PW: GetWidth + GetLayer + TryInto + TryInto + TryInto + Retag + Copy, DW: AccessDotWeight + GetLayer, SW: AccessSegWeight + GetLayer, BW: AccessBendWeight + GetLayer, CW: Copy, PI: GetPetgraphIndex + TryInto + TryInto + TryInto + Eq + Ord + Copy, DI: GetPetgraphIndex + Into + Eq + Ord + Copy, SI: GetPetgraphIndex + Into + Eq + Ord + Copy, BI: GetPetgraphIndex + Into + Eq + Ord + Copy, > ApplyGeometryEdit for RecordingGeometryWithRtree { fn apply(&mut self, edit: &GeometryEdit) { for (compound, (maybe_old_data, ..)) in &edit.compounds { if maybe_old_data.is_some() { self.geometry_with_rtree.remove_compound(*compound); } } for (bend, (maybe_old_data, ..)) in &edit.bends { if maybe_old_data.is_some() { self.geometry_with_rtree.remove_bend(*bend); } } for (seg, (maybe_old_data, ..)) in &edit.segs { if maybe_old_data.is_some() { self.geometry_with_rtree.remove_seg(*seg); } } for (dot, (maybe_old_data, ..)) in &edit.dots { if maybe_old_data.is_some() { self.geometry_with_rtree.remove_dot(*dot); } } for (dot, (.., maybe_new_data)) in &edit.dots { if let Some(weight) = maybe_new_data { self.geometry_with_rtree.add_dot_at_index(*dot, *weight); } } for (seg, (.., maybe_new_data)) in &edit.segs { if let Some(((from, to), weight)) = maybe_new_data { self.geometry_with_rtree .add_seg_at_index(*seg, *from, *to, *weight); } } for (bend, (.., maybe_new_data)) in &edit.bends { if let Some(((from, to, core), weight)) = maybe_new_data { self.geometry_with_rtree .add_bend_at_index(*bend, *from, *to, *core, *weight); } } for (compound, (.., maybe_new_data)) in &edit.compounds { if let Some((members, weight)) = maybe_new_data { self.geometry_with_rtree .add_compound_at_index(*compound, *weight); for member in members { self.geometry_with_rtree.add_to_compound( GenericIndex::::new(member.petgraph_index()), *compound, ); } } } } }