feat(exporters): implement image_dimensions with TDD

This commit is contained in:
2026-03-23 02:33:22 +01:00
parent 0d0627b223
commit 56c53d7f53

View File

@@ -1,5 +1,55 @@
use lib::{BlockPalette, StructureExporter, VoxelGrid, VoxelType};
const GAP: u32 = 1;
// Returns VoxelTypes that (1) are configured in the palette AND (2) appear in the grid.
fn active_voxel_types(palette: &BlockPalette, grid: &VoxelGrid) -> Vec<VoxelType> {
let mut candidates = vec![VoxelType::Body];
if palette.blocks.outline.is_some() {
candidates.push(VoxelType::Outline);
}
if palette.blocks.shadow.is_some() {
candidates.push(VoxelType::Shadow);
}
candidates.retain(|&vt| {
(0..grid.depth).any(|z|
(0..grid.height).any(|y|
(0..grid.width).any(|x| grid.get(x, y, z) == Some(vt))
)
)
});
candidates
}
pub fn image_dimensions(grid: &VoxelGrid, palette: &BlockPalette, cell_size: u32) -> (u32, u32) {
let label_height = cell_size + 4;
let per_layer_height = if grid.height == 0 {
0
} else {
grid.height * (cell_size + GAP) - GAP
};
let layer_block_height = label_height + GAP + per_layer_height;
let total_grid_height = grid.depth * layer_block_height
+ grid.depth.saturating_sub(1) * GAP;
let active = active_voxel_types(palette, grid);
let legend_height = if active.is_empty() {
0
} else {
active.len() as u32 * (cell_size + GAP) + GAP
};
let img_width = if grid.width == 0 {
1
} else {
GAP + grid.width * (cell_size + GAP)
};
let img_height = total_grid_height
+ if legend_height > 0 { GAP + legend_height } else { 0 };
(img_width, img_height)
}
pub struct PngExporter {
palette: BlockPalette,
cell_size: u32,
@@ -20,3 +70,50 @@ impl StructureExporter for PngExporter {
"png"
}
}
#[cfg(test)]
mod tests {
use super::*;
fn palette_full() -> BlockPalette {
serde_json::from_str(r#"{
"name": "test",
"blocks": {
"body": "minecraft:stone",
"outline": "minecraft:cobblestone",
"shadow": "minecraft:gravel"
}
}"#).unwrap()
}
fn palette_body_only() -> BlockPalette {
serde_json::from_str(r#"{
"name": "test",
"blocks": { "body": "minecraft:stone" }
}"#).unwrap()
}
#[test]
fn dimensions_single_layer() {
let grid = VoxelGrid::new(4, 3, 1);
let palette = palette_full();
let (w, h) = image_dimensions(&grid, &palette, 16);
// width: 1 + 4*(16+1) = 69
assert_eq!(w, 69);
// label_height = 20, per_layer = 3*17-1 = 50, layer_block = 71
// total_grid = 71
// legend = 3*17 + 1 = 52 (BUT: all-None grid → 0 active types → legend_height=0)
// total_h = 71 + 0 = 71
assert_eq!(h, 71);
}
#[test]
fn dimensions_multi_layer() {
let g1 = VoxelGrid::new(4, 3, 1);
let g3 = VoxelGrid::new(4, 3, 3);
let palette = palette_full();
let (_, h1) = image_dimensions(&g1, &palette, 16);
let (_, h3) = image_dimensions(&g3, &palette, 16);
assert!(h3 > h1);
}
}