Skip to main content

doc_quad/geom/
transform.rs

1// src/geom/transform.rs
2use glam::{Vec2, Mat3};
3
4/// 顶点排序与坐标变换
5pub struct Transformer;
6
7impl Transformer {
8    /// 将四个点排序为 [左上, 右上, 右下, 左下] 顺序。
9    ///
10    /// # 算法说明
11    /// 1. 计算四点质心。
12    /// 2. 基于各点相对质心的极角排序(图像坐标系 y 向下,atan2 产生顺时针顺序)。
13    /// 3. 旋转数组,使 x+y 最小的点(左上角)位于索引 0。
14    ///
15    /// # 坐标系说明
16    /// 输入为图像坐标系(y 轴向下)。atan2 在此坐标系下产生顺时针角度增长,
17    /// 排序结果为顺时针顶点序列,符合 [左上, 右上, 右下, 左下] 的预期语义。
18    pub fn sort_points(mut pts: [Vec2; 4]) -> [Vec2; 4] {
19        // P2 修复:移除不必要的 Instant 计时(sort_points 不在强制统计点列表中)
20
21        // 计算质心用于极角排序
22        let center = (pts[0] + pts[1] + pts[2] + pts[3]) * 0.25;
23
24        // P2 修复:将 unwrap() 替换为 unwrap_or,防止坐标含 NaN/inf 时 panic
25        pts.sort_by(|a, b| {
26            let angle_a = (a.y - center.y).atan2(a.x - center.x);
27            let angle_b = (b.y - center.y).atan2(b.x - center.x);
28            angle_a
29                .partial_cmp(&angle_b)
30                .unwrap_or(std::cmp::Ordering::Equal)
31        });
32
33        // 找到 x+y 最小的点(图像坐标系中最接近左上角的点)
34        // P2 修复:将 unwrap() 替换为 unwrap_or,防止坐标含 NaN 时 panic
35        let tl_idx = pts
36            .iter()
37            .enumerate()
38            .min_by(|(_, a), (_, b)| {
39                (a.x + a.y)
40                    .partial_cmp(&(b.x + b.y))
41                    .unwrap_or(std::cmp::Ordering::Equal)
42            })
43            .map(|(i, _)| i)
44            .unwrap_or(0);
45
46        // 旋转数组使左上角点位于索引 0
47        pts.rotate_left(tl_idx);
48
49        log::debug!(
50            "[Geom::Transform] - Points sorted: {:?}",
51            pts.map(|p| (p.x, p.y))
52        );
53
54        pts
55    }
56
57    /// 计算单应性矩阵(Homography),将透视四边形映射到标准矩形。
58    ///
59    /// # 算法说明
60    /// 标准实现需解 8×8 线性方程组 Ah=b(DLT 算法),利用 SVD 求最小二乘解。
61    /// 当前为占位实现,返回单位矩阵。
62    ///
63    /// # 参数
64    /// - `src`:源四边形顶点,顺序为 [左上, 右上, 右下, 左下]
65    /// - `dst_w`、`dst_h`:目标矩形宽高
66    ///
67    // TODO(feat): 实现 DLT 算法求解单应性矩阵,需引入 SVD 分解。
68    //             可考虑使用 nalgebra crate 或手动实现 4 点 DLT。
69    pub fn get_homography(_src: [Vec2; 4], _dst_w: f32, _dst_h: f32) -> Mat3 {
70        Mat3::IDENTITY
71    }
72}