// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2026 Martino Ferrari #include namespace plot::math { namespace { /// Resolve the endpoints of one axis in transform space, widening a degenerate /// range by +/-0.5 so the mapping stays invertible. void axis_ends(Range r, bool log, f64& lo, f64& hi) noexcept { lo = log ? Transform::log10_positive(r.min) : r.min; hi = log ? Transform::log10_positive(r.max) : r.max; if (!(hi > lo)) { lo -= 0.5; hi += 0.5; } } /// Scale mapping `[lo,hi]` (transform space, already widened by `axis_ends`) /// onto the pixel interval `[p0,p1]`. /// /// A collapsed pixel span (`|p1 - p0| <= kMinPixelSpan`, e.g. a zero-height /// panel or an untouched layout) would yield a zero scale, so `to_data_*` would /// divide by zero and return NaN or +/-inf. Instead the span is substituted by /// the unit span `p0 -> p0 + 1`: the scale is then finite and non-zero and the /// mapping stays invertible (`to_data_x(to_screen_x(v)) == v`), the axis simply /// occupying one pixel rather than none. Non-collapsed spans are used verbatim, /// so ordinary ranges are unaffected. f64 axis_scale(f64 lo, f64 hi, f64 p0, f64 p1) noexcept { /// Pixel coordinates in this library are O(1e3), so 1e-12 is /// indistinguishable from zero while staying far below any span a real /// viewport can produce. constexpr f64 kMinPixelSpan = 1e-12; const f64 span = p1 - p0; const f64 effective_span = std::fabs(span) <= kMinPixelSpan ? 1.0 : span; return effective_span / (hi - lo); } } // namespace f64 Transform::log10_positive(f64 v) noexcept { constexpr f64 kMin = 1e-300; return std::log10(v < kMin ? kMin : v); } Transform Transform::from_range(Range x, Range y, f64 px0, f64 px1, f64 py0, f64 py1, bool lx, bool ly) noexcept { Transform t; t.log_x = lx; t.log_y = ly; f64 x_lo = 0.0, x_hi = 0.0; axis_ends(x, lx, x_lo, x_hi); t.sx = axis_scale(x_lo, x_hi, px0, px1); t.tx = px0 - x_lo * t.sx; f64 y_lo = 0.0, y_hi = 0.0; axis_ends(y, ly, y_lo, y_hi); t.sy = axis_scale(y_lo, y_hi, py0, py1); t.ty = py0 - y_lo * t.sy; return t; } } // namespace plot::math