"""Run with python -m unittest discover -s blender/scripts -p test_patch_geometry.py.""" import unittest from patch_geometry import (area, barycentric, cell_fragments, clip_rect, interpolate_uv, project_triangle, visible_triangles) class GeometryTests(unittest.TestCase): def test_perspective_correct(self): points = project_triangle([(-1, -1, 0, 1), (2, -2, 0, 2), (-4, 4, 0, 4)]) p = tuple((a + b + c) / 3 for a, b, c in zip(*points)) self.assertAlmostEqual(sum(barycentric(p)), 1) uv = interpolate_uv(p, [(0, 0), (1, 0), (0, 1)]) self.assertAlmostEqual(uv[0], 2 / 7) self.assertAlmostEqual(uv[1], 1 / 7) def test_quad_both_loop_triangles_cover_square(self): corners = [(-1, -1, 0, 1), (1, -1, 0, 1), (1, 1, 0, 1), (-1, 1, 0, 1)] fragments = [] for indices in ((0, 1, 2), (0, 2, 3)): fragments.extend(cell_fragments([corners[k] for k in indices], 3, 2, lambda _: True)) self.assertAlmostEqual(sum(area(list(p)) for _, _, p in fragments), 1) for i, j, poly in fragments: self.assertTrue(all(i / 3 - 1e-12 <= p[0] <= (i + 1) / 3 + 1e-12 for p in poly)) self.assertTrue(all(j / 2 - 1e-12 <= p[1] <= (j + 1) / 2 + 1e-12 for p in poly)) def test_frustum_and_near_clipping(self): poly = project_triangle([(-2, -1, -2, 1), (1, -1, 0, 1), (0, 2, 0, 1)]) self.assertGreater(len(poly), 2) for p in poly: self.assertTrue(0 <= p[0] <= 1 and 0 <= p[1] <= 1) self.assertAlmostEqual(sum(barycentric(p)), 1) self.assertTrue(all(w >= -1e-12 for w in barycentric(p))) def test_behind_camera_is_empty(self): self.assertEqual(project_triangle([(-1, -1, 0, -1), (1, -1, 0, -1), (0, 1, 0, -1)]), []) def test_wide_uv_triangle_does_not_wrap(self): poly = project_triangle([(-1, -1, 0, 1), (1, -1, 0, 1), (-1, 1, 0, 1)]) uvs = [(0.02, 0.1), (0.98, 0.1), (0.02, 0.9)] self.assertEqual([interpolate_uv(p, uvs) for p in poly], uvs) def test_seam_islands_remain_independent(self): p = (0, 0, 1, 0.5, 0.25, 0.25) left = interpolate_uv(p, [(0, 0), (.1, 0), (0, .1)]) right = interpolate_uv(p, [(.9, .9), (1, .9), (.9, 1)]) self.assertLess(left[0], .1) self.assertGreater(right[0], .9) def test_hidden_rejected(self): tri = project_triangle([(-1, -1, 0, 1), (1, -1, 0, 1), (-1, 1, 0, 1)]) self.assertEqual(list(visible_triangles(tri, lambda _: False, 1, 1)), []) def test_mixed_visibility_conservative(self): tri = project_triangle([(-1, -1, 0, 1), (1, -1, 0, 1), (-1, 1, 0, 1)]) accepted = list(visible_triangles(tri, lambda w: w[1] < .4, 1, 1)) self.assertTrue(accepted) self.assertTrue(all(barycentric(p)[1] < .4 for t in accepted for p in t)) self.assertLess(sum(area(list(t)) for t in accepted), .5) def test_unresolved_depth_limit_rejected(self): tri = project_triangle([(-1, -1, 0, 1), (1, -1, 0, 1), (-1, 1, 0, 1)]) self.assertEqual(list(visible_triangles(tri, lambda w: w[1] < .4, 1, 1, depth=10)), []) def test_uv_tile_clips_without_repeating(self): poly = clip_rect([(-.2, .1), (.2, .1), (.2, .9)], 0, 1, 0, 1) self.assertTrue(all(0 <= p[0] <= .2 for p in poly)) if __name__ == '__main__': unittest.main()