-
YAML 元数据 已设置 tags: [KACTL, 几何, 核心实体]。
-
核心概述 在二维中,将点 p 按直线 ab 的方向作正交投影;可选 refl=true 以返回 p 关于该直线的镜像对称点,时间 O(1)。
-
原文引述
Projects point p onto line ab. Set refl=true to get reflection of point p across line ab instead. Status: stress-tested
- 展开阐述
-
定义与背景
- 投影(projection):把点 p 沿着直线 ab 的法向“垂下去”,落到直线 ab 上得到最近点 proj(p)。
- 反射(reflection):关于直线 ab 的镜像点 refl(p),满足直线 ab 是线段 p–refl(p) 的中垂线。
- 常见场景:最近点查询、光线反射与法线反弹、到线段的最短距离计算、与半平面/裁剪等模块组合。
-
接口/字段说明(据实现)
- 函数签名:template
P lineProj(P a, P b, P p, bool refl=false) - a,b:定义直线的两点(需 a≠b)
- p:待投影/反射的点
- refl:false 返回投影;true 返回反射
- 几何量含义与单位:
- v = b − a:直线方向向量
- v.perp():把 v 旋转 90° 得到法向(长度同 |v|)
- v.cross(p−a):p 相对 ab 的有向面积(底为 |v|),单位为“长度²”
- v.dist2() = |v|²:作归一比例的分母
- 返回点坐标单位与输入坐标一致
- 函数签名:template
-
核心流程/要点(向量分解与公式)
- 方向与法向
- 令 v = b − a,n = v.perp(),则 n 是 ab 的法向
- 投影/反射统一公式
- 返回值:p − n * (1 + refl) * (v.cross(p−a)) / |v|²
- refl = 0(投影):减去法向分量的 1 倍,落到直线上
- refl = 1(反射):减去法向分量的 2 倍,实现镜像
- 返回值:p − n * (1 + refl) * (v.cross(p−a)) / |v|²
- 与参数化的一致性
- 亦可用参数 t = dot(p−a, v)/|v|²,投影点为 a + v*t;上式等价且避免重复 dot 计算(直接使用 cross 与 perp)
- 方向与法向
-
复杂度与边界条件
- 时间复杂度:O(1)
- 退化:
- 若 a==b,则 |v|²=0,直线未定义;调用前需规避
- 数值注意:
- 中间涉及“三坐标乘积”与除法;若 P=Point
且结果不为整数,会因整除截断返回错误点(文件注释已指出) - 建议在整数坐标大值域或高精度要求下使用 long double/double 版本
- 近退化 |v|² 很小会放大误差;工程上以 eps 判断并分支处理
- 中间涉及“三坐标乘积”与除法;若 P=Point
-
变体与扩展
- 点到射线/线段的投影:
- 先按直线投影得到参数 t = dot(p−a, v)/|v|²
- 射线:裁剪 t 至 [0, +∞);线段:裁剪 t 至 [0,1],得到最近点
- 最近距离/最短向量可与 032-几何-点线距离 的分子/分母共用缓存
- 多次反射/镜像:在光线追踪/几何光学中可迭代调用,注意累计误差与终止条件
- 法向与切向分解:在动力学与碰撞中,把速度分解到切/法方向,配合“反射=法向分量取反”实现弹性反弹
- 点到射线/线段的投影:
-
正确性要点与不变式
- 向量分解直觉:p−a 可分解到切向 v 与法向 n 上;投影/反射仅修改法向分量的大小/符号
- 交替性质:refl(refl(p)) = p(对同一直线重复反射两次回到原点)
- 正交性:p−proj(p) 平行于法向 n;proj(p) 在 ab 上
-
与相邻技术的对比和取舍
- 032-几何-点线距离:距离的有向/无向量化度量;本函数直接返回坐标点,互为补充
- 034-几何-直线相交:当需要与另一条线/边相交点时,应切换到线与线求交
- 047-几何-线段间距离:线段最近距离内部即包含“对端点的投影再裁剪”的模式
- 049-几何-点在直线哪侧:由 cross 符号判侧,常与投影/反射的法向选择配合
-
工程实践注意
- eps 策略:比较“是否落在线上/哪一侧/是否顶点接触”时应统一阈值
- 预计算与缓存:批量调用时缓存 |v|²、其倒数 invLen2、以及 n,可显著降低常数
- 坐标系一致性:保证输入坐标单位一致;必要时在变换/投影前统一坐标系或执行归一化
- 关联节点