use crate::geom::V2;
use crate::pack::{pack_unbounded, ChartGeom, Packer, Placement};
use crate::progress::QUIET;
use crate::Error;
#[derive(Clone, Copy)]
pub(crate) struct TileSpec<'a> {
pub charts: &'a [ChartGeom<'a>],
pub scales: &'a [f64],
}
impl TileSpec<'_> {
pub fn area(&self) -> f64 {
self.charts.iter().map(|c| c.area).sum::<f64>() * self.sum_sq_scales()
}
pub fn bbox_area(&self) -> f64 {
self.charts
.iter()
.map(|c| c.size[0] * c.size[1])
.sum::<f64>()
* self.sum_sq_scales()
}
fn sum_sq_scales(&self) -> f64 {
self.scales.iter().map(|k| k * k).sum()
}
}
#[derive(Clone, Debug)]
pub(crate) struct TileLayout {
pub placements: Vec<Placement>,
pub density: f64,
pub chart_limit: u32,
pub inner: V2,
}
pub(crate) fn layout_tile(
p: &Packer<'_>,
t: &TileSpec<'_>,
s: f64,
page: Option<u32>,
) -> Result<TileLayout, Error> {
let k_min = t.scales.iter().copied().fold(f64::INFINITY, f64::min);
let k_max = t.scales.iter().copied().fold(0.0, f64::max);
let density = s * k_min;
let pad = 2 * p.padding;
let shrink = |texels: u32| ((texels as f64 * k_min / k_max).floor() as u32).max(1);
let chart_limit = if p.max_chart_size == 0 {
0
} else {
shrink(p.max_chart_size)
};
let cap = page.map_or(u32::MAX, |size| {
shrink(size.saturating_sub(pad)).saturating_add(pad)
});
let sub = Packer {
charts: t.charts,
tiles: &[],
max_chart_size: chart_limit,
block: 1,
ctx: &QUIET,
..*p
};
let r = pack_unbounded(&sub, density, cap)?;
let inner = [
r.width.saturating_sub(pad) as f64 / density,
r.height.saturating_sub(pad) as f64 / density,
];
Ok(TileLayout {
placements: r.placements,
density,
chart_limit,
inner,
})
}