From 59180cc600f1b91c72d2224f5a14cd509b637246 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Sun, 28 Jan 2024 14:53:26 +0000 Subject: [PATCH] primitive,geometry: move bend shape-making code to `Geometry` too --- src/layout.rs | 8 +++- src/layout/bend.rs | 52 ++++++++++++++++++++---- src/layout/geometry.rs | 91 ++++++++++++++++++++++++++++++++++++++---- src/primitive.rs | 71 +------------------------------- 4 files changed, 137 insertions(+), 85 deletions(-) diff --git a/src/layout.rs b/src/layout.rs index 2bb87c3..4438a3e 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -43,6 +43,8 @@ use crate::segbend::Segbend; use crate::shape::{Shape, ShapeTrait}; use crate::wraparoundable::{GetWraparound, Wraparoundable, WraparoundableIndex}; +use self::bend::BendWeight; + pub type RTreeWrapper = GeomWithData; #[enum_dispatch] @@ -75,7 +77,7 @@ pub struct AlreadyConnected(pub i64, pub GeometryIndex); pub struct Layout { rtree: RTree, connectivity: ConnectivityGraph, - geometry: Geometry, + geometry: Geometry, } #[debug_invariant(self.geometry.graph().node_count() == self.rtree.size())] @@ -953,7 +955,9 @@ impl Layout { #[debug_ensures(self.geometry.graph().node_count() == old(self.geometry.graph().node_count()))] #[debug_ensures(self.geometry.graph().edge_count() == old(self.geometry.graph().edge_count()))] - pub fn geometry(&self) -> &Geometry { + pub fn geometry( + &self, + ) -> &Geometry { &self.geometry } diff --git a/src/layout/bend.rs b/src/layout/bend.rs index 34cdbc5..eda7dbb 100644 --- a/src/layout/bend.rs +++ b/src/layout/bend.rs @@ -9,8 +9,9 @@ use crate::{ use super::geometry::{ BendWeightTrait, GeometryIndex, GeometryWeight, GetBandIndex, GetComponentIndex, - GetComponentIndexMut, GetOffset, GetWidth, MakePrimitive, Retag, + GetComponentIndexMut, GetOffset, GetPos, GetWidth, MakePrimitive, Retag, }; +use geo::Point; use petgraph::stable_graph::NodeIndex; #[enum_dispatch(GetNodeIndex, MakePrimitive)] @@ -29,16 +30,53 @@ impl From for GeometryIndex { } } +#[enum_dispatch(GetOffset, GetWidth)] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum BendWeight { + Fixed(FixedBendWeight), + Loose(LooseBendWeight), +} + +impl From for GeometryWeight { + fn from(bend: BendWeight) -> Self { + match bend { + BendWeight::Fixed(weight) => GeometryWeight::FixedBend(weight), + BendWeight::Loose(weight) => GeometryWeight::LooseBend(weight), + } + } +} + +impl TryFrom for BendWeight { + type Error = (); // TODO. + + fn try_from(weight: GeometryWeight) -> Result { + match weight { + GeometryWeight::FixedBend(weight) => Ok(BendWeight::Fixed(weight)), + GeometryWeight::LooseBend(weight) => Ok(BendWeight::Loose(weight)), + _ => unreachable!(), + } + } +} + +impl BendWeightTrait for BendWeight {} + #[derive(Debug, Clone, Copy, PartialEq)] pub struct FixedBendWeight { pub component: ComponentIndex, pub width: f64, + pub offset: f64, pub cw: bool, } impl_fixed_weight!(FixedBendWeight, FixedBend, FixedBendIndex); impl BendWeightTrait for FixedBendWeight {} +impl GetOffset for FixedBendWeight { + fn offset(&self) -> f64 { + self.offset + } +} + impl GetWidth for FixedBendWeight { fn width(&self) -> f64 { self.width @@ -53,17 +91,17 @@ pub struct LooseBendWeight { pub cw: bool, } -impl GetWidth for LooseBendWeight { - fn width(&self) -> f64 { - self.width - } -} - impl GetOffset for LooseBendWeight { fn offset(&self) -> f64 { self.offset } } +impl GetWidth for LooseBendWeight { + fn width(&self) -> f64 { + self.width + } +} + impl_loose_weight!(LooseBendWeight, LooseBend, LooseBendIndex); impl BendWeightTrait for LooseBendWeight {} diff --git a/src/layout/geometry.rs b/src/layout/geometry.rs index bdde36e..14e3550 100644 --- a/src/layout/geometry.rs +++ b/src/layout/geometry.rs @@ -3,7 +3,10 @@ use std::marker::PhantomData; use contracts::debug_invariant; use enum_dispatch::enum_dispatch; use geo::Point; -use petgraph::stable_graph::{NodeIndex, StableDiGraph}; +use petgraph::{ + stable_graph::{NodeIndex, StableDiGraph}, + Direction::Incoming, +}; use crate::{ connectivity::{BandIndex, ComponentIndex}, @@ -11,12 +14,12 @@ use crate::{ layout::Layout, math::Circle, primitive::Primitive, - shape::{DotShape, SegShape, Shape}, + shape::{BendShape, DotShape, SegShape, Shape}, }; use super::{ bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight}, - dot::{FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, + dot::{DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight}, seg::{ FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex, SeqLooseSegWeight, @@ -142,12 +145,13 @@ pub trait MakePrimitive { pub trait DotWeightTrait: GetPos + GetWidth + Into + Copy {} pub trait SegWeightTrait: GetWidth + Into + Copy {} -pub trait BendWeightTrait: GetWidth + Into + Copy {} +pub trait BendWeightTrait: GetOffset + GetWidth + Into + Copy {} #[derive(Debug)] pub struct Geometry< - GW: GetWidth + TryInto + Copy, + GW: GetWidth + TryInto + TryInto + Copy, DW: DotWeightTrait, + BW: BendWeightTrait, DI: GetNodeIndex, SI: GetNodeIndex, BI: GetNodeIndex, @@ -155,24 +159,27 @@ pub struct Geometry< pub graph: StableDiGraph, weight_marker: PhantomData, dot_weight_marker: PhantomData, + bend_weight_marker: PhantomData, dot_index_marker: PhantomData, seg_index_marker: PhantomData, bend_index_marker: PhantomData, } impl< - GW: GetWidth + TryInto + Copy, + GW: GetWidth + TryInto + TryInto + Copy, DW: DotWeightTrait, + BW: BendWeightTrait, DI: GetNodeIndex + Copy, SI: GetNodeIndex + Copy, BI: GetNodeIndex + Copy, - > Geometry + > Geometry { pub fn new() -> Self { Self { graph: StableDiGraph::default(), weight_marker: PhantomData, dot_weight_marker: PhantomData, + bend_weight_marker: PhantomData, dot_index_marker: PhantomData, seg_index_marker: PhantomData, bend_index_marker: PhantomData, @@ -237,6 +244,50 @@ impl< }) } + pub fn bend_shape(&self, bend: BI) -> Shape { + let joint_weights = self.joint_weights(bend.node_index()); + let core_weight = self.core_weight(bend); + Shape::Bend(BendShape { + from: joint_weights[0].pos(), + to: joint_weights[1].pos(), + c: Circle { + pos: core_weight.pos(), + r: self.inner_radius(bend), + }, + width: self.weight(bend.node_index()).width(), + }) + } + + fn inner_radius(&self, bend: BI) -> f64 { + let mut r = self.bend_weight(bend).offset(); + let mut rail = bend.node_index(); + + while let Some(inner) = self.inner(rail) { + let weight: BW = self + .weight(inner) + .try_into() + .unwrap_or_else(|_| unreachable!()); + r += weight.width() + weight.offset(); + rail = inner; + } + + self.core_weight(bend).width() / 2.0 + r + } + + fn inner(&self, index: NodeIndex) -> Option> { + self.graph + .neighbors_directed(index, Incoming) + .filter(|node| { + matches!( + self.graph + .edge_weight(self.graph.find_edge(*node, index).unwrap()) + .unwrap(), + GeometryLabel::Outer + ) + }) + .next() + } + fn weight(&self, index: NodeIndex) -> GW { *self.graph.node_weight(index).unwrap() } @@ -247,6 +298,12 @@ impl< .unwrap_or_else(|_| unreachable!()) } + fn bend_weight(&self, bend: BI) -> BW { + self.weight(bend.node_index()) + .try_into() + .unwrap_or_else(|_| unreachable!()) + } + fn joint_weights(&self, index: NodeIndex) -> Vec { self.graph .neighbors_undirected(index) @@ -266,6 +323,26 @@ impl< .collect() } + fn core_weight(&self, bend: BI) -> DW { + self.graph + .neighbors(bend.node_index()) + .filter(|node| { + matches!( + self.graph + .edge_weight(self.graph.find_edge(bend.node_index(), *node).unwrap()) + .unwrap(), + GeometryLabel::Core + ) + }) + .map(|node| { + self.weight(node) + .try_into() + .unwrap_or_else(|_| unreachable!()) + }) + .next() + .unwrap() + } + pub fn graph(&self) -> &StableDiGraph { &self.graph } diff --git a/src/primitive.rs b/src/primitive.rs index 1857052..ef481c3 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -520,38 +520,9 @@ impl<'a> GetOtherEnd for SeqLooseSeg<'a> {} pub type FixedBend<'a> = GenericPrimitive<'a, FixedBendWeight>; impl_fixed_primitive!(FixedBend, FixedBendWeight); -impl<'a> FixedBend<'a> { - fn inner_radius(&self) -> f64 { - todo!(); - } - - pub fn cross_product(&self) -> f64 { - let center = self.primitive(self.core()).weight().circle.pos; - let ends = self.ends(); - let end1 = self.primitive(ends.0).weight().circle.pos; - let end2 = self.primitive(ends.1).weight().circle.pos; - math::cross_product(end1 - center, end2 - center) - } -} - impl<'a> MakeShape for FixedBend<'a> { fn shape(&self) -> Shape { - let ends = self.ends(); - - let mut bend_shape = BendShape { - from: self.primitive(ends.0).weight().circle.pos, - to: self.primitive(ends.1).weight().circle.pos, - c: Circle { - pos: self.primitive(self.core()).weight().circle.pos, - r: self.inner_radius(), - }, - width: self.width(), - }; - - if self.weight().cw { - swap(&mut bend_shape.from, &mut bend_shape.to); - } - Shape::Bend(bend_shape) + self.layout.geometry().bend_shape(self.index.into()) } } @@ -572,47 +543,9 @@ impl<'a> GetCore for FixedBend<'a> {} // TODO: Fixed bends don't have cores actu pub type LooseBend<'a> = GenericPrimitive<'a, LooseBendWeight>; impl_loose_primitive!(LooseBend, LooseBendWeight); -impl<'a> LooseBend<'a> { - fn inner_radius(&self) -> f64 { - let mut r = self.offset(); - let mut rail = LooseBendIndex::new(self.index.node_index()); - - while let Some(inner) = self.primitive(rail).inner() { - let primitive = self.primitive(inner); - r += primitive.width() + primitive.offset(); - rail = inner; - } - - let core_circle = self - .primitive( - self.primitive(LooseBendIndex::new(self.index.node_index())) - .core(), - ) - .weight() - .circle; - - core_circle.r + r - } -} - impl<'a> MakeShape for LooseBend<'a> { fn shape(&self) -> Shape { - let ends = self.ends(); - - let mut bend_shape = BendShape { - from: self.primitive(ends.0).weight().circle.pos, - to: self.primitive(ends.1).weight().circle.pos, - c: Circle { - pos: self.primitive(self.core()).weight().circle.pos, - r: self.inner_radius(), - }, - width: self.width(), - }; - - if self.weight().cw { - swap(&mut bend_shape.from, &mut bend_shape.to); - } - Shape::Bend(bend_shape) + self.layout.geometry().bend_shape(self.index.into()) } }