runmat_plot/core/viewport.rs
1use crate::core::BoundingBox;
2
3/// Compute the scale factor to convert pixel-sized geometry into data units.
4///
5/// Many plot style controls (e.g. `LineWidth`) are expressed in *pixels*, but some geometry
6/// generators (like thick polyline extrusion) operate in *data space*. This helper provides a
7/// conservative conversion factor based on the current data bounds and viewport size:
8///
9/// \[
10/// \text{data\_units\_per\_px} = \min\left(\frac{\Delta x}{w_{px}}, \frac{\Delta y}{h_{px}}\right)
11/// \]
12///
13/// Using the minimum axis scale avoids pathological over-thick extrusion when one data axis spans
14/// orders of magnitude more than the other (for example semilog/loglog plots). In those cases a
15/// `max(...)` conversion can turn a modest pixel width into a near-filled ribbon.
16pub fn data_units_per_px(bounds: &BoundingBox, viewport_px: (u32, u32)) -> f32 {
17 let (w_px, h_px) = viewport_px;
18 let w_px = w_px.max(1) as f32;
19 let h_px = h_px.max(1) as f32;
20
21 let x_range = (bounds.max.x - bounds.min.x).abs().max(1e-6);
22 let y_range = (bounds.max.y - bounds.min.y).abs().max(1e-6);
23
24 (x_range / w_px).min(y_range / h_px)
25}