# TrapMap完整图片导出与终端日志开关设计

## 目标

为`MovementTest.Trapmaptest.cs`增加两个相互独立的测试开关：

- 成功建图后，将完整栅格地图独立渲染为300 DPI PNG，不依赖Clumsy当前视口、缩放或其他Painter。
- 控制TrapMap调试信息是否同步打印到宿主进程终端，同时始终保留`DLog`日志。

现有`TrapMapTest` Painter初始化和清理已经使用世界坐标调用`UI.GetPainter("TrapMapTest")`，本次不重复修改。两腿检测ROI继续使用车体局部Painter及`false`参数。

## 用户开关与默认值

在`TrapMapTest`手动编辑区增加：

```csharp
private const bool _saveFullMapImage = true;
private const bool _enableTerminalDebugLog = true;
```

两个值传入`TrapMapBuilder`或共享日志/导出组件。关闭图片开关时不得创建目录、临时文件或PNG。关闭终端开关时只抑制`Console.WriteLine`，不得抑制`DLog`和必要的UI提示。

## 图片内容

图片从最终发布的`GridMapData`离屏渲染，包含完整地图边界而不是屏幕截图：

- 白色背景。
- 浅灰色完整栅格线，确保每个小格可见。
- 红色占用栅格。
- 蓝色车辆轮廓、几何中心和朝向。
- 绿色工作站目标标记。
- 黑色地图外边界。
- 标题/图例区域，显示世界边界、分辨率、行列数、占据率、障碍物数量、轮胎层状态和输入来源。

世界X轴在图片中向右；世界Y轴向上，因此从`Cells[row,col]`映射到位图时反转图像Y方向。工作站仅绘制标记，不写入占用数据。

## 图片尺寸与文件约束

- 每个栅格使用`4×4`像素。
- PNG水平和垂直DPI都设置为`300`。
- 包含边距和标题后，任一图片边长不得超过`4000`像素。
- 最终PNG文件大小不得超过`50 * 1024 * 1024`字节。

尺寸在分配RGBA像素缓冲区前检查。若超过4000像素，跳过导出并报告明确原因。编码先写入同目录临时文件，完成后检查实际字节数；超过50MB时删除临时文件，不留下超限最终文件。只有所有检查通过后，才原子移动/重命名为最终PNG。

典型`327×139`地图的栅格主体约为`1308×556`像素，另加标题和边距。

## 保存位置与命名

输出根目录使用宿主进程当前工作目录：

```text
TrapMapExports\TrapMap_yyyyMMdd_HHmmss_fff.png
```

毫秒时间戳避免同一秒多次测试覆盖。目录只在图片开关打开且地图成功后创建。临时文件使用同目录、同文件名加`.tmp`后缀，以保证最终重命名不跨磁盘。

## 日志行为

引入TrapMap专用日志入口，其行为为：

```text
所有消息 -> DLog.Log(message, "TrapMapTest")
终端开关开启 -> 额外Console.WriteLine("[TrapMapTest] " + message)
```

至少覆盖测试开始、输入参数、Detour位姿、车辆尺寸、地图边界/尺寸、轮胎层状态、图片保存成功/跳过/失败、最终统计和测试停止。图片错误不得因终端开关关闭而静默，仍必须进入`DLog`。

## 组件边界

图片导出放在独立文件`ClumsyPilot/TrapMapImageExporter.cs`，避免继续扩大已经较长的MovementTest文件。组件只消费不可变的导出请求数据：地图、车辆位姿、工作站、轮胎层元数据和目标文件路径；它不读取Detour、雷达或UI，也不修改栅格。

`MovementTest.Trapmaptest.cs`负责开关、调用时机、日志和错误降级。导出发生在地图成功生成之后；导出失败不改变`TrapMapBuilder.Succeeded`或`GridMap`。

实现使用内部纯C# RGBA光栅器绘制栅格、车辆、工作站和5×7位图文字，再由精确版本`StbImageWriteSharp` 1.16.7编码PNG。编码后立即在`IHDR`后插入`pHYs=11811/11811/unit1`，以保留300 DPI元数据。运行时不依赖平台绘图程序集或原生图形资产；除单个托管Stb编码程序集外，光栅、元数据和文件流程均只使用BCL。

## 错误处理

以下情况只导致图片导出失败，不导致建图失败：

- 图片开关关闭。
- 图片尺寸超过4000像素。
- 输出目录创建失败。
- RGBA缓冲区创建、绘制或PNG编码异常。
- 临时文件超过50MB。
- 临时文件重命名失败。

异常路径必须尽力删除本次临时文件，不得删除已有的成功PNG。

## 验证要求

至少验证：

1. 图片开关关闭时不创建文件和目录。
2. 小型已知栅格导出的PNG由BCL测试解码器重新读取；所有chunk CRC有效，`IHDR`为RGBA8，`pHYs`表示300 DPI，像素尺寸符合4像素/格及布局规则。
3. PNG中占用格、车辆和工作站采样位置颜色正确，Y轴没有上下颠倒。
4. 超过4000像素的请求在RGBA缓冲区分配前失败。
5. 最终路径使用毫秒时间戳且不覆盖旧文件。
6. 成功文件严格小于或等于50MB，超限临时文件被删除。
7. 终端开关开启时消息同时进入DLog和终端；关闭时仍进入DLog但不写终端。
8. 图片失败时地图仍为成功状态。
9. 现有源码契约、栅格行为、生命周期测试及`ClumsyPilot`编译继续通过。

## 非目标

- 不截取Clumsy/CycleGUI窗口。
- 不保存紫色UI背景、小车3D模型、绿色两腿ROI或橙色检测猜测线。
- 不改变栅格数据格式或地图边界计算。
- 不接入新的点云来源。
- 不修改`TrajPlanner`。
- 不提交或暂存本次工作区改动。
