agg_rust/
trans_warp_magnifier.rs1use crate::span_interpolator_linear::Transformer;
7
8pub struct TransWarpMagnifier {
13 pub xc: f64,
14 pub yc: f64,
15 pub magn: f64,
16 pub radius: f64,
17}
18
19impl TransWarpMagnifier {
20 pub fn new() -> Self {
21 Self {
22 xc: 0.0,
23 yc: 0.0,
24 magn: 1.0,
25 radius: 1.0,
26 }
27 }
28
29 pub fn center(&mut self, x: f64, y: f64) {
30 self.xc = x;
31 self.yc = y;
32 }
33
34 pub fn magnification(&mut self, m: f64) {
35 self.magn = m;
36 }
37
38 pub fn set_radius(&mut self, r: f64) {
39 self.radius = r;
40 }
41
42 pub fn inverse_transform(&self, x: &mut f64, y: &mut f64) {
43 let dx = *x - self.xc;
44 let dy = *y - self.yc;
45 let r = (dx * dx + dy * dy).sqrt();
46
47 if r < self.radius * self.magn {
48 *x = self.xc + dx / self.magn;
49 *y = self.yc + dy / self.magn;
50 } else {
51 let rnew = r - self.radius * (self.magn - 1.0);
52 *x = self.xc + rnew * dx / r;
53 *y = self.yc + rnew * dy / r;
54 }
55 }
56}
57
58impl Transformer for TransWarpMagnifier {
59 fn transform(&self, x: &mut f64, y: &mut f64) {
60 let dx = *x - self.xc;
61 let dy = *y - self.yc;
62 let r = (dx * dx + dy * dy).sqrt();
63 if r < self.radius {
64 *x = self.xc + dx * self.magn;
65 *y = self.yc + dy * self.magn;
66 return;
67 }
68 let m = (r + self.radius * (self.magn - 1.0)) / r;
69 *x = self.xc + dx * m;
70 *y = self.yc + dy * m;
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_identity_magnification() {
80 let t = TransWarpMagnifier::new();
81 let (mut x, mut y) = (5.0, 5.0);
82 t.transform(&mut x, &mut y);
83 assert!((x - 5.0).abs() < 1e-10);
84 assert!((y - 5.0).abs() < 1e-10);
85 }
86
87 #[test]
88 fn test_center_magnification() {
89 let mut t = TransWarpMagnifier::new();
90 t.center(100.0, 100.0);
91 t.magnification(2.0);
92 t.set_radius(50.0);
93
94 let (mut x, mut y) = (100.0, 100.0);
96 t.transform(&mut x, &mut y);
97 assert!((x - 100.0).abs() < 1e-10);
98 assert!((y - 100.0).abs() < 1e-10);
99
100 let (mut x, mut y) = (120.0, 100.0);
102 t.transform(&mut x, &mut y);
103 assert!((x - 140.0).abs() < 1e-10); assert!((y - 100.0).abs() < 1e-10);
105 }
106
107 #[test]
108 fn test_inverse_roundtrip() {
109 let mut t = TransWarpMagnifier::new();
110 t.center(50.0, 50.0);
111 t.magnification(3.0);
112 t.set_radius(30.0);
113
114 for &(ox, oy) in &[(50.0, 50.0), (60.0, 50.0), (90.0, 90.0), (20.0, 30.0)] {
115 let (mut x, mut y) = (ox, oy);
116 t.transform(&mut x, &mut y);
117 t.inverse_transform(&mut x, &mut y);
118 assert!((x - ox).abs() < 1e-8, "x: {x} != {ox}");
119 assert!((y - oy).abs() < 1e-8, "y: {y} != {oy}");
120 }
121 }
122}