use image::GenericImage;
use sl_glw::{GlwEvent, GlwStyle, MapLikeGlwExt as _};
use sl_map_apis::coverage::PlacementSlot;
use sl_map_apis::map_tiles::MapLike;
use sl_types::map::{GridCoordinates, GridRectangle, GridRectangleLike, ZoomLevel};
struct TestMap {
image: image::DynamicImage,
grid_rectangle: GridRectangle,
zoom_level: ZoomLevel,
}
impl GridRectangleLike for TestMap {
fn grid_rectangle(&self) -> GridRectangle {
self.grid_rectangle.clone()
}
}
impl image::GenericImageView for TestMap {
type Pixel = image::Rgba<u8>;
fn dimensions(&self) -> (u32, u32) {
self.image.dimensions()
}
fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
self.image.get_pixel(x, y)
}
}
impl GenericImage for TestMap {
fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
#[expect(deprecated, reason = "delegates to deprecated DynamicImage method")]
self.image.get_pixel_mut(x, y)
}
fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
self.image.put_pixel(x, y, pixel);
}
fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
#[expect(deprecated, reason = "delegates to deprecated DynamicImage method")]
self.image.blend_pixel(x, y, pixel);
}
}
impl MapLike for TestMap {
fn zoom_level(&self) -> ZoomLevel {
self.zoom_level
}
fn image(&self) -> &image::DynamicImage {
&self.image
}
fn image_mut(&mut self) -> &mut image::DynamicImage {
&mut self.image
}
}
const SAMPLE_JSON: &str = r#"{
"eventId": 6910,
"eventName": "test cruise",
"eventKey": "key cruise",
"eventNum": 3381,
"directorName": "LaliaCasau Resident",
"directorKey": "b609826a-b167-41e0-8e67-9fc0e78b97a1",
"sailMode": 2,
"extra1": "",
"extra2": "",
"base": {
"wind": { "dir": 0, "speed": 17, "gusts": 8, "shifts": 5, "period": 90 },
"waves": {
"height": 1.5, "speed": 3, "length": 35,
"heightVar": 5, "lengthVar": 5,
"effects": { "speed": 1, "steer": 1 }
},
"currents": { "speed": 0, "dir": 180, "waterDepth": 0 }
},
"areas": {
"area1": {
"coordSW": { "x": 1133, "y": 1048 },
"coordNE": { "x": 1135, "y": 1049 },
"margin": 25, "overlap": 0,
"wind": { "dir": 270, "speed": 12 },
"currents": { "speed": 1, "dir": 225, "waterDepth": 8 }
},
"area2": {
"coordSW": { "x": 1133, "y": 1050 },
"coordNE": { "x": 1134, "y": 1053 },
"margin": 0, "overlap": 0,
"wind": { "dir": 45, "speed": 14 },
"currents": { "speed": 1, "dir": 250 }
}
},
"circles": {
"circle1": {
"centerSim": { "x": 1136, "y": 1051 },
"centerPoint": { "x": 90, "y": 175 },
"radius": 127, "margin": 25, "overlap": 0,
"wind": { "dir": 135, "speed": 15 },
"waves": {
"height": 2, "speed": 3, "length": 35,
"heightVar": 5, "lengthVar": 5,
"effects": { "speed": 1, "steer": 1 }
},
"currents": { "speed": 0.1, "dir": 225, "waterDepth": 6 }
},
"circle2": {
"centerSim": { "x": 1139, "y": 1051 },
"centerPoint": { "x": 12, "y": 159 },
"radius": 261, "margin": 25, "overlap": 0,
"wind": { "dir": 90, "speed": 18 },
"currents": { "speed": 2, "dir": 90, "waterDepth": 6 }
}
}
}"#;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let font_path = std::env::args_os()
.nth(1)
.ok_or_else(|| -> Box<dyn std::error::Error> {
"usage: render_sample <path-to-ttf>\n\
Supply a TrueType font; a copy of DejaVuSans is checked in at \
the workspace root."
.into()
})?;
let event: GlwEvent = serde_json::from_str(SAMPLE_JSON)?;
let grid = GridRectangle::new(
GridCoordinates::new(1130, 1045),
GridCoordinates::new(1140, 1055),
);
let zoom = ZoomLevel::try_new(2)?;
let image_size: u32 = grid.size_x() * u32::from(zoom.pixels_per_region());
let background = image::Rgba([28u8, 64, 100, 255]);
let mut map = TestMap {
image: image::DynamicImage::ImageRgba8(image::ImageBuffer::from_pixel(
image_size, image_size, background,
)),
grid_rectangle: grid,
zoom_level: zoom,
};
let style = GlwStyle {
draw_margin_band: true,
legend_position: Some(PlacementSlot::TopLeft),
..GlwStyle::default()
};
let bytes = fs_err::read(&font_path)?;
let font = ab_glyph::FontVec::try_from_vec(bytes)?;
map.draw_glw_event_with_font(&event, &style, &font);
let out = std::path::Path::new("target/sl-glw-sample.png");
map.image().save(out)?;
Ok(())
}