mirror of https://codeberg.org/topola/topola.git
155 lines
5.1 KiB
Rust
155 lines
5.1 KiB
Rust
use std::mem::swap;
|
|
|
|
use petgraph::Direction::{Outgoing, Incoming};
|
|
use petgraph::stable_graph::StableDiGraph;
|
|
|
|
use crate::graph::{Set, DotIndex, SegIndex, BendIndex, TaggedIndex, Tag, Index, DotWeight, SegWeight, BendWeight, TaggedWeight, Label};
|
|
use crate::shape::Shape;
|
|
|
|
pub struct Primitive<'a, Weight> {
|
|
pub index: Index<Weight>,
|
|
graph: &'a StableDiGraph<TaggedWeight, Label, usize>,
|
|
}
|
|
|
|
impl<'a, Weight> Primitive<'a, Weight> {
|
|
pub fn new(index: Index<Weight>, graph: &'a StableDiGraph<TaggedWeight, Label, usize>) -> Self {
|
|
Self {index, graph}
|
|
}
|
|
|
|
pub fn shape(&self) -> Shape {
|
|
let ends = self.ends();
|
|
match self.tagged_weight() {
|
|
TaggedWeight::Dot(dot) => Shape {
|
|
width: dot.circle.r * 2.0,
|
|
from: dot.circle.pos,
|
|
to: dot.circle.pos,
|
|
center: None,
|
|
},
|
|
TaggedWeight::Seg(seg) => {
|
|
Shape {
|
|
width: seg.width,
|
|
from: self.primitive(ends[0]).weight().circle.pos,
|
|
to: self.primitive(ends[1]).weight().circle.pos,
|
|
center: None,
|
|
}
|
|
}
|
|
TaggedWeight::Bend(bend) => {
|
|
let mut shape = Shape {
|
|
width: self.primitive(ends[0]).weight().circle.r * 2.0,
|
|
from: self.primitive(ends[0]).weight().circle.pos,
|
|
to: self.primitive(ends[1]).weight().circle.pos,
|
|
center: Some(self.primitive(self.core().unwrap()).weight().circle.pos),
|
|
};
|
|
|
|
if bend.cw {
|
|
swap(&mut shape.from, &mut shape.to);
|
|
}
|
|
shape
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn next(&self) -> Option<TaggedIndex> {
|
|
self.graph.neighbors_directed(self.index.index, Outgoing)
|
|
.filter(|ni| self.graph.edge_weight(self.graph.find_edge(*ni, self.index.index).unwrap()).unwrap().is_end())
|
|
.map(|ni| Index::<Label>::new(ni).retag(*self.graph.node_weight(ni).unwrap()))
|
|
.next()
|
|
}
|
|
|
|
pub fn prev(&self) -> Option<TaggedIndex> {
|
|
self.graph.neighbors_directed(self.index.index, Incoming)
|
|
.filter(|ni| self.graph.edge_weight(self.graph.find_edge(self.index.index, *ni).unwrap()).unwrap().is_end())
|
|
.map(|ni| Index::<Label>::new(ni).retag(*self.graph.node_weight(ni).unwrap()))
|
|
.next()
|
|
}
|
|
|
|
pub fn ends(&self) -> Vec<DotIndex> {
|
|
self.graph.neighbors_undirected(self.index.index)
|
|
.filter(|ni| self.graph.edge_weight(self.graph.find_edge_undirected(self.index.index, *ni).unwrap().0).unwrap().is_end())
|
|
.filter(|ni| self.graph.node_weight(*ni).unwrap().is_dot())
|
|
.map(|ni| DotIndex::new(ni))
|
|
.collect()
|
|
}
|
|
|
|
pub fn core(&self) -> Option<DotIndex> {
|
|
self.graph.neighbors(self.index.index)
|
|
.filter(|ni| self.graph.edge_weight(self.graph.find_edge(self.index.index, *ni).unwrap()).unwrap().is_core())
|
|
.map(|ni| DotIndex::new(ni))
|
|
.next()
|
|
}
|
|
|
|
pub fn tagged_index(&self) -> TaggedIndex {
|
|
self.index.retag(*self.graph.node_weight(self.index.index).unwrap())
|
|
}
|
|
|
|
pub fn tagged_weight(&self) -> TaggedWeight {
|
|
*self.graph.node_weight(self.index.index).unwrap()
|
|
}
|
|
|
|
fn primitive<W>(&self, index: Index<W>) -> Primitive<W> {
|
|
Primitive::new(index, &self.graph)
|
|
}
|
|
}
|
|
|
|
impl<'a, Weight> Set for Primitive<'a, Weight> {
|
|
fn interior(&self) -> Vec<TaggedIndex> {
|
|
vec![self.tagged_index()]
|
|
}
|
|
|
|
fn closure(&self) -> Vec<TaggedIndex> {
|
|
let ends: Vec<TaggedIndex> = self.ends()
|
|
.into_iter()
|
|
.map(|end| TaggedIndex::Dot(end))
|
|
.collect();
|
|
[[self.tagged_index()].as_slice(), ends.as_slice()].concat()
|
|
}
|
|
|
|
fn boundary(&self) -> Vec<DotIndex> {
|
|
self.ends()
|
|
}
|
|
}
|
|
|
|
pub type Dot<'a> = Primitive<'a, DotWeight>;
|
|
pub type Seg<'a> = Primitive<'a, SegWeight>;
|
|
pub type Bend<'a> = Primitive<'a, BendWeight>;
|
|
|
|
impl<'a> Dot<'a> {
|
|
pub fn weight(&self) -> DotWeight {
|
|
*self.tagged_weight().as_dot().unwrap()
|
|
}
|
|
}
|
|
|
|
impl<'a> Seg<'a> {
|
|
pub fn weight(&self) -> SegWeight {
|
|
*self.tagged_weight().as_seg().unwrap()
|
|
}
|
|
}
|
|
|
|
impl<'a> Bend<'a> {
|
|
pub fn around(&self) -> TaggedIndex {
|
|
if let Some(inner) = self.inner() {
|
|
TaggedIndex::Bend(inner)
|
|
} else {
|
|
TaggedIndex::Dot(self.core().unwrap())
|
|
}
|
|
}
|
|
|
|
pub fn inner(&self) -> Option<BendIndex> {
|
|
self.graph.neighbors_directed(self.index.index, Incoming)
|
|
.filter(|ni| self.graph.edge_weight(self.graph.find_edge(*ni, self.index.index).unwrap()).unwrap().is_outer())
|
|
.map(|ni| BendIndex::new(ni))
|
|
.next()
|
|
}
|
|
|
|
pub fn outer(&self) -> Option<BendIndex> {
|
|
self.graph.neighbors_directed(self.index.index, Outgoing)
|
|
.filter(|ni| self.graph.edge_weight(self.graph.find_edge(self.index.index, *ni).unwrap()).unwrap().is_outer())
|
|
.map(|ni| BendIndex::new(ni))
|
|
.next()
|
|
}
|
|
|
|
pub fn weight(&self) -> BendWeight {
|
|
*self.tagged_weight().as_bend().unwrap()
|
|
}
|
|
}
|