primitive,geometry: move bend shape-making code to `Geometry` too

This commit is contained in:
Mikolaj Wielgus 2024-01-28 14:53:26 +00:00
parent c855853a79
commit 59180cc600
4 changed files with 137 additions and 85 deletions

View File

@ -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<Shape, GeometryIndex>;
#[enum_dispatch]
@ -75,7 +77,7 @@ pub struct AlreadyConnected(pub i64, pub GeometryIndex);
pub struct Layout {
rtree: RTree<RTreeWrapper>,
connectivity: ConnectivityGraph,
geometry: Geometry<GeometryWeight, DotWeight, DotIndex, SegIndex, BendIndex>,
geometry: Geometry<GeometryWeight, DotWeight, BendWeight, DotIndex, SegIndex, BendIndex>,
}
#[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<GeometryWeight, DotWeight, DotIndex, SegIndex, BendIndex> {
pub fn geometry(
&self,
) -> &Geometry<GeometryWeight, DotWeight, BendWeight, DotIndex, SegIndex, BendIndex> {
&self.geometry
}

View File

@ -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<BendIndex> for GeometryIndex {
}
}
#[enum_dispatch(GetOffset, GetWidth)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BendWeight {
Fixed(FixedBendWeight),
Loose(LooseBendWeight),
}
impl From<BendWeight> for GeometryWeight {
fn from(bend: BendWeight) -> Self {
match bend {
BendWeight::Fixed(weight) => GeometryWeight::FixedBend(weight),
BendWeight::Loose(weight) => GeometryWeight::LooseBend(weight),
}
}
}
impl TryFrom<GeometryWeight> for BendWeight {
type Error = (); // TODO.
fn try_from(weight: GeometryWeight) -> Result<BendWeight, ()> {
match weight {
GeometryWeight::FixedBend(weight) => Ok(BendWeight::Fixed(weight)),
GeometryWeight::LooseBend(weight) => Ok(BendWeight::Loose(weight)),
_ => unreachable!(),
}
}
}
impl BendWeightTrait<GeometryWeight> 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<GeometryWeight> 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<GeometryWeight> for LooseBendWeight {}

View File

@ -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<GW>: GetPos + GetWidth + Into<GW> + Copy {}
pub trait SegWeightTrait<GW>: GetWidth + Into<GW> + Copy {}
pub trait BendWeightTrait<GW>: GetWidth + Into<GW> + Copy {}
pub trait BendWeightTrait<GW>: GetOffset + GetWidth + Into<GW> + Copy {}
#[derive(Debug)]
pub struct Geometry<
GW: GetWidth + TryInto<DW> + Copy,
GW: GetWidth + TryInto<DW> + TryInto<BW> + Copy,
DW: DotWeightTrait<GW>,
BW: BendWeightTrait<GW>,
DI: GetNodeIndex,
SI: GetNodeIndex,
BI: GetNodeIndex,
@ -155,24 +159,27 @@ pub struct Geometry<
pub graph: StableDiGraph<GW, GeometryLabel, usize>,
weight_marker: PhantomData<GW>,
dot_weight_marker: PhantomData<DW>,
bend_weight_marker: PhantomData<BW>,
dot_index_marker: PhantomData<DI>,
seg_index_marker: PhantomData<SI>,
bend_index_marker: PhantomData<BI>,
}
impl<
GW: GetWidth + TryInto<DW> + Copy,
GW: GetWidth + TryInto<DW> + TryInto<BW> + Copy,
DW: DotWeightTrait<GW>,
BW: BendWeightTrait<GW>,
DI: GetNodeIndex + Copy,
SI: GetNodeIndex + Copy,
BI: GetNodeIndex + Copy,
> Geometry<GW, DW, DI, SI, BI>
> Geometry<GW, DW, BW, DI, SI, BI>
{
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<usize>) -> Option<NodeIndex<usize>> {
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<usize>) -> 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<usize>) -> Vec<DW> {
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<GW, GeometryLabel, usize> {
&self.graph
}

View File

@ -520,38 +520,9 @@ impl<'a> GetOtherEnd<DotIndex, LooseDotIndex> 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())
}
}