From 907691685c524ea9c92ee14eff9c345032ad44af Mon Sep 17 00:00:00 2001 From: hal8174 Date: Thu, 26 Sep 2024 00:30:57 +0200 Subject: [PATCH] Add centering of layouts. --- src/common/block.rs | 28 +++++++++++++++-- src/common/transformation.rs | 61 +++++++++++++++++++++++++++++------- src/layout/mod.rs | 29 +++++++++++++++-- 3 files changed, 101 insertions(+), 17 deletions(-) diff --git a/src/common/block.rs b/src/common/block.rs index 26baf1f..74644fd 100644 --- a/src/common/block.rs +++ b/src/common/block.rs @@ -1,5 +1,6 @@ use crate::prelude::*; +/// The size field is in block space #[derive(Clone, Copy, Debug)] pub struct Block { pos: Position, @@ -42,7 +43,7 @@ impl Block { } pub fn world_to_block(&self) -> Transformation { - todo!() + self.block_to_world().invert() } pub fn block_to_world(&self) -> Transformation { @@ -50,6 +51,12 @@ impl Block { } } +impl Transformable for Block { + fn transform(&self, t: Transformation) -> Self { + Self::new(self.pos.transform(t), self.dir.transform(t), self.size) + } +} + #[cfg(test)] mod test { use super::*; @@ -64,8 +71,23 @@ mod test { let p = Position::new(3, 2); - dbg!(p.transform(t)); + let m = p.transform(t); - assert!(false); + assert_eq!(m, Position::new(8, 8)); + } + + #[test] + fn identity_transformation() { + let b = Block::new(Position::new(10, 5), Direction::Right, Position::new(4, 3)); + + let t = b.world_to_block(); + + let n = b.transform(t); + + dbg!(t, n); + + assert_eq!(n.dir, Direction::Up); + assert_eq!(n.pos, Position::new(0, 0)); + assert_eq!(n.size, Position::new(4, 3)); } } diff --git a/src/common/transformation.rs b/src/common/transformation.rs index 6ce8221..63f3a4d 100644 --- a/src/common/transformation.rs +++ b/src/common/transformation.rs @@ -15,18 +15,30 @@ impl Transformation { Self { rot, pos } } - pub fn transform_position(&self, pos: &Position) -> Position { - (match self.rot { - Direction::Up => *pos, - Direction::Right => Position::new(-pos.y, pos.x), - Direction::Down => Position::new(-pos.x, -pos.y), - Direction::Left => Position::new(pos.y, -pos.x), - }) + self.pos - } - pub fn rot(&self) -> Direction { self.rot } + + pub fn invert(self) -> Self { + Self::new( + match self.rot { + Direction::Up => Direction::Up, + Direction::Right => Direction::Left, + Direction::Down => Direction::Down, + Direction::Left => Direction::Right, + }, + match self.rot { + Direction::Up => Position::new(-self.pos.x, -self.pos.y), + Direction::Right => Position::new(-self.pos.y, self.pos.x), + Direction::Down => self.pos, + Direction::Left => Position::new(self.pos.y, -self.pos.x), + }, + ) + } + + pub fn chain(self, other: Self) -> Self { + Self::new(self.rot.transform(other), self.pos.transform(other)) + } } impl Transformable for Position { @@ -43,7 +55,7 @@ impl Transformable for Position { impl Transformable for Direction { fn transform(&self, t: Transformation) -> Self { match (t.rot, self) { - (Direction::Up, _) => Direction::Up, + (Direction::Up, _) => *self, (Direction::Right, Direction::Up) => Direction::Right, (Direction::Right, Direction::Right) => Direction::Down, (Direction::Right, Direction::Down) => Direction::Left, @@ -69,9 +81,34 @@ mod test { let p = Position::new(3, 5); let t = Transformation::new(Direction::Up, Position::new(-3, -5)); - assert_eq!(t.transform_position(&p), Position::new(0, 0)); + assert_eq!(p.transform(t), Position::new(0, 0)); let t = Transformation::new(Direction::Down, Position::new(-3, -5)); - assert_eq!(t.transform_position(&p), Position::new(-6, -10)); + assert_eq!(p.transform(t), Position::new(-6, -10)); + } + + #[test] + fn invert() { + let transformations = [ + Transformation::new(Direction::Up, Position::new(-3, -5)), + Transformation::new(Direction::Right, Position::new(-3, -5)), + Transformation::new(Direction::Down, Position::new(-3, -5)), + Transformation::new(Direction::Left, Position::new(-3, -5)), + ]; + + for o in transformations { + let i = o.invert(); + let c = o.chain(i); + + assert_eq!(c.rot, Direction::Up, "o: {:?}, i: {:?}, c: {:?}", o, i, c); + assert_eq!( + c.pos, + Position::new(0, 0), + "o: {:?}, i: {:?}, c: {:?}", + o, + i, + c + ); + } } } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 0470653..fc34bde 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -325,7 +325,9 @@ impl Layout<'_> { assert!(Self::place_block(problem, &mut blocks, rng)); - Layout { problem, blocks } + let mut l = Layout { problem, blocks }; + l.center(); + l } fn place_block( @@ -381,6 +383,28 @@ impl Layout<'_> { false } + pub fn get_aabb(&self) -> AABB { + self.blocks + .iter() + .map(|b| b.get_aabb()) + .reduce(AABB::combine) + .expect("At least one block is required.") + } + + pub fn center(&mut self) { + let aabb = self.get_aabb(); + + let rest = self.problem.size - aabb.size(); + + let new_min = Position::new(rest.x / 2, rest.y / 2); + + let t = Transformation::new(Direction::Up, new_min - aabb.min()); + + for b in &mut self.blocks { + *b = b.transform(t); + } + } + /// Mutate existing layout, creating a valid layout pub fn mutate(&self, rng: &mut R) -> Self { let mut s = self.clone(); @@ -395,11 +419,12 @@ impl Layout<'_> { loop { let p = r.choose_weighted(rng, |i| i.1).unwrap(); - if p.0(&mut s, rng) && rng.gen_bool(0.05) { + if p.0(&mut s, rng) && rng.gen_bool(0.2) { break; } } + s.center(); s }