graphics/
grid.rs

1//! A flat grid with square cells.
2
3use crate::{
4    math::{Matrix2d, Scalar, Vec2d},
5    DrawState, Graphics, Line,
6};
7
8/// Represents a flat grid with square cells.
9#[derive(Debug, Copy, Clone)]
10pub struct Grid {
11    /// Number of columns.
12    pub cols: u32,
13    /// Number of rows.
14    pub rows: u32,
15    /// The width and height of each grid cell.
16    pub units: Scalar,
17}
18
19/// Iterates through the cells of a grid as (u32, u32).
20#[derive(Debug, Copy, Clone)]
21pub struct GridCells {
22    cols: u32,
23    rows: u32,
24    state: u64,
25}
26
27impl Grid {
28    /// Draws the grid.
29    pub fn draw<G>(&self, line: &Line, draw_state: &DrawState, transform: Matrix2d, g: &mut G)
30    where
31        G: Graphics,
32    {
33        let &Grid { cols, rows, units } = self;
34        for x in 0..cols + 1 {
35            let x1 = x as Scalar * units;
36            let y1 = 0.0;
37            let x2 = x1;
38            let y2 = rows as Scalar * units;
39            line.draw([x1, y1, x2, y2], draw_state, transform, g);
40        }
41        for y in 0..rows + 1 {
42            let x1 = 0.0;
43            let y1 = y as Scalar * units;
44            let x2 = cols as Scalar * units;
45            let y2 = y1;
46            line.draw([x1, y1, x2, y2], draw_state, transform, g);
47        }
48    }
49
50    /// Get a GridIterator for the grid
51    pub fn cells(&self) -> GridCells {
52        GridCells {
53            cols: self.cols,
54            rows: self.rows,
55            state: 0,
56        }
57    }
58
59    /// Get on-screen position of a grid cell
60    pub fn cell_position(&self, cell: (u32, u32)) -> Vec2d {
61        [
62            cell.0 as Scalar * self.units,
63            cell.1 as Scalar * self.units,
64        ]
65    }
66
67    /// Get on-screen x position of a grid cell
68    pub fn x_pos(&self, cell: (u32, u32)) -> Scalar {
69        self.cell_position(cell)[0]
70    }
71
72    /// Get on-screen y position of a grid cell
73    pub fn y_pos(&self, cell: (u32, u32)) -> Scalar {
74        self.cell_position(cell)[1]
75    }
76}
77
78impl Iterator for GridCells {
79    type Item = (u32, u32);
80
81    fn next(&mut self) -> Option<(u32, u32)> {
82        let cols = self.cols as u64;
83        let rows = self.rows as u64;
84
85        if self.state == cols * rows {
86            return None;
87        }
88
89        // reverse of: state = x + (y * cols)
90        let ret = ((self.state % cols) as u32, (self.state / cols) as u32);
91        self.state += 1;
92
93        Some(ret)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_grid_iterator() {
103        let combinations = vec![(2, 2), (2, 3), (3, 2)];
104
105        for (cols, rows) in combinations {
106            let grid = Grid {
107                cols,
108                rows,
109                units: 2.0,
110            };
111            println!("Testing {:?}", grid);
112
113            let mut iter = grid.cells();
114            for y in 0..rows {
115                for x in 0..cols {
116                    assert_eq!(iter.next(), Some((x, y)));
117                    println!("Got: {:?}", (x, y));
118                }
119            }
120
121            assert_eq!(iter.next(), None);
122        }
123    }
124
125    #[test]
126    fn test_cell_positions() {
127        let g: Grid = Grid {
128            cols: 2,
129            rows: 3,
130            units: 2.0,
131        };
132        assert_eq!(4.0, g.x_pos((2, 3)));
133        assert_eq!(6.0, g.y_pos((2, 3)));
134    }
135}