mirror of https://codeberg.org/topola/topola.git
geometry: create bboxes for groupings
This commit is contained in:
parent
3a812d5621
commit
31189a9f5e
|
|
@ -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<R: RulesTrait> Drawing<R> {
|
|||
.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<R: RulesTrait> Drawing<R> {
|
|||
[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<R: RulesTrait> Drawing<R> {
|
|||
.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<R: RulesTrait> Drawing<R> {
|
|||
.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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ pub enum GeometryLabel {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Compound<PW, XW> {
|
||||
pub enum Node<PW, GW> {
|
||||
Primitive(PW),
|
||||
Grouping(XW),
|
||||
Grouping(GW),
|
||||
}
|
||||
|
||||
pub trait DotWeightTrait<GW>: GetPos + SetPos + GetWidth + Into<GW> + Copy {}
|
||||
|
|
@ -77,7 +77,7 @@ pub struct Geometry<
|
|||
SI: GetNodeIndex + Into<PI> + Copy,
|
||||
BI: GetNodeIndex + Into<PI> + Copy,
|
||||
> {
|
||||
graph: StableDiGraph<Compound<PW, GW>, GeometryLabel, usize>,
|
||||
graph: StableDiGraph<Node<PW, GW>, GeometryLabel, usize>,
|
||||
weight_marker: PhantomData<PW>,
|
||||
dot_weight_marker: PhantomData<DW>,
|
||||
seg_weight_marker: PhantomData<SW>,
|
||||
|
|
@ -117,7 +117,7 @@ impl<
|
|||
}
|
||||
|
||||
pub fn add_dot<W: DotWeightTrait<PW>>(&mut self, weight: W) -> GenericIndex<W> {
|
||||
GenericIndex::<W>::new(self.graph.add_node(Compound::Primitive(weight.into())))
|
||||
GenericIndex::<W>::new(self.graph.add_node(Node::Primitive(weight.into())))
|
||||
}
|
||||
|
||||
pub fn add_seg<W: SegWeightTrait<PW>>(
|
||||
|
|
@ -126,7 +126,7 @@ impl<
|
|||
to: DI,
|
||||
weight: W,
|
||||
) -> GenericIndex<W> {
|
||||
let seg = GenericIndex::<W>::new(self.graph.add_node(Compound::Primitive(weight.into())));
|
||||
let seg = GenericIndex::<W>::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<W> {
|
||||
let bend = GenericIndex::<W>::new(self.graph.add_node(Compound::Primitive(weight.into())));
|
||||
let bend = GenericIndex::<W>::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<GW> {
|
||||
GenericIndex::<GW>::new(self.graph.add_node(Compound::Grouping(weight)))
|
||||
GenericIndex::<GW>::new(self.graph.add_node(Node::Grouping(weight)))
|
||||
}
|
||||
|
||||
pub fn assign_to_grouping<W>(
|
||||
|
|
@ -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<usize>) -> 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>) -> 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<BI> {
|
||||
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<Compound<PW, GW>, GeometryLabel, usize> {
|
||||
pub fn members(&self, grouping: GenericIndex<GW>) -> impl Iterator<Item = PI> + '_ {
|
||||
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<Node<PW, GW>, GeometryLabel, usize> {
|
||||
&self.graph
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<PI> + Copy,
|
||||
> {
|
||||
geometry: Geometry<PW, DW, SW, BW, GW, PI, DI, SI, BI>,
|
||||
rtree: RTree<BboxedIndex<Compound<PI, GenericIndex<GW>>>>,
|
||||
rtree: RTree<BboxedIndex<Node<PI, GenericIndex<GW>>>>,
|
||||
layer_count: u64,
|
||||
weight_marker: PhantomData<PW>,
|
||||
dot_weight_marker: PhantomData<DW>,
|
||||
|
|
@ -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<GW> {
|
||||
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<W>,
|
||||
grouping: GenericIndex<GW>,
|
||||
) {
|
||||
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<PI> + Copy,
|
||||
> GeometryWithRtree<PW, DW, SW, BW, GW, PI, DI, SI, BI>
|
||||
{
|
||||
fn make_dot_bbox(&self, dot: DI) -> BboxedIndex<Compound<PI, GenericIndex<GW>>> {
|
||||
fn make_bbox(&self, primitive: PI) -> BboxedIndex<Node<PI, GenericIndex<GW>>> {
|
||||
if let Ok(dot) = <PI as TryInto<DI>>::try_into(primitive) {
|
||||
self.make_dot_bbox(dot)
|
||||
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(primitive) {
|
||||
self.make_seg_bbox(seg)
|
||||
} else if let Ok(bend) = <PI as TryInto<BI>>::try_into(primitive) {
|
||||
self.make_bend_bbox(bend)
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
fn make_dot_bbox(&self, dot: DI) -> BboxedIndex<Node<PI, GenericIndex<GW>>> {
|
||||
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<Compound<PI, GenericIndex<GW>>> {
|
||||
fn make_seg_bbox(&self, seg: SI) -> BboxedIndex<Node<PI, GenericIndex<GW>>> {
|
||||
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<Compound<PI, GenericIndex<GW>>> {
|
||||
fn make_bend_bbox(&self, bend: BI) -> BboxedIndex<Node<PI, GenericIndex<GW>>> {
|
||||
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<GW>,
|
||||
) -> BboxedIndex<Compound<PI, GenericIndex<GW>>> {
|
||||
BboxedIndex::new(
|
||||
Bbox::new(AABB::<[f64; 3]>::from_point([0.0, 0.0, -1.0].into())),
|
||||
Compound::Grouping(grouping),
|
||||
)
|
||||
) -> BboxedIndex<Node<PI, GenericIndex<GW>>> {
|
||||
let mut aabb = AABB::<[f64; 3]>::new_empty();
|
||||
|
||||
for member in self.geometry.members(grouping) {
|
||||
aabb.merge(&self.make_bbox(member).geom().aabb);
|
||||
}
|
||||
|
||||
fn shape(&self, index: PI) -> Shape {
|
||||
if let Ok(dot) = <PI as TryInto<DI>>::try_into(index) {
|
||||
BboxedIndex::new(Bbox::new(aabb), Node::Grouping(grouping))
|
||||
}
|
||||
|
||||
fn shape(&self, primitive: PI) -> Shape {
|
||||
if let Ok(dot) = <PI as TryInto<DI>>::try_into(primitive) {
|
||||
self.geometry.dot_shape(dot)
|
||||
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(index) {
|
||||
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(primitive) {
|
||||
self.geometry.seg_shape(seg)
|
||||
} else if let Ok(bend) = <PI as TryInto<BI>>::try_into(index) {
|
||||
} else if let Ok(bend) = <PI as TryInto<BI>>::try_into(primitive) {
|
||||
self.geometry.bend_shape(bend)
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
fn layer(&self, index: PI) -> u64 {
|
||||
if let Ok(dot) = <PI as TryInto<DI>>::try_into(index) {
|
||||
fn layer(&self, primitive: PI) -> u64 {
|
||||
if let Ok(dot) = <PI as TryInto<DI>>::try_into(primitive) {
|
||||
self.geometry.dot_weight(dot).layer()
|
||||
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(index) {
|
||||
} else if let Ok(seg) = <PI as TryInto<SI>>::try_into(primitive) {
|
||||
self.geometry.seg_weight(seg).layer()
|
||||
} else if let Ok(bend) = <PI as TryInto<BI>>::try_into(index) {
|
||||
} else if let Ok(bend) = <PI as TryInto<BI>>::try_into(primitive) {
|
||||
self.geometry.bend_weight(bend).layer()
|
||||
} else {
|
||||
unreachable!();
|
||||
|
|
@ -346,25 +359,25 @@ impl<
|
|||
&self.geometry
|
||||
}
|
||||
|
||||
pub fn rtree(&self) -> &RTree<BboxedIndex<Compound<PI, GenericIndex<GW>>>> {
|
||||
pub fn rtree(&self) -> &RTree<BboxedIndex<Node<PI, GenericIndex<GW>>>> {
|
||||
&self.rtree
|
||||
}
|
||||
|
||||
pub fn graph(&self) -> &StableDiGraph<Compound<PW, GW>, GeometryLabel, usize> {
|
||||
pub fn graph(&self) -> &StableDiGraph<Node<PW, GW>, 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue