智能分区(Intelligent Segmentation)设计 · 初版方案(待 REFUTE)
迭代目标(来自用户):实现"真正理解特征"的多算法可配置分区;参考切片引擎与图形学找轮廓; 做 3D 或 3→2→3 的真实特征识别;提供用户微调能力;以 golden samples 为验收标准。 本文件为 PLAN 阶段初版,尚未实现。下一步交给对抗子 agent 证伪。
0. 现有基础(来自代码调研,file:line 见 agent 报告)
segment/mod.rs仅 4 行pub mod,无统一 trait / 抽象 —— 多算法调度的天然空位。- 已有两个 auto 命令:
auto_segment(dihedral,segment/dihedral.rs:75)、auto_segment_smart(SDF,sdf.rs:339)。 - 签名不统一:
segment_by_dihedral_angle(mesh, f32, &ProgressFn)vssegment_by_sdf(mesh, u32)(无 progress)。 - 真实 bug:
sdf.rs:30-72的consistent_normals会永久改写mesh.normals;之后若再跑 dihedral,法线已被翻转 → 多算法串联会污染。 SegmentResult(commands/segment.rs:22-28)已是通用返回体;前端updateSegmentLabels/aSegLabelshader 高亮 /SegmentsPanel零改动即可复用。- 不变量:算法必须写
mesh.segment_labels(长度==faces.len())并rebuild_segments();自动分割后mesh.history.clear();auto 标签 <MANUAL_SEGMENT_OFFSET(100_000);label 0 是合法分区。 - 测试现状:dihedral 0 测试;sdf 5 个;manual 9 个;无
tests/目录(全内联#[cfg(test)])。 - 依赖:
nalgebra 0.33、petgraph 0.6、kiddo 4、stl_io 0.7(仅 STL)。无 OFF/OBJ loader,无 parry3d。
1. 统一接口(最小改动集)
segment/mod.rs 新增:
pub enum SegmentationAlgorithm {
Dihedral { angle_threshold: f32 }, // 现有,包一层
ShapeDiameter { k: u32, cone_rays: u32, cone_half_angle: f32 }, // 现有 sdf,补 progress
CurvatureKMeans { k: u32, smoothing_iters: u32, use_sdf: bool }, // 新增
MultiView { views: u32, grid_res: u32, normal_tol: f32 }, // 新增 3→2→3
// ConcaveDecomp { .. } // 推迟(需 parry3d/V-HACD,重依赖)
}
pub fn run_segmentation(
mesh: &mut MeshModel,
algo: &SegmentationAlgorithm,
on_progress: &ProgressFn,
) -> Vec<Segment>;
- 两个旧命令保留(参数透传),新增
auto_segment_v2(algorithm_json, params_json)复用SegmentResult。 ProgressFn = dyn Fn(f32, &str) + Send + Sync(沿用loader.rs:6),所有算法必须 emit 进度(修 SDF 无进度)。
2. 算法 A:Dihedral(保留现有,仅包接口)
dihedral.rs 不动逻辑,仅让 run_segmentation 调用它。默认 angle_threshold=30.0 收口到一处(消除 useTauriCommand.ts:41 / Toolbar.tsx:89,105 三处硬编码)。
3. 算法 B:ShapeDiameter(改进现有 SDF)
- 给
segment_by_sdf加on_progress,分 4 阶段 emit(锥形射线 / 空洞插补 / kmeans / 凹度合并)。 - 修副作用:
consistent_normals改为不写回mesh.normals(返回 oriented 副本供 SDF 内部用),避免污染 dihedral 的后续调用。 - 凹度合并阈值
0.93提为命名常量SDF_CONCAVITY_DOT。 - 性能:删除
sdf.rs:387在区域对循环内重复遍历edge_references()的 O(clusters²×E) 路径(改为预构建 RAG,与 dihedral 同构)。
4. 算法 C(新增):CurvatureKMeans —— 几何/曲率特征聚类
动机:dihedral 只看二面角(平/曲),无法区分"厚装甲板 vs 细肢体""凸球面 vs 平面"。SDF 是厚度特征。把多特征联合聚类才能"理解特征"。
- 逐面特征向量(全部归一化到 ~[0,1] 或 z-score):
f = [mean_curvature, gaussian_curvature, |SDF|, normal·principalX, normal·principalY, normal·principalZ]- 曲率用离散 Laplace-Beltrami(nalgebra 构造 cotangent 权重 Laplacian,
mesh.normals+face_adjacency)。 - 主方向用模型级 PCA(nalgebra
SymmetricEigen)固定全局坐标系 → 法线投影稳定。
- 曲率用离散 Laplace-Beltrami(nalgebra 构造 cotangent 权重 Laplacian,
- 可选
smoothing_iters:Laplacian 平滑法线/曲率后再聚类(抗 STL 噪声;survey 指出曲率对噪声敏感)。 - K-means(Lloyd,20 轮,k-means++ 初始化:
k由用户配置,默认 6)。 - 连通性保证(关键):纯 K-means 会产生空间不连通的"碎片簇"。后处理:用
face_adjacency做区域邻接图(RAG),对每对相邻、但被分属不同簇的面,按"特征距离 + 边界长度"贪心合并小簇到大邻居(与 dihedral 的normal_consistency_merge/merge_small_regions_fast同构,复用其框架)。最终每个 label 是连通分量,匹配人类"部件"语义。 - 阈值出处:合并 dot 阈值沿用 dihedral 的
MERGE_NORMAL_DOT_THRESHOLD=0.93(≈22°),与现有行为一致;smoothing_iters默认 1(轻量)。
5. 算法 D(新增):MultiView 3→2→3 —— 多视角投影分割
动机:用户明确说"先 3→2,处理,再 2→3"。切片引擎(Orca/Prusa)靠"可见性 + 投影"做支撑/接缝绘制;SAMesh(2024) 用多视角渲染→SAM→回投→图社区检测得到部件分割。我们做经典版(无 SAM/PyTorch,纯 Rust):
- 投影(3→2):取
views个相机(PCA 对齐后沿包围球均匀分布,如 6 或 12 方向;用 nalgebra 构造正交投影矩阵)。逐面质心投影到 (u,v),记录depth(沿视线)、face_normal、所属面 id。 - 2D 分割:对每个视角,把面按 (u,v) 落到
grid_res×grid_res栅格;仅最近深度面占据该栅格单元(解决自遮挡歧义)。在同一单元及 8-邻域内、且法线夹角 <normal_tol的面聚为同一 2D 区域(连通分量标记)。 - 回投+融合(2→3):每个面获得一组"各视角 2D 区域 id"。构建面图:若两面在任一视角同属一个 2D 区域则连边;对该图做 union-find / 轻量社区检测(petgraph)得到最终 3D 部件。
- 为什么有效:平面装甲板在多视角下投影稳定成大片连通 2D 区;球面在每个视角是圆盘;分叉肢体在多数视角被"颈"分开 → 多视角融合自然切出部件。与 SAMesh "render→2D mask→match graph→community detection" 架构一致,只是 2D 前端从 SAM 换成经典连通分量。
- 理论风险(待 REFUTE):薄特征在少数视角被遮挡 → 该视角无标签;靠多视角覆盖 + 融合缓解。栅格分辨率与
normal_tol是需调的旋钮。
6. ConcaveDecomp(V-HACD)—— 推迟
- parry3d 的 V-HACD 是"近似凸分解",概念上最贴近"把模型拆成可制造的部件(球体/护甲片)",但引入 parry3d 是重依赖(simba/crossbeam/大量几何代码),且
vhacd-rs绑定陈旧(2017)。 - 决定:本轮不做,列入 backlog;若后续要"工业级部件分解"再单独评估(可能用
vhacd-rs子仓库或自研体素分解)。
7. 用户微调交互(前端)
- 新增
IntelligentSegmentPanel(参考BrushSettings.tsx的 docked 面板样式 +appStore的brushRadius持久化模式):- 算法
<select>(Dihedral / ShapeDiameter / CurvatureKMeans / MultiView)。 - 动态参数滑块:角度(dihedral)、k/rays( SDF)、k/smoothing(Curvature)、views/grid/tol(MultiView)。
- 运行按钮 →
invoke("auto_segment_v2", {...})。
- 算法
- 微调能力:分割后在
SegmentsPanel支持"合并选中分区""拆分选中分区(按连通分量)""重命名";并可调参后一键重跑(mesh.history.clear()已处理撤销)。 - 交互形态:用户说"弹窗或直接切视口都行" → 采用 docked 可折叠面板 + 高级参数 popover(非强制模态),与现有工具栏风格一致;不引入独立视口切换以免破坏 R3F 渲染状态。
8. 验收标准:Golden Samples + PSB 指标(诚实评估,非假满分)
- 新增最小 OFF loader(
mesh/load_off.rs,OFF 是纯文本、约 40 行):用于加载 PSB 黄金样本。 - Golden samples:尝试从 Princeton Segmentation Benchmark 下载若干(19 类、人工 GT);若沙箱下载受限,则确定性合成几个带已知 GT 的模型(双球融合=2 部件、球+盒、类人形)并明确标注为 synthetic。两者都进
examples/golden/。 - PSB 指标实现(
segment/metrics.rs):- Rand Index(聚类一致性)
- Boundary Precision / Recall / F1(边界匹配,最关键,人类"在哪切")
- Segmentation Consistency(对多份 GT 取均值,抗单一 GT 偏差)
- 验收测试(
#[cfg(test)]或tests/accuracy.rs):每个算法跑 golden samples,打印并断言Boundary-F1 ≥ 基线(基线由各算法在样本上的实测值回填,绝不预先拍脑袋写死通过阈值)。报告真实数值,不返回"满分"掩盖退化。 - 离线 E2E 无法跑 Tauri 渲染,但 Rust 分割逻辑 + 指标可
cargo test全绿;视觉验收仍由用户cargo tauri dev完成。
9. 理论缺口清单(提交 REFUTE 的重点)
- G1 连通性:K-means/Curvature 必产生不连通碎片,靠 RAG 合并;合并阈值拍错会过/欠分割 → 阈值需有出处 + 测试覆盖。
- G2 曲率噪声敏感:STL 噪声下曲率失效 → 需平滑,但平滑会抹掉真实锐边 → 迭代次数旋钮 + 默认保守。
- G3 MultiView 遮挡:薄特征单视角丢失 → 多视角 + 仅最近深度占格;
views/grid_res/normal_tol需调参协议。 - G4 重依赖:V-HACD 推迟,不阻塞。
- G5 假满分风险:golden GT 必须真实;synthetic 明确标注;指标阈值由实测回填,禁止
!has_gt → 100。 - G6 SDF 副作用 bug:先修
consistent_normals不写回,否则多算法串联崩。 - G7 dihedral 递归 find 爆栈:超大网格风险,改为迭代式(backlog,本轮若顺手可修)。
- G8
seg_log()写源码目录:发布版会写文件,清理(backlog)。
10. 实施分阶段(最小改动优先)
- 修 SDF 副作用 + 补 progress + 提常量(前置 bugfix,独立提交)。
- 统一接口
SegmentationAlgorithm+run_segmentation+auto_segment_v2(行为不变,独立提交)。 - CurvatureKMeans(新算法 + 连通性合并 + 测试)。
- MultiView 3→2→3(新算法 + 测试)。
- OFF loader + golden samples + PSB 指标 + 验收测试。
- 前端
IntelligentSegmentPanel+ SegmentsPanel 微调(合并/拆分)。 - 收口三处
30.0硬编码;清理seg_log。
每步带测试,全套 cargo test 报告 "X/X(原 N + K)"。
99. REFUTE 结论与修订(对抗子 agent,2026-08-09)
子 agent 返回 7 个 blocker。逐条处置:
| # | Blocker | 修订 / 处置 |
|---|---|---|
| 1 | SDF 性能误诊:真瓶颈在 sdf.rs:172-174 kdtree 查询半径=全 bbox 对角线且放在射线循环内 → O(12·n²);:387 处的 edge_references() 只是 k²·E≈3e8,差 5 个数量级 |
改:候选查询提出射线循环、且改用 nearest_n(K) 有界候选(SDF_CANDIDATE_K=512),成本降至 O(n·K·rays)。原 :387 全图重扫改为预构建 RAG(与 dihedral 同构)。 |
| 2 | §4「RAG 贪心合并保证每个 label 连通」逻辑不可达:合并是单调运算,永不产生连通性 | 改:先对每个 k-means 簇做连通分量拆分(BFS over face_adjacency),再做小分量按特征距离合并。合并判据用特征欧氏距离,不复用 dihedral 的 0.93(语义不同:区域平均法线 dot f64 vs 边界二面角 cos f32,且是 private const)。 |
| 3 | §5 MultiView 融合算子方向反了:「任一视角同区即并查集连边」+ union-find 单调坍缩 → 视角越多越合并,传递闭包大概率并成 1 块;petgraph 0.6 无任何社区检测 | 砍掉本轮。正确版需带权 matching graph + 可切割算法(normalized cut / Louvain 自研),非最小改动。列入 backlog,附正确设计(见 §11)。用户说"或者 3→2→3",3D 特征聚类(C+D)已满足"真实特征识别"。 |
| 4 | §5 栅格占格 → 单例爆炸:多数面在所有视角无标签 → 各自成 label,击穿 MANUAL_SEGMENT_OFFSET=100_000 命名空间 |
随 §5 砍掉而消解;若未来做,必须 cap label 数 < 100_000。 |
| 5 | 标签命名空间被击穿:rebuild_segments 会把 ≥100_000 的 label 当手动分区改名+随机上色 |
CurvatureKMeans 最终 label 数 = 最终连通分量数(k 小 + 小分量合并)→ 远 < 100_000;加断言守卫。 |
| 6 | §4 引入随机性(k-means++ 需 rand,但 Cargo.toml 无 rand;现有 kmeans_1d 明确 Deterministic)破坏确定性 → §8 断言 flaky |
改:用确定性最远点播种(max 两两特征距离选种子,survey 提及),无 rand 依赖。 |
| 7 | §8「基线由实测回填 + 断言 ≥ 基线」= 构造性绿灯(假满分换皮);synthetic 双球/球+盒对 dihedral/SDF 平凡可分 → 四算法全 ~1.0,零区分度 | 改:阈值来自外部公开 PSB 基线(论文报告值)而非自测回填;synthetic 仅作 smoke(断言"切出正确部件数"这种非平凡拓扑事实,非假满分);GT 缺失时测试 skip/fail,绝不计分。Rand 用列联表公式。 |
其他 major 处置
- "凹度合并"名不副实:
sdf.rs:395的acos(dot)无符号,分不出凸/凹;§3 把0.93命名为SDF_CONCAVITY_DOT会把错误固化 → 不命名常量,保留字面量并加注释说明其语义边界。 - "复用 dihedral 框架"不成立:
normal_consistency_merge/merge_small_regions_fast是 private 且合并判据仍是法线 dot,曲率特征在合并阶段被丢弃 → CurvatureKMeans 不调用 dihedral 私有函数,自写"连通拆分 + 特征距离合并"。 - PCA 特征非确定:主轴符号 ±、特征值简并(球/立方体)→
normal·principalXYZ随机翻转,等于按朝向聚类 → 特征向量剔除法线方向,只用 [曲率, |SDF|, 凸性] 内在描述子。 - SDF 副作用修复会静默改行为:
consistent_normals不写回却不透传副本 →segment_by_sdf_block_with_plate漂移 → 改:consistent_normals→oriented_normals(mesh)->Vec不写回;compute_sdf/segment_by_sdf各自本地持有 oriented(新增compute_sdf_inner(mesh,&oriented)),compute_sdf的pub签名与返回不变,测试不受影响。 - "一键重跑"毁数据:
history.clear()+ 全量覆盖 labels,但face_colors保留手动色 → 颜色/标签失配且不可撤销 → 前端层面提示"重跑将清除手动分区",后端重跑前 backup 当前 labels(backlog,本轮先不阻断)。 - §8 指标命名:PSB 官方为 Cut Discrepancy / Hamming / Rand / Consistency Error;Boundary-F1 是派生代理,标注清楚。
- OFF loader「40 行」低估:需
.segGT 解析 + 面序对齐 + 复刻build_mesh全套前置 → 本轮不写 OFF loader;golden samples 用确定性合成 STL(双球/球+盒/类人形)写入examples/golden/,并保留"掉落真实 PSB .off 即自动启用"的挂接点。
11. MultiView 3→2→3 的正确设计(backlog,本轮不做)
若未来做,必须:
- 每个视角:面质心正交投影到 (u,v),记录 depth + 2D 区域 id(仅最近深度面占栅格)。
- 构建带权 match graph:边权 = 两面在多少个视角同属一个 2D 区域(≥T 视角才连边,T≥2,避免单视角巧合合并)。
- 用可切割算法(normalized spectral cut 或自研 Louvain)切分,不是 union-find(union-find 单调不可切)。
- 工业级替代:parry3d 的 V-HACD 近似凸分解(重依赖,单独评估)。
12. 实现状态(2026-08-07)
后端(已全部落地,b087c3c)
- §1 统一接口
SegmentationAlgorithm(serde 内部标签枚举,camelCase,契约由serde_wire_format_is_stable锁死)+run_segmentation+auto_segment_v2命令。 - §2 Dihedral、§3 ShapeDiameter(补 progress + 修
consistent_normals不写回mesh.normals的副作用)、§4 CurvatureKMeans(确定性最远点播种 + 连通拆分 + 特征距离合并)。 - 共享后处理
postprocess.rs:split_connected_components沿棱角切割(特征∩棱角 交集,根治"uniform 场聚一类"),merge_smooth_boundaries(coplanar 必溶解 + 特征间距护栏),min_region_faces(n)(低面数模型不死坍),finalize_segments。 - 验收:golden-sample harness 抓出 5 个真实 bug(cube 均匀场、SDF 噪声放大、共面对角、非传递 union、低面数溶解);
cargo test --lib74 passed / 0 failed。拓扑断言:cube→6(curv 双变体)、single_sphere→1(四算法)、two_spheres→2(四算法);golden_eval 曲率(SDF) vs GT:Rand=1.000 / Boundary-F1=1.000 / Hamming=0.000。
前端(本轮落地)
- §7
IntelligentSegmentPanel已实现,但形态为模态(沿用 ExportDialog overlay/dialog)而非原草案的 docked 面板——模态更低侵入、与appStorepersist 模式一致;算法集为 dihedral / shapeDiameter / curvatureKMeans(MultiView 按 §11 推迟)。 - 收口 §2 / §10.7 三处
30.0硬编码:导入自动分区改走autoSegmentV2(buildAlgorithm(持久化 or 默认 dihedral 30°, 参数));旧autoSegment/autoSegmentSmart钩子退役。 appStore持久化lastAlgorithmParams(sanitizeAlgorithmParams值域校验)+lastSegmentKind;tsc --noEmit通过。
验收结论
- 诚实评估:后端 golden 拓扑断言全绿;但视觉/交互仍须需求方
cargo tauri dev手动复验(headless 无 Tauri runtime,依赖 IPCinvoke的模型加载/分区无法自动化)。 - 推迟项(backlog):MultiView 3→2→3(§11)、OFF loader + PSB 真实样本、SegmentsPanel 合并/拆分微调、dihedral 递归→迭代、重跑前 labels 备份。