use std::collections::HashSet;
use petgraph::graph::NodeIndex;
use crate::layout::hierarchical::Orientation;
pub(crate) type DefaultPositionMapFn = fn(NodeIndex) -> (f32, f32);
pub mod bipartite;
pub mod force_directed;
pub mod hierarchical;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum Layout {
Circular,
Hierarchical(Orientation),
ForceDirected,
Bipartite(Option<HashSet<NodeIndex>>),
Random,
}
#[derive(Debug, Clone)]
pub enum LayoutOrPositionMap<PositionMapFn = DefaultPositionMapFn> {
Layout(Layout),
PositionMap(PositionMapFn),
}
pub mod circular {
use petgraph::visit::{IntoNodeReferences, NodeIndexable};
pub fn circular_layout<G>(graph: &G) -> impl Fn(G::NodeId) -> (f32, f32) + '_
where
G: IntoNodeReferences + NodeIndexable,
{
let node_count = graph.node_references().count() as f32;
move |node_id| {
let index = graph.to_index(node_id) as f32;
let angle = index / node_count * std::f32::consts::TAU - std::f32::consts::FRAC_PI_2;
let x = 0.5 + 0.5 * angle.cos();
let y = 0.5 + 0.5 * angle.sin();
(x, y)
}
}
}
pub mod random {
use petgraph::visit::{IntoNodeReferences, NodeIndexable, NodeRef};
pub fn random_layout<G>(graph: &G) -> impl Fn(G::NodeId) -> (f32, f32) + '_
where
G: IntoNodeReferences + NodeIndexable,
{
let mut rng = fastrand::Rng::new();
let mut positions = vec![(0.0f32, 0.0f32); graph.node_bound()];
for node_ref in graph.node_references() {
let x = rng.f32();
let y = rng.f32();
let idx = graph.to_index(node_ref.id());
positions[idx] = (x, y);
}
move |node_id| {
let index = graph.to_index(node_id);
positions[index]
}
}
}