Files
endorphin-tessera-gui/src/render/geometry.rs
T

71 lines
3.1 KiB
Rust

//! 共享的二维点和矩形值。命中判断在调用方完成坐标系转换后使用,矩形本身不隐式处理相机。
//! 调用路径:布局与 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 {
// 闭区间四边比较;自身不处理裁剪叠加、圆角或世界面板遮挡,这些属于更上层命中流程。
// 相邻矩形共享边缘时两者都可命中,Frame/工具命中调用方按绘制顺序选目标;这里不负责消除重叠。
// 零宽/零高矩形也可能命中其线段/端点;要求正面积的裁剪或视口调用方必须另外判断尺寸。
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)));
}
}