diff --git a/servicepoint2/src/byte_grid.rs b/servicepoint2/src/byte_grid.rs index 9cf323f..da7a0a1 100644 --- a/servicepoint2/src/byte_grid.rs +++ b/servicepoint2/src/byte_grid.rs @@ -9,17 +9,6 @@ pub struct ByteGrid { } impl ByteGrid { - /// Creates a new byte grid with the specified dimensions. - /// - /// returns: ByteGrid initialized to 0. - pub fn new(width: usize, height: usize) -> Self { - Self { - data: vec![0; width * height], - width, - height, - } - } - /// Loads a byte grid with the specified dimensions from the provided data. /// /// returns: ByteGrid that contains a copy of the provided data @@ -47,6 +36,17 @@ impl ByteGrid { } impl Grid for ByteGrid { + /// Creates a new byte grid with the specified dimensions. + /// + /// returns: ByteGrid initialized to 0. + fn new(width: usize, height: usize) -> Self { + Self { + data: vec![0; width * height], + width, + height, + } + } + fn set(&mut self, x: usize, y: usize, value: u8) -> u8 { self.check_indexes(x, y); let pos = &mut self.data[x + y * self.width]; @@ -71,6 +71,17 @@ impl Grid for ByteGrid { fn height(&self) -> usize { self.height } + + fn window(&self, x: usize, y: usize, w: usize, h: usize) -> Self { + let mut win = Self::new(w, h); + for win_x in 0..w { + for win_y in 0..h { + let value = self.get(x + win_x, y + win_y); + win.set(win_x, win_y, value); + } + } + win + } } impl DataRef for ByteGrid { diff --git a/servicepoint2/src/command.rs b/servicepoint2/src/command.rs index d9601ae..605f264 100644 --- a/servicepoint2/src/command.rs +++ b/servicepoint2/src/command.rs @@ -9,6 +9,16 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq)] pub struct Origin(pub u16, pub u16); +impl std::ops::Add for Origin { + type Output = Origin; + + fn add(self, rhs: Origin) -> Self::Output { + let Origin(x1, y1) = self; + let Origin(x2, y2) = rhs; + Origin(x1 + x2, y1 + y2) + } +} + /// Size defines the width and height of a window #[derive(Debug, Clone, Copy)] pub struct Size(pub u16, pub u16); diff --git a/servicepoint2/src/grid.rs b/servicepoint2/src/grid.rs index 4140fe2..2516279 100644 --- a/servicepoint2/src/grid.rs +++ b/servicepoint2/src/grid.rs @@ -1,4 +1,6 @@ pub trait Grid { + fn new(width: usize, height: usize) -> Self; + /// Sets the value at the specified position /// /// returns: the old value @@ -15,4 +17,35 @@ pub trait Grid { /// the height in y-direction fn height(&self) -> usize; + + /// Creates a new instance containing the specified window. + /// + /// Use concrete types to avoid boxing. + /// + /// # Arguments + /// + /// * `x`: column of the top left cell + /// * `y`: row of the top left cell + /// * `w`: size of window in x-direction + /// * `h`: size of window in y-direction + /// + /// returns: Self + /// + /// # Examples + /// To avoid boxing, this example is using the concrete type `ByteGrid`. + /// ``` + /// use servicepoint2::{ByteGrid, Grid}; + /// fn split(grid: ByteGrid) -> (ByteGrid, ByteGrid) { + /// assert!(grid.width() >= 2); + /// let split_x = grid.width() / 2; + /// let right_w = grid.width() - split_x; + /// + /// let left = grid.window(0, 0, split_x, grid.height()); + /// let right = grid.window(split_x, 0, right_w, grid.height()); + /// (left, right) + /// } + /// + /// let (l, r) = split(ByteGrid::new(9, 5)); + /// ``` + fn window(&self, x: usize, y: usize, w: usize, h: usize) -> Self; } diff --git a/servicepoint2/src/pixel_grid.rs b/servicepoint2/src/pixel_grid.rs index a2c0257..3aa8113 100644 --- a/servicepoint2/src/pixel_grid.rs +++ b/servicepoint2/src/pixel_grid.rs @@ -9,27 +9,6 @@ pub struct PixelGrid { } impl PixelGrid { - /// Creates a new pixel grid with the specified dimensions. - /// - /// # Arguments - /// - /// * `width`: size in pixels in x-direction - /// * `height`: size in pixels in y-direction - /// - /// returns: PixelGrid initialized to all pixels off - /// - /// # Panics - /// - /// - when the width is not dividable by 8 - pub fn new(width: usize, height: usize) -> Self { - assert_eq!(width % 8, 0); - Self { - width, - height, - bit_vec: BitVec::new(width * height), - } - } - /// Creates a new pixel grid with the size of the whole screen. pub fn max_sized() -> Self { Self::new(PIXEL_WIDTH as usize, PIXEL_HEIGHT as usize) @@ -69,6 +48,27 @@ impl PixelGrid { } impl Grid for PixelGrid { + /// Creates a new pixel grid with the specified dimensions. + /// + /// # Arguments + /// + /// * `width`: size in pixels in x-direction + /// * `height`: size in pixels in y-direction + /// + /// returns: PixelGrid initialized to all pixels off + /// + /// # Panics + /// + /// - when the width is not dividable by 8 + fn new(width: usize, height: usize) -> Self { + assert_eq!(width % 8, 0); + Self { + width, + height, + bit_vec: BitVec::new(width * height), + } + } + fn set(&mut self, x: usize, y: usize, value: bool) -> bool { self.check_indexes(x, y); self.bit_vec.set(x + y * self.width, value) @@ -89,6 +89,19 @@ impl Grid for PixelGrid { fn height(&self) -> usize { self.height } + + fn window(&self, x: usize, y: usize, w: usize, h: usize) -> Self { + // TODO: how to deduplicate? + // this cannot be moved into the trait because there, Self is not Sized + let mut win = Self::new(w, h); + for win_x in 0..w { + for win_y in 0..h { + let value = self.get(x + win_x, y + win_y); + win.set(win_x, win_y, value); + } + } + win + } } impl DataRef for PixelGrid {