# 二维图查错工具流程

四类查错流程的边界见：`../DIAGNOSTIC_FLOW_BOUNDARIES.md`。本目录只负责二维零件图和二维装配图相关流程；三维零件/装配体的 B-rep 提取、接触功能语义和规则判定在 `tools/model-diagnostics` 下处理。

本目录是二维工程图查错相关工具。当前确定采用的主流程是：

1. 用 AutoCAD 提取学生 DWG 的主视图几何签名。
2. 用 SolidWorks 从三维模型生成 24 个候选主视图，并逐个导出为 DWG。
3. 再用 AutoCAD 串行提取这 24 个候选 DWG 的几何签名。
4. 用类型、尺寸数值、方向信息、相对中点坐标等特征排序，确定学生主视图对应的 SolidWorks 视角。


## 当前保留工具

### AutoCadDwgExtractor

位置：`AutoCadDwgExtractor`

连接 AutoCAD，读取 DWG 实体并输出结构化 JSON。它负责：

- 提取 `line`、`circle`、`arc`、`polyline`、`hatch`、文字、尺寸、公差、粗糙度等对象。
- 将 polyline 展开成基础线段/圆弧。
- 对共线、连续、重叠或部分重叠的线段做强合并和重叠关系记录。
- 选择主视图并输出主视图几何。
- 生成用于匹配的 `main-view-signature.json`。

主视图选择有两种有效模式：

- 默认模式：用于学生 DWG。先排除图框，从 `minX` 最小、同等情况下 `maxY` 最大的线段作为左上角种子线，按几何连通关系扩展，再吸收包围盒内部孤立圆孔/圆弧。
- `--main-view-seed-mode solidworks-candidate`：用于 SolidWorks 导出的单候选 DWG。先找外框边线，扩展出图框和标题栏连通块并排除，剩余几何作为候选视图。

签名里关键字段：

- `primitive_counts`：图元类型数量。
- `line_direction_counts`：水平、竖直、斜线数量。
- `line_length_histogram`：线长直方图。
- `circle_radius_histogram`、`arc_radius_histogram`、`arc_length_histogram`：圆和圆弧特征。
- `relative_line_coordinates`：相对坐标特征。原点取主视图中最左侧竖直线段的最上点，每条直线记录相对于该原点的中点坐标。

### SolidWorksViewCandidateGenerator

位置：`SolidWorksViewCandidateGenerator`

从 SolidWorks 零件或装配体生成 24 个候选主视图：

- 6 个观察方向：`+X`、`-X`、`+Y`、`-Y`、`+Z`、`-Z`。
- 每个方向绕屏幕法向旋转 `0`、`90`、`180`、`270` 度。

当前只保留推荐用法：`--export-candidate-dwgs-sequential`。它会在当前工程图中每次只放置一个候选视图，按 `1:1` 比例导出一个 DWG，随后删除该视图，再处理下一个候选。这样不会打开 24 个工程图窗口，也不会让候选视图互相重叠。

输出：

- `candidate-result.json`：执行结果。
- `candidate-views.json`：24 个候选视图的方向、旋转角、DWG 路径、保存状态。
- `candidate-dwgs/`：逐个导出的候选 DWG。

### ExtractCandidateDwgsSequential.ps1

位置：`SolidWorksViewCandidateGenerator/ExtractCandidateDwgsSequential.ps1`

读取 `candidate-views.json`，逐个打开候选 DWG，调用 `AutoCadDwgExtractor` 提取签名，然后关闭当前 DWG。脚本会先构建一次提取器，再运行编译后的 DLL，避免每个候选都 `dotnet run` 导致速度和 AutoCAD COM 稳定性问题。

### RankExtractedCandidateDwgs.ps1

位置：`SolidWorksViewCandidateGenerator/RankExtractedCandidateDwgs.ps1`

读取学生主视图签名和 24 个候选签名，输出排序文件：

- 默认输出：`candidate-ranking-relative.json`
- 当前权重：
  - `primitive_counts`: 0.15
  - `line_direction_counts`: 0.15
  - `line_length_histogram`: 0.15
  - `circle_radius_histogram`: 0.03
  - `arc_radius_histogram`: 0.03
  - `arc_length_histogram`: 0.04
  - `relative_midpoint_histogram`: 0.30
  - `relative_feature_histogram`: 0.15

相对中点坐标是现在区分旋转方向的关键特征。之前只靠类型、长度和方向时，前几名分数太接近。

### DwgSheetFrameAligner

位置：`DwgSheetFrameAligner`

将学生 DWG 的整张图纸平移到 SolidWorks 图纸坐标系下。工具会：

- 从 SolidWorks 导出的参考 DWG 中识别图框内圈中心。
- 从学生 DWG 中识别图框内圈中心。
- 计算两个中心的差值。
- 复制学生 DWG 到输出路径。
- 对输出副本中的 `ModelSpace` 和 `PaperSpace` 全部实体执行整体平移。

注意：它不是只移动图框内框，而是移动学生图纸中的所有对象，包括外框、内框、标题栏、视图、标注、文字、块参照等。

### SolidWorksHoverProbe

位置：`SolidWorksHoverProbe`

保留的独立调试工具。它连接当前打开的 SolidWorks 工程图，监听鼠标悬停和动态高亮事件，打印预选对象、选择对象、视图和组件归属信息。它只用于人工排查 SolidWorks 悬停对象来源，不参与当前主流程的 DWG 导出、DWG 签名比较、图框中心对齐或主视图平移。

网格读取模式：

```powershell
dotnet run --project tools\drawing-diagnostics\SolidWorksHoverProbe\SolidWorksHoverProbe.csproj -- `
  --grid `
  --step-mm 1 `
  --output "D:\CSharpProjects\agent4\runtime\solidworks-hover-grid\grid-ownership.jsonl"
```

默认按当前工程图 sheet 尺寸以 1 mm 间隔扫描，尝试选择 `EDGE,EXTSKETCHSEGMENT,SKETCHSEGMENT,ANNOTATION`，只输出命中的点。需要输出空白点时加 `--include-empty`；调试时可加 `--max-points 1000` 限制扫描点数。

如果只想扫描模型视图范围，跳过标题栏、图框等空白区域：

```powershell
dotnet run --project tools\drawing-diagnostics\SolidWorksHoverProbe\SolidWorksHoverProbe.csproj -- `
  --grid `
  --views-only `
  --step-mm 1 `
  --types EDGE,EXTSKETCHSEGMENT,SKETCHSEGMENT `
  --output "D:\CSharpProjects\agent4\runtime\solidworks-hover-grid\grid-ownership-views.jsonl"
```

悬停读取模式会先调用 SolidWorks `ViewZoomtofit2()` 执行整屏显示全图，再读取 sheet 到屏幕的线性映射，然后移动鼠标读取 `GetPreSelectedObject()`：

执行 `--hover-grid` 或 `--print-sheet-origin` 前，工具会先调用 `SetFeatureManagerWidth(0)` 隐藏左侧 FeatureManager/特征树边栏，再执行整屏显示全图，避免左侧边栏影响绘图区坐标映射。

```powershell
dotnet run --project tools\drawing-diagnostics\SolidWorksHoverProbe\SolidWorksHoverProbe.csproj -- `
  --hover-grid `
  --views-only `
  --step-mm 1 `
  --hover-delay-ms 80 `
  --zoom-fit-delay-ms 500 `
  --output "D:\CSharpProjects\agent4\runtime\solidworks-hover-grid\hover-grid-views.jsonl"
```

校准工程图原点和主视图屏幕矩形：

```powershell
dotnet run --project tools\drawing-diagnostics\SolidWorksHoverProbe\SolidWorksHoverProbe.csproj -- `
  --print-sheet-origin `
  --zoom-fit-delay-ms 500
```
## 标准执行流程

### 1. 提取学生 DWG 主视图

```powershell
dotnet run --project tools\drawing-diagnostics\AutoCadDwgExtractor\AutoCadDwgExtractor.csproj -- `
  --drawing-path "D:\Desktop\新建文件夹\毕设\二维图\A2_肘关节装配.DWG" `
  --output-dir "D:\CSharpProjects\agent4\runtime\dwg-main-view\A2_肘关节装配_relative_signature" `
  --visible true `
  --close-after-extract true
```

重点检查：

- `main-view-selection.json`
- `main-view-normalized-geometry.json`
- `main-view-merged-lines.json`
- `main-view-signature.json`

### 2. 用 SolidWorks 导出 24 个候选 DWG

要求：SolidWorks 已经打开三维模型和一个工程图，工程图纸尺寸按需要设为 A2。

```powershell
dotnet run --project tools\drawing-diagnostics\SolidWorksViewCandidateGenerator\SolidWorksViewCandidateGenerator.csproj -- `
  --model "D:\Desktop\新建文件夹\毕设\建模\小臂肘关节装配\小臂肘关节.SLDASM" `
  --use-active-drawing `
  --export-candidate-dwgs-sequential `
  --output-dir "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1"
```

