35
35
display_enable = False
36
36
37
37
38
- def display (vertices , faces , color = None , view = True ):
38
+ def display (vertices , faces , colors = None , view = True ):
39
39
"""3D display of a polyhedron with PlantGL
40
40
41
41
Args:
42
42
vertices (list of tuples): list of 3D coordinates of polyhedron vertices
43
43
faces (list of tuple): list of vertex indices defining the faces
44
- color: a (r,g,b) tuple defining color.
44
+ color: a list of (r,g,b) tuple defining color.
45
45
If None (default), default PlantGL material is used.
46
46
view (bool): should the shape be displayed ?
47
47
@@ -50,18 +50,23 @@ def display(vertices, faces, color=None, view=True):
50
50
"""
51
51
global display_enable
52
52
if display_enable :
53
- if color is None :
53
+ scene = pgl .Scene ()
54
+ if colors is None :
54
55
shape = pgl .Shape (pgl .FaceSet (pointList = vertices , indexList = faces ))
56
+ scene += shape
55
57
else :
56
- m = pgl .Material (pgl .Color3 (* color ))
57
- shape = pgl .Shape (pgl .FaceSet (pointList = vertices , indexList = faces ),
58
- m )
58
+ for i ,face in enumerate (faces ):
59
+ vtx = [vertices [v ] for v in face ]
60
+ idx = range (len (face ))
61
+ mat = pgl .Material (pgl .Color3 (* colors [i ]))
62
+ shape = pgl .Shape (pgl .FaceSet (pointList = vtx , indexList = [idx ]), mat )
63
+ scene += shape
59
64
if view :
60
- pgl .Viewer .display (shape )
65
+ pgl .Viewer .display (scene )
61
66
else :
62
67
warnings .warn ('PlantGL not installed: display is not enable!' )
63
68
shape = None
64
- return shape
69
+ return scene
65
70
66
71
67
72
def normed (point ):
@@ -81,8 +86,11 @@ def norm(vector):
81
86
82
87
def spherical (points ):
83
88
""" zenital and azimutal coordinate of a list of points"""
84
- x , y , z = list (zip (* points ))
85
- return numpy .arccos (z ), numpy .arctan2 (y , x )
89
+ proj = [normed (p ) for p in points ]
90
+ x , y , z = zip (* proj )
91
+ theta = numpy .arccos (z )
92
+ phi = numpy .arctan2 (y , x )
93
+ return zip (theta , phi )
86
94
87
95
88
96
def rotation_matrix (axis , theta ):
@@ -154,7 +162,7 @@ def icosahedron():
154
162
vertices .append (normed ((- t , 0 , 1 )))
155
163
156
164
# align to get second point on Z+
157
- theta , phi = list ( zip ( * spherical (vertices )) )[1 ]
165
+ theta , phi = spherical (vertices )[1 ]
158
166
vertices = inverse_rotation (vertices , theta , phi )
159
167
160
168
# create 20 triangles of the icosahedron
@@ -206,11 +214,16 @@ def split_triangles(vertices, faces, tags=None):
206
214
This is a python implementation of the C code found here:
207
215
http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html
208
216
"""
217
+ # copy input
218
+ new_faces = [f for f in faces ]
219
+ new_vertices = [v for v in vertices ]
220
+ if tags is not None :
221
+ new_tags = [t for t in tags ]
209
222
# cache is a (index_p1, index_p2): middle_point_index dict refering
210
223
# to vertices
211
224
cache = {}
212
225
for i in range (len (faces )):
213
- face = faces .pop (0 )
226
+ face = new_faces .pop (0 )
214
227
v1 , v2 , v3 = face
215
228
p1 = vertices [v1 ]
216
229
p2 = vertices [v2 ]
@@ -221,35 +234,35 @@ def split_triangles(vertices, faces, tags=None):
221
234
if ka in cache :
222
235
va = cache [ka ]
223
236
else :
224
- vertices .append (normed (middle_point (p1 , p2 )))
225
- va = len (vertices ) - 1
237
+ new_vertices .append (normed (middle_point (p1 , p2 )))
238
+ va = len (new_vertices ) - 1
226
239
cache .update ({ka : va })
227
240
if kb in cache :
228
241
vb = cache [kb ]
229
242
else :
230
- vertices .append (normed (middle_point (p2 , p3 )))
231
- vb = len (vertices ) - 1
243
+ new_vertices .append (normed (middle_point (p2 , p3 )))
244
+ vb = len (new_vertices ) - 1
232
245
cache .update ({kb : vb })
233
246
if kc in cache :
234
247
vc = cache [kc ]
235
248
else :
236
- vertices .append (normed (middle_point (p1 , p3 )))
237
- vc = len (vertices ) - 1
249
+ new_vertices .append (normed (middle_point (p1 , p3 )))
250
+ vc = len (new_vertices ) - 1
238
251
cache .update ({kc : vc })
239
252
240
- faces .append ((v1 , va , vc ))
241
- faces .append ((v2 , vb , va ))
242
- faces .append ((v3 , vc , vb ))
243
- faces .append ((va , vb , vc ))
253
+ new_faces .append ((v1 , va , vc ))
254
+ new_faces .append ((v2 , vb , va ))
255
+ new_faces .append ((v3 , vc , vb ))
256
+ new_faces .append ((va , vb , vc ))
244
257
245
258
if tags is not None :
246
- tag = tags .pop (0 )
247
- tags .extend ([tag ] * 4 )
259
+ tag = new_tags .pop (0 )
260
+ new_tags .extend ([tag ] * 4 )
248
261
249
262
if tags is None :
250
- return vertices , faces
263
+ return new_vertices , new_faces
251
264
else :
252
- return vertices , faces , tags
265
+ return new_vertices , new_faces , new_tags
253
266
254
267
255
268
def sorted_faces (center , face_indices , faces ):
@@ -309,21 +322,27 @@ def star_split(vertices, faces, tags=None):
309
322
of tags referencing the tag of the parent face
310
323
"""
311
324
325
+ # copy input
326
+ new_faces = [f for f in faces ]
327
+ new_vertices = [v for v in vertices ]
328
+ if tags is not None :
329
+ new_tags = [t for t in tags ]
330
+
312
331
for i in range (len (faces )):
313
- face = faces .pop (0 )
332
+ face = new_faces .pop (0 )
314
333
center = normed (centroid ([vertices [p ] for p in face ]))
315
- icenter = len (vertices )
316
- vertices .append (center )
334
+ icenter = len (new_vertices )
335
+ new_vertices .append (center )
317
336
for j in range (len (face ) - 1 ):
318
- faces .append ((face [j ], face [j + 1 ], icenter ))
319
- faces .append ((face [- 1 ], face [0 ], icenter ))
337
+ new_faces .append ((face [j ], face [j + 1 ], icenter ))
338
+ new_faces .append ((face [- 1 ], face [0 ], icenter ))
320
339
if tags is not None :
321
- tag = tags .pop (0 )
322
- tags .extend ([tag ] * len (face ))
340
+ tag = new_tags .pop (0 )
341
+ new_tags .extend ([tag ] * len (face ))
323
342
if tags is None :
324
- return vertices , faces
343
+ return new_vertices , new_faces
325
344
else :
326
- return vertices , faces , tags
345
+ return new_vertices , new_faces , new_tags
327
346
328
347
329
348
def icosphere (iter_triangle = 0 , iter_star = 0 ):
@@ -382,7 +401,7 @@ def turtle_dome(refine_level=3):
382
401
383
402
Args:
384
403
refine_level (int): the level of refinement of the dual icosphere. By
385
- default 46 ^ polygons are returned (refine_level=3).
404
+ default 46 polygons are returned (refine_level=3).
386
405
387
406
For information, here are the number of faces obtained for the first ten
388
407
refinement level: 0: 6, 1: 16, 2: 26, 3: 46, 4: 66, 5: 91, 6: 136,
@@ -446,36 +465,34 @@ def turtle_sectors(nb_sectors=46):
446
465
447
466
448
467
def sample_faces (vertices , faces , iter = 2 , spheric = False ):
449
- """Generate a set of points that regularly sample the faces of a polyhedron
468
+ """Generate a set of points or spherical directions that regularly sample
469
+ the faces of a polyhedron
450
470
the number of sampling points is 6 * 4**iter or 5 * 4**iter
451
471
452
472
Args:
453
473
vertices (list of tuples): list of 3D coordinates of polyhedron vertices
454
474
faces (list of tuple): list of vertex indices defining the faces
455
- iter: the number of triangular interation to apply on the satr -split
475
+ iter: the number of triangular iteration to apply on the star -split
456
476
of the polyhedron. If None, face centers are returned
457
- speric (bool): if True, zenital and azimuth are returnd
477
+ spheric (bool): if True, zenithal and azimuth are returned
458
478
instead of points
459
479
460
480
Returns:
461
- a {face_index: [ points]} dict
481
+ a list of points or of (theta, phi) tuples and a list of tags
462
482
"""
463
-
464
- if iter is None :
465
- points = {i : [centroid ([vertices [p ] for p in face ])] for i , face in
466
- enumerate (faces )}
467
- else :
468
- tags = list (range (len (faces )))
483
+ tags = range (len (faces ))
484
+ if iter is not None :
469
485
vertices , faces , tags = star_split (vertices , faces , tags )
470
486
for i in range (iter ):
471
487
vertices , faces , tags = split_triangles (vertices , faces , tags )
472
488
473
- points = {tag : [] for tag in set (tags )}
474
- for i , face in enumerate (faces ):
475
- points [tags [i ]].append (centroid ([vertices [p ] for p in face ]))
489
+ face_points = [[centroid ([vertices [p ] for p in face ])] for face in faces ]
476
490
491
+ points = reduce (lambda x , y : x + y , face_points )
492
+ npt = map (len , face_points )
493
+ tags = reduce (lambda x , y : x + y , [[t ] * n for t , n in zip (tags , npt )])
477
494
if spheric :
478
- points = { k : spherical (v ) for k , v in points . items ()}
495
+ points = spherical (points )
479
496
480
- return points
497
+ return points , tags
481
498
0 commit comments