use rustsim_core::{interaction::PositionedAgent, prelude::Agent, types::AgentId};
use rustsim_spaces::continuous::{ContinuousPos, ContinuousSpace2D};
#[derive(Debug, Clone)]
struct Particle {
id: AgentId,
pos: ContinuousPos,
}
impl Agent for Particle {
fn id(&self) -> AgentId {
self.id
}
}
impl PositionedAgent for Particle {
type Position = ContinuousPos;
fn position(&self) -> &ContinuousPos {
&self.pos
}
fn set_position(&mut self, pos: ContinuousPos) {
self.pos = pos;
}
}
#[test]
fn continuous_space_add_and_nearby() {
let mut space = ContinuousSpace2D::new(10.0, 10.0, false, 1.0).unwrap();
let p1 = Particle {
id: 1,
pos: ContinuousPos::new(2.5, 2.5),
};
let p2 = Particle {
id: 2,
pos: ContinuousPos::new(3.0, 2.5),
};
let p3 = Particle {
id: 3,
pos: ContinuousPos::new(8.0, 8.0),
};
use rustsim_core::interaction::SpaceInteraction;
space.add_agent(&p1).unwrap();
space.add_agent(&p2).unwrap();
space.add_agent(&p3).unwrap();
let near = space.nearby_ids_euclidean(&ContinuousPos::new(2.5, 2.5), 1.0);
assert!(near.contains(&1));
assert!(near.contains(&2));
assert!(!near.contains(&3));
}
#[test]
fn continuous_space_periodic_wrapping() {
let mut space = ContinuousSpace2D::new(10.0, 10.0, true, 2.0).unwrap();
let p1 = Particle {
id: 1,
pos: ContinuousPos::new(0.5, 0.5),
};
let p2 = Particle {
id: 2,
pos: ContinuousPos::new(9.5, 9.5),
};
use rustsim_core::interaction::SpaceInteraction;
space.add_agent(&p1).unwrap();
space.add_agent(&p2).unwrap();
let near = space.nearby_ids_euclidean(&ContinuousPos::new(0.5, 0.5), 2.0);
assert!(near.contains(&1));
assert!(near.contains(&2), "periodic wrapping should find agent 2");
}
#[test]
fn continuous_space_move_updates_grid() {
let mut space = ContinuousSpace2D::new(10.0, 10.0, false, 1.0).unwrap();
let p1 = Particle {
id: 1,
pos: ContinuousPos::new(1.0, 1.0),
};
use rustsim_core::interaction::SpaceInteraction;
space.add_agent(&p1).unwrap();
let near_old = space.nearby_ids_euclidean(&ContinuousPos::new(1.0, 1.0), 0.5);
assert!(near_old.contains(&1));
space
.move_agent_pos(1, ContinuousPos::new(8.0, 8.0))
.unwrap();
let near_old = space.nearby_ids_euclidean(&ContinuousPos::new(1.0, 1.0), 0.5);
assert!(!near_old.contains(&1));
let near_new = space.nearby_ids_euclidean(&ContinuousPos::new(8.0, 8.0), 0.5);
assert!(near_new.contains(&1));
}
#[test]
fn continuous_space_remove() {
let mut space = ContinuousSpace2D::new(10.0, 10.0, false, 1.0).unwrap();
let p1 = Particle {
id: 1,
pos: ContinuousPos::new(5.0, 5.0),
};
use rustsim_core::interaction::SpaceInteraction;
space.add_agent(&p1).unwrap();
assert!(!space
.nearby_ids_euclidean(&ContinuousPos::new(5.0, 5.0), 1.0)
.is_empty());
space.remove_agent(&p1).unwrap();
assert!(space
.nearby_ids_euclidean(&ContinuousPos::new(5.0, 5.0), 1.0)
.is_empty());
}
#[test]
fn continuous_pos_2d_arithmetic() {
let a = ContinuousPos::new(1.0, 2.0);
let b = ContinuousPos::new(3.0, 5.0);
let sum = a + b;
assert!((sum.x - 4.0).abs() < 1e-10);
assert!((sum.y - 7.0).abs() < 1e-10);
let diff = b - a;
assert!((diff.x - 2.0).abs() < 1e-10);
assert!((diff.y - 3.0).abs() < 1e-10);
let scaled = a * 3.0;
assert!((scaled.x - 3.0).abs() < 1e-10);
assert!((scaled.y - 6.0).abs() < 1e-10);
}
#[test]
fn continuous_pos_2d_length_and_normalized() {
let v = ContinuousPos::new(3.0, 4.0);
assert!((v.length() - 5.0).abs() < 1e-10);
let n = v.normalized();
assert!((n.length() - 1.0).abs() < 1e-10);
assert!((n.x - 0.6).abs() < 1e-10);
assert!((n.y - 0.8).abs() < 1e-10);
let zero = ContinuousPos::zero();
let nz = zero.normalized();
assert!((nz.length()).abs() < 1e-10);
}