feat(review): 几何干涉检查 find_collisions(BVH 粗筛 + 容器过滤)

C++(cad_mcp_plugins):
- 新增 bvh.h:header-only 2D BVH(质心中位分割,叶<=4,SelfPairs 交叉对枚举)
- 新增 find_collisions.cpp:粗筛 AABB 相交实体对,附重叠盒 + 逐轴重叠比 ratio
  (= 逐轴重叠长/较短长 之积,退化轴取 1.0),按 ratio 降序 + 分页;
  narrow=true 只对返回页跑 intersectWith 细筛(附 exact)
- 容器过滤(关键):图框块/分区边界会与一切相交,用重叠【度】判定
  deg >= max(exclude_container_deg=8, exclude_container_frac=0.25 * 其他实体数),
  与图幅/缩放无关;被剔除者在 excluded_containers 里如实报告
  (初版用面积判据对多图框并排失效:3 框只占并集 27/13/7% 全部漏过,
   全模型 163 对噪声;改度判据后图框 deg=35/25/23 vs 其余 deg<=3,分离干净)
- cmakelists.txt + 两个 mcp_config.json 注册(28 工具)

agent 侧(Python):
- cad_tools.READ_ONLY_TOOLS += find_collisions(受控子循环可调用)
- checks.check_collisions + run_deterministic_checks(受 CHECK_COLLISIONS 开关,默认关)
- config += CHECK_COLLISIONS=False / COLLISION_MIN_OVERLAP=0.5
- checklist.py / review_checklist.json += 「干涉/碰撞」类别(high)+ 提示词协议
  (先 find_collisions 拿候选 → inspect_region 目视确认;AABB 相交 != 真干涉)

验证:
- verify_collisions.py 17/17 PASS:全模型候选 163→80(全部 ratio=0.000),
  min_overlap=0.5 → 0 对;逐图框 0 对;narrow top-5 中 4 条 exact=true;
  --inject 注入深重叠矩形报出 ratio=0.902 并清理 2/2
- pytest 355 passed(新增 12 项)
- 端到端:LLM 主动调用 find_collisions{min_overlap:0.2,narrow:true,window:<图框>},未误报
This commit is contained in:
gjm committed 2026-10-16 19:46:44 +08:00
1 parent a77a090281
commit d4a9442e30
20 files changed
+1152 -13

No files matched your search

