diff --git a/Tools/ModelTranslator/bl_decimate.py b/Tools/ModelTranslator/bl_decimate.py index ce28d707..3ccb4a93 100644 --- a/Tools/ModelTranslator/bl_decimate.py +++ b/Tools/ModelTranslator/bl_decimate.py @@ -28,9 +28,10 @@ UV_FLIP_TOL = 0.02 # 质量门:UV 翻转面占比超此值回退 smart_pr UV_OVERLAP_TOL = 0.08 # 质量门:UV 重叠面占比阈值(手工 UV 同口径约 5%,灾难性失败 >20%) -def uv_gate_ok(flipped, overlap): - """UV 质量门:翻转与重叠占比都在阈值内。overlap 为 None(op 不可用)按 0 处理。""" - return flipped <= UV_FLIP_TOL and (overlap or 0.0) <= UV_OVERLAP_TOL +def uv_gate_ok(flipped, overlap, overlap_tol=UV_OVERLAP_TOL): + """UV 质量门:翻转按 UV_FLIP_TOL 固定,重叠按 overlap_tol(默认 UV_OVERLAP_TOL)。 + overlap 为 None(op 不可用)按 0 处理。""" + return flipped <= UV_FLIP_TOL and (overlap or 0.0) <= overlap_tol def uvpm_mode_label(base, applied): @@ -38,11 +39,11 @@ def uvpm_mode_label(base, applied): return base + "+uvpm" if applied else base -def pick_best_candidate(candidates): +def pick_best_candidate(candidates, overlap_tol=UV_OVERLAP_TOL): """从候选 UV 指标 dict 列表选过质量门且岛数最少者;无过门候选返回 None。 - 每个 candidate 至少含 flipped/overlap/islands。""" + overlap_tol 覆盖重叠容忍。每个 candidate 至少含 flipped/overlap/islands。""" passing = [c for c in candidates - if uv_gate_ok(c["flipped"], c["overlap"])] + if uv_gate_ok(c["flipped"], c["overlap"], overlap_tol)] if not passing: return None return min(passing, key=lambda c: c["islands"]) diff --git a/Tools/ModelTranslator/tests/test_bl_decimate.py b/Tools/ModelTranslator/tests/test_bl_decimate.py index 4edc217a..3846eb62 100644 --- a/Tools/ModelTranslator/tests/test_bl_decimate.py +++ b/Tools/ModelTranslator/tests/test_bl_decimate.py @@ -91,6 +91,18 @@ class TestUvGateOk(unittest.TestCase): def test_overlap_none_treated_as_zero(self): self.assertTrue(bd.uv_gate_ok(0.01, None)) + def test_custom_overlap_tol_allows_higher_overlap(self): + self.assertTrue(bd.uv_gate_ok(0.0, 0.12, overlap_tol=0.15)) + self.assertFalse(bd.uv_gate_ok(0.0, 0.16, overlap_tol=0.15)) + + def test_custom_overlap_tol_does_not_relax_flip(self): + # 放宽重叠不影响翻转判定(翻转仍按 UV_FLIP_TOL) + self.assertFalse(bd.uv_gate_ok(0.03, 0.0, overlap_tol=0.5)) + + def test_default_overlap_tol_matches_constant(self): + self.assertTrue(bd.uv_gate_ok(0.0, bd.UV_OVERLAP_TOL)) + self.assertFalse(bd.uv_gate_ok(0.0, bd.UV_OVERLAP_TOL + 0.01)) + class TestUvpmModeLabel(unittest.TestCase): def test_applied_appends_suffix(self): @@ -131,6 +143,13 @@ class TestPickBestCandidate(unittest.TestCase): best = bd.pick_best_candidate(cands) self.assertEqual(best["islands"], 42) + def test_overlap_tol_lets_more_candidates_pass(self): + # overlap=0.12 在默认 8% 门限下不过;放宽到 0.15 后过门并被选中 + cands = [self._c(0.0, 0.12, 50, 55)] + self.assertIsNone(bd.pick_best_candidate(cands)) + best = bd.pick_best_candidate(cands, overlap_tol=0.15) + self.assertEqual(best["angle"], 55) + if __name__ == "__main__": unittest.main()