AI 协作日志

学生 Web 实验作品平台

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

# 实验二 AI协作记录

> 工具:Trae(AI 编程助手,模型 DeepSeek-V4.1-Flash)。本次 A—E 五个任务在同一会话中连续完成。
> 记录原则:保留我的原始提示词;AI 的建议单独列出;**每条建议都由我自己运行页面或跑数值自检后才决定采纳或修改**,测试结果与最终结论一并记录在下面。

## 总提示词(原文)

```text
C:\Users\Administrator\Desktop\新建文件夹\实验2_学号 阅读实验二,完成代码
```

我先让 AI 通读 `实验二.md` 和教师提供的学生填充版(`README-TODO.md` + 5 个 `js/task-*.js`),
再按 A→B→C→D→E 逐项填写 `TODO`。B 的 Koch 算法在 C、E 中复用同一实现。

---

## AI协作1 · Koch算法

### 我的目标与初步判断
原始 `subdivideSegment()` 里 `p=a; q=b; r=(a+b)/2`,`out.push(a)` 只输出一个点,等于什么都没剖分。
我先把规则写成公式再看方向:`P=A+(B-A)/3`、`Q=A+2(B-A)/3`、`R=P+rot(Q-P,θ)`,然后需要确定 `θ=+60°` 还是 `-60°`。
我的初步判断:底边 `(-0.82,-0.43)→(0.82,-0.43)` 方向为 `+x`,突起必须朝下,所以要把 `Q-P` 顺时针转 60°(即 `θ=-60°`)。
但教师给的初始三角形三条边方向不同(底边向右、两条斜边向右上/向左下),我不敢只按一张截图定方向。

### 关键提示词(保留原文)
```text
线段 A→B 的三等分点 P、Q 已算出,R 用 Q-P 旋转 ±60° 再加到 P 上。
怎么判断该用 +60° 还是 -60° 才能保证突起永远朝轮廓外侧?
其中 c=0.5, s=Math.sqrt(3)/2,允许直接使用这个 s。另外请说明 Level n 为什么是 3×4^n 段。
```

### AI关键建议摘要
1. 不要用“截图朝向”判断,用**绕行方向的右手法则**:初始三顶点按逆时针排列时,沿 `A→B` 走,外侧恒在前进方向的**右侧**;
   因此把 `Q-P` 顺时针旋转 60° 即得外凸点,对应 `R = P + (c·dx + s·dy, −s·dx + c·dy)`,其中 `c=0.5, s=√3/2`。
2. 递归终止只 `out.push(a)`(叶子线段只写起点),因为下一段的起点与前一段终点重合,
   于是三条初始边递归完得到一个有序点列,`LINE_LOOP` 的顶点数正好等于线段数 `3×4^n`。
3. 建议我用“面积是否变大”来验证方向,而不是只看图:向内凹会让面积变小,向外凸会让面积单调增大并收敛。

### 我的测试方法与结果
我没有直接相信结论,而是把这段算法原样用 Python 重写(`koch_check.py`)做数值核验:

| Level | 顶点数 | 应为 3·4^n | 有向面积 |
|---:|---:|---:|---:|
| 0 | 3 | 3 | 1.164400 |
| 1 | 12 | 12 | 1.552533 |
| 2 | 48 | 48 | 1.725037 |
| 3 | 192 | 192 | 1.801705 |
| 4 | 768 | 768 | 1.835780 |

- 顶点数与 `3×4^n` **逐层完全吻合**;每段长度实测等于“初始边长/3^n”(Level 1 实测 0.54666667 = 1.64/3)。
- 面积从 1.1644 单调增到 1.8358,符合 Koch 雪花收敛到 `(8/5)·A₀ = 1.863` 的理论值 → **凸起方向确实朝外**。
- 底边第一段的凸点实测为 `(0.0, −0.9034)`,y 明显小于底边 y=−0.43,即向下凸出,与我的初步判断一致。
- 最大半径只有 0.990 ≤ 1,Level 0—4 都不会被裁切。
- 浏览器实测:Level 0/2/4 分别显示 `Level 0 · 线段 3`、`Level 2 · 线段 48`、`Level 4 · 线段 768`,
  图形始终闭合、尖刺朝外,Level 4 未触及画布边缘。

### 是否采纳、修正后的结论
采纳 AI 的“右手法则 + 顺时针 60°”和“面积单调增大”验证思路,但我**把它的实现细节改成更短、且与教师框架一致的形式**:
用框架已经给出的 `c=0.5, s=Math.sqrt(3)/2` 直接写成 `r=[p[0]+c*dx+s*dy, p[1]-s*dx+c*dy]`。
经上表数值与浏览器双重验证,`buildKoch` 输出长度稳定为 `3×4^n`,方向朝外,结论确认。

---

## AI协作2 · 绘图板调试

### 具体错误现象
Task D 最难的是坐标与状态两件事。我按教师参考公式实现后,主动做了 **“错误注入”** 测试:
把 Y 翻转那一步临时注释掉(`yNDC = 2*yCanvas/H − 1`),看会发生什么。
(测试是在临时副本上做的,提交目录里的实现始终是正确的翻转版本。)

### 我的初步排查
我猜:不做 Y 翻转时,点击画布下方的点会被画到上方,而且**画布中心附近的点偏移很小、越靠边偏移越大**,因为只有 y 一项符号变了。

### 关键提示词(保留原文)
```text
我在 WebGL 画布里画点,鼠标点击位置和画出来的位置对不上。
task-d.js 里我按 getBoundingClientRect() 算 xCanvas、yCanvas,然后 xNDC=2*xCanvas/w-1、yNDC=1-2*yCanvas/h。
如果我把 y 的翻转去掉,会出现什么现象?怎么用一次点击就能快速判断是坐标换算错、还是 CSS 尺寸和 canvas 像素尺寸不一致?
另外:线段模式点了一次之后切换成矩形,半成品状态要怎么清理?
```

