mirror of https://codeberg.org/topola/topola.git
feat(geometry): implement recording geometry changes to edit objects
This commit is contained in:
parent
c1271e570e
commit
ad1b43b806
|
|
@ -65,9 +65,9 @@ pub enum GenericNode<P, C> {
|
|||
Compound(C),
|
||||
}
|
||||
|
||||
pub trait AccessDotWeight<CW>: GetPos + SetPos + GetWidth + Into<CW> + Copy {}
|
||||
pub trait AccessSegWeight<CW>: GetWidth + Into<CW> + Copy {}
|
||||
pub trait AccessBendWeight<CW>: GetOffset + SetOffset + GetWidth + Into<CW> + Copy {}
|
||||
pub trait AccessDotWeight<PW>: GetPos + SetPos + GetWidth + Into<PW> + Copy {}
|
||||
pub trait AccessSegWeight<PW>: GetWidth + Into<PW> + Copy {}
|
||||
pub trait AccessBendWeight<PW>: GetOffset + SetOffset + GetWidth + Into<PW> + Copy {}
|
||||
|
||||
#[derive(Debug, Getters)]
|
||||
pub struct Geometry<
|
||||
|
|
@ -82,7 +82,7 @@ pub struct Geometry<
|
|||
BI: GetPetgraphIndex + Into<PI> + Copy,
|
||||
> {
|
||||
graph: StableDiGraph<GenericNode<PW, CW>, GeometryLabel, usize>,
|
||||
weight_marker: PhantomData<PW>,
|
||||
primitive_weight_marker: PhantomData<PW>,
|
||||
dot_weight_marker: PhantomData<DW>,
|
||||
seg_weight_marker: PhantomData<SW>,
|
||||
bend_weight_marker: PhantomData<BW>,
|
||||
|
|
@ -108,7 +108,7 @@ impl<
|
|||
pub fn new() -> Self {
|
||||
Self {
|
||||
graph: StableDiGraph::default(),
|
||||
weight_marker: PhantomData,
|
||||
primitive_weight_marker: PhantomData,
|
||||
dot_weight_marker: PhantomData,
|
||||
seg_weight_marker: PhantomData,
|
||||
bend_weight_marker: PhantomData,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ mod geometry;
|
|||
pub mod compound;
|
||||
pub mod poly;
|
||||
pub mod primitive;
|
||||
pub mod recording_with_rtree;
|
||||
pub mod shape;
|
||||
pub mod with_rtree;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,355 @@
|
|||
use std::{collections::HashMap, hash::Hash, marker::PhantomData};
|
||||
|
||||
use geo::Point;
|
||||
use petgraph::stable_graph::StableDiGraph;
|
||||
|
||||
use crate::{
|
||||
drawing::graph::{GetLayer, Retag},
|
||||
graph::{GenericIndex, GetPetgraphIndex},
|
||||
};
|
||||
|
||||
use super::{
|
||||
compound::ManageCompounds, with_rtree::GeometryWithRtree, AccessBendWeight, AccessDotWeight,
|
||||
AccessSegWeight, GenericNode, GeometryLabel, GetWidth,
|
||||
};
|
||||
|
||||
pub struct GeometryEdit<
|
||||
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||
DW: AccessDotWeight<PW> + GetLayer,
|
||||
SW: AccessSegWeight<PW> + GetLayer,
|
||||
BW: AccessBendWeight<PW> + GetLayer,
|
||||
CW: Copy,
|
||||
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Hash + Copy,
|
||||
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
> {
|
||||
dots: HashMap<DI, (Option<DW>, Option<DW>)>,
|
||||
segs: HashMap<SI, (Option<((DI, DI), SW)>, Option<((DI, DI), SW)>)>,
|
||||
bends: HashMap<BI, (Option<((DI, DI, DI), BW)>, Option<((DI, DI, DI), BW)>)>,
|
||||
compounds: HashMap<GenericIndex<CW>, (Option<(Vec<PI>, CW)>, Option<(Vec<PI>, CW)>)>,
|
||||
primitive_weight_marker: PhantomData<PW>,
|
||||
}
|
||||
|
||||
pub struct RecordingGeometryWithRtree<
|
||||
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||
DW: AccessDotWeight<PW> + GetLayer,
|
||||
SW: AccessSegWeight<PW> + GetLayer,
|
||||
BW: AccessBendWeight<PW> + GetLayer,
|
||||
CW: Copy,
|
||||
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Hash + Copy,
|
||||
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
> {
|
||||
geometry_with_rtree: GeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
}
|
||||
|
||||
impl<
|
||||
PW: GetWidth + GetLayer + TryInto<DW> + TryInto<SW> + TryInto<BW> + Retag<PI> + Copy,
|
||||
DW: AccessDotWeight<PW> + GetLayer,
|
||||
SW: AccessSegWeight<PW> + GetLayer,
|
||||
BW: AccessBendWeight<PW> + GetLayer,
|
||||
CW: Copy,
|
||||
PI: GetPetgraphIndex + TryInto<DI> + TryInto<SI> + TryInto<BI> + Eq + Hash + Copy,
|
||||
DI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
SI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
BI: GetPetgraphIndex + Into<PI> + Eq + Hash + Copy,
|
||||
> RecordingGeometryWithRtree<PW, DW, SW, BW, CW, PI, DI, SI, BI>
|
||||
{
|
||||
pub fn add_dot<W: AccessDotWeight<PW> + GetLayer>(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
weight: W,
|
||||
) -> GenericIndex<W>
|
||||
where
|
||||
GenericIndex<W>: Into<PI>,
|
||||
{
|
||||
let dot = self.geometry_with_rtree.add_dot(weight);
|
||||
recorder.dots.insert(
|
||||
Into::<PI>::into(dot)
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| unreachable!()),
|
||||
(
|
||||
None,
|
||||
Some(weight.into().try_into().unwrap_or_else(|_| unreachable!())),
|
||||
),
|
||||
);
|
||||
dot
|
||||
}
|
||||
|
||||
pub fn add_seg<W: AccessSegWeight<PW> + GetLayer>(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
from: DI,
|
||||
to: DI,
|
||||
weight: W,
|
||||
) -> GenericIndex<W>
|
||||
where
|
||||
GenericIndex<W>: Into<PI>,
|
||||
{
|
||||
let seg = self.geometry_with_rtree.add_seg(from, to, weight);
|
||||
recorder.segs.insert(
|
||||
Into::<PI>::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<W: AccessBendWeight<PW> + GetLayer>(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
from: DI,
|
||||
to: DI,
|
||||
core: DI,
|
||||
weight: W,
|
||||
) -> GenericIndex<W>
|
||||
where
|
||||
GenericIndex<W>: Into<PI>,
|
||||
{
|
||||
let bend = self.geometry_with_rtree.add_bend(from, to, core, weight);
|
||||
recorder.bends.insert(
|
||||
Into::<PI>::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<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
weight: CW,
|
||||
) -> GenericIndex<CW> {
|
||||
let compound = self.geometry_with_rtree.add_compound(weight);
|
||||
recorder
|
||||
.compounds
|
||||
.insert(compound, (None, Some((vec![], weight))));
|
||||
compound
|
||||
}
|
||||
|
||||
pub fn add_to_compound<W>(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
primitive: GenericIndex<W>,
|
||||
compound: GenericIndex<CW>,
|
||||
) {
|
||||
let old_members = self
|
||||
.geometry_with_rtree
|
||||
.geometry()
|
||||
.compound_members(compound)
|
||||
.collect();
|
||||
let old_weight = self
|
||||
.geometry_with_rtree
|
||||
.geometry()
|
||||
.compound_weight(compound);
|
||||
|
||||
let new_members = self
|
||||
.geometry_with_rtree
|
||||
.geometry()
|
||||
.compound_members(compound)
|
||||
.collect();
|
||||
let new_weight = self
|
||||
.geometry_with_rtree
|
||||
.geometry()
|
||||
.compound_weight(compound);
|
||||
|
||||
if let Some(value) = recorder.compounds.get_mut(&compound) {
|
||||
value.1 = Some((new_members, new_weight));
|
||||
} else {
|
||||
recorder.compounds.insert(
|
||||
compound,
|
||||
(
|
||||
Some((old_members, old_weight)),
|
||||
Some((new_members, new_weight)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_dot(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
dot: DI,
|
||||
) -> Result<(), ()> {
|
||||
let weight = self.geometry_with_rtree.geometry().dot_weight(dot);
|
||||
self.geometry_with_rtree.remove_dot(dot)?;
|
||||
recorder.dots.insert(dot, (Some(weight), None));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_seg(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
seg: SI,
|
||||
) {
|
||||
let weight = self.geometry_with_rtree.geometry().seg_weight(seg);
|
||||
let joints = self.geometry_with_rtree.geometry().seg_joints(seg);
|
||||
self.geometry_with_rtree.remove_seg(seg);
|
||||
recorder.segs.insert(seg, (Some((joints, weight)), None));
|
||||
}
|
||||
|
||||
pub fn remove_bend(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
bend: BI,
|
||||
) {
|
||||
let weight = self.geometry_with_rtree.geometry().bend_weight(bend);
|
||||
let joints = self.geometry_with_rtree.geometry().bend_joints(bend);
|
||||
let core = self.geometry_with_rtree.geometry().core(bend);
|
||||
self.geometry_with_rtree.remove_bend(bend);
|
||||
recorder
|
||||
.bends
|
||||
.insert(bend, (Some(((joints.0, joints.1, core), weight)), None));
|
||||
}
|
||||
|
||||
pub fn remove_compound(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
compound: GenericIndex<CW>,
|
||||
) {
|
||||
let weight = self
|
||||
.geometry_with_rtree
|
||||
.geometry()
|
||||
.compound_weight(compound);
|
||||
let members = self
|
||||
.geometry_with_rtree
|
||||
.geometry()
|
||||
.compound_members(compound)
|
||||
.collect();
|
||||
self.geometry_with_rtree.remove_compound(compound);
|
||||
recorder
|
||||
.compounds
|
||||
.insert(compound, (Some((members, weight)), None));
|
||||
}
|
||||
|
||||
pub fn move_dot(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
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);
|
||||
|
||||
if let Some(value) = recorder.dots.get_mut(&dot) {
|
||||
value.1 = Some(new_weight);
|
||||
} else {
|
||||
recorder
|
||||
.dots
|
||||
.insert(dot, (Some(old_weight), Some(new_weight)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shift_bend(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
bend: BI,
|
||||
offset: f64,
|
||||
) {
|
||||
let old_joints = self.geometry_with_rtree.geometry().bend_joints(bend);
|
||||
let old_core = self.geometry_with_rtree.geometry().core(bend);
|
||||
let old_weight = self.geometry_with_rtree.geometry().bend_weight(bend);
|
||||
self.geometry_with_rtree.shift_bend(bend, offset);
|
||||
let new_joints = self.geometry_with_rtree.geometry().bend_joints(bend);
|
||||
let new_core = self.geometry_with_rtree.geometry().core(bend);
|
||||
let new_weight = self.geometry_with_rtree.geometry().bend_weight(bend);
|
||||
|
||||
if let Some(value) = recorder.bends.get_mut(&bend) {
|
||||
value.1 = Some(((new_joints.0, new_joints.1, new_core), new_weight));
|
||||
} else {
|
||||
recorder.bends.insert(
|
||||
bend,
|
||||
(
|
||||
Some(((old_joints.0, old_joints.1, old_core), old_weight)),
|
||||
Some(((new_joints.0, new_joints.1, new_core), new_weight)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flip_bend(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
bend: BI,
|
||||
) {
|
||||
let old_joints = self.geometry_with_rtree.geometry().bend_joints(bend);
|
||||
let old_core = self.geometry_with_rtree.geometry().core(bend);
|
||||
let old_weight = self.geometry_with_rtree.geometry().bend_weight(bend);
|
||||
self.geometry_with_rtree.flip_bend(bend);
|
||||
let new_joints = self.geometry_with_rtree.geometry().bend_joints(bend);
|
||||
let new_core = self.geometry_with_rtree.geometry().core(bend);
|
||||
let new_weight = self.geometry_with_rtree.geometry().bend_weight(bend);
|
||||
|
||||
if let Some(value) = recorder.bends.get_mut(&bend) {
|
||||
value.1 = Some(((new_joints.0, new_joints.1, new_core), new_weight));
|
||||
} else {
|
||||
recorder.bends.insert(
|
||||
bend,
|
||||
(
|
||||
Some(((old_joints.0, old_joints.1, old_core), old_weight)),
|
||||
Some(((new_joints.0, new_joints.1, new_core), new_weight)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reattach_bend(
|
||||
&mut self,
|
||||
recorder: &mut GeometryEdit<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
bend: BI,
|
||||
maybe_new_inner: Option<BI>,
|
||||
) {
|
||||
let old_joints = self.geometry_with_rtree.geometry().bend_joints(bend);
|
||||
let old_core = self.geometry_with_rtree.geometry().core(bend);
|
||||
let old_weight = self.geometry_with_rtree.geometry().bend_weight(bend);
|
||||
self.geometry_with_rtree
|
||||
.reattach_bend(bend, maybe_new_inner);
|
||||
let new_joints = self.geometry_with_rtree.geometry().bend_joints(bend);
|
||||
let new_core = self.geometry_with_rtree.geometry().core(bend);
|
||||
let new_weight = self.geometry_with_rtree.geometry().bend_weight(bend);
|
||||
|
||||
if let Some(value) = recorder.bends.get_mut(&bend) {
|
||||
value.1 = Some(((new_joints.0, new_joints.1, new_core), new_weight));
|
||||
} else {
|
||||
recorder.bends.insert(
|
||||
bend,
|
||||
(
|
||||
Some(((old_joints.0, old_joints.1, old_core), old_weight)),
|
||||
Some(((new_joints.0, new_joints.1, new_core), new_weight)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compound_weight(&self, compound: GenericIndex<CW>) -> CW {
|
||||
self.geometry_with_rtree.compound_weight(compound)
|
||||
}
|
||||
|
||||
pub fn compounds<'a, W: 'a>(
|
||||
&'a self,
|
||||
node: GenericIndex<W>,
|
||||
) -> impl Iterator<Item = GenericIndex<CW>> + 'a {
|
||||
self.geometry_with_rtree.compounds(node)
|
||||
}
|
||||
|
||||
pub fn graph(&self) -> &StableDiGraph<GenericNode<PW, CW>, GeometryLabel, usize> {
|
||||
self.geometry_with_rtree.graph()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use contracts_try::debug_invariant;
|
||||
use derive_getters::Getters;
|
||||
use geo::Point;
|
||||
|
|
@ -52,14 +50,6 @@ pub struct GeometryWithRtree<
|
|||
geometry: Geometry<PW, DW, SW, BW, CW, PI, DI, SI, BI>,
|
||||
rtree: RTree<BboxedIndex<GenericNode<PI, GenericIndex<CW>>>>,
|
||||
layer_count: usize,
|
||||
weight_marker: PhantomData<PW>,
|
||||
dot_weight_marker: PhantomData<DW>,
|
||||
seg_weight_marker: PhantomData<SW>,
|
||||
bend_weight_marker: PhantomData<BW>,
|
||||
index_marker: PhantomData<PI>,
|
||||
dot_index_marker: PhantomData<DI>,
|
||||
seg_index_marker: PhantomData<SI>,
|
||||
bend_index_marker: PhantomData<BI>,
|
||||
}
|
||||
|
||||
#[debug_invariant(self.test_envelopes())]
|
||||
|
|
@ -81,14 +71,6 @@ impl<
|
|||
geometry: Geometry::<PW, DW, SW, BW, CW, PI, DI, SI, BI>::new(),
|
||||
rtree: RTree::new(),
|
||||
layer_count,
|
||||
weight_marker: PhantomData,
|
||||
dot_weight_marker: PhantomData,
|
||||
seg_weight_marker: PhantomData,
|
||||
bend_weight_marker: PhantomData,
|
||||
index_marker: PhantomData,
|
||||
dot_index_marker: PhantomData,
|
||||
seg_index_marker: PhantomData,
|
||||
bend_index_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue