geng_utils/torus/
position.rs1use geng::prelude::*;
2
3#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
5pub struct PositionTorus<T> {
6 pos: vec2<T>,
7 world_size: vec2<T>,
8}
9
10impl<T: Num> PositionTorus<T> {
11 pub fn from_world(mut pos: vec2<T>, world_size: vec2<T>) -> Self {
13 while pos.y < T::ZERO {
14 pos.y += world_size.y;
15 }
16 while pos.y > world_size.y {
17 pos.y -= world_size.y;
18 }
19 while pos.x < T::ZERO {
20 pos.x += world_size.x;
21 }
23 while pos.x > world_size.x {
24 pos.x -= world_size.x;
25 }
27
28 Self { pos, world_size }
29 }
30
31 pub fn zero(world_size: vec2<T>) -> Self {
33 Self::from_world(vec2::ZERO, world_size)
34 }
35
36 pub fn random(rng: &mut impl Rng, world_size: vec2<T>) -> Self {
38 Self::from_world(
39 vec2(
40 rng.gen_range(T::ZERO..=world_size.x),
41 rng.gen_range(T::ZERO..=world_size.y),
42 ),
43 world_size,
44 )
45 }
46
47 pub fn to_world(self) -> vec2<T> {
48 self.pos
49 }
50
51 pub fn world_size(self) -> vec2<T> {
52 self.world_size
53 }
54
55 pub fn as_dir(self) -> vec2<T> {
57 Self::zero(self.world_size).delta_to(self)
58 }
59
60 pub fn shift(&mut self, delta: vec2<T>) {
62 *self = self.shifted(delta);
63 }
64
65 pub fn shifted(self, delta: vec2<T>) -> Self {
67 Self::from_world(self.to_world() + delta, self.world_size)
68 }
69
70 pub fn delta_to(self, towards: Self) -> vec2<T> {
75 assert_eq!(
76 self.world_size, towards.world_size,
77 "two positions are not from the same world"
78 );
79
80 let mut delta = towards.to_world() - self.to_world();
81
82 let two = T::ONE + T::ONE;
84 if delta.x.abs() * two > self.world_size.x {
85 let signum = delta.x.signum();
86 delta.x -= self.world_size.x * signum;
87 }
88 if delta.y.abs() * two > self.world_size.y {
89 let signum = delta.y.signum();
90 delta.y -= self.world_size.y * signum;
91 }
92
93 delta
94 }
95}
96
97impl<T: Float> PositionTorus<T> {
98 pub fn to_world_f32(self) -> vec2<f32> {
99 self.pos.map(T::as_f32)
100 }
101
102 pub fn distance(self, other: Self) -> T {
106 self.delta_to(other).len()
107 }
108}
109
110#[test]
111fn test_delta() {
112 let world_size = vec2(20.0, 10.0);
113 let a = PositionTorus::from_world(vec2(15.0, 1.0), world_size);
114 let b = PositionTorus::from_world(vec2(10.0, 5.0), world_size);
115 let c = PositionTorus::from_world(vec2(2.0, 7.0), world_size);
116 assert_eq!(a.delta_to(b), vec2(-5.0, 4.0));
117 assert_eq!(a.delta_to(c), vec2(7.0, -4.0));
118 assert_eq!(b.delta_to(c), vec2(-8.0, 2.0));
119}