规则：

- 一个候选视图一个 DWG。
- 每次只保留当前候选视图。
- 保存成功后删除当前候选视图。
- 默认比例是 `1:1`。
- 如果保存失败，会重建并重试，默认不跳过。

候选顺序：

- 01-04：`+X`，roll `0/90/180/270`
- 05-08：`-X`，roll `0/90/180/270`
- 09-12：`+Y`，roll `0/90/180/270`
- 13-16：`-Y`，roll `0/90/180/270`
- 17-20：`+Z`，roll `0/90/180/270`
- 21-24：`-Z`，roll `0/90/180/270`

### 3. 串行提取 24 个候选 DWG

```powershell
powershell -ExecutionPolicy Bypass -File tools\drawing-diagnostics\SolidWorksViewCandidateGenerator\ExtractCandidateDwgsSequential.ps1 `
  -CandidateViewsJson "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\candidate-views.json" `
  -OutputRoot "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\autocad-extractions-relative" `
  -Visible
```

脚本会对每个候选传入：

```text
--main-view-seed-mode solidworks-candidate
--close-after-extract true
```

### 4. 排序确定主视图视角

```powershell
powershell -ExecutionPolicy Bypass -File tools\drawing-diagnostics\SolidWorksViewCandidateGenerator\RankExtractedCandidateDwgs.ps1 `
  -TargetSignaturePath "D:\CSharpProjects\agent4\runtime\dwg-main-view\A2_肘关节装配_relative_signature\main-view-signature.json" `
  -CandidateExtractionRoot "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\autocad-extractions-relative" `
  -CandidateViewsJson "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\candidate-views.json"
```

本次实测结果：

- 第一名：`agent4_candidate_04_px_r270`
- 方向：`+X`
- 旋转：`270` 度
- 分数：`0.421348`
- 第二名：`agent4_candidate_02_px_r90`
- 分差：约 `0.03559`

### 5. 在 SolidWorks 工程图中放置主视图

排序完成后，可以把第一名候选作为工程图主视图插入当前打开的 SolidWorks 工程图：

```powershell
dotnet run --project tools\drawing-diagnostics\SolidWorksViewCandidateGenerator\SolidWorksViewCandidateGenerator.csproj -- `
  --model "D:\Desktop\新建文件夹\毕设\建模\小臂肘关节装配\小臂肘关节.SLDASM" `
  --use-active-drawing `
  --place-main-view `
  --ranking-json "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\autocad-extractions-relative\candidate-ranking-relative.json" `
  --output-dir "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\placed-main-view"
```

本次实测已放置：

- 工程图视图名：`工程图视图212`
- 命名视图：`agent4_main_view_04_px_r270`
- 候选编号：`4`
- 方向：`+X`
- 旋转：`270` 度
- 比例：`1:1`
- 位置：图纸中心 `(0.297, 0.21)` 米

### 6. 对齐学生 DWG 到 SolidWorks 图框中心

用 SolidWorks 导出的候选 DWG 作为参考图纸，读取其图框内圈中心；再读取学生 DWG 的图框内圈中心，把学生 DWG 副本整体平移到一致位置：

```powershell
dotnet run --project tools\drawing-diagnostics\DwgSheetFrameAligner\DwgSheetFrameAligner.csproj -- `
  --reference-dwg "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\candidate-dwgs\04_agent4_candidate_04_px_r270.dwg" `
  --student-dwg "D:\Desktop\新建文件夹\毕设\二维图\A2_肘关节装配.DWG" `
  --output-dwg "D:\CSharpProjects\agent4\runtime\aligned-student-dwg\A2_肘关节装配_aligned_to_solidworks_frame.dwg" `
  --visible true `
  --close-after-align true
```

本次实测：

- SolidWorks 参考 DWG 图框内圈：`x=20~584, y=10~410`
- SolidWorks 参考内框中心：`(302, 210)`
- 学生 DWG 平移前内框中心：`(304.5, 210)`
- 平移量：`dx=-2.5, dy≈0`
- 学生 DWG 平移后内框中心：`(302, 210)`
- 被整体移动实体数：`1967`
- 输出副本：`runtime\aligned-student-dwg\A2_肘关节装配_aligned_to_solidworks_frame.dwg`
- 对齐报告：`runtime\aligned-student-dwg\A2_肘关节装配_aligned_to_solidworks_frame.align-report.json`

### 7. 对齐 SolidWorks 主视图到学生主视图原点

图框中心对齐后，学生 DWG 和 SolidWorks 工程图位于同一个图纸坐标框架中。下一步读取移动后学生图主视图中“最左侧竖直线段最上点”的绝对位置，并把 SolidWorks 工程图里的主视图整体平移到对应位置。

实际执行时不是移动单条线，而是修改 SolidWorks 工程图视图的 `IView.Position`，因此整个主视图会一起移动：

```powershell
dotnet run --project tools\drawing-diagnostics\SolidWorksViewCandidateGenerator\SolidWorksViewCandidateGenerator.csproj -- `
  --model "D:\Desktop\新建文件夹\毕设\建模\小臂肘关节装配\小臂肘关节.SLDASM" `
  --use-active-drawing `
  --align-main-view-origin `
  --student-signature "D:\CSharpProjects\agent4\runtime\aligned-student-dwg\extraction-check\main-view-signature.json" `
  --reference-signature "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\autocad-extractions-relative\04_agent4_candidate_04_px_r270\main-view-signature.json" `
  --main-view-orientation-name "agent4_main_view_04_px_r270" `
  --output-dir "D:\CSharpProjects\agent4\runtime\sw_candidate_dwg_1to1\aligned-main-view-origin"
```

本次实测：

- SolidWorks 工程图视图名：`工程图视图212`
- 命名视图：`agent4_main_view_04_px_r270`
- 学生主视图原点：`(45.990114407105125, 338.275336225917)` mm
- SolidWorks 候选 04 原点：`(229.50000000000037, 260.00000000000057)` mm
- 平移量：`dx=-183.50988559289524 mm, dy=78.27533622591642 mm`
- 平移前视图位置：`(0.297, 0.21)` m
- 平移后视图位置：`(0.11349011440710474, 0.2882753362259164)` m
- 输出报告：`runtime\sw_candidate_dwg_1to1\aligned-main-view-origin\candidate-result.json`

## 已废弃方法

- CAXA：接口能力不足，已放弃。
- 候选 DWG 中用中心点找种子线扩展：覆盖不稳定，已废弃。
- 候选 DWG 中显式识别右下角标题栏并删除：容易误删或漏删，已废弃。
- 学生 DWG 的同列吸收：会把不属于主视图的线吸进来，已废弃。
- 弱合并：会引入不可靠匹配，已废弃。

## 关键判断原则

匹配时不要依赖绝对起点/终点坐标，因为学生 DWG 和 SolidWorks 导出 DWG 的坐标系、插入位置可能不同。当前主要依赖：

- 图元类型数量。
- 线段长度分布。
- 线段方向分布。
- 圆和圆弧半径/弧长分布。
- 以主视图最左侧竖直线段最上点为原点的相对中点坐标分布。

后续如果要继续增强，可以在相对坐标基础上增加局部拓扑关系，例如“某个相对位置附近有哪些长度/方向组合”，但仍应保持两侧都从 AutoCAD DWG 提取。
# Canonical DWG alignment workflow

This is the required production flow. Do not use an old candidate DWG
signature as the final coordinate reference.

1. Extract the student DWG main-view signature for candidate ranking.
2. Generate and rank SolidWorks candidate views to choose the main-view
   orientation.
3. Place that main view in the currently opened SolidWorks drawing.
4. Export the current SolidWorks drawing to a fresh DWG.
5. Run `DwgSheetFrameAligner` with that freshly exported SolidWorks DWG as
   `--reference-dwg`; this aligns the whole student DWG copy by inner-frame
   center.
6. Extract the aligned student DWG with `AutoCadDwgExtractor` and save its
   `main-view-signature.json`.
7. Extract the freshly exported current SolidWorks drawing DWG with
   `AutoCadDwgExtractor` and save its `main-view-signature.json`.
8. Run `SolidWorksViewCandidateGenerator --align-main-view-origin` with:
   - `--student-signature`: the aligned student DWG signature from step 6.
   - `--reference-signature`: the current SolidWorks drawing DWG signature
     from step 7.
9. Export the current SolidWorks drawing to DWG again and re-extract it to
   verify the SolidWorks main-view origin matches the aligned student DWG
   origin.
10. Only after both alignments pass, run `view-regions.json` analysis for
    section views and other orthographic views.

Candidate DWGs under `runtime/sw_candidate_dwg_*/candidate-dwgs` are only for
orientation ranking. They are not valid references for final frame-center
alignment or main-view origin alignment.