### AI建议及逐项测试
| AI 给出的可能原因 | 我的验证步骤 | 实测结果 |
|---|---|---|
| Y 轴未翻转,图形上下镜像 | 用与 `task-d.js` 相同的公式重新算一遍点击→NDC(`flip_check.py`),对比翻转/不翻转两种实现 | 右下角 `(690,590)`:正确实现 y=−0.903,注入错误后 y=+0.903,Δy=1.806;左上角同理反向;**画布中心 `(360,310)` 两者都是 0.000,完全看不出区别** → 证实“只有边缘才明显”的猜想 |
| CSS 尺寸 ≠ canvas 像素尺寸造成缩放误差 | 检查页面 CSS:canvas 只有 `max-width:100%`,在 720px 视口内按 1:1 显示;公式里仍除以 `rect.width/rect.height` 做兜底 | 实测四角点击,画出的点都落在点击位置,无偏移 |
| 两次点击之间 `firstPoint` 未清理 | 在浏览器中:线段模式只点一次(#status 变为“等待第二次点击”),再切到矩形,读 #status | 切换后 #status 立刻恢复为“等待点击;共 N 个对象”,**旧的第一点没有被复用**(`tool.change` 里做了 `firstPoint=null`) |
| 矩形只按 `a→b` 顺序画会出错 | 矩形模式故意先点右下角、再点左上角 | 生成正常轴对齐矩形,四边直角,没有出现交叉的“蝴蝶结” |

### 最终原因及修复证据
坐标映射本身没有 bug,但**“不翻转 Y” 会造成上下镜像**这一点被我用数值直接证实(Δy=1.806);
`task-d.js` 最终保留 `yNDC = 1 − 2*yCanvas/canvas.height`,并保留 `* canvas.width/rect.width` 这一层缩放兜底。
矩形用 `loX/hiX/loY/hiY` 归一化后按 `[lo,lo]→[hi,lo]→[hi,hi]→[lo,hi]` 输出四角,任意对角点击顺序都正确。
浏览器复测:4 个角点位置准确、线段颜色取自当前 `#color`、线段+矩形+点同时保留、点击“清空”后画布为空且 #status 为“共 0 个对象”,Console 无报错。

---

## AI协作3 · 主题整合

### 主题及预期效果
主题词定为 **“绽放”**。视觉含义:Koch 雪花边界作为旋转的“花心”,外面一圈花瓣缓缓反向转动,
花蕊由长短相间的放射线和节点组成,整体通过尺度滑块“张开/收拢”。
复用任务:Task B 的 Koch 顶点生成 + Task C 的 `requestAnimationFrame` 旋转与状态控制(另外复用 Task D 的鼠标坐标映射)。

### 两个方案的AI提示词(原文)
```text
Task E 我要做一个“绽放”主题,必须复用 B/C 的能力,并新增至少两个几何组成部分和至少两种交互。
请给我两个只用 WebGL 基本图元(LINES/LINE_LOOP/LINE_STRIP/POINTS)就能表达的方案,
分别说明各自的图元数量、交互难度和可解释性,我要选一个自己实现。
```

### 方案比较、取舍理由
| 方案 | AI 给出的几何构成 | 图元数量/数据量 | 交互难度 | 我的取舍 |
|---|---|---|---|---|
| 方案一(射线花) | 环形花瓣 + 放射线 + 节点 | 花瓣 6×18 点、射线 12 段、节点 13 点,共约 150 顶点;每帧 4 次 `bufferData` | 低:只需一个滑块改花瓣数 | 采用 |
| 方案二(N 次旋转叠加的花瓣,类似教材 Twist 思路) | 用多层旋转副本叠加出花瓣密度 | Level 4 时顶点数按层数倍增,容易上千 | 中高:需要额外维护层数与缩放列表 | **拒绝**:本质更接近复现教材的旋转变换,且顶点量随层数快速膨胀,可解释性不如方案一 |

拒绝理由具体化:方案二靠“多画几份旋转副本”撑画面,新增的几何规则其实只有一条(旋转+缩放),
而方案一的两组新增几何(花瓣参数曲线、花蕊射线+节点)各自都有独立的几何定义,更符合“新增至少两个可辨识几何组成部分”。

### 实际实现、测试与结果
新增几何(`js/task-e.js` 的 `rebuildDecor()` 与 `render()` 中的花瓣/射线/节点绘制调用):
1. **花瓣环**:每片花瓣在角度区间 `a0…a0+2π/p` 内满足 `r(t)=0.70+0.32·sin(πt)`,相邻花瓣端点重合,
   整体连成一条封闭的波浪形外环(`LINE_LOOP`,与花心反向以 `-theta*0.4` 缓慢旋转)。
2. **花蕊放射线 + 花药节点**:`2×petals` 条射线从 r=0.14 出发、长短相间(0.80 / 0.54),端点用 `POINTS` 标出节点。

新增/实质改变的交互:
- **按住拖动画布实时移动作品中心**(示例框架只有单击跳转一次):`mousedown`→`mousemove`→`mouseup`,`center` 实时更新并重绘;
- **花瓣数量滑块**(3—12):直接改变花瓣与射线的**几何顶点**,属于“几何数据变化”而非 uniform 变化。

浏览器实测结果:
- 初始 `#status` = `主题:绽放 · Koch线段 48 · 花瓣 6 · 尺度 0.62 · 中心(0.00,0.00)`,雪花+花瓣环+射线+节点全部可见且未裁切;
- 点击“开始旋转”后图案持续转动;花瓣数改成 10 后 `#status` 变为“花瓣 10”,花瓣与射线数量肉眼可见地改变(几何确实重新生成);
- 尺度调到 0.35 时整幅作品按中心等比缩小、形状不变;
- 拖动后 `#status` 的 `中心` 由 `(0.00,0.00)` 变为 `(0.10,-0.10)`,说明拖拽实时生效;
- “复位”后回到 `花瓣 6 · 尺度 0.62 · 中心(0.00,0.00)`;整个过程 Console 无报错。

---

## 其他AI使用(若有)
- 让 AI 逐行讲解了 `common/initShaders.js` 如何把 HTML 里的 `#version 300 es` 着色器取出并编译,确认实验要求的
  `in/out`、显式 `out vec4 fColor` 写法没有被教材旧语法(`attribute/varying/gl_FragColor`)污染。
- Task C 的动画循环结构由我自己检查:全页只有一处 `requestAnimationFrame(animate)`,`animate` 内部再排下一帧,
  不存在重复启动多个循环的问题;暂停时只把 `theta` 冻结、不重新上传 Buffer。
- 所有页面的 Console 报错、Level 数量、点击位置均由我自己在浏览器中打开页面复核,AI 的结论只有在与实测一致时才被采纳。