word_cloud/placement/
from_center_placer.rs

1use crate::geometry::Rectangle;
2use rand::Rng;
3
4use super::PlacementStrategy;
5
6type IVector = (i32, i32);
7
8pub struct FromCenterPlacer {
9    viewport: Rectangle,
10    cur_dir: Directions,
11    precision: i32,
12}
13
14impl FromCenterPlacer {
15    pub fn new(viewport: Rectangle, precision: u32) -> FromCenterPlacer {
16        FromCenterPlacer {
17            viewport,
18            cur_dir: Directions::random(),
19            precision: precision as i32,
20        }
21    }
22}
23
24impl PlacementStrategy for FromCenterPlacer {
25    fn find_next_place(
26        &mut self,
27        start_pos: Option<crate::geometry::Vector>,
28        r: &Rectangle,
29    ) -> Option<crate::geometry::Vector> {
30        let start_pos = match start_pos {
31            Some(pos) => pos,
32            None => {
33                self.cur_dir = Directions::random();
34                return Some((self.viewport.center().0, self.viewport.center().1));
35            }
36        };
37
38        let dir = &self.cur_dir;
39        let delta = dir.to_vector();
40
41        let next_pos: (i32, i32);
42        let new_x = start_pos.0 as i32 + delta.0 * self.precision;
43        let new_y = start_pos.1 as i32 + delta.1 * self.precision;
44        if (new_x >= 0) && (r.size().0 as i32 + new_x < self.viewport.x2() as i32) {
45            next_pos = (start_pos.0 as i32 + delta.0, start_pos.1 as i32);
46        } else if (new_y >= 0) && (r.size().1 as i32 + new_y < self.viewport.y2() as i32) {
47            next_pos = (self.viewport.center().0 as i32, new_y)
48        } else {
49            return None;
50        }
51
52        Some((next_pos.0 as u32, next_pos.1 as u32))
53    }
54}
55
56#[derive(Eq, PartialEq, Hash, Clone)]
57enum Directions {
58    TopRight,
59    TopLeft,
60    BottomLeft,
61    BottomRight,
62}
63
64impl Directions {
65    fn random() -> Directions {
66        let mut generator = rand::thread_rng();
67        let rand = generator.gen_range(0..=3);
68
69        match rand {
70            0 => Self::TopRight,
71            1 => Self::TopLeft,
72            2 => Self::BottomLeft,
73            3 => Self::BottomRight,
74            _ => panic!("This should not happen"),
75        }
76    }
77
78    fn to_vector(&self) -> IVector {
79        match self {
80            Self::TopRight => (-1, -1),
81            Self::TopLeft => (1, -1),
82            Self::BottomLeft => (1, 1),
83            Self::BottomRight => (-1, 1),
84        }
85    }
86}