台球与反射
在多边形台球桌里打一颗球。撞边的反弹公式长得非常复数: v′ = e2iφ·conj(v) —— 先共轭(镜像)、再乘旋转把方向摆回边的倾角。 打开「施瓦茨展开」,桌子沿命中边一路镜像复制,曲折的轨迹立刻被拉成一条直线。
球桌预设
弹射
—动手
拖 白点 = 球桌顶点(桌形即时更新)· 拖 橙点 = 起点 · 拖 青点 = 瞄准方向。任意改动即刻重算整条轨迹。
- 球与轨迹
- 瞄准方向
- 桌面 / 展开副本
反弹为什么是 e^{2iφ}·conj(v)
- 先把坐标系摆正:乘 e−iφ 让边落在实轴上。
- 对实轴镜像 = 共轭:conj。入射角与出射角就此对称。
- 再乘 eiφ 摆回来。合成 e2iφ·conj(v) —— 反全纯,恰是"镜像"该有的代数。
展开视图里发生了什么
不折球路,折桌子:每次撞边后把整张桌关于命中边镜像,球沿直线穿进副本。 这条直线就是「施瓦茨展开」——世界里的每次反弹,对应展开世界里跨过一条桌边。 展开位移是一个复数:位移 = 2 × (各边向量按反射链旋转后的和的一半),正方形的水平往返就是纯平移。
正方形的有理斜率(如 1/2)闭轨、正三角形的 Fagnano 三重点轨道 —— 都是这条直线的周期性在说话。 角全是有理倍 π 的多边形,轨道必周期;直角等腰三角形是展开铺满平面的典型。
凹桌:展开法失灵,光线投射依然正确
换成 L 形或箭头形 的凹桌,展开视图就不好使了:镜像副本会与原桌重叠——直线穿过"副本" 时,分不清它对应的是桌子的哪个部分,拉直的等价性被破坏。但反弹的物理规律一条没变: 每次碰撞仍是 e2iφ·conj(v)。本引擎取"最近边界交点"作命中边, 这对任意简单多边形(凹或凸)都成立——球永远先撞上离它最近的那面墙,所以凹桌轨迹与凸桌同一套代码算出。
凹桌带来两个凸桌没有的怪脾气:① 锐角死角——凹进去的尖角是个陷阱,球一旦进入夹角 < π/n 的窄角区, 每次反弹都把它更紧地弹向角尖,轨迹无限收窄、渐近地困在顶点附近(数值模拟里表现为在角内反复折返)。 这也是拖顶点时引擎拒绝自交、要求"简单多边形"的原因: 蝴蝶结状自交桌连"哪面墙最近"都没有确定答案。② 阴影区——L 形的两臂互为视线盲区, 一条边能不能被"直接看见"要逐边判定;周期轨判定倒是不变:看的是(命中点+出射方向)这个状态是否重现, 与桌子凹凸无关。
键盘
空格 发射 · U 切换展开视图 · P 找周期轨 · B 最佳周期轨。