forceatlas2 0.8.0

fast force-directed generic n-dimension graph layout
Documentation
//! Traits and implementations about the forces used in the layout.
//!
//! You typically do not need to use this directly.

pub(crate) mod attraction;
pub(crate) mod gravity;
pub(crate) mod repulsion;

use crate::{edge::*, layout::*, node::*, util::*};

/// Attraction force, that pulls neighbors together
pub trait Attraction<T: Coord, const N: usize, E, O, Id> {
	/// Select an implementation depending on the settings
	fn choose_attraction(settings: &Settings<T>) -> fn(&mut Layout<T, N, E, O, Id>);
}

/// Gravity force, that pulls every node to the center
pub trait Gravity<T: Coord, const N: usize, E, O, Id> {
	/// Select an implementation depending on the settings
	fn choose_gravity(settings: &Settings<T>) -> fn(&mut Layout<T, N, E, O, Id>);
}

/// Repulsion force, that makes every node repell each other
pub trait Repulsion<T: Coord, const N: usize, E, O, Id> {
	/// Select an implementation depending on the settings
	fn choose_repulsion(settings: &Settings<T>) -> fn(&mut Layout<T, N, E, O, Id>);
}

impl<T: Coord, const N: usize, E: Edges<T, Id>, O: Nodes<T, N, Id>, Id> Attraction<T, N, E, O, Id>
	for Layout<T, N, E, O, Id>
{
	#[allow(clippy::collapsible_else_if)]
	fn choose_attraction(settings: &Settings<T>) -> fn(&mut Layout<T, N, E, O, Id>) {
		if settings.prevent_overlapping.is_some() {
			if settings.lin_log {
				attraction::apply_attraction_log_po
			} else {
				attraction::apply_attraction_po
			}
		} else {
			if settings.lin_log {
				attraction::apply_attraction_log
			} else {
				attraction::apply_attraction
			}
		}
	}
}

impl<T: Coord + Send + Sync, const N: usize, E, O: Nodes<T, N, Id>, Id: Sync>
	Gravity<T, N, E, O, Id> for Layout<T, N, E, O, Id>
{
	fn choose_gravity(settings: &Settings<T>) -> fn(&mut Layout<T, N, E, O, Id>) {
		if settings.kg.is_zero() {
			return |_| {};
		}
		if settings.strong_gravity {
			gravity::apply_gravity_sg
		} else {
			gravity::apply_gravity
		}
	}
}

impl<T: Coord + Send + Sync, E, O: Nodes<T, 2, Id>, Id: Sync> Repulsion<T, 2, E, O, Id>
	for Layout<T, 2, E, O, Id>
{
	fn choose_repulsion(settings: &Settings<T>) -> fn(&mut Layout<T, 2, E, O, Id>) {
		if settings.prevent_overlapping.is_some() {
			repulsion::apply_repulsion_2d_po
		} else {
			repulsion::apply_repulsion_2d
		}
	}
}

impl<T: Coord + Send + Sync, E, O: Nodes<T, 3, Id>, Id: Sync> Repulsion<T, 3, E, O, Id>
	for Layout<T, 3, E, O, Id>
{
	fn choose_repulsion(settings: &Settings<T>) -> fn(&mut Layout<T, 3, E, O, Id>) {
		if settings.prevent_overlapping.is_some() {
			repulsion::apply_repulsion_3d_po
		} else {
			repulsion::apply_repulsion_3d
		}
	}
}