1use crate::{Error, ErrorCode, Rect};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Affine([f64; 6]);
8
9impl Affine {
10 pub const IDENTITY: Self = Self([1., 0., 0., 1., 0., 0.]);
11
12 pub fn values(self) -> [f64; 6] {
14 self.0
15 }
16
17 pub fn new(values: [f64; 6]) -> Result<Self, Error> {
19 if values.iter().any(|value| !value.is_finite()) {
20 return Err(invalid("变换矩阵包含非有限值"));
21 }
22 Ok(Self(values))
23 }
24
25 pub fn point(self, point: [f64; 2]) -> Result<[f64; 2], Error> {
27 let [a, b, c, d, e, f] = self.0;
28 let [x, y] = point;
29 let result = [a * x + c * y + e, b * x + d * y + f];
30 if result.iter().any(|value| !value.is_finite()) {
31 return Err(invalid("点变换产生非有限坐标"));
32 }
33 Ok(result)
34 }
35
36 pub fn then(self, next: Self) -> Result<Self, Error> {
38 let [a, b, c, d, e, f] = self.0;
39 let [g, h, i, j, k, l] = next.0;
40 Self::new([
41 g * a + i * b,
42 h * a + j * b,
43 g * c + i * d,
44 h * c + j * d,
45 g * e + i * f + k,
46 h * e + j * f + l,
47 ])
48 }
49
50 pub fn inverse(self) -> Result<Self, Error> {
52 let [a, b, c, d, e, f] = self.0;
53 let determinant = a * d - b * c;
54 if determinant == 0. || !determinant.is_finite() {
55 return Err(invalid("变换矩阵不可逆"));
56 }
57 Self::new([
58 d / determinant,
59 -b / determinant,
60 -c / determinant,
61 a / determinant,
62 (c * f - d * e) / determinant,
63 (b * e - a * f) / determinant,
64 ])
65 }
66
67 pub fn rect(self, rect: Rect) -> Result<Rect, Error> {
69 let [left, bottom, right, top] = rect.into();
70 bounds(&[
71 self.point([left, bottom])?,
72 self.point([left, top])?,
73 self.point([right, bottom])?,
74 self.point([right, top])?,
75 ])
76 }
77}
78
79pub fn page_transform(bbox: Rect, rotation: u16) -> Result<Affine, Error> {
81 let [left, bottom, right, top] = bbox.into();
82 if right <= left || top <= bottom {
83 return Err(invalid("页面框必须有正面积"));
84 }
85 Affine::new(match rotation {
86 0 => [1., 0., 0., -1., -left, top],
87 90 => [0., 1., 1., 0., -bottom, -left],
88 180 => [-1., 0., 0., 1., right, -bottom],
89 270 => [0., -1., -1., 0., top, right],
90 _ => return Err(invalid("页面旋转必须为 0/90/180/270")),
91 })
92}
93
94pub fn bounds(points: &[[f64; 2]]) -> Result<Rect, Error> {
96 let first = points.first().ok_or_else(|| invalid("几何点集为空"))?;
97 let mut values = [first[0], first[1], first[0], first[1]];
98 for [x, y] in points {
99 if !x.is_finite() || !y.is_finite() {
100 return Err(invalid("点集包含非有限值"));
101 }
102 values[0] = values[0].min(*x);
103 values[1] = values[1].min(*y);
104 values[2] = values[2].max(*x);
105 values[3] = values[3].max(*y);
106 }
107 Rect::try_from(values)
108}
109
110pub fn intersect(first: Rect, second: Rect) -> Result<Rect, Error> {
112 let [a, b, c, d] = first.into();
113 let [e, f, g, h] = second.into();
114 let left = a.max(e);
115 let bottom = b.max(f);
116 Rect::try_from([left, bottom, c.min(g).max(left), d.min(h).max(bottom)])
117}
118
119fn invalid(message: &str) -> Error {
121 Error {
122 code: ErrorCode::InvalidInput,
123 message: message.into(),
124 }
125}