primitive,geometry: move dot, seg shape-making code to `Geometry`

We still need to move the code for bends -- but that's for tomorrow.
This commit is contained in:
Mikolaj Wielgus 2024-01-28 00:35:16 +00:00
parent d35d8cd8dc
commit c855853a79
8 changed files with 164 additions and 97 deletions

View File

@ -62,12 +62,26 @@ impl<'a> Draw<'a> {
match head.face() {
DotIndex::Fixed(dot) => {
self.layout
.add_lone_loose_seg(dot, into.into(), LoneLooseSegWeight { band: head.band() })
.add_lone_loose_seg(
dot,
into.into(),
LoneLooseSegWeight {
band: head.band(),
width: 3.0,
},
)
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
}
DotIndex::Loose(dot) => {
self.layout
.add_seq_loose_seg(into.into(), dot, SeqLooseSegWeight { band: head.band() })
.add_seq_loose_seg(
into.into(),
dot,
SeqLooseSegWeight {
band: head.band(),
width: 3.0,
},
)
.map_err(|err| DrawException::CannotFinishIn(into, err.into()))?;
}
}
@ -205,9 +219,13 @@ impl<'a> Draw<'a> {
r: width / 2.0,
},
},
SeqLooseSegWeight { band: head.band() },
SeqLooseSegWeight {
band: head.band(),
width: 3.0,
},
LooseBendWeight {
band: head.band(),
width: 3.0,
offset: 3.0,
cw,
},

View File

