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::shape::{Shape, ShapeTrait};
|
||||||
use crate::wraparoundable::{GetWraparound, Wraparoundable, WraparoundableIndex};
|
use crate::wraparoundable::{GetWraparound, Wraparoundable, WraparoundableIndex};
|
||||||
|
|
||||||
|
use self::bend::BendWeight;
|
||||||
|
|
||||||
pub type RTreeWrapper = GeomWithData<Shape, GeometryIndex>;
|
pub type RTreeWrapper = GeomWithData<Shape, GeometryIndex>;
|
||||||
|
|
||||||
#[enum_dispatch]
|
#[enum_dispatch]
|
||||||
|
|
@ -75,7 +77,7 @@ pub struct AlreadyConnected(pub i64, pub GeometryIndex);
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
rtree: RTree<RTreeWrapper>,
|
rtree: RTree<RTreeWrapper>,
|
||||||
connectivity: ConnectivityGraph,
|
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())]
|
#[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().node_count() == old(self.geometry.graph().node_count()))]
|
||||||
#[debug_ensures(self.geometry.graph().edge_count() == old(self.geometry.graph().edge_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
|
&self.geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@ use crate::{
|
||||||
|
|
||||||
use super::geometry::{
|
use super::geometry::{
|
||||||
BendWeightTrait, GeometryIndex, GeometryWeight, GetBandIndex, GetComponentIndex,
|
BendWeightTrait, GeometryIndex, GeometryWeight, GetBandIndex, GetComponentIndex,
|
||||||
GetComponentIndexMut, GetOffset, GetWidth, MakePrimitive, Retag,
|
GetComponentIndexMut, GetOffset, GetPos, GetWidth, MakePrimitive, Retag,
|
||||||
};
|
};
|
||||||
|
use geo::Point;
|
||||||
use petgraph::stable_graph::NodeIndex;
|
use petgraph::stable_graph::NodeIndex;
|
||||||
|
|
||||||
#[enum_dispatch(GetNodeIndex, MakePrimitive)]
|
#[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)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct FixedBendWeight {
|
pub struct FixedBendWeight {
|
||||||
pub component: ComponentIndex,
|
pub component: ComponentIndex,
|
||||||
pub width: f64,
|
pub width: f64,
|
||||||
|
pub offset: f64,
|
||||||
pub cw: bool,
|
pub cw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_fixed_weight!(FixedBendWeight, FixedBend, FixedBendIndex);
|
impl_fixed_weight!(FixedBendWeight, FixedBend, FixedBendIndex);
|
||||||
impl BendWeightTrait<GeometryWeight> for FixedBendWeight {}
|
impl BendWeightTrait<GeometryWeight> for FixedBendWeight {}
|
||||||
|
|
||||||
|
impl GetOffset for FixedBendWeight {
|
||||||
|
fn offset(&self) -> f64 {
|
||||||
|
self.offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GetWidth for FixedBendWeight {
|
impl GetWidth for FixedBendWeight {
|
||||||
fn width(&self) -> f64 {
|
fn width(&self) -> f64 {
|
||||||
self.width
|
self.width
|
||||||
|
|
@ -53,17 +91,17 @@ pub struct LooseBendWeight {
|
||||||
pub cw: bool,
|
pub cw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetWidth for LooseBendWeight {
|
|
||||||
fn width(&self) -> f64 {
|
|
||||||
self.width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetOffset for LooseBendWeight {
|
impl GetOffset for LooseBendWeight {
|
||||||
fn offset(&self) -> f64 {
|
fn offset(&self) -> f64 {
|
||||||
self.offset
|
self.offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GetWidth for LooseBendWeight {
|
||||||
|
fn width(&self) -> f64 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_loose_weight!(LooseBendWeight, LooseBend, LooseBendIndex);
|
impl_loose_weight!(LooseBendWeight, LooseBend, LooseBendIndex);
|
||||||
impl BendWeightTrait<GeometryWeight> for LooseBendWeight {}
|
impl BendWeightTrait<GeometryWeight> for LooseBendWeight {}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ use std::marker::PhantomData;
|
||||||
use contracts::debug_invariant;
|
use contracts::debug_invariant;
|
||||||
use enum_dispatch::enum_dispatch;
|
use enum_dispatch::enum_dispatch;
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
use petgraph::stable_graph::{NodeIndex, StableDiGraph};
|
use petgraph::{
|
||||||
|
stable_graph::{NodeIndex, StableDiGraph},
|
||||||
|
Direction::Incoming,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
connectivity::{BandIndex, ComponentIndex},
|
connectivity::{BandIndex, ComponentIndex},
|
||||||
|
|
@ -11,12 +14,12 @@ use crate::{
|
||||||
layout::Layout,
|
layout::Layout,
|
||||||
math::Circle,
|
math::Circle,
|
||||||
primitive::Primitive,
|
primitive::Primitive,
|
||||||
shape::{DotShape, SegShape, Shape},
|
shape::{BendShape, DotShape, SegShape, Shape},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
bend::{FixedBendIndex, FixedBendWeight, LooseBendIndex, LooseBendWeight},
|
||||||
dot::{FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
|
dot::{DotWeight, FixedDotIndex, FixedDotWeight, LooseDotIndex, LooseDotWeight},
|
||||||
seg::{
|
seg::{
|
||||||
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex,
|
FixedSegIndex, FixedSegWeight, LoneLooseSegIndex, LoneLooseSegWeight, SeqLooseSegIndex,
|
||||||
SeqLooseSegWeight,
|
SeqLooseSegWeight,
|
||||||
|
|
@ -142,12 +145,13 @@ pub trait MakePrimitive {
|
||||||
|
|
||||||
pub trait DotWeightTrait<GW>: GetPos + GetWidth + Into<GW> + Copy {}
|
pub trait DotWeightTrait<GW>: GetPos + GetWidth + Into<GW> + Copy {}
|
||||||
pub trait SegWeightTrait<GW>: 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)]
|
#[derive(Debug)]
|
||||||
pub struct Geometry<
|
pub struct Geometry<
|
||||||
GW: GetWidth + TryInto<DW> + Copy,
|
GW: GetWidth + TryInto<DW> + TryInto<BW> + Copy,
|
||||||
DW: DotWeightTrait<GW>,
|
DW: DotWeightTrait<GW>,
|
||||||
|
BW: BendWeightTrait<GW>,
|
||||||
DI: GetNodeIndex,
|
DI: GetNodeIndex,
|
||||||
SI: GetNodeIndex,
|
SI: GetNodeIndex,
|
||||||
BI: GetNodeIndex,
|
BI: GetNodeIndex,
|
||||||
|
|
@ -155,24 +159,27 @@ pub struct Geometry<
|
||||||
pub graph: StableDiGraph<GW, GeometryLabel, usize>,
|
pub graph: StableDiGraph<GW, GeometryLabel, usize>,
|
||||||
weight_marker: PhantomData<GW>,
|
weight_marker: PhantomData<GW>,
|
||||||
dot_weight_marker: PhantomData<DW>,
|
dot_weight_marker: PhantomData<DW>,
|
||||||
|
bend_weight_marker: PhantomData<BW>,
|
||||||
dot_index_marker: PhantomData<DI>,
|
dot_index_marker: PhantomData<DI>,
|
||||||
seg_index_marker: PhantomData<SI>,
|
seg_index_marker: PhantomData<SI>,
|
||||||
bend_index_marker: PhantomData<BI>,
|
bend_index_marker: PhantomData<BI>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
GW: GetWidth + TryInto<DW> + Copy,
|
GW: GetWidth + TryInto<DW> + TryInto<BW> + Copy,
|
||||||
DW: DotWeightTrait<GW>,
|
DW: DotWeightTrait<GW>,
|
||||||
|
BW: BendWeightTrait<GW>,
|
||||||
DI: GetNodeIndex + Copy,
|
DI: GetNodeIndex + Copy,
|
||||||
SI: GetNodeIndex + Copy,
|
SI: GetNodeIndex + Copy,
|
||||||
BI: GetNodeIndex + Copy,
|
BI: GetNodeIndex + Copy,
|
||||||
> Geometry<GW, DW, DI, SI, BI>
|
> Geometry<GW, DW, BW, DI, SI, BI>
|
||||||
{
|
{
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
graph: StableDiGraph::default(),
|
graph: StableDiGraph::default(),
|
||||||
weight_marker: PhantomData,
|
weight_marker: PhantomData,
|
||||||
dot_weight_marker: PhantomData,
|
dot_weight_marker: PhantomData,
|
||||||
|
bend_weight_marker: PhantomData,
|
||||||
dot_index_marker: PhantomData,
|
dot_index_marker: PhantomData,
|
||||||
seg_index_marker: PhantomData,
|
seg_index_marker: PhantomData,
|
||||||
bend_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 {
|
fn weight(&self, index: NodeIndex<usize>) -> GW {
|
||||||
*self.graph.node_weight(index).unwrap()
|
*self.graph.node_weight(index).unwrap()
|
||||||
}
|
}
|
||||||
|
|
@ -247,6 +298,12 @@ impl<
|
||||||
.unwrap_or_else(|_| unreachable!())
|
.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> {
|
fn joint_weights(&self, index: NodeIndex<usize>) -> Vec<DW> {
|
||||||
self.graph
|
self.graph
|
||||||
.neighbors_undirected(index)
|
.neighbors_undirected(index)
|
||||||
|
|
@ -266,6 +323,26 @@ impl<
|
||||||
.collect()
|
.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> {
|
pub fn graph(&self) -> &StableDiGraph<GW, GeometryLabel, usize> {
|
||||||
&self.graph
|
&self.graph
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -520,38 +520,9 @@ impl<'a> GetOtherEnd<DotIndex, LooseDotIndex> for SeqLooseSeg<'a> {}
|
||||||
pub type FixedBend<'a> = GenericPrimitive<'a, FixedBendWeight>;
|
pub type FixedBend<'a> = GenericPrimitive<'a, FixedBendWeight>;
|
||||||
impl_fixed_primitive!(FixedBend, 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> {
|
impl<'a> MakeShape for FixedBend<'a> {
|
||||||
fn shape(&self) -> Shape {
|
fn shape(&self) -> Shape {
|
||||||
let ends = self.ends();
|
self.layout.geometry().bend_shape(self.index.into())
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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>;
|
pub type LooseBend<'a> = GenericPrimitive<'a, LooseBendWeight>;
|
||||||
impl_loose_primitive!(LooseBend, 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> {
|
impl<'a> MakeShape for LooseBend<'a> {
|
||||||
fn shape(&self) -> Shape {
|
fn shape(&self) -> Shape {
|
||||||
let ends = self.ends();
|
self.layout.geometry().bend_shape(self.index.into())
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue