AI 协作日志

学生 Web 实验作品平台

学号:202412211402009 · 来源:ai-log.md

# 实验二 AI协作记录

> 协作工具:豆包(AI 助手)。全程以"先自己写与判断、再让 AI 辅助解释与排错、最后用运行结果核验"的方式完成。以下仅记录影响代码走向的关键协作,核心代码均经本人阅读、测试并能在本地运行。

---

## AI协作1 · Koch 算法:凸起方向与 3×4ⁿ 线段数

### 我的目标与初步判断
我要独立实现 `subdivideSegment`:算三等分点 P、Q,再算向外凸出的等边三角形顶点 R。我最初判断"底边(从左到右)的凸起应指向下方(向外)",所以猜测需要对向量 `Q-P` 做顺时针(-60°)旋转;但我不确定三条边都满足"向外",想先验证再写。

### 关键提示词(原文)
> "Koch 雪花中,三角形顶点按逆时针排列、边沿逆时针行走时,外凸应该用 +60° 还是 -60° 旋转 Q-P 来求 R?如何用一段水平线或打印点坐标来验证?为什么第 n 层线段数是 3×4ⁿ?"

### AI关键建议摘要
- 对逆时针多边形,内部在行走方向的**左侧**,因此"向外"在行走方向的**右侧**,应对 `Q-P` 做**右转 60°**(即 -60°)。
- -60° 旋转公式:`x' = c·x + s·y`,`y' = -s·x + c·y`,其中 `c=cos60°=0.5`,`s=sin60°=√3/2`。于是 `R = P + 旋转(-60°, Q-P)`。
- 递归:Level n 把一条线段换成 4 段,所以 3 条边 → `3×4ⁿ` 段;每段在 Level 0 只 push 起点,用 `LINE_LOOP` 即可自动闭合。

### 我的测试方法与结果
1. 先在纸上对底边 `A(-0.82,-0.43)→B(0.82,-0.43)` 验证:`R` 的 y 应为约 `-0.90 < -0.43`,即凸起在底边下方(向外)✓。
2. 用一段临时 Node 脚本打印 `buildKoch` 各层的点数,并与预期表核对:

| Level | 脚本输出 | 预期 3×4ⁿ | 一致 |
|---|---:|---:|---|
| 0 | 3 | 3 | ✓ |
| 1 | 12 | 12 | ✓ |
| 2 | 48 | 48 | ✓ |
| 3 | 192 | 192 | ✓ |
| 4 | 768 | 768 | ✓ |

3. 用鞋带公式算有向面积为 **正**,证明顶点顺序为逆时针、图形闭合且方向正确。

### 采纳情况及修正结论
采纳 AI 的 -60° 右转方案,并保留 `c=0.5, s=√3/2` 代入计算;同时自己确认了 `A→P→R→Q→B` 的递归顺序能保证顶点连续、线段数吻合。结论:凸起方向由"逆时针边 + 向外=右转"决定,且层数与数据量关系经打印坐标验证成立。

---

## AI协作2 · 绘图板调试:Y 轴翻转与两次点击状态

### 具体错误现象(如一次成功,可先人为注入并恢复一个小错误)
第一次实现时点击 Canvas 右上角,点却出现在左下角——典型的 Y 轴方向相反。我先人为保留这个错误(不翻转 Y),复现现象后再修复,最后恢复正确实现,验证 Bug Hunt 闭环。

### 我的初步排查
我怀疑 `pointerToNDC` 里没有做 Y 翻转:NDC 的 y 向上为正,而 Canvas 像素 y 向下为正,所以 `yNDC = 1 - 2·yCanvas/height` 而不是 `2·yCanvas/height - 1`。另外担心是否应直接用 `clientX/Y`。

### 关键提示词(原文)
> "Task D 点击位置上下相反,可能原因是什么?如何用 getBoundingClientRect 把 clientX/clientY 正确换算成 WebGL 的 NDC 坐标?两次点击的 firstPoint 状态在哪些情况下会残留导致画错图形?"

