ModelTranslator: uv_gate_ok/pick_best_candidate 加 overlap_tol 参数
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2673cda83a
commit
b02877a2cf
@@ -28,9 +28,10 @@ UV_FLIP_TOL = 0.02 # 质量门:UV 翻转面占比超此值回退 smart_pr
|
|||||||
UV_OVERLAP_TOL = 0.08 # 质量门:UV 重叠面占比阈值(手工 UV 同口径约 5%,灾难性失败 >20%)
|
UV_OVERLAP_TOL = 0.08 # 质量门:UV 重叠面占比阈值(手工 UV 同口径约 5%,灾难性失败 >20%)
|
||||||
|
|
||||||
|
|
||||||
def uv_gate_ok(flipped, overlap):
|
def uv_gate_ok(flipped, overlap, overlap_tol=UV_OVERLAP_TOL):
|
||||||
"""UV 质量门:翻转与重叠占比都在阈值内。overlap 为 None(op 不可用)按 0 处理。"""
|
"""UV 质量门:翻转按 UV_FLIP_TOL 固定,重叠按 overlap_tol(默认 UV_OVERLAP_TOL)。
|
||||||
return flipped <= UV_FLIP_TOL and (overlap or 0.0) <= 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):
|
def uvpm_mode_label(base, applied):
|
||||||
@@ -38,11 +39,11 @@ def uvpm_mode_label(base, applied):
|
|||||||
return base + "+uvpm" if applied else base
|
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。
|
"""从候选 UV 指标 dict 列表选过质量门且岛数最少者;无过门候选返回 None。
|
||||||
每个 candidate 至少含 flipped/overlap/islands。"""
|
overlap_tol 覆盖重叠容忍。每个 candidate 至少含 flipped/overlap/islands。"""
|
||||||
passing = [c for c in candidates
|
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:
|
if not passing:
|
||||||
return None
|
return None
|
||||||
return min(passing, key=lambda c: c["islands"])
|
return min(passing, key=lambda c: c["islands"])
|
||||||
|
|||||||
@@ -91,6 +91,18 @@ class TestUvGateOk(unittest.TestCase):
|
|||||||
def test_overlap_none_treated_as_zero(self):
|
def test_overlap_none_treated_as_zero(self):
|
||||||
self.assertTrue(bd.uv_gate_ok(0.01, None))
|
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):
|
class TestUvpmModeLabel(unittest.TestCase):
|
||||||
def test_applied_appends_suffix(self):
|
def test_applied_appends_suffix(self):
|
||||||
@@ -131,6 +143,13 @@ class TestPickBestCandidate(unittest.TestCase):
|
|||||||
best = bd.pick_best_candidate(cands)
|
best = bd.pick_best_candidate(cands)
|
||||||
self.assertEqual(best["islands"], 42)
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user