fjadra 0.2.1

Library for simulating physical forces on particles
Documentation
use itertools::Itertools;

use fjadra::{
    force::{Link, ManyBody, SimulationBuilder},
    Node,
};
use rerun::{components::GraphType, Color, GraphEdges, GraphNodes};

const NUM_NODES: usize = 10;

fn main() -> anyhow::Result<()> {
    let rec = rerun::RecordingStreamBuilder::new("fjadra_lattice").spawn()?;

    let coordinates = (0..NUM_NODES).cartesian_product(0..NUM_NODES);

    let (nodes, colors): (Vec<_>, Vec<_>) = coordinates
        .clone()
        .enumerate()
        .map(|(i, (x, y))| {
            let r = ((x as f32 / (NUM_NODES - 1) as f32) * 255.0).round() as u8;
            let g = ((y as f32 / (NUM_NODES - 1) as f32) * 255.0).round() as u8;
            (i, Color::from_rgb(r, g, 0))
        })
        .unzip();

    let mut edges = Vec::new();
    for (x, y) in coordinates.clone() {
        if y > 0 {
            let source = (y - 1) * NUM_NODES + x;
            let target = y * NUM_NODES + x;
            edges.push((source, target));
        }
        if x > 0 {
            let source = y * NUM_NODES + (x - 1);
            let target = y * NUM_NODES + x;
            edges.push((source, target));
        }
    }

    let mut simulation = SimulationBuilder::default()
        .build(nodes.iter().map(|_| Node::default()))
        .add_force(
            "link",
            Link::new(edges.clone().into_iter())
                .strength(1.0)
                .distance(60.0)
                .iterations(10),
        )
        .add_force("charge", ManyBody::new().strength(-70.0));

    rec.log_static(
        "/lattice",
        &GraphEdges::new(
            edges
                .iter()
                .map(|(source, target)| (source.to_string(), target.to_string())),
        )
        .with_graph_type(GraphType::Directed),
    )?;

    for positions in simulation.iter() {
        rec.log(
            "/lattice",
            &GraphNodes::new(nodes.iter().map(|key| key.to_string()))
                .with_positions(positions.into_iter().map(|[x, y]| [x as f32, y as f32]))
                .with_colors(colors.clone())
                .with_labels(coordinates.clone().map(|(x, y)| format!("({x}, {y})"))),
        )?;
    }

    Ok(())
}