"""Pure coordinate-mapping math shared by the QQuickPaintedItem chart items (GraphQuickItem, TrendChartItem). No QPainter or Qt-widget dependency, so it's testable without a GUI — unlike the paint() methods that call it. """ from __future__ import annotations def value_to_pixel( value: float, value_min: float, value_max: float, pixel_start: float, pixel_span: float, ) -> float: """Map a value onto a pixel range, inverted so larger values sit at smaller pixel coordinates (screen y grows downward). Also used for evenly-spaced tick indices: pass the tick index as `value` and `(tick_count - 1)` as `value_max` with `value_min=0`. """ value_range = value_max - value_min if value_range < 1e-9: return pixel_start + pixel_span / 2 fraction = 1.0 - (value - value_min) / value_range return pixel_start + fraction * pixel_span def index_to_pixel(index: float, count: int, pixel_start: float, pixel_span: float) -> float: """Map a 0-based sample index onto a pixel range, left to right.""" if count <= 1: return pixel_start + pixel_span / 2 fraction = index / (count - 1) return pixel_start + fraction * pixel_span def elapsed_to_pixel( elapsed: float, window_start: float, window_end: float, pixel_start: float, pixel_span: float, ) -> float: """Map an elapsed-seconds value onto a pixel range, left to right. Unlike `value_to_pixel`, this is not inverted: larger elapsed values sit at larger pixel x-coordinates, matching how time flows left-to-right. """ window_span = window_end - window_start if window_span < 1e-9: return pixel_start + pixel_span fraction = (elapsed - window_start) / window_span return pixel_start + fraction * pixel_span