From 812f2467064e7c98c367503e8de1aad848659edc Mon Sep 17 00:00:00 2001 From: hal8174 Date: Wed, 18 Sep 2024 13:55:03 +0200 Subject: [PATCH] Add grid layout for images. --- examples/layout.rs | 38 +++++++++++----------- src/common/visualize/image.rs | 59 +++++++++++++++++++++++++++++++++-- src/common/visualize/mod.rs | 17 +++++----- src/layout/mod.rs | 6 +++- 4 files changed, 89 insertions(+), 31 deletions(-) diff --git a/examples/layout.rs b/examples/layout.rs index 617c6b5..432bb2a 100644 --- a/examples/layout.rs +++ b/examples/layout.rs @@ -1,7 +1,7 @@ use clap::Parser; use factorio_blueprint::{ common::visualize::Visualize, - layout::{genetic_algorithm2, PathLayout}, + layout::{genetic_algorithm2, GeneticAlgorithm, PathLayout}, }; use rand::{rngs::SmallRng, SeedableRng}; @@ -22,25 +22,25 @@ fn main() { dbg!(&p); - // let mut g = GeneticAlgorithm::new(&p, 20, 2, 0, &mut rng); + let mut g = GeneticAlgorithm::new(&p, 20, 2, 0, &mut rng); - // for i in 0..100 { - // println!("Generatrion {i}"); - // g.generation(&mut rng); - // } - - // g.output_population(); - - let mut m: Option = None; - for _ in 0..20 { - let g = genetic_algorithm2(&p, 10, 320, &mut rng); - - g.print_visualization(); - g.png_visualization("test.png"); - if m.as_ref().is_none_or(|m| g.score() < m.score()) { - m = Some(g); - } + for i in 0..100 { + println!("Generatrion {i}"); + g.generation(&mut rng); } - m.unwrap().print_visualization(); + g.output_population(); + + // let mut m: Option = None; + // for _ in 0..20 { + // let g = genetic_algorithm2(&p, 10, 320, &mut rng); + + // g.print_visualization(); + // g.png_visualization("test.png"); + // if m.as_ref().is_none_or(|m| g.score() < m.score()) { + // m = Some(g); + // } + // } + + // m.unwrap().print_visualization(); } diff --git a/src/common/visualize/image.rs b/src/common/visualize/image.rs index 45fb9ec..2efee1b 100644 --- a/src/common/visualize/image.rs +++ b/src/common/visualize/image.rs @@ -1,8 +1,8 @@ use super::Visualization; use crate::{common::visualize::Symbol, prelude::Direction}; -use image::{GenericImage, Rgba}; +use image::{GenericImage, Pixel, Rgba, RgbaImage}; -pub(super) fn draw>>(v: Visualization, image: &mut I) { +pub(super) fn draw>>(v: &Visualization, image: &mut I) { assert_eq!( (v.size.x as u32 * 10, v.size.y as u32 * 10), image.dimensions() @@ -110,6 +110,61 @@ pub(super) fn draw>>(v: Visualization, image: & } } +pub fn image_grid( + visualizations: &[Visualization], + width: u32, + height: u32, + columns: u32, +) -> RgbaImage { + let border_color = Rgba::from([255, 255, 255, 255]); + let rows = visualizations.len().div_ceil(columns as usize) as u32; + + let mut img = RgbaImage::new((width * 10 + 2) * columns, (height * 10 + 2) * rows); + + for (i, v) in visualizations.iter().enumerate() { + let i = i as u32; + let r = i / columns; + let c = i % columns; + + let size = v.size(); + + let mut sub_img = img.sub_image( + 1 + c * (width * 10 + 2), + 1 + r * (height * 10 + 2), + (size.x as u32) * 10, + (size.y as u32) * 10, + ); + draw(v, &mut *sub_img); + + for x in 0..(size.x as u32 * 10 + 2) { + img.put_pixel( + c * (width * 10 + 2) + x, + r * (height * 10 + 2), + border_color, + ); + img.put_pixel( + c * (width * 10 + 2) + x, + r * (height * 10 + 2) + (size.y as u32) * 10 + 1, + border_color, + ); + } + for y in 0..(size.y as u32 * 10 + 2) { + img.put_pixel( + c * (width * 10 + 2), + r * (height * 10 + 2) + y, + border_color, + ); + img.put_pixel( + c * (width * 10 + 2) + (size.x as u32) * 10 + 1, + r * (height * 10 + 2) + y, + border_color, + ); + } + } + + img +} + fn rotate(dir: Direction, pos: (u32, u32)) -> (u32, u32) { match dir { Direction::Up => pos, diff --git a/src/common/visualize/mod.rs b/src/common/visualize/mod.rs index c98dbed..33d1f3b 100644 --- a/src/common/visualize/mod.rs +++ b/src/common/visualize/mod.rs @@ -1,11 +1,10 @@ mod image; mod print; -use std::collections::HashMap; - -use ::image::RgbaImage; - use crate::prelude::*; +use ::image::RgbaImage; +pub use image::image_grid; +use std::collections::HashMap; pub trait Visualize { fn visualize(&self) -> Visualization; @@ -20,7 +19,7 @@ pub trait Visualize { let mut img = RgbaImage::new((v.size.x * 10) as u32, (v.size.y * 10) as u32); - image::draw(v, &mut img); + image::draw(&v, &mut img); let mut f = std::fs::File::create(file).unwrap(); let _ = img.write_to(&mut f, ::image::ImageFormat::Png); @@ -62,10 +61,6 @@ impl Symbol { Symbol::Space => ' ', } } - - // fn get_char(&self) -> char { - // self.get_str().chars().next().unwrap() - // } } pub struct Visualization { @@ -119,4 +114,8 @@ impl Visualization { ) { self.symbols.insert(pos, (symbol, fg, bg)); } + + pub fn size(&self) -> Position { + self.size + } } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 8c6524a..da48966 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -3,7 +3,7 @@ use std::time::Instant; use crate::belt_finding::common::PathField; use crate::belt_finding::conflict_avoidance::ConflictAvoidance; -use crate::common::visualize::{Color, Symbol, Visualization, Visualize}; +use crate::common::visualize::{image_grid, Color, Symbol, Visualization, Visualize}; use crate::prelude::*; use rand::{seq::SliceRandom, Rng}; use serde::{Deserialize, Serialize}; @@ -94,6 +94,10 @@ impl<'a> GeneticAlgorithm<'a> { duration_mutate.as_secs_f32() ); self.population[0].print_visualization(); + let v: Vec<_> = self.population.iter().map(|p| p.visualize()).collect(); + let img = image_grid(&v, v[0].size().x as u32, v[0].size().y as u32, 5); + let mut file = std::fs::File::create("generation.png").unwrap(); + img.write_to(&mut file, image::ImageFormat::Png).unwrap(); } pub fn output_population(&self) {