44
55import math
66
7+ import trimesh
8+
9+ from flitter .model import Matrix44
710from flitter .render .window .models import Model
811
912from . import utils
1013
1114
15+ DefaultSegments = 64
16+
17+
1218class TestPrimitives (utils .TestCase ):
19+ def tearDown (self ):
20+ Model .flush_caches (0 , 0 )
21+
1322 def test_box (self ):
14- box = Model .box ()
15- mesh = box .get_trimesh ()
23+ model = Model .box ()
24+ mesh = model .get_trimesh ()
25+ self .assertEqual (model .name , '!box' )
1626 self .assertEqual (mesh .bounds .tolist (), [[- 0.5 , - 0.5 , - 0.5 ], [0.5 , 0.5 , 0.5 ]])
1727 self .assertEqual (len (mesh .vertices ), 24 )
1828 self .assertEqual (len (mesh .faces ), 12 )
1929 self .assertEqual (mesh .area , 6 )
2030 self .assertEqual (mesh .volume , 1 )
2131
2232 def test_sphere (self ):
23- for segments in (4 , 64 , 1024 ):
33+ for segments in (4 , DefaultSegments , 1024 ):
2434 with self .subTest (segments = segments ):
25- sphere = Model .sphere (segments )
26- mesh = sphere .get_trimesh ()
35+ model = Model .sphere (segments )
36+ self .assertEqual (model .name , f'!sphere-{ segments } ' if segments != DefaultSegments else '!sphere' )
37+ mesh = model .get_trimesh ()
2738 self .assertEqual (mesh .bounds .tolist (), [[- 1 , - 1 , - 1 ], [1 , 1 , 1 ]])
2839 nrows = segments // 4
2940 self .assertEqual (len (mesh .vertices ), 4 * (nrows + 1 )* (nrows + 2 ))
@@ -36,10 +47,11 @@ def test_sphere(self):
3647 self .assertAlmostEqual (mesh .volume , 4 / 3 * math .pi , places = int (math .log10 (segments )))
3748
3849 def test_cylinder (self ):
39- for segments in (4 , 64 , 1024 ):
50+ for segments in (4 , DefaultSegments , 1024 ):
4051 with self .subTest (segments = segments ):
41- cylinder = Model .cylinder (segments )
42- mesh = cylinder .get_trimesh ()
52+ model = Model .cylinder (segments )
53+ self .assertEqual (model .name , f'!cylinder-{ segments } ' if segments != DefaultSegments else '!cylinder' )
54+ mesh = model .get_trimesh ()
4355 self .assertEqual (mesh .bounds .tolist (), [[- 1 , - 1 , - 0.5 ], [1 , 1 , 0.5 ]])
4456 self .assertEqual (len (mesh .vertices ), 6 * (segments + 1 ))
4557 self .assertEqual (len (mesh .faces ), 4 * segments )
@@ -51,10 +63,11 @@ def test_cylinder(self):
5163 self .assertAlmostEqual (mesh .volume , math .pi , places = int (math .log10 (segments )))
5264
5365 def test_cone (self ):
54- for segments in (4 , 64 , 1024 ):
66+ for segments in (4 , DefaultSegments , 1024 ):
5567 with self .subTest (segments = segments ):
56- cone = Model .cone (segments )
57- mesh = cone .get_trimesh ()
68+ model = Model .cone (segments )
69+ self .assertEqual (model .name , f'!cone-{ segments } ' if segments != DefaultSegments else '!cone' )
70+ mesh = model .get_trimesh ()
5871 self .assertEqual (mesh .bounds .tolist (), [[- 1 , - 1 , - 0.5 ], [1 , 1 , 0.5 ]])
5972 self .assertEqual (len (mesh .vertices ), 4 * (segments + 1 ))
6073 self .assertEqual (len (mesh .faces ), 2 * segments )
@@ -64,3 +77,134 @@ def test_cone(self):
6477 else :
6578 self .assertAlmostEqual (mesh .area , (1 + math .sqrt (2 ))* math .pi , places = int (math .log10 (segments )))
6679 self .assertAlmostEqual (mesh .volume , math .pi / 3 , places = int (math .log10 (segments )))
80+
81+
82+ class TestManifoldPrimitives (utils .TestCase ):
83+ def tearDown (self ):
84+ Model .flush_caches (0 , 0 )
85+
86+ def test_box (self ):
87+ mesh = Model .box ().get_manifold ().to_mesh ()
88+ mesh = trimesh .Trimesh (vertices = mesh .vert_properties , faces = mesh .tri_verts , process = False )
89+ self .assertEqual (mesh .bounds .tolist (), [[- 0.5 , - 0.5 , - 0.5 ], [0.5 , 0.5 , 0.5 ]])
90+ self .assertEqual (len (mesh .vertices ), 8 )
91+ self .assertEqual (len (mesh .faces ), 12 )
92+ self .assertEqual (mesh .area , 6 )
93+ self .assertEqual (mesh .volume , 1 )
94+
95+ def test_sphere (self ):
96+ for segments in (4 , DefaultSegments , 1024 ):
97+ with self .subTest (segments = segments ):
98+ mesh = Model .sphere (segments ).get_manifold ().to_mesh ()
99+ mesh = trimesh .Trimesh (vertices = mesh .vert_properties , faces = mesh .tri_verts , process = False )
100+ self .assertEqual (mesh .bounds .tolist (), [[- 1 , - 1 , - 1 ], [1 , 1 , 1 ]])
101+ nrows = segments // 2
102+ self .assertEqual (len (mesh .vertices ), 2 + nrows * nrows )
103+ self .assertEqual (len (mesh .faces ), 2 * nrows * nrows )
104+ if segments == 4 :
105+ self .assertAlmostEqual (mesh .area , 4 * math .sqrt (3 ))
106+ self .assertAlmostEqual (mesh .volume , 4 / 3 )
107+ else :
108+ self .assertAlmostEqual (mesh .area , 4 * math .pi , places = int (math .log10 (segments )))
109+ self .assertAlmostEqual (mesh .volume , 4 / 3 * math .pi , places = int (math .log10 (segments )))
110+
111+ def test_cylinder (self ):
112+ for segments in (4 , DefaultSegments , 1024 ):
113+ with self .subTest (segments = segments ):
114+ mesh = Model .cylinder (segments ).get_manifold ().to_mesh ()
115+ mesh = trimesh .Trimesh (vertices = mesh .vert_properties , faces = mesh .tri_verts , process = False )
116+ self .assertEqual (mesh .bounds .tolist (), [[- 1 , - 1 , - 0.5 ], [1 , 1 , 0.5 ]])
117+ self .assertEqual (len (mesh .vertices ), 2 * segments )
118+ self .assertEqual (len (mesh .faces ), 4 * (segments - 1 ))
119+ if segments == 4 :
120+ self .assertAlmostEqual (mesh .area , 4 * (1 + math .sqrt (2 )))
121+ self .assertAlmostEqual (mesh .volume , 2 )
122+ else :
123+ self .assertAlmostEqual (mesh .area , 4 * math .pi , places = int (math .log10 (segments )))
124+ self .assertAlmostEqual (mesh .volume , math .pi , places = int (math .log10 (segments )))
125+
126+ def test_cone (self ):
127+ for segments in (4 , DefaultSegments , 1024 ):
128+ with self .subTest (segments = segments ):
129+ mesh = Model .cone (segments ).get_manifold ().to_mesh ()
130+ mesh = trimesh .Trimesh (vertices = mesh .vert_properties , faces = mesh .tri_verts , process = False )
131+ self .assertEqual (mesh .bounds .tolist (), [[- 1 , - 1 , - 0.5 ], [1 , 1 , 0.5 ]])
132+ self .assertEqual (len (mesh .vertices ), segments + 1 )
133+ self .assertEqual (len (mesh .faces ), 2 * (segments - 1 ))
134+ if segments == 4 :
135+ self .assertAlmostEqual (mesh .area , 2 * (1 + math .sqrt (3 )))
136+ self .assertAlmostEqual (mesh .volume , 2 / 3 )
137+ else :
138+ self .assertAlmostEqual (mesh .area , (1 + math .sqrt (2 ))* math .pi , places = int (math .log10 (segments )))
139+ self .assertAlmostEqual (mesh .volume , math .pi / 3 , places = int (math .log10 (segments )))
140+
141+
142+ class TestTransform (utils .TestCase ):
143+ def tearDown (self ):
144+ Model .flush_caches (0 , 0 )
145+
146+ def assertTransform (self , base_model , matrix ):
147+ transformed_model = base_model .transform (matrix )
148+ self .assertEqual (transformed_model .name , f'{ base_model .name } @{ hex (matrix .hash (False ))[2 :]} ' )
149+ base_mesh = base_model .get_trimesh ()
150+ transformed_mesh = transformed_model .get_trimesh ()
151+ self .assertEqual (len (base_mesh .vertices ), len (transformed_mesh .vertices ))
152+ self .assertEqual (base_mesh .faces .tolist (), transformed_mesh .faces .tolist ())
153+ for vertex1 , vertex2 in zip (base_mesh .vertices .tolist (), transformed_mesh .vertices .tolist ()):
154+ self .assertAllAlmostEqual (vertex2 , matrix @ vertex1 , places = 6 )
155+ base_mesh = base_model .get_manifold ().to_mesh ()
156+ transformed_mesh = transformed_model .get_manifold ().to_mesh ()
157+ self .assertEqual (len (base_mesh .vert_properties ), len (transformed_mesh .vert_properties ))
158+ self .assertEqual (base_mesh .tri_verts .tolist (), transformed_mesh .tri_verts .tolist ())
159+ for vertex1 , vertex2 in zip (base_mesh .vert_properties .tolist (), transformed_mesh .vert_properties .tolist ()):
160+ self .assertAllAlmostEqual (vertex2 , matrix @ vertex1 , places = 6 )
161+
162+ def test_translate (self ):
163+ self .assertTransform (Model .cylinder (), Matrix44 .translate ((1 , 2 , 3 )))
164+
165+ def test_rotate (self ):
166+ self .assertTransform (Model .cylinder (), Matrix44 .rotate (1 / 3 ))
167+
168+ def test_scale (self ):
169+ self .assertTransform (Model .cylinder (), Matrix44 .scale ((2 , 3 , 4 )))
170+
171+
172+ class TestCache (utils .TestCase ):
173+ def tearDown (self ):
174+ Model .flush_caches (0 , 0 )
175+
176+ def test_cached_trimesh (self ):
177+ model = Model .box ()
178+ bounds = model .get_bounds ()
179+ mesh = model .get_trimesh ()
180+ manifold = model .get_manifold ()
181+ self .assertIs (model .get_bounds (), bounds )
182+ self .assertIs (model .get_trimesh (), mesh )
183+ self .assertIs (model .get_manifold (), manifold )
184+
185+ def test_invalidate (self ):
186+ model = Model .box ()
187+ bounds = model .get_bounds ()
188+ mesh = model .get_trimesh ()
189+ manifold = model .get_manifold ()
190+ self .assertIs (model .get_bounds (), bounds )
191+ self .assertIs (model .get_trimesh (), mesh )
192+ self .assertIs (model .get_manifold (), manifold )
193+ model .invalidate ()
194+ self .assertIsNot (model .get_bounds (), bounds )
195+ self .assertIsNot (model .get_trimesh (), mesh )
196+ self .assertIsNot (model .get_manifold (), manifold )
197+
198+ def test_invalidate_dependency (self ):
199+ dependency = Model .box ()
200+ model = dependency .transform (Matrix44 ())
201+ bounds = model .get_bounds ()
202+ mesh = model .get_trimesh ()
203+ manifold = model .get_manifold ()
204+ self .assertIs (model .get_bounds (), bounds )
205+ self .assertIs (model .get_trimesh (), mesh )
206+ self .assertIs (model .get_manifold (), manifold )
207+ dependency .invalidate ()
208+ self .assertIsNot (model .get_bounds (), bounds )
209+ self .assertIsNot (model .get_trimesh (), mesh )
210+ self .assertIsNot (model .get_manifold (), manifold )
0 commit comments