From 31189a9f5e75924c9a60a6a412f3ab4df63ee6fe Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Thu, 28 Mar 2024 01:31:12 +0000 Subject: [PATCH] geometry: create bboxes for groupings --- src/drawing/drawing.rs | 10 ++--- src/drawing/primitive.rs | 14 ++----- src/geometry/geometry.rs | 52 +++++++++++++++++------ src/geometry/with_rtree.rs | 85 ++++++++++++++++++++++---------------- 4 files changed, 97 insertions(+), 64 deletions(-) diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs index ca65786..a88b924 100644 --- a/src/drawing/drawing.rs +++ b/src/drawing/drawing.rs @@ -27,7 +27,7 @@ use crate::drawing::{ SeqLooseSegIndex, SeqLooseSegWeight, }, }; -use crate::geometry::Compound; +use crate::geometry::Node; use crate::geometry::{ shape::{Shape, ShapeTrait}, with_rtree::GeometryWithRtree, @@ -637,7 +637,7 @@ impl Drawing { .rtree() .iter() .filter_map(|wrapper| { - if let Compound::Primitive(primitive_node) = wrapper.data { + if let Node::Primitive(primitive_node) = wrapper.data { Some(primitive_node) } else { None @@ -653,7 +653,7 @@ impl Drawing { [f64::INFINITY, f64::INFINITY, layer as f64], )) .filter_map(|wrapper| { - if let Compound::Primitive(primitive_node) = wrapper.data { + if let Node::Primitive(primitive_node) = wrapper.data { Some(primitive_node) } else { None @@ -748,7 +748,7 @@ impl Drawing { .rtree() .locate_in_envelope_intersecting(&limiting_shape.full_height_envelope_3d(0.0, 2)) .filter_map(|wrapper| { - if let Compound::Primitive(primitive_node) = wrapper.data { + if let Node::Primitive(primitive_node) = wrapper.data { Some(primitive_node) } else { None @@ -783,7 +783,7 @@ impl Drawing { .rtree() .locate_in_envelope_intersecting(&shape.full_height_envelope_3d(0.0, 2)) .filter_map(|wrapper| { - if let Compound::Primitive(primitive_node) = wrapper.data { + if let Node::Primitive(primitive_node) = wrapper.data { Some(primitive_node) } else { None diff --git a/src/drawing/primitive.rs b/src/drawing/primitive.rs index fba545c..5a46388 100644 --- a/src/drawing/primitive.rs +++ b/src/drawing/primitive.rs @@ -20,7 +20,7 @@ use crate::{ }, Drawing, }, - geometry::Compound, + geometry::Node, }; #[enum_dispatch] @@ -184,7 +184,7 @@ impl<'a, W, R: RulesTrait> GenericPrimitive<'a, W, R> { } fn tagged_weight(&self) -> PrimitiveWeight { - if let Compound::Primitive(weight) = *self + if let Node::Primitive(weight) = *self .drawing .geometry() .graph() @@ -258,15 +258,9 @@ impl<'a, R: RulesTrait> FixedDot<'a, R> { .graph() .node_weight(ni.node_index()) .unwrap(); - if matches!( - weight, - Compound::Primitive(PrimitiveWeight::LoneLooseSeg(..)) - ) { + if matches!(weight, Node::Primitive(PrimitiveWeight::LoneLooseSeg(..))) { Some(LoneLooseSegIndex::new(ni.node_index()).into()) - } else if matches!( - weight, - Compound::Primitive(PrimitiveWeight::SeqLooseSeg(..)) - ) { + } else if matches!(weight, Node::Primitive(PrimitiveWeight::SeqLooseSeg(..))) { Some(SeqLooseSegIndex::new(ni.node_index()).into()) } else { None diff --git a/src/geometry/geometry.rs b/src/geometry/geometry.rs index 91d37aa..59f845d 100644 --- a/src/geometry/geometry.rs +++ b/src/geometry/geometry.rs @@ -56,9 +56,9 @@ pub enum GeometryLabel { } #[derive(Debug, Clone, Copy, PartialEq)] -pub enum Compound { +pub enum Node { Primitive(PW), - Grouping(XW), + Grouping(GW), } pub trait DotWeightTrait: GetPos + SetPos + GetWidth + Into + Copy {} @@ -77,7 +77,7 @@ pub struct Geometry< SI: GetNodeIndex + Into + Copy, BI: GetNodeIndex + Into + Copy, > { - graph: StableDiGraph, GeometryLabel, usize>, + graph: StableDiGraph, GeometryLabel, usize>, weight_marker: PhantomData, dot_weight_marker: PhantomData, seg_weight_marker: PhantomData, @@ -117,7 +117,7 @@ impl< } pub fn add_dot>(&mut self, weight: W) -> GenericIndex { - GenericIndex::::new(self.graph.add_node(Compound::Primitive(weight.into()))) + GenericIndex::::new(self.graph.add_node(Node::Primitive(weight.into()))) } pub fn add_seg>( @@ -126,7 +126,7 @@ impl< to: DI, weight: W, ) -> GenericIndex { - let seg = GenericIndex::::new(self.graph.add_node(Compound::Primitive(weight.into()))); + let seg = GenericIndex::::new(self.graph.add_node(Node::Primitive(weight.into()))); self.graph .update_edge(from.node_index(), seg.node_index(), GeometryLabel::Joined); @@ -143,7 +143,7 @@ impl< core: DI, weight: W, ) -> GenericIndex { - let bend = GenericIndex::::new(self.graph.add_node(Compound::Primitive(weight.into()))); + let bend = GenericIndex::::new(self.graph.add_node(Node::Primitive(weight.into()))); self.graph .update_edge(from.node_index(), bend.node_index(), GeometryLabel::Joined); @@ -156,7 +156,7 @@ impl< } pub fn add_grouping(&mut self, weight: GW) -> GenericIndex { - GenericIndex::::new(self.graph.add_node(Compound::Grouping(weight))) + GenericIndex::::new(self.graph.add_node(Node::Grouping(weight))) } pub fn assign_to_grouping( @@ -182,14 +182,13 @@ impl< pub fn move_dot(&mut self, dot: DI, to: Point) { let mut weight = self.dot_weight(dot); weight.set_pos(to); - *self.graph.node_weight_mut(dot.node_index()).unwrap() = Compound::Primitive(weight.into()); + *self.graph.node_weight_mut(dot.node_index()).unwrap() = Node::Primitive(weight.into()); } pub fn shift_bend(&mut self, bend: BI, offset: f64) { let mut weight = self.bend_weight(bend); weight.set_offset(offset); - *self.graph.node_weight_mut(bend.node_index()).unwrap() = - Compound::Primitive(weight.into()); + *self.graph.node_weight_mut(bend.node_index()).unwrap() = Node::Primitive(weight.into()); } pub fn flip_bend(&mut self, bend: BI) { @@ -285,7 +284,7 @@ impl< } fn primitive_weight(&self, index: NodeIndex) -> PW { - if let Compound::Primitive(weight) = *self.graph.node_weight(index).unwrap() { + if let Node::Primitive(weight) = *self.graph.node_weight(index).unwrap() { weight } else { unreachable!() @@ -310,6 +309,14 @@ impl< .unwrap_or_else(|_| unreachable!()) } + fn grouping_weight(&self, grouping: GenericIndex) -> GW { + if let Node::Grouping(weight) = *self.graph.node_weight(grouping.node_index()).unwrap() { + weight + } else { + unreachable!() + } + } + fn core_weight(&self, bend: BI) -> DW { self.graph .neighbors(bend.node_index()) @@ -393,7 +400,7 @@ impl< pub fn outer(&self, bend: BI) -> Option { self.graph - .neighbors_directed(bend.node_index(), Outgoing) + .neighbors(bend.node_index()) .filter(|ni| { matches!( self.graph @@ -459,7 +466,26 @@ impl< self.joineds(dot.into()).filter_map(|ni| ni.try_into().ok()) } - pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { + pub fn members(&self, grouping: GenericIndex) -> impl Iterator + '_ { + self.graph + .neighbors(grouping.node_index()) + .filter(move |ni| { + matches!( + self.graph + .edge_weight(self.graph.find_edge(grouping.node_index(), *ni).unwrap()) + .unwrap(), + GeometryLabel::Grouping + ) + }) + .map(|ni| { + self.primitive_weight(ni) + .retag(ni) + .try_into() + .unwrap_or_else(|_| unreachable!()) + }) + } + + pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { &self.graph } } diff --git a/src/geometry/with_rtree.rs b/src/geometry/with_rtree.rs index 8c0532e..f13e62a 100644 --- a/src/geometry/with_rtree.rs +++ b/src/geometry/with_rtree.rs @@ -3,21 +3,20 @@ use std::marker::PhantomData; use contracts::debug_invariant; use geo::Point; use petgraph::stable_graph::StableDiGraph; -use rstar::{primitives::GeomWithData, RTree, RTreeObject, AABB}; +use rstar::{primitives::GeomWithData, Envelope, RTree, RTreeObject, AABB}; use crate::{ drawing::graph::{GetLayer, Retag}, geometry::{ shape::{Shape, ShapeTrait}, - BendWeightTrait, Compound, DotWeightTrait, Geometry, GeometryLabel, GetWidth, - SegWeightTrait, + BendWeightTrait, DotWeightTrait, Geometry, GeometryLabel, GetWidth, Node, SegWeightTrait, }, graph::{GenericIndex, GetNodeIndex}, }; #[derive(Debug, Clone, Copy, PartialEq)] pub struct Bbox { - aabb: AABB<[f64; 3]>, + pub aabb: AABB<[f64; 3]>, } impl Bbox { @@ -48,7 +47,7 @@ pub struct GeometryWithRtree< BI: GetNodeIndex + Into + Copy, > { geometry: Geometry, - rtree: RTree>>>, + rtree: RTree>>>, layer_count: u64, weight_marker: PhantomData, dot_weight_marker: PhantomData, @@ -101,7 +100,7 @@ impl< .dot_shape(dot.into().try_into().unwrap_or_else(|_| unreachable!())) .envelope_3d(0.0, weight.layer()), ), - Compound::Primitive(dot.into()), + Node::Primitive(dot.into()), )); dot } @@ -122,7 +121,7 @@ impl< .seg_shape(seg.into().try_into().unwrap_or_else(|_| unreachable!())) .envelope_3d(0.0, weight.layer()), ), - Compound::Primitive(seg.into()), + Node::Primitive(seg.into()), )); seg } @@ -144,17 +143,14 @@ impl< .bend_shape(bend.into().try_into().unwrap_or_else(|_| unreachable!())) .envelope_3d(0.0, weight.layer()), ), - Compound::Primitive(bend.into()), + Node::Primitive(bend.into()), )); bend } pub fn add_grouping(&mut self, weight: GW) -> GenericIndex { let grouping = self.geometry.add_grouping(weight); - self.rtree.insert(BboxedIndex::new( - Bbox::new(AABB::<[f64; 3]>::from_point([0.0, 0.0, -1.0].into())), - Compound::Grouping(grouping), - )); + self.rtree.insert(self.make_grouping_bbox(grouping)); grouping } @@ -163,7 +159,9 @@ impl< primitive: GenericIndex, grouping: GenericIndex, ) { - self.geometry.assign_to_grouping(primitive, grouping) + self.rtree.remove(&self.make_grouping_bbox(grouping)); + self.geometry.assign_to_grouping(primitive, grouping); + self.rtree.insert(self.make_grouping_bbox(grouping)); } pub fn remove_dot(&mut self, dot: DI) -> Result<(), ()> { @@ -275,67 +273,82 @@ impl< BI: GetNodeIndex + Into + Copy, > GeometryWithRtree { - fn make_dot_bbox(&self, dot: DI) -> BboxedIndex>> { + fn make_bbox(&self, primitive: PI) -> BboxedIndex>> { + if let Ok(dot) = >::try_into(primitive) { + self.make_dot_bbox(dot) + } else if let Ok(seg) = >::try_into(primitive) { + self.make_seg_bbox(seg) + } else if let Ok(bend) = >::try_into(primitive) { + self.make_bend_bbox(bend) + } else { + unreachable!(); + } + } + + fn make_dot_bbox(&self, dot: DI) -> BboxedIndex>> { BboxedIndex::new( Bbox::new( self.geometry .dot_shape(dot) .envelope_3d(0.0, self.layer(dot.into())), ), - Compound::Primitive(dot.into()), + Node::Primitive(dot.into()), ) } - fn make_seg_bbox(&self, seg: SI) -> BboxedIndex>> { + fn make_seg_bbox(&self, seg: SI) -> BboxedIndex>> { BboxedIndex::new( Bbox::new( self.geometry .seg_shape(seg) .envelope_3d(0.0, self.layer(seg.into())), ), - Compound::Primitive(seg.into()), + Node::Primitive(seg.into()), ) } - fn make_bend_bbox(&self, bend: BI) -> BboxedIndex>> { + fn make_bend_bbox(&self, bend: BI) -> BboxedIndex>> { BboxedIndex::new( Bbox::new( self.geometry .bend_shape(bend) .envelope_3d(0.0, self.layer(bend.into())), ), - Compound::Primitive(bend.into()), + Node::Primitive(bend.into()), ) } fn make_grouping_bbox( &self, grouping: GenericIndex, - ) -> BboxedIndex>> { - BboxedIndex::new( - Bbox::new(AABB::<[f64; 3]>::from_point([0.0, 0.0, -1.0].into())), - Compound::Grouping(grouping), - ) + ) -> BboxedIndex>> { + let mut aabb = AABB::<[f64; 3]>::new_empty(); + + for member in self.geometry.members(grouping) { + aabb.merge(&self.make_bbox(member).geom().aabb); + } + + BboxedIndex::new(Bbox::new(aabb), Node::Grouping(grouping)) } - fn shape(&self, index: PI) -> Shape { - if let Ok(dot) = >::try_into(index) { + fn shape(&self, primitive: PI) -> Shape { + if let Ok(dot) = >::try_into(primitive) { self.geometry.dot_shape(dot) - } else if let Ok(seg) = >::try_into(index) { + } else if let Ok(seg) = >::try_into(primitive) { self.geometry.seg_shape(seg) - } else if let Ok(bend) = >::try_into(index) { + } else if let Ok(bend) = >::try_into(primitive) { self.geometry.bend_shape(bend) } else { unreachable!(); } } - fn layer(&self, index: PI) -> u64 { - if let Ok(dot) = >::try_into(index) { + fn layer(&self, primitive: PI) -> u64 { + if let Ok(dot) = >::try_into(primitive) { self.geometry.dot_weight(dot).layer() - } else if let Ok(seg) = >::try_into(index) { + } else if let Ok(seg) = >::try_into(primitive) { self.geometry.seg_weight(seg).layer() - } else if let Ok(bend) = >::try_into(index) { + } else if let Ok(bend) = >::try_into(primitive) { self.geometry.bend_weight(bend).layer() } else { unreachable!(); @@ -346,25 +359,25 @@ impl< &self.geometry } - pub fn rtree(&self) -> &RTree>>> { + pub fn rtree(&self) -> &RTree>>> { &self.rtree } - pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { + pub fn graph(&self) -> &StableDiGraph, GeometryLabel, usize> { self.geometry.graph() } fn test_envelopes(&self) -> bool { !self.rtree.iter().any(|wrapper| { // TODO: Test envelopes of groupings too. - let Compound::Primitive(primitive_node) = wrapper.data else { + let Node::Primitive(primitive_node) = wrapper.data else { return false; }; let shape = self.shape(primitive_node); let layer = self.layer(primitive_node); let wrapper = BboxedIndex::new( Bbox::new(shape.envelope_3d(0.0, layer)), - Compound::Primitive(primitive_node), + Node::Primitive(primitive_node), ); !self .rtree