# Four-bar linkage：连续角度驱动案例

固定支点 A、D，保持三条活动杆长度不变，仅修改 AB 相对 AD 的有向角度。B、C 的新位置由同一个草图连续求解，上一次成功解作为下一步初值。

![四杆机构的实际求解轨迹与选定构型](../../docs/images/four-bar-motion.svg)

## 运行

需要项目要求的 MoonBit 工具链（`moonc >= 0.10.15`）：

```sh
moon run examples/four_bar
```

输出一条机构配置记录和 25 条姿态 JSON Lines。驱动角度从 0° 以 15° 步长到 180°，再从 165° 返回 0°；初始及转向姿态各只计一次。每一步都检查杆长、角度、装配分支和求解报告，检查失败会以非零状态退出。

如安装了 Node.js 18+，可执行第二次独立验证及图形再生成：

```sh
node scripts/four_bar_showcase.cjs --check
node scripts/four_bar_showcase.cjs --check --target wasm
node scripts/four_bar_showcase.cjs --write
```

默认使用 JS 后端，另接受 `wasm`、`wasm-gc`。检查脚本运行真实 MoonBit 示例，通过解析几何独立核对所有姿态、往返位置、固定支点、约束句柄和逐约束残差。SVG 使用实际返回坐标绘制，并以相同生成逻辑检查提交图形是否过期。

原始数据保存于：

- `_build/showcase/four-bar-js.json`：配置、25 个姿态、约束编号与全部残差。
- `_build/showcase/four-bar-js.csv`：角度、方向、A/B/C/D 坐标、求解状态与局部自由度。
- 使用其他后端时，文件名中的 `js` 对应替换为 `wasm` 或 `wasm-gc`。

图中细点线表示 13 个前进姿态的 B、C 轨迹；粗线显示 90°，浅色显示 0° 与 180°。右侧三个构型使用真实求解坐标。绘图保留三位小数，解析核对在舍入之前执行。

## 尺寸与构造

本例采用毫米作为长度单位，逆时针角度以度显示、以弧度传给求解器。

| 对象 | 设定 |
| --- | --- |
| 固定支点 A | (0,0) |
| 固定支点 D | (80,0)，即地杆 AD=80 |
| 曲柄 AB | 30 |
| 连杆 BC | 70 |
| 摇杆 CD | 50 |
| 角度驱动 | 从有向地杆 AD 到有向曲柄 AB 的 `Angle` |

AD=80 是案例选定的地杆长度。B 到 D 的距离始终在 50～110 之间，严格满足两圆交点条件 20 < BD < 120，因此所展示的角度范围避开共线肘节。参数检查也排除退化长度组合；这只是案例的输入范围，并未给核心库新增不等式约束。

[main.mbt](main.mbt) 使用四个点、四条线及六条关系：

| 关系 | 方程数 |
| --- | --- |
| `Fix(A,0,0)`、`Fix(D,80,0)` | 4 |
| `Distance(A,B,30)`、`Distance(B,C,70)`、`Distance(C,D,50)` | 3 |
| `Angle(AD,AB,theta)` | 1 |
| 合计 | 8 |

四点共 8 个标量变量。启用角度驱动时有 8 个方程，满足解的局部自由度为 0；暂时禁用 `Angle` 后有 7 个方程，局部自由度为 1。示例用 `solve()` 检查未驱动状态，不应用另一个构型，然后恢复原角度句柄继续运行。

## 同一草图上的连续编辑

`FourBar::advance()` 只替换原 `Angle` 关系，然后调用 `solve_and_apply()`；不重建 `Sketch`，不逐帧设置 B 或 C 的坐标。几何句柄、三条长度约束和一个角度约束的编号全程保留。

初值中的 C 位于有向 B→D 的左侧，选择一个装配分支。后续每一步检查：

```
cross(D-B, C-B) > 0
```

这里的“上分支”指相对有向 B→D 的这一侧，不是对所有尺寸或角度都要求 `C.y` 大于某个常量。镜像装配是另一组合法解，本例不把它误判为无解。

| 驱动角度 | B 坐标 | C 坐标 |
| --- | --- | --- |
| 0° | (30,0) | (79,49.989999) |
| 90° | (0,30) | (67.532779,48.420743) |
| 180° | (-30,0) | (35.909091,23.579477) |

表中为实际姿态的舍入结果。返回相同角度时再次与前进姿态核对，坐标差不超过 5e-6。原始完整精度可从 JSON 或 CSV 查看。

## 独立解析核对

MoonBit 案例与 Node 检查脚本各自实现一个只用于校验的解析参考：

1. 根据 AB 长度和目标角度计算参考 B=(30 cos(theta),30 sin(theta))。
2. 将 C 表示为以 B 为圆心、半径 70，以及以 D 为圆心、半径 50 的两圆交点。
3. 取满足正有向叉积的交点，与返回的 C 比较。
4. 另从返回坐标独立测量 AB、BC、CD、AD，核对固定点和角度，并检查每条启用关系的残差达到容差。

这些解析公式不用于逐步更新初值或覆盖求解坐标。求解过程仍由核心库的距离和角度方程完成。

[four_bar_wbtest.mbt](four_bar_wbtest.mbt) 另验证驱动启停的自由度变化，并以 AD=60、AB=20、BC=50、CD=40 的另一组尺寸在相反装配分支做往返求解，覆盖不同于主案例的几何构型。原有的 21 个曲柄位置回归仍保留在 [numerics_wbtest.mbt](../../numerics_wbtest.mbt)。

## 验证与应用边界

CI 在四个后端运行测试，并在 wasm 与 JS 上核对 25 个姿态及 SVG。源码包检查确认案例、图、说明与脚本进入分发包，并从解包后的源码运行机构示例和独立验证。

本例展示给定驱动角度下的**运动学位置序列**，没有时间积分、速度、加速度、质量、载荷或碰撞求解。离散步进和分支检查证明的是这些已验证姿态，不是任意初值、任意步长或任意机构的全局追踪保证。