+10 -5
View File
@@ -29,11 +29,16 @@ type: feedback
- **Why:** 用户(2026-10-14)明确要求:「以后遇到 cad 没有运行的情况,就直接打开,
运行你的测试就行,我已经设置好了自动加载」。自动加载确实已配好。
- **How to apply:** PowerShell 里
`Start-Process "C:\Program Files\Autodesk\AutoCAD 2020\acad.exe"`,再轮询 8080
(实测约 10 秒内监听)。自动加载链路:`bin/Debug-R230/acad.rx`(内容一行
`cad_mcp_frame.arx`)+ 该目录已在 CAD 的搜索/信任路径中。
**注意**:CAD 默认打开的是**空模板**(0 图元、无图框),端到端审查会因
「未识别到任何图框」提前退出;要跑完整审查需另开一张真实图纸。
`Start-Process "C:\Program Files\Autodesk\AutoCAD 2020\acad.exe" -ArgumentList '/p','SHS-ENVI2026','e:\desktop\agent_test.dwg'`,
再轮询 8080(实测**数秒内**即监听,AutoCAD 2020 热启动很快)。自动加载链路:
`bin/Debug-R230/acad.rx`(内容一行 `cad_mcp_frame.arx`)+ 该目录已在 CAD 的搜索/信任路径中。
**`/p SHS-ENVI2026` 不可省**——否则 Plant 3D 自定义实体(`AECDBEW*`)**不显示**,
截图里是空的;`e:\desktop\agent_test.dwg` 是标准真实测试图纸(3 图框 / 86 实体)。
**注意**:不带图纸参数时 CAD 打开的是**空模板**(0 图元、无图框),端到端审查会因
「未识别到任何图框」提前退出。
**重建插件后必须先 `Stop-Process acad -Force`**(DLL 被占用会 LNK1168),再重启。
另:AutoCAD 2019(R23.0)也装了同名 profile,但**实际使用的是 2020(R23.1)**——
MRU 里 `E:\desktop\agent_test.dwg` 属 2020。
## 调试用 R230 + Debug,不用 Release
+57 -2
View File
@@ -1,6 +1,6 @@
---
name: Agent 路线与多源架构(2026-10-15)
description: dwg_review agent 的总目标、多源图纸分层架构(视觉为最大公约数)、工具层与 agent 层的正交分工、多源证据层、截图去 UI、grounding 实测、热力图 + 自适应瓦片规划 + VLM 分辨率标定、绘图区最大化(set_drawing_area)与空瓦片过滤、审查阶段分辨率对齐、agent 侧虚拟工具 inspect_region(放大取证闭环)、后续路线
description: dwg_review agent 的总目标、多源图纸分层架构(视觉为最大公约数)、工具层与 agent 层的正交分工、多源证据层、截图去 UI、grounding 实测、热力图 + 自适应瓦片规划 + VLM 分辨率标定、绘图区最大化(set_drawing_area)与空瓦片过滤、审查阶段分辨率对齐、agent 侧虚拟工具 inspect_region(放大取证闭环)、几何干涉检查 find_collisions(BVH + 容器过滤)、后续路线
type: project
---
@@ -93,6 +93,7 @@ Agent 推理层(审查逻辑 / 清单 / 规则)
(只回 handle/type/bbox、放开 limit),**而不是新增"热力图工具"**。
- `CollisionDetection.h/cpp`(用户写的 BVH)**本步不用**,留作后续**几何相交/干涉检查**引擎。
其按质心中位分割 → 节点框**可能重叠**,不适合铺屏瓦片;瓦片切分用四叉树/网格(空间不相交)。
(**2026-10-16 已落地**:见下文「C2:几何干涉检查 `find_collisions`」——重写了 header-only 2D BVH。)
- 标定判据:**同时测「读出文字」与「分辨线细节」**;标定字高 **200 图形单位**(1:100 = 纸面 2mm,国标最小)。
**已落地(提交 `9b8a232` 热力图;`cba05b0` 瓦片规划 + 离线标定)**:
@@ -145,7 +146,8 @@ Agent 推理层(审查逻辑 / 清单 / 规则)
- **实测收益(屏幕 3440×1440)**:绘图区 **2110×462 → 3310×1084**(面积 **3.68×**),
窗口矩形 `[68,0,2316,960]` → `[-4,-2,3444,1442]`,还原**精确回位**。
- 验收脚本:`verify_drawing_area.py`(基线 → max → restore,断言矩形/最大化态/绘图区尺寸全回位)。
- 工具注册:`mcp_config.json` 的 `tools[]`(现 **27** 个),工厂 `CreateSetDrawingAreaTool`。
- 工具注册:`mcp_config.json` 的 `tools[]`(`set_drawing_area` 加入时 **27** 个;后加 `find_collisions` 现为 **28** 个),
工厂 `CreateSetDrawingAreaTool`。
`set_drawing_area` 以 `set_` 开头 → 被 `cad_tools.is_write_tool` 判为写类(不重试),
且**不在** `READ_ONLY_TOOLS` 里 → LLM 的受控子循环**不能**动用户界面。
@@ -244,3 +246,56 @@ LLM 在受控子循环里 zoom + 截图拿到的是**未最大化的 2110×462**
- **验收口径达成**:报告报出标题栏**乱码/占位字符 `???????????????`**,
而 `get_text_content` 对全图返回 **0 条文字**(本图文字全在块/自定义实体内)——
即**块内文字是被视觉放大读出来的**,不是结构化数据给的。
## C2:几何干涉检查 `find_collisions`(2026-10-16)
**方向选择**:用户拍板「C 两个都做,C2 先(BVH → MCP 工具)」;并说明目录里的
`CollisionDetection.h/cpp` 是**参考例子**(可用可重写)。分析后:其中纯 ObjectARX 的
`AABB/EntityProxy/BVHTree`(约 1~367 行)可移植,其余(`needCD` 领域过滤 + MFC 对话框)
依赖用户 App 私有头文件(不在仓库),故**只重写 BVH 内核**。
**新增(C++,`src/cad_mcp_plugins/`)**:
- `bvh.h`:header-only 2D BVH(`namespace dwg_bvh`)。质心中位分割(取较长轴,
`std::nth_element`),叶 ≤ `kLeafSize=4`;`SelfPairs` 枚举相交对(叶内 `i<j` + 子树交叉)。
- `find_collisions.cpp`:`mcp_Tool_FindCollisions`,`EXPORT_MCP_TOOL` 导出。
参数:`window/layer_filter/limit/offset`(通用)+ `min_overlap` / `narrow` /
`include_same_layer` / `exclude_oversized` / `exclude_container_deg` / `exclude_container_frac`。
- **`ratio` = 逐轴重叠比之积**;某轴重叠比 = 该轴重叠长 / 两实体该轴**较短**长,
任一方该轴退化为 0 时取 1.0。于是共线相接→0、横管穿阀门→≈1。
- 按 `ratio` 降序 + 分页;`narrow=true` 只对**返回页**跑 `AcDbEntity::intersectWith` 细筛(附 `exact`)。
- 返回 `{total, returned, offset, entity_count, items[], excluded_containers[]}`。
**关键调参发现:容器(图框块)过滤必须用「重叠度」而非「面积」**。
初版用面积(`exclude_oversized` 相对**实体并集**)——3 张图框并排在模型空间里,
union 面积极大,图框只占 27%/13%/7%,**全部漏过** → 全模型 86 实体产生 **163 对候选**,
top 全是 `INSERT/40B × 一切` 且 ratio=1.0(图框完全包住小实体),`min_overlap=0.99` 仍剩 83 对。
实测重叠**度**分布:**图框 deg=35/25/23,其余实体全部 deg≤3**(分离极干净)。
故新增容器过滤:`deg >= max(exclude_container_deg=8, exclude_container_frac=0.25 × 其他实体数)`
→ 剔除其全部配对并在 `excluded_containers` 里**如实报告**(含 reason=oversized/container)。
**与图幅/缩放无关**,窗口态与非窗口态都生效。
**实测(真实 Plant 3D 图纸 `agent_test.dwg`,86 实体,`verify_collisions.py` 17/17 PASS)**:
- 全模型候选 **163 → 80**,且 80 对**全部 ratio=0.000**(仅管线接口相接);
`min_overlap=0.5` → **0 对**;逐图框(window)同样 0 对 → 本图**无真实干涉**(真阴性)。
- 容器过滤剔除 3 个 INSERT(deg 35/25/23,reason=container)。
- `narrow` 细筛:top-5 里 **4 条 `exact=true`**(接口处 pipe/fitting 真的几何相交)——
与 ratio=0.0 一致:**相交但未深度重叠**。
- **注入式正例**(`--inject`,画 2 个深重叠矩形于图框外 → 应报出 → 删除):
报出 `ratio=0.902`(= (380/400)²,与理论一致),清理 2/2 成功。
**agent 侧接入**(Python):
- `cad_tools.READ_ONLY_TOOLS` 加 `find_collisions` → LLM 受控子循环可调用(写类判定不受影响)。
- `checks.check_collisions` + `run_deterministic_checks`:受 `CHECK_COLLISIONS` 开关控制,
**默认关闭**(AABB 相交噪声大,平面图里管线穿墙/引线跨图元属正常相交),
改由 LLM 按「干涉/碰撞」清单条目**按需**调用;`COLLISION_MIN_OVERLAP` 默认 0.5。
产出的 issue `category="干涉"`(清单新增类别,输出枚举同步加「干涉」)。
- `checklist.py` / `review_checklist.json`:新增「干涉/碰撞」类别(severity=high),
提示词写明「先 `find_collisions` 拿候选 → 对可疑 handle 用 `inspect_region` 目视确认,
**AABB 相交 ≠ 真干涉**」。
**端到端实测(`python -m dwg_review --frames 1`)**:清单显示 **6 类**(含干涉/碰撞);
LLM 在受控子循环里**主动调用** `find_collisions {'min_overlap': 0.2, 'narrow': True,
'limit': 60, 'window': <图框>}`,并结合 `inspect_region`;最终**未误报干涉**(正确真阴性)。
**待办**:C1(PDF / 图片源适配,见「后续路线」第 2 条)仍未做。
+1
View File
@@ -48,6 +48,7 @@ type: reference
| `verify_text_resolution.py` | **CAD 实测**标定(临时加字 + 平行线,测完 `delete_entities` 清理);`--keep` 保留 |
| `verify_drawing_area.py` | 绘图区最大化验收:基线 → `set_drawing_area(max)` → `restore`,断言窗口矩形/最大化态/绘图区尺寸全回位(实测 3.68×) |
| `verify_review_maximized.py` | 审查全链路验收:在 `collect`/`review_frame` 入口各采一次窗口矩形,断言**取证与审查两阶段都在最大化态**、结束精确还原;并统计子循环 zoom/截图次数 + 记录 LLM 实际调用的取证工具(含虚拟工具 `inspect_region`) |
| `verify_collisions.py` | `find_collisions` 验收:工具注册 / 全模型与逐图框粗筛 / **容器过滤**(图框块剔除)/ `min_overlap` 阈值 / 分页 / `narrow` 细筛 / `--inject` 注入干涉正例(画 2 个深重叠矩形 → 应报出 ratio≈0.902 → 清理)。**只读**(`--inject` 段除外,会自动清理) |
> 历史:根目录 `test.py` / `test_autoagent.py` / `countOfCircle.py` / `agent_loop.py` /
> `dwg_review_agent.py` 五个遗留调试脚本已于 2026-10-14 删除(前三个含硬编码 API Key,