### AI建议与逐项测试
AI 给出三条排查项,我逐条测试:
1. **坐标来源**:`clientX/Y` 是相对浏览器窗口的,必须减去 `rect.left/top` 再按 `canvas.width/rect.width` 缩放,不能直接当 NDC —— 采纳。
2. **Y 翻转**:`yNDC = 1 - 2·yCanvas/height`。故意先不翻转 → 复现"上下相反";加上翻转后四角点击定位正确 —— 采纳并作为根因修复。
3. **firstPoint 残留**:切换工具或清空时必须 `firstPoint=null`,否则旧第一点被复用。逐项测试后确认两处事件(`tool change` 与 `clear`)都已重置 —— 采纳。

### 最终原因及修复证据
根因是缺少 Y 轴翻转(画布像素坐标与 NDC 的 y 方向相反)。修复后:在画布四角附近分别创建点,位置均正确;先画一点、一线、一矩形后再画新图形,旧对象不消失;清空后旧图形不再出现。人为注入的错误已移除,最终实现为:
```js
const xCanvas=(event.clientX-rect.left)*canvas.width/rect.width;
const yCanvas=(event.clientY-rect.top)*canvas.height/rect.height;
return [2*xCanvas/canvas.width-1, 1-2*yCanvas/canvas.height];
```

---

## AI协作3 · 主题整合:方案比较与取舍

### 主题及预期效果
主题词选 **生长(Growth)**:以一个 Koch 雪花作为"生物轮廓",同心生长环象征年轮/生长阶段,向外伸展的枝条与叶表达"向外生长"。预期:改变"生长阶段"滑块能看到环数和枝条长度同步变化,点击画布可移动生长中心。

### 两个方案的AI提示词(原文)
> "请用基本 WebGL 图元(LINE_LOOP/LINES/POINTS)为'生长'主题设计两种整合方案:方案一要复用 Task B、C、D,至少两个新增几何组成、至少两条交互;比较两者的图元数量、交互难度与可解释性。"

### 方案比较、取舍理由
| 维度 | 方案一:同心环 + 枝条叶 | 方案二:多圈嵌套雪花 + 轨迹点 |
|---|---|---|
| 图元数量 | LINE_LOOP×若干 + LINES + POINTS,较少 | 嵌套雪花本身点量大,较多 |
| 交互难度 | 低:滑块/点击即生效 | 中:轨迹点需维护历史数组 |
| 可解释性 | 高:环数、枝长与"生长阶段"一一对应 | 中:轨迹更偏"轨迹"主题 |

**取舍**:选方案一。理由:环数与枝条长度能直接由"生长阶段"这一几何参数驱动,解释最清楚、图元开销小、运行更稳;方案二的嵌套雪花会让顶点数据量随层数迅速膨胀,且与示例"绽放"风格更接近,区分度不足。

### 实际实现、测试与结果
- **新增几何1**:`buildRings()` 生成 `2+growth` 个同心生长环(96 边形 `LINE_LOOP`),半径随 `scale` 与序号变化。
- **新增几何2**:`buildBranches()` 生成 6 根两段式枝条(`LINES`)+ 枝梢等边三角"叶"(`LINE_LOOP`),枝条长度随 `growth` 增长。
- **新增交互**:① 点击画布 → 用 `getBoundingClientRect` 转 NDC 移动中心(仅改 `uOffset` uniform);② 新增"生长阶段"滑块 → 改变环数与枝长(重新生成并上传顶点)。另复用 C 的开始/暂停旋转与 B 的 Koch 生成。
- **验证**:初始态与拖动"生长阶段"0→5 后对比,生长环从 2 圈增至 7 圈、枝条明显伸长,且整体可旋转、点击后中心移动正确。新几何分别位于 `js/task-e.js` 的 `buildRings`/`buildBranches`,交互位于 `growthInput` 事件与 `canvas click` 事件。

---

## 其他实际使用的AI协作(如有)
- Task A:咨询"改 Level 应重新生成并上传顶点,改颜色只需更新 uniform"的差异,并用 Level 1/4 截图确认三角数量 `3ⁿ` 正确。
- Task C:咨询 `requestAnimationFrame` 用时间戳差算 `dt` 以避免帧率差异,采纳 `dt = min((time-lastTime)/1000, 0.1)`,并确认只允许一个动画循环(点击开始仅改 `paused` 状态,不重复启动 rAF)。