//! Read collections of tiles from JSON files and draw them as PNG files. //! //! Run this as an example to draw arbitrary tile collections: //! //! cargo run --example draw_tiles -- --help //! //! Run this as a test to draw the tile collections generated by the //! save_tiles example: //! //! cargo test --example draw_tiles //! use navig18xx::prelude::*; mod output; type Result = std::result::Result<(), Box>; #[test] fn test_draw_tiles() -> Result { let json_dir = output::Dir::Examples; let output_dir = output::Dir::Examples; let try_files = vec![ ("tile_catalogue.json", 8, 16, Orientation::FlatTop), ("tile_1830.json", 8, 13, Orientation::PointedTop), ("tile_1861.json", 8, 16, Orientation::FlatTop), ("tile_1867.json", 8, 16, Orientation::FlatTop), ]; for (basename, rows, cols, orientation) in &try_files { let json_file = json_dir.join(basename); if !json_file.exists() { println!("{} not found", json_file.to_str().unwrap()); continue; } let png_basename = std::path::Path::new(basename).with_extension("png"); let png_file = output_dir.join(png_basename); draw_tiles(&json_file, png_file, *rows, *cols, *orientation)?; } Ok(()) } fn main() -> Result { let output_dir = output::Dir::Root; let mut rows: usize = 6; let mut cols: usize = 14; let mut orientation = Orientation::FlatTop; let mut json_files: Vec = vec![]; // Skip the first argument, which is typically the path to this // executable, but could conceivably contain anything. let mut args = std::env::args(); args.next(); while let Some(arg) = args.next() { match arg.as_str() { "-h" | "--help" => { print_usage(); return Ok(()); } "-r" => { if let Some(row_str) = args.next() { rows = row_str.parse::()? } else { panic!("Missing argument for {}", arg) } } "-c" => { if let Some(row_str) = args.next() { cols = row_str.parse::()? } else { panic!("Missing argument for {}", arg) } } "-f" => { orientation = Orientation::FlatTop; } "-p" => { orientation = Orientation::PointedTop; } _ => json_files.push(arg), } } if json_files.is_empty() { println!("ERROR: No input files given"); print_usage(); return Ok(()); } for json_file in &json_files { let png_basename = std::path::Path::new(json_file).with_extension("png"); let png_file = output_dir.join(png_basename); draw_tiles(json_file, png_file, rows, cols, orientation)?; } Ok(()) } fn draw_tiles>( json_file: P, png_file: std::path::PathBuf, rows: usize, cols: usize, orientation: Orientation, ) -> Result { let hex_max_diameter = 125.0; let mut hex = Hex::new(hex_max_diameter); hex.set_orientation(orientation); let margin = 10; let bg_rgba = Some(Colour::WHITE); let json_str = json_file.as_ref().to_str().unwrap(); println!("Reading {} ...", json_str); let tiles = read_tiles(json_file)?; let example = place_tiles(hex, &tiles, rows, cols); example.draw_map(); println!("Writing {} ...", png_file.to_str().unwrap()); example.write_png(margin, bg_rgba, png_file); Ok(()) } fn print_usage() { println!(); println!("draw_tiles [-c COLS] [-r ROWS] [-f|-p] JSON_FILES"); println!(); println!(" -c COLS The number of tile columns"); println!(" -r ROWS The number of tile rows"); println!(" -f Orient tiles so the top is flat (default)"); println!(" -p Orient tiles so the top is pointed"); println!(" JSON_FILES The tile JSON file(s) to draw"); println!(); } fn place_tiles( hex: Hex, tiles: &[Tile], rows: usize, cols: usize, ) -> Example { // Build an iterator over tile names for the tile catalogue. let tile_names = tiles.iter().map(|t| &t.name).cycle(); let coords = Coordinates { orientation: hex.orientation(), letters: Letters::AsColumns, first_row: FirstRow::OddColumns, }; // Build an iterator over the map hexes. let mut tile_addrs: Vec = vec![]; let rows: Vec = (0..rows as isize).collect(); let cols: Vec = (0..cols as isize).collect(); for row in &rows { for col in &cols { let addr = HexAddress::new(*row, *col); let addr_string = coords.format(&addr).unwrap(); tile_addrs.push(addr_string) } } // Combine the two iterators to place a tile at each map hex. let placed_tiles: Vec<_> = tile_addrs .iter() .zip(tile_names) .map(|(addr, name)| tile_at(name, addr)) .collect(); let tokens: Vec<(String, _)> = vec![]; Example::new_catalogue(hex, tokens, placed_tiles, tiles.to_vec(), coords) }