mirror of https://codeberg.org/topola/topola.git
primitive,geometry: move bend shape-making code to `Geometry` too
This commit is contained in:
parent
c855853a79
commit
59180cc600
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue