Files
AIC-Project/Tools/ModelTranslator/tests/test_bl_decimate.py
T
2026-07-21 12:28:53 +08:00

156 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import sys
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import bl_decimate as bd
class TestDecimateRatio(unittest.TestCase):
def test_normal_reduction(self):
self.assertAlmostEqual(bd.decimate_ratio(5000, 1500000), 5000 / 1500000.0)
def test_current_below_target_returns_one(self):
self.assertEqual(bd.decimate_ratio(5000, 3000), 1.0)
def test_current_equal_target_returns_one(self):
self.assertEqual(bd.decimate_ratio(5000, 5000), 1.0)
def test_zero_current_returns_one(self):
self.assertEqual(bd.decimate_ratio(5000, 0), 1.0)
class TestWithinTolerance(unittest.TestCase):
def test_exact_hit(self):
self.assertTrue(bd.within_tolerance(5000, 5000))
def test_within_3_percent(self):
self.assertTrue(bd.within_tolerance(5000, 5150)) # +3%
self.assertTrue(bd.within_tolerance(5000, 4850)) # -3%
def test_outside_3_percent(self):
self.assertFalse(bd.within_tolerance(5000, 5200))
self.assertFalse(bd.within_tolerance(5000, 4700))
def test_zero_target_is_false(self):
self.assertFalse(bd.within_tolerance(0, 0))
class TestCountIslands(unittest.TestCase):
def test_no_faces(self):
self.assertEqual(bd.count_islands(0, []), 0)
def test_no_pairs_each_face_is_island(self):
self.assertEqual(bd.count_islands(3, []), 3)
def test_chain_merges_to_one(self):
self.assertEqual(bd.count_islands(4, [(0, 1), (1, 2), (2, 3)]), 1)
def test_two_groups(self):
self.assertEqual(bd.count_islands(5, [(0, 1), (3, 4)]), 3) # {0,1} {2} {3,4}
def test_duplicate_pairs_ok(self):
self.assertEqual(bd.count_islands(2, [(0, 1), (1, 0), (0, 1)]), 1)
class TestFlippedFraction(unittest.TestCase):
def test_empty_is_zero(self):
self.assertEqual(bd.flipped_fraction([]), 0.0)
def test_mixed(self):
self.assertAlmostEqual(bd.flipped_fraction([0.1, -0.2, 0.3, 0.4]), 0.25)
def test_all_positive(self):
self.assertEqual(bd.flipped_fraction([0.1, 0.2]), 0.0)
class TestFillRatio(unittest.TestCase):
def test_sum(self):
self.assertAlmostEqual(bd.fill_ratio([0.2, 0.3]), 0.5)
def test_clamped_to_one(self):
self.assertEqual(bd.fill_ratio([0.8, 0.9]), 1.0)
def test_empty_is_zero(self):
self.assertEqual(bd.fill_ratio([]), 0.0)
class TestUvGateOk(unittest.TestCase):
def test_clean_passes(self):
self.assertTrue(bd.uv_gate_ok(0.0, 0.0))
def test_boundary_passes(self):
self.assertTrue(bd.uv_gate_ok(bd.UV_FLIP_TOL, bd.UV_OVERLAP_TOL))
def test_flip_exceeds_fails(self):
self.assertFalse(bd.uv_gate_ok(0.03, 0.0))
def test_overlap_exceeds_fails(self):
self.assertFalse(bd.uv_gate_ok(0.0, 0.09))
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):
self.assertEqual(bd.uvpm_mode_label("seam", True), "seam+uvpm")
self.assertEqual(bd.uvpm_mode_label("smart", True), "smart+uvpm")
self.assertEqual(bd.uvpm_mode_label("smart_fallback", True), "smart_fallback+uvpm")
def test_not_applied_keeps_base(self):
self.assertEqual(bd.uvpm_mode_label("seam", False), "seam")
self.assertEqual(bd.uvpm_mode_label("smart_fallback", False), "smart_fallback")
class TestPickBestCandidate(unittest.TestCase):
def _c(self, flipped, overlap, islands, angle):
return {"flipped": flipped, "overlap": overlap,
"islands": islands, "angle": angle}
def test_none_when_empty(self):
self.assertIsNone(bd.pick_best_candidate([]))
def test_none_when_no_candidate_passes_gate(self):
cands = [self._c(0.30, 0.50, 100, 66), self._c(0.20, 0.40, 200, 45)]
self.assertIsNone(bd.pick_best_candidate(cands))
def test_picks_only_passing(self):
cands = [self._c(0.30, 0.50, 50, 66), self._c(0.00, 0.00, 300, 45)]
best = bd.pick_best_candidate(cands)
self.assertEqual(best["angle"], 45)
def test_picks_fewest_islands_among_passing(self):
cands = [self._c(0.00, 0.00, 120, 55), self._c(0.01, 0.02, 90, 45),
self._c(0.00, 0.00, 300, 35)]
best = bd.pick_best_candidate(cands)
self.assertEqual(best["islands"], 90)
def test_overlap_none_treated_as_pass(self):
cands = [self._c(0.01, None, 42, 66)]
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()