feat(tiling): CAD 实测标定 R_text/R_line + 瓦片粒度内容过滤 + 默认参数定稿

Stage B2(CAD 实测标定)与收尾:

- 新增 verify_text_resolution.py:临时加字(字高 200 图形单位 = 1:100 纸面 2mm)+
  平行线对,按目标像素换算 zoom 窗口 → 截图 → 问 VLM;测完 delete_entities 清理不保存。
- 标定结论:
  * **可读下限与字体强相关**——离线合成(Consolas 抗锯齿填充字体)12px;
    真实 CAD 单线体 .shx(描边字体)6px 即可读对(3/3,两轮)。
  * 线条「1 条 vs 2 条」:2/3/4px 失败,5/8/12px 成功 → R_line ≈ 5px。
  * **必须用 ACI 7 白字**:实测红字(ACI 1)12px 因对比度不足完全读不出。
- config 定稿:TEXT_READABLE_PX=8(折中)、LINE_READABLE_PX=6、
  EVIDENCE_MAX_IMAGES=12(原 5 会把规划结果截到只剩 4 张瓦片)。
- 新增 heatmap.occupied_boxes:占用格的**世界 bbox**。
- tiling.plan_regions 新增 keep 谓词;evidence._plan_tiles 按占用格剔除**空瓦片**
  (簇 bbox 是包围盒,L 形/斜向分布含大片空白,实测有效)。
- 测试:test_heatmap 补 occupied_boxes;test_tiling 补 keep 过滤;全量 286 项全绿。
- 真实图纸端到端验证:A0 图框出 12 张(1 整体 + 11 瓦片),单框审查 1m38s 通过。
- 记忆库同步:工具语义坑(type_filter 必须传列表 / layer_filter 是通配字符串 /
  add_* 返回句柄在 created 键)、标定结论与默认值。
This commit is contained in:
gjm committed 2026-10-15 23:22:15 +08:00
1 parent cba05b0c65
commit 9c4ab62dc1
9 files changed
+454 -11

No files matched your search

+6 -2
View File
@@ -236,7 +236,7 @@ def subdivide(box, cols, rows, overlap=0.0, frame_win=None):
def plan_regions(frame, clusters, *, text_clusters=(), s_text=0.0, s_line=0.0,
view_px=(0, 0), max_tiles=36, overlap=0.0):
view_px=(0, 0), max_tiles=36, overlap=0.0, keep=None):
"""把图框内的簇规划成一组 zoom 窗口(自适应瓦片)。
参数:
@@ -246,7 +246,9 @@ def plan_regions(frame, clusters, *, text_clusters=(), s_text=0.0, s_line=0.0,
- `s_text`/`s_line`:CAD 图形单位 / 像素(`world_per_px` 的输出);
- `view_px` :单张截图的**有效像素** (ew, eh)(`effective_px` 的输出);
- `max_tiles` :返回窗口数硬上界(文字簇优先保留);
- `overlap` :相邻瓦片重叠比例。
- `overlap` :相邻瓦片重叠比例;
- `keep` :可选谓词 `f(window) -> bool`,返回 False 的瓦片被丢弃。
用于按**占用格**剔除簇 bbox 内的空白瓦片(簇 bbox 对 L 形/斜向分布含大片空白)。
返回行优先的 window 列表;**无法规划时返回 []**(调用方退回固定策略)。
"""
@@ -278,6 +280,8 @@ def plan_regions(frame, clusters, *, text_clusters=(), s_text=0.0, s_line=0.0,
cols, rows = tiles_for_box(box, cap_w, cap_h, overlap)
# 单屏可覆盖 → 1 张(subdivide 仍会按 overlap 外扩并夹到图框)
for win in subdivide(box, cols, rows, overlap, frame_win):
if keep is not None and not keep(win):
continue # 该瓦片落在空白区,不出图
regions.append(win)
if len(regions) >= max_tiles:
break