/rust/registry/src/index.crates.io-1949cf8c6b5b557f/i_float-1.15.0/src/adapter.rs
Line | Count | Source |
1 | | use crate::float::compatible::FloatPointCompatible; |
2 | | use crate::float::rect::FloatRect; |
3 | | use crate::float::number::FloatNumber; |
4 | | use crate::int::point::IntPoint; |
5 | | |
6 | | #[derive(Clone)] |
7 | | pub struct FloatPointAdapter<P: FloatPointCompatible<T>, T: FloatNumber> { |
8 | | pub dir_scale: T, |
9 | | pub inv_scale: T, |
10 | | pub offset: P, |
11 | | pub rect: FloatRect<T> |
12 | | } |
13 | | |
14 | | impl<P: FloatPointCompatible<T>, T: FloatNumber> FloatPointAdapter<P, T> { |
15 | | #[inline] |
16 | 0 | pub fn new(rect: FloatRect<T>) -> Self { |
17 | 0 | let a = rect.width() * FloatNumber::from_float(0.5); |
18 | 0 | let b = rect.height() * FloatNumber::from_float(0.5); |
19 | | |
20 | 0 | let x = rect.min_x + a; |
21 | 0 | let y = rect.min_y + b; |
22 | | |
23 | 0 | let offset = P::from_xy(x, y); |
24 | | |
25 | 0 | let max = a.max(b); |
26 | | |
27 | | // degenerate case |
28 | 0 | if max == FloatNumber::from_float(0.0) { |
29 | 0 | return Self { |
30 | 0 | dir_scale: FloatNumber::from_float(1.0), |
31 | 0 | inv_scale: FloatNumber::from_float(1.0), |
32 | 0 | offset, |
33 | 0 | rect, |
34 | 0 | }; |
35 | 0 | } |
36 | | |
37 | 0 | let log2 = max.log2().to_i32(); |
38 | 0 | let ie = 29 - log2; |
39 | 0 | let e = ie as f64; |
40 | | |
41 | 0 | let dir_scale = FloatNumber::from_float(libm::exp2(e)); |
42 | 0 | let inv_scale = FloatNumber::from_float(libm::exp2(-e)); |
43 | | |
44 | 0 | Self { |
45 | 0 | dir_scale, |
46 | 0 | inv_scale, |
47 | 0 | offset, |
48 | 0 | rect, |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | | #[inline] |
53 | 0 | pub fn with_scale(rect: FloatRect<T>, scale: f64) -> Self { |
54 | 0 | let a = rect.width() * FloatNumber::from_float(0.5); |
55 | 0 | let b = rect.height() * FloatNumber::from_float(0.5); |
56 | | |
57 | 0 | let x = rect.min_x + a; |
58 | 0 | let y = rect.min_y + b; |
59 | | |
60 | 0 | let offset = P::from_xy(x, y); |
61 | | |
62 | 0 | let max = a.max(b); |
63 | | |
64 | | // degenerate case |
65 | 0 | if max == FloatNumber::from_float(0.0) { |
66 | 0 | return Self { |
67 | 0 | dir_scale: FloatNumber::from_float(1.0), |
68 | 0 | inv_scale: FloatNumber::from_float(1.0), |
69 | 0 | offset, |
70 | 0 | rect, |
71 | 0 | }; |
72 | 0 | } |
73 | | |
74 | 0 | let dir_scale = FloatNumber::from_float(scale); |
75 | 0 | let inv_scale = FloatNumber::from_float(1.0 / scale); |
76 | | |
77 | 0 | Self { |
78 | 0 | dir_scale, |
79 | 0 | inv_scale, |
80 | 0 | offset, |
81 | 0 | rect, |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | | #[inline] |
86 | 0 | pub fn with_iter<'a, I>(iter: I) -> Self |
87 | 0 | where |
88 | 0 | I: Iterator<Item=&'a P>, |
89 | 0 | T: FloatNumber, P: 'a |
90 | | { |
91 | 0 | Self::new(FloatRect::with_iter(iter).unwrap_or(FloatRect::zero())) |
92 | 0 | } |
93 | | |
94 | | #[inline(always)] |
95 | 0 | pub fn int_to_float(&self, point: &IntPoint) -> P { |
96 | 0 | let fx: T = FloatNumber::from_i32(point.x); |
97 | 0 | let fy: T = FloatNumber::from_i32(point.y); |
98 | 0 | let x = fx * self.inv_scale + self.offset.x(); |
99 | 0 | let y = fy * self.inv_scale + self.offset.y(); |
100 | 0 | let float = P::from_xy(x, y); |
101 | | |
102 | 0 | if cfg!(debug_assertions) { |
103 | 0 | let radius = self.rect.height().max(self.rect.width()) * T::from_float(0.01); |
104 | 0 | if !self.rect.contains_with_radius(&float, radius) { |
105 | 0 | panic!( |
106 | | "You are trying to convert a point[{}, {}] which is out of rect: {}", |
107 | | x, y, self.rect |
108 | | ); |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | 0 | float |
113 | 0 | } |
114 | | |
115 | | #[inline(always)] |
116 | 0 | pub fn float_to_int(&self, point: &P) -> IntPoint { |
117 | 0 | if cfg!(debug_assertions) { |
118 | 0 | let radius = self.rect.height().max(self.rect.width()) * T::from_float(0.01); |
119 | 0 | if !self.rect.contains_with_radius(point, radius) { |
120 | 0 | panic!( |
121 | | "You are trying to convert a point[{}, {}] which is out of rect: {}", |
122 | 0 | point.x(), point.y(), self.rect |
123 | | ); |
124 | 0 | } |
125 | 0 | } |
126 | 0 | let x = ((point.x() - self.offset.x()) * self.dir_scale).to_i32(); |
127 | 0 | let y = ((point.y() - self.offset.y()) * self.dir_scale).to_i32(); |
128 | 0 | IntPoint { x, y } |
129 | 0 | } |
130 | | |
131 | | #[inline(always)] |
132 | 0 | pub fn sqr_float_to_int(&self, value: T) -> u64 { |
133 | 0 | let scale = self.dir_scale; |
134 | 0 | let sqr_scale = scale * scale; |
135 | 0 | (sqr_scale * value).to_f64() as u64 |
136 | 0 | } |
137 | | |
138 | | #[inline(always)] |
139 | 0 | pub fn len_float_to_int(&self, value: T) -> i32 { |
140 | 0 | (self.dir_scale * value).to_f64() as i32 |
141 | 0 | } |
142 | | } |
143 | | |
144 | | #[cfg(test)] |
145 | | mod tests { |
146 | | use crate::adapter::FloatPointAdapter; |
147 | | use crate::float::compatible::FloatPointCompatible; |
148 | | use crate::float::point::FloatPoint; |
149 | | use crate::float::rect::FloatRect; |
150 | | |
151 | | #[test] |
152 | | fn test_0() { |
153 | | let rect = FloatRect { |
154 | | min_x: 1.0, |
155 | | max_x: 1.0, |
156 | | min_y: -2.0, |
157 | | max_y: -2.0, |
158 | | }; |
159 | | |
160 | | let adapter = FloatPointAdapter::<FloatPoint<f64>, f64>::new(rect); |
161 | | |
162 | | assert_eq!(adapter.dir_scale, 1.0); |
163 | | assert_eq!(adapter.inv_scale, 1.0); |
164 | | } |
165 | | |
166 | | #[test] |
167 | | fn test_1() { |
168 | | let rect = FloatRect { |
169 | | min_x: 0.0, |
170 | | max_x: 10.0, |
171 | | min_y: 0.0, |
172 | | max_y: 100.0, |
173 | | }; |
174 | | |
175 | | let adapter = FloatPointAdapter::new(rect); |
176 | | |
177 | | let f0 = [10.0, 2.0]; |
178 | | let p0 = adapter.float_to_int(&f0); |
179 | | let f1: [f64; 2] = adapter.int_to_float(&p0); |
180 | | |
181 | | assert_eq!((f0.x() - f1.x()).abs() < 0.000_0001, true); |
182 | | assert_eq!((f0.y() - f1.y()).abs() < 0.000_0001, true); |
183 | | } |
184 | | |
185 | | #[test] |
186 | | fn test_2() { |
187 | | let points = [ |
188 | | [-2.0, -4.0], |
189 | | [-2.0, 3.0], |
190 | | [5.0, 3.0], |
191 | | [5.0, -4.0], |
192 | | ]; |
193 | | |
194 | | let adapter = FloatPointAdapter::with_iter(points.iter()); |
195 | | |
196 | | let f0 = [1.0, 2.0]; |
197 | | let p0 = adapter.float_to_int(&f0); |
198 | | let f1: [f64; 2] = adapter.int_to_float(&p0); |
199 | | |
200 | | assert_eq!((f0.x() - f1.x()).abs() < 0.000_0001, true); |
201 | | assert_eq!((f0.y() - f1.y()).abs() < 0.000_0001, true); |
202 | | } |
203 | | } |