Coverage Report

Created: 2026-03-11 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}