dugong 0.8.0

Dagre-compatible graph layout algorithms (port of dagrejs/dagre).
Documentation
use crate::graphlib::Graph;
use crate::{EdgeLabel, GraphLabel, LabelPos, NodeLabel};

#[derive(Debug, Clone, Copy, Default)]
pub(super) struct SepNodeMetrics {
    pub(super) width: f64,
    pub(super) labelpos: Option<LabelPos>,
    pub(super) is_dummy: bool,
}

impl From<&NodeLabel> for SepNodeMetrics {
    fn from(label: &NodeLabel) -> Self {
        Self {
            width: label.width,
            labelpos: label.labelpos,
            is_dummy: label.dummy.is_some(),
        }
    }
}

pub(super) fn sep(
    g: &Graph<NodeLabel, EdgeLabel, GraphLabel>,
    v: &str,
    w: &str,
    reverse_sep: bool,
) -> f64 {
    let v_metrics = g.node(v).map(SepNodeMetrics::from).unwrap_or_default();
    let w_metrics = g.node(w).map(SepNodeMetrics::from).unwrap_or_default();
    sep_metrics(
        v_metrics,
        w_metrics,
        g.graph().nodesep,
        g.graph().edgesep,
        reverse_sep,
    )
}

pub(super) fn sep_metrics(
    v: SepNodeMetrics,
    w: SepNodeMetrics,
    node_sep: f64,
    edge_sep: f64,
    reverse_sep: bool,
) -> f64 {
    let mut sum: f64 = 0.0;
    let mut delta: f64 = 0.0;

    sum += v.width / 2.0;
    if let Some(labelpos) = v.labelpos {
        delta = match labelpos {
            LabelPos::L => -v.width / 2.0,
            LabelPos::R => v.width / 2.0,
            LabelPos::C => 0.0,
        };
    }
    if delta != 0.0 {
        sum += if reverse_sep { delta } else { -delta };
    }
    delta = 0.0;

    sum += if v.is_dummy { edge_sep } else { node_sep } / 2.0;
    sum += if w.is_dummy { edge_sep } else { node_sep } / 2.0;

    sum += w.width / 2.0;
    if let Some(labelpos) = w.labelpos {
        delta = match labelpos {
            LabelPos::L => w.width / 2.0,
            LabelPos::R => -w.width / 2.0,
            LabelPos::C => 0.0,
        };
    }
    if delta != 0.0 {
        sum += if reverse_sep { delta } else { -delta };
    }

    sum
}

pub(super) fn width(g: &Graph<NodeLabel, EdgeLabel, GraphLabel>, v: &str) -> f64 {
    g.node(v).map(|n| n.width).unwrap_or(0.0)
}