forceatlas2 0.8.0

fast force-directed generic n-dimension graph layout
Documentation
use crate::{edge::*, layout::*, node::*, util::*};

use num_traits::Zero;

pub(crate) fn apply_attraction<
	T: Coord,
	const N: usize,
	E: Edges<T, Id>,
	O: Nodes<T, N, Id>,
	Id,
>(
	layout: &mut Layout<T, N, E, O, Id>,
) {
	for ((n1, n2), weight) in layout.edges.iter_edges() {
		let (n1, n2) = layout.nodes.get_2_mut(n1, n2);
		let f = (n2.pos - n1.pos) * layout.settings.ka * weight;
		n1.speed += f;
		n2.speed -= f;
	}
}

pub(crate) fn apply_attraction_log<
	T: Coord,
	const N: usize,
	E: Edges<T, Id>,
	O: Nodes<T, N, Id>,
	Id,
>(
	layout: &mut Layout<T, N, E, O, Id>,
) {
	for ((n1, n2), weight) in layout.edges.iter_edges() {
		let (n1, n2) = layout.nodes.get_2_mut(n1, n2);
		let mut d = T::zero();
		let mut dv = VecN::<T, N>::zero();
		for ((n1_pos, n2_pos), dvi) in n1.pos.iter().zip(n2.pos.iter()).zip(dv.iter_mut()) {
			*dvi = *n2_pos - *n1_pos;
			d += *dvi * *dvi;
		}
		if d.is_zero() {
			continue;
		}
		d = d.sqrt();
		let f = dv * (d.ln_1p() / d * layout.settings.ka * weight);
		n1.speed += f;
		n2.speed -= f;
	}
}

pub(crate) fn apply_attraction_po<
	T: Coord,
	const N: usize,
	E: Edges<T, Id>,
	O: Nodes<T, N, Id>,
	Id,
>(
	layout: &mut Layout<T, N, E, O, Id>,
) {
	for ((n1, n2), weight) in layout.edges.iter_edges() {
		let (n1, n2) = layout.nodes.get_2_mut(n1, n2);
		let mut d = T::zero();
		let mut dv = VecN::<T, N>::zero();
		for ((n1_pos, n2_pos), dvi) in n1.pos.iter().zip(n2.pos.iter()).zip(dv.iter_mut()) {
			*dvi = *n2_pos - *n1_pos;
			d += *dvi * *dvi;
		}
		d = d.sqrt();
		let dprime = d - n1.size - n2.size;
		if !dprime.is_positive() {
			continue;
		}
		let f = dv * (dprime / d * layout.settings.ka * weight);
		n1.speed += f;
		n2.speed -= f;
	}
}

pub(crate) fn apply_attraction_log_po<
	T: Coord,
	const N: usize,
	E: Edges<T, Id>,
	O: Nodes<T, N, Id>,
	Id,
>(
	layout: &mut Layout<T, N, E, O, Id>,
) {
	for ((n1, n2), weight) in layout.edges.iter_edges() {
		let (n1, n2) = layout.nodes.get_2_mut(n1, n2);
		let mut d = T::zero();
		let mut dv = VecN::<T, N>::zero();
		for ((n1_pos, n2_pos), dvi) in n1.pos.iter().zip(n2.pos.iter()).zip(dv.iter_mut()) {
			*dvi = *n2_pos - *n1_pos;
			d += *dvi * *dvi;
		}
		d = d.sqrt();
		let dprime = d - n1.size - n2.size;
		if !dprime.is_positive() {
			continue;
		}
		let f = dv * (dprime.ln_1p() / d * layout.settings.ka * weight);
		n1.speed += f;
		n2.speed -= f;
	}
}