@ -8,7 +8,10 @@ use petgraph::stable_graph::NodeIndex;
// Due to apparent limitations of enum_dispatch we're forced to import some types backwards.
use crate::layout::{bend::BendIndex, dot::DotIndex, geometry::GeometryIndex, seg::SegIndex};
#[enum_dispatch]
pub trait NewFromNodeIndex {
fn new(index: NodeIndex<usize>) -> Self;
}
#[enum_dispatch]
pub trait GetNodeIndex {
@ -21,15 +24,6 @@ pub struct GenericIndex<W> {
marker: PhantomData<W>,
}
impl<W> GenericIndex<W> {
pub fn new(index: NodeIndex<usize>) -> Self {
Self {
node_index: index,
marker: PhantomData,
}
}
}
impl<W> Hash for GenericIndex<W> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.node_index.hash(state)
@ -44,6 +38,15 @@ impl<W> PartialEq for GenericIndex<W> {
impl<W> Eq for GenericIndex<W> {}
impl<W> NewFromNodeIndex for GenericIndex<W> {
fn new(index: NodeIndex<usize>) -> Self {
Self {
node_index: index,
marker: PhantomData,
}
}
}
impl<W> GetNodeIndex for GenericIndex<W> {
fn node_index(&self) -> NodeIndex<usize> {
self.node_index

View File

@ -19,7 +19,7 @@ use crate::connectivity::{
BandIndex, BandWeight, ComponentIndex, ComponentWeight, ConnectivityGraph, ConnectivityLabel,
ConnectivityWeight, GetNet,
};
use crate::graph::{GenericIndex, GetNodeIndex};
use crate::graph::{GenericIndex, GetNodeIndex, NewFromNodeIndex};
use crate::guide::Guide;
use crate::layout::bend::BendIndex;
use crate::layout::dot::DotWeight;

View File

@ -3,7 +3,7 @@ use enum_dispatch::enum_dispatch;
use crate::{
connectivity::{BandIndex, ComponentIndex},
graph::GenericIndex,
layout::{GetNodeIndex, Layout},
layout::{GetNodeIndex, Layout, NewFromNodeIndex},
primitive::{GenericPrimitive, Primitive},
};
@ -48,10 +48,17 @@ impl GetWidth for FixedBendWeight {
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LooseBendWeight {
pub band: BandIndex,
pub width: f64,
pub offset: f64,
pub cw: bool,
}
impl GetWidth for LooseBendWeight {
fn width(&self) -> f64 {
self.width
}
}
impl GetOffset for LooseBendWeight {
fn offset(&self) -> f64 {
self.offset

View File

@ -1,16 +1,17 @@
use enum_dispatch::enum_dispatch;
use geo::Point;
use crate::{
connectivity::{BandIndex, ComponentIndex},
graph::GenericIndex,
layout::{GetNodeIndex, Layout},
layout::{GetNodeIndex, Layout, NewFromNodeIndex},
math::Circle,
primitive::{GenericPrimitive, Primitive},
};
use super::geometry::{
DotWeightTrait, GeometryIndex, GeometryWeight, GetBandIndex, GetComponentIndex,
GetComponentIndexMut, GetWidth, MakePrimitive, Retag,
GetComponentIndexMut, GetPos, GetWidth, MakePrimitive, Retag,
};
use petgraph::stable_graph::NodeIndex;
@ -30,7 +31,7 @@ impl From<DotIndex> for GeometryIndex {
}
}
#[enum_dispatch(GetWidth)]
#[enum_dispatch(GetPos, GetWidth)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DotWeight {
Fixed(FixedDotWeight),
@ -69,6 +70,12 @@ pub struct FixedDotWeight {
impl_fixed_weight!(FixedDotWeight, FixedDot, FixedDotIndex);
impl DotWeightTrait<GeometryWeight> for FixedDotWeight {}
impl GetPos for FixedDotWeight {
fn pos(&self) -> Point {
self.circle.pos
}
}
impl GetWidth for FixedDotWeight {
fn width(&self) -> f64 {
self.circle.r * 2.0
@ -84,6 +91,12 @@ pub struct LooseDotWeight {
impl_loose_weight!(LooseDotWeight, LooseDot, LooseDotIndex);
impl DotWeightTrait<GeometryWeight> for LooseDotWeight {}
impl GetPos for LooseDotWeight {
fn pos(&self) -> Point {
self.circle.pos
}
}
impl GetWidth for LooseDotWeight {
fn width(&self) -> f64 {
self.circle.r * 2.0

View File

@ -7,9 +7,11 @@ use petgraph::stable_graph::{NodeIndex, StableDiGraph};
use crate::{
connectivity::{BandIndex, ComponentIndex},
graph::{GenericIndex, GetNodeIndex},
graph::{GenericIndex, GetNodeIndex, NewFromNodeIndex},
layout::Layout,
math::Circle,
primitive::Primitive,
shape::{DotShape, SegShape, Shape},
};
use super::{
@ -39,6 +41,11 @@ pub trait GetBandIndex {
fn band(&self) -> BandIndex;
}
#[enum_dispatch]
pub trait GetPos {
fn pos(&self) -> Point;
}
#[enum_dispatch]
pub trait GetWidth {
fn width(&self) -> f64;
@ -97,7 +104,7 @@ macro_rules! impl_loose_weight {
};
}
#[enum_dispatch(Retag)]
#[enum_dispatch(GetWidth, Retag)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GeometryWeight {
FixedDot(FixedDotWeight),
@ -123,7 +130,7 @@ pub enum GeometryIndex {
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GeometryLabel {
Adjacent,
Joint,
Outer,
Core,
}
@ -133,13 +140,13 @@ pub trait MakePrimitive {
fn primitive<'a>(&self, layout: &'a Layout) -> Primitive<'a>;
}
pub trait DotWeightTrait<GW>: GetWidth + Into<GW> + Copy {}
pub trait SegWeightTrait<GW>: Into<GW> + Copy {}
pub trait BendWeightTrait<GW>: Into<GW> + Copy {}
pub trait DotWeightTrait<GW>: GetPos + GetWidth + Into<GW> + Copy {}
pub trait SegWeightTrait<GW>: GetWidth + Into<GW> + Copy {}
pub trait BendWeightTrait<GW>: GetWidth + Into<GW> + Copy {}
#[derive(Debug)]
pub struct Geometry<
GW: TryInto<DW>,
GW: GetWidth + TryInto<DW> + Copy,
DW: DotWeightTrait<GW>,
DI: GetNodeIndex,
SI: GetNodeIndex,
@ -154,11 +161,11 @@ pub struct Geometry<
}
impl<
GW: TryInto<DW>,
DW: DotWeightTrait<GW> + Copy,
DI: GetNodeIndex,
SI: GetNodeIndex,
BI: GetNodeIndex,
GW: GetWidth + TryInto<DW> + Copy,
DW: DotWeightTrait<GW>,
DI: GetNodeIndex + Copy,
SI: GetNodeIndex + Copy,
BI: GetNodeIndex + Copy,
> Geometry<GW, DW, DI, SI, BI>
{
pub fn new() -> Self {
@ -185,9 +192,9 @@ impl<
let seg = GenericIndex::<W>::new(self.graph.add_node(weight.into()));
self.graph
.update_edge(from.node_index(), seg.node_index(), GeometryLabel::Adjacent);
.update_edge(from.node_index(), seg.node_index(), GeometryLabel::Joint);
self.graph
.update_edge(seg.node_index(), to.node_index(), GeometryLabel::Adjacent);
.update_edge(seg.node_index(), to.node_index(), GeometryLabel::Joint);
seg
}
@ -201,19 +208,64 @@ impl<
) -> GenericIndex<W> {
let bend = GenericIndex::<W>::new(self.graph.add_node(weight.into()));
self.graph.update_edge(
from.node_index(),
bend.node_index(),
GeometryLabel::Adjacent,
);
self.graph
.update_edge(bend.node_index(), to.node_index(), GeometryLabel::Adjacent);
.update_edge(from.node_index(), bend.node_index(), GeometryLabel::Joint);
self.graph
.update_edge(bend.node_index(), to.node_index(), GeometryLabel::Joint);
self.graph
.update_edge(bend.node_index(), core.node_index(), GeometryLabel::Core);
bend
}
pub fn dot_shape(&self, dot: DI) -> Shape {
let weight = self.dot_weight(dot);
Shape::Dot(DotShape {
c: Circle {
pos: weight.pos(),
r: weight.width() / 2.0,
},
})
}
pub fn seg_shape(&self, seg: SI) -> Shape {
let joint_weights = self.joint_weights(seg.node_index());
Shape::Seg(SegShape {
from: joint_weights[0].pos(),
to: joint_weights[1].pos(),
width: self.weight(seg.node_index()).width(),
})
}
fn weight(&self, index: NodeIndex<usize>) -> GW {
*self.graph.node_weight(index).unwrap()
}
fn dot_weight(&self, dot: DI) -> DW {
self.weight(dot.node_index())
.try_into()
.unwrap_or_else(|_| unreachable!())
}
fn joint_weights(&self, index: NodeIndex<usize>) -> Vec<DW> {
self.graph
.neighbors_undirected(index)
.filter(|node| {
matches!(
self.graph
.edge_weight(self.graph.find_edge_undirected(index, *node).unwrap().0,)
.unwrap(),
GeometryLabel::Joint
)
})
.map(|node| {
self.weight(node)
.try_into()
.unwrap_or_else(|_| unreachable!())
})
.collect()
}
pub fn graph(&self) -> &StableDiGraph<GW, GeometryLabel, usize> {
&self.graph
}

View File

@ -3,7 +3,7 @@ use enum_dispatch::enum_dispatch;
use crate::{
connectivity::{BandIndex, ComponentIndex},
graph::GenericIndex,
layout::{GetNodeIndex, Layout},
layout::{GetNodeIndex, Layout, NewFromNodeIndex},
primitive::{GenericPrimitive, Primitive},
};
@ -49,15 +49,29 @@ impl GetWidth for FixedSegWeight {
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LoneLooseSegWeight {
pub band: BandIndex,
pub width: f64,
}
impl_loose_weight!(LoneLooseSegWeight, LoneLooseSeg, LoneLooseSegIndex);
impl SegWeightTrait<GeometryWeight> for LoneLooseSegWeight {}
impl GetWidth for LoneLooseSegWeight {
fn width(&self) -> f64 {
self.width
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SeqLooseSegWeight {
pub band: BandIndex,
pub width: f64,
}
impl_loose_weight!(SeqLooseSegWeight, SeqLooseSeg, SeqLooseSegIndex);
impl SegWeightTrait<GeometryWeight> for SeqLooseSegWeight {}
impl GetWidth for SeqLooseSegWeight {
fn width(&self) -> f64 {
self.width
}
}

View File

@ -5,7 +5,7 @@ use petgraph::stable_graph::NodeIndex;
use petgraph::Direction::{Incoming, Outgoing};
use crate::connectivity::{BandIndex, ComponentIndex, GetNet};
use crate::graph::{GenericIndex, GetNodeIndex};
use crate::graph::{GenericIndex, GetNodeIndex, NewFromNodeIndex};
use crate::layout::seg::{
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SegIndex,
SeqLooseSegIndex, SeqLooseSegWeight,
@ -275,7 +275,7 @@ impl<'a, W> GenericPrimitive<'a, W> {
.unwrap()
}
fn adjacents(&self) -> Vec<NodeIndex<usize>> {
fn joints(&self) -> Vec<NodeIndex<usize>> {
self.layout
.geometry()
.graph()
@ -294,7 +294,7 @@ impl<'a, W> GenericPrimitive<'a, W> {
.0,
)
.unwrap(),
GeometryLabel::Adjacent
GeometryLabel::Joint
)
})
.collect()
@ -339,7 +339,7 @@ impl_fixed_primitive!(FixedDot, FixedDotWeight);
impl<'a> FixedDot<'a> {
pub fn first_loose(&self, _band: BandIndex) -> Option<LooseIndex> {
self.adjacents().into_iter().find_map(|node| {
self.joints().into_iter().find_map(|node| {
let weight = self.layout.geometry().graph().node_weight(node).unwrap();
if matches!(weight, GeometryWeight::LoneLooseSeg(..)) {
Some(LoneLooseSegIndex::new(node).into())
@ -354,15 +354,13 @@ impl<'a> FixedDot<'a> {
impl<'a> MakeShape for FixedDot<'a> {
fn shape(&self) -> Shape {
Shape::Dot(DotShape {
c: self.weight().circle,
})
self.layout.geometry().dot_shape(self.index.into())
}
}
impl<'a> GetLegs for FixedDot<'a> {
fn segs(&self) -> Vec<SegIndex> {
self.adjacents()
self.joints()
.into_iter()
.filter_map(
|node| match self.layout.geometry().graph().node_weight(node).unwrap() {
@ -382,7 +380,7 @@ impl<'a> GetLegs for FixedDot<'a> {
}
fn bends(&self) -> Vec<BendIndex> {
self.adjacents()
self.joints()
.into_iter()
.filter(|node| {
matches!(
@ -402,7 +400,7 @@ impl_loose_primitive!(LooseDot, LooseDotWeight);
impl<'a> LooseDot<'a> {
pub fn seg(&self) -> Option<SeqLooseSegIndex> {
self.adjacents()
self.joints()
.into_iter()
.filter(|node| {
matches!(
@ -415,7 +413,7 @@ impl<'a> LooseDot<'a> {
}
pub fn bend(&self) -> LooseBendIndex {
self.adjacents()
self.joints()
.into_iter()
.filter(|node| {
matches!(
@ -431,9 +429,7 @@ impl<'a> LooseDot<'a> {
impl<'a> MakeShape for LooseDot<'a> {
fn shape(&self) -> Shape {
Shape::Dot(DotShape {
c: self.weight().circle,
})
self.layout.geometry().dot_shape(self.index.into())
}
}
@ -456,12 +452,7 @@ impl_fixed_primitive!(FixedSeg, FixedSegWeight);
impl<'a> MakeShape for FixedSeg<'a> {
fn shape(&self) -> Shape {
let ends = self.ends();
Shape::Seg(SegShape {
from: self.primitive(ends.0).weight().circle.pos,
to: self.primitive(ends.1).weight().circle.pos,
width: self.width(),
})
self.layout.geometry().seg_shape(self.index.into())
}
}
@ -469,7 +460,7 @@ impl<'a> GetLegs for FixedSeg<'a> {}
impl<'a> GetEnds<FixedDotIndex, FixedDotIndex> for FixedSeg<'a> {
fn ends(&self) -> (FixedDotIndex, FixedDotIndex) {
let v = self.adjacents();
let v = self.joints();
(FixedDotIndex::new(v[0]), FixedDotIndex::new(v[1]))
}
}
@ -481,26 +472,15 @@ impl_loose_primitive!(LoneLooseSeg, LoneLooseSegWeight);
impl<'a> MakeShape for LoneLooseSeg<'a> {
fn shape(&self) -> Shape {
let ends = self.ends();
Shape::Seg(SegShape {
from: self.primitive(ends.0).weight().circle.pos,
to: self.primitive(ends.1).weight().circle.pos,
width: self.width(),
})
self.layout.geometry().seg_shape(self.index.into())
}
}
impl<'a> GetLegs for LoneLooseSeg<'a> {}
impl<'a> GetWidth for LoneLooseSeg<'a> {
fn width(&self) -> f64 {
self.primitive(self.ends().1).weight().width()
}
}
impl<'a> GetEnds<FixedDotIndex, FixedDotIndex> for LoneLooseSeg<'a> {
fn ends(&self) -> (FixedDotIndex, FixedDotIndex) {
let v = self.adjacents();
let v = self.joints();
(FixedDotIndex::new(v[0]), FixedDotIndex::new(v[1]))
}
}
@ -512,29 +492,15 @@ impl_loose_primitive!(SeqLooseSeg, SeqLooseSegWeight);
impl<'a> MakeShape for SeqLooseSeg<'a> {
fn shape(&self) -> Shape {
let ends = self.ends();
Shape::Seg(SegShape {
from: match ends.0 {
DotIndex::Fixed(dot) => self.primitive(dot).weight().circle.pos,
DotIndex::Loose(dot) => self.primitive(dot).weight().circle.pos,
},
to: self.primitive(ends.1).weight().circle.pos,
width: self.width(),
})
self.layout.geometry().seg_shape(self.index.into())
}
}
impl<'a> GetLegs for SeqLooseSeg<'a> {}
impl<'a> GetWidth for SeqLooseSeg<'a> {
fn width(&self) -> f64 {
self.primitive(self.ends().1).weight().width()
}
}
impl<'a> GetEnds<DotIndex, LooseDotIndex> for SeqLooseSeg<'a> {
fn ends(&self) -> (DotIndex, LooseDotIndex) {
let v = self.adjacents();
let v = self.joints();
if let GeometryWeight::FixedDot(..) =
self.layout.geometry().graph().node_weight(v[0]).unwrap()
{
@ -593,7 +559,7 @@ impl<'a> GetLegs for FixedBend<'a> {}
impl<'a> GetEnds<FixedDotIndex, FixedDotIndex> for FixedBend<'a> {
fn ends(&self) -> (FixedDotIndex, FixedDotIndex) {
let v = self.adjacents();
let v = self.joints();
(FixedDotIndex::new(v[0]), FixedDotIndex::new(v[1]))
}
}
@ -652,12 +618,6 @@ impl<'a> MakeShape for LooseBend<'a> {
impl<'a> GetLegs for LooseBend<'a> {}
impl<'a> GetWidth for LooseBend<'a> {
fn width(&self) -> f64 {
self.primitive(self.ends().1).weight().width()
}
}
impl<'a> GetOffset for LooseBend<'a> {
fn offset(&self) -> f64 {
self.weight().offset
@ -666,7 +626,7 @@ impl<'a> GetOffset for LooseBend<'a> {
impl<'a> GetEnds<LooseDotIndex, LooseDotIndex> for LooseBend<'a> {
fn ends(&self) -> (LooseDotIndex, LooseDotIndex) {
let v = self.adjacents();
let v = self.joints();
(LooseDotIndex::new(v[0]), LooseDotIndex::new(v[1]))
}
}