//! 共享的二维点和矩形值。命中判断在调用方完成坐标系转换后使用,矩形本身不隐式处理相机。 //! 调用路径:布局与 viewport 生成点/矩形,文档命中先做坐标逆变换再调用 contains;软件渲染也用它们表达设备区域。 //! 这里只是数值容器,不隐式校验/夹取/做相机变换;有限性和尺寸合法性在各协议入口检查。 //! #[derive(Clone, Copy, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)] /// 二维坐标值;具体处于逻辑、局部还是设备空间由调用上下文决定。 pub struct Point { // 横坐标原值,单位与空间由构造方约定。 pub x: f32, // 纵坐标原值,不假定一定是世界向上或屏幕向下。 pub y: f32, } impl Point { /// 直接保存二维坐标;不缩放、不舍入,也不检查有限性,调用方负责坐标空间和输入校验。 pub const fn new(x: f32, y: f32) -> Self { Self { x, y } } } #[derive(Clone, Copy, Debug, Default, PartialEq)] /// 轴对齐矩形,保存原点和宽高,用于布局、裁剪与命中。 pub struct Rect { // 左侧原点,在同一坐标系中与 point.x 比较。 pub x: f32, // 顶部原点,在同一坐标系中与 point.y 比较。 pub y: f32, // 横向长度,不存储右端点;contains 使用 x+width。 pub width: f32, // 纵向长度,不存储下端点;调用方负责非负尺寸约定。 pub height: f32, } impl Rect { /// 直接保存左上角和宽高;不归一化负尺寸,布局调用方需先产生合法边界。 pub const fn new(x: f32, y: f32, width: f32, height: f32) -> Self { Self { x, y, width, height, } } /// 用闭区间比较判断点是否命中,左右上下边缘都计入;调用前需将点转换到矩形所在空间。 pub fn contains(self, point: Point) -> bool { // 闭区间四边比较;自身不处理裁剪叠加、圆角或世界面板遮挡,这些属于更上层命中流程。 point.x >= self.x && point.x <= self.x + self.width && point.y >= self.y && point.y <= self.y + self.height } } #[cfg(test)] mod tests { use super::*; #[test] /// 矩形左上/右下边界均包含,刚越过左边界的点排除,固定基础命中边界策略。 fn rectangle_contains_edges_but_not_outside_points() { // 同时验证左上和右下边界被包含,以及仅越过左边界的小偏差也会被排除。 let rect = Rect::new(10.0, 20.0, 30.0, 40.0); assert!(rect.contains(Point::new(10.0, 20.0))); assert!(rect.contains(Point::new(40.0, 60.0))); assert!(!rect.contains(Point::new(9.9, 20.0))); } }