stipple_geometry/
physical.rs1use crate::Size;
2
3#[derive(Clone, Copy, Debug, PartialEq)]
7pub struct ScaleFactor(f64);
8
9impl ScaleFactor {
10 pub const IDENTITY: Self = Self(1.0);
12
13 #[inline]
16 pub fn new(factor: f64) -> Self {
17 if factor.is_finite() && factor > 0.0 {
18 Self(factor)
19 } else {
20 Self::IDENTITY
21 }
22 }
23
24 #[inline]
25 pub fn get(self) -> f64 {
26 self.0
27 }
28
29 #[inline]
31 pub fn to_physical(self, logical: Size) -> PhysicalSize {
32 PhysicalSize {
33 width: (logical.width * self.0).round().max(0.0) as u32,
34 height: (logical.height * self.0).round().max(0.0) as u32,
35 }
36 }
37
38 #[inline]
40 pub fn to_logical(self, physical: PhysicalSize) -> Size {
41 Size::new(
42 physical.width as f64 / self.0,
43 physical.height as f64 / self.0,
44 )
45 }
46}
47
48impl Default for ScaleFactor {
49 #[inline]
50 fn default() -> Self {
51 Self::IDENTITY
52 }
53}
54
55#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
58pub struct PhysicalSize {
59 pub width: u32,
60 pub height: u32,
61}
62
63impl PhysicalSize {
64 #[inline]
65 pub const fn new(width: u32, height: u32) -> Self {
66 Self { width, height }
67 }
68
69 #[inline]
71 pub const fn pixel_count(self) -> u64 {
72 self.width as u64 * self.height as u64
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn hidpi_roundtrip() {
82 let s = ScaleFactor::new(2.0);
83 assert_eq!(
84 s.to_physical(Size::new(100.0, 50.0)),
85 PhysicalSize::new(200, 100)
86 );
87 assert_eq!(
88 s.to_logical(PhysicalSize::new(200, 100)),
89 Size::new(100.0, 50.0)
90 );
91 }
92
93 #[test]
94 fn invalid_scale_falls_back_to_identity() {
95 assert_eq!(ScaleFactor::new(0.0), ScaleFactor::IDENTITY);
96 assert_eq!(ScaleFactor::new(f64::NAN), ScaleFactor::IDENTITY);
97 assert_eq!(ScaleFactor::new(-1.0), ScaleFactor::IDENTITY);
98 }
99}