def generate_polytope_data(coxeter_diagram, trunc_type, extra_relations=(), snub=False, dual=False): """ Generate polyhedra vertex coordinates and face indices. The result is output to the file `data.frag`. """ if snub: P = models.Snub(coxeter_diagram, extra_relations=extra_relations) else: P = models.Polyhedra(coxeter_diagram, trunc_type, extra_relations) if dual: P = models.Catalan3D(P) P.build_geometry() vertices_coords = P.vertices_coords def get_oriented_faces(face_group, name): """The faces returned by `P.build_geometry()` may not have their normal vectors pointing outward, we need to rearange them in the right order before sending them to the gpu. """ m = len(face_group) n = len(face_group[0]) faces_data = np.zeros((m, n, 3), dtype=float) for ind, face in enumerate(face_group): face_coords = [vertices_coords[ind] for ind in face] face_center = sum(face_coords) / len(face) v0, v1, v2 = face_coords[:3] normal = np.cross(v1 - v0, v2 - v0) if np.dot(face_center, normal) < 0: face_coords = face_coords[::-1] faces_data[ind, :, :] = face_coords faces_data = faces_data.reshape(m * n, 3) vec_string = ",\n".join(f" vec3({x}, {y}, {z})" for x, y, z in faces_data) return (f"#define {name}Enabled {n}\n\n" + f"vec3[{m * n}] {name} = vec3[{m * n}](\n{vec_string}\n);\n\n") result = get_oriented_faces(P.face_indices[0], "facesA") if len(P.face_indices) > 1: result += get_oriented_faces(P.face_indices[1], "facesB") if len(P.face_indices) > 2: result += get_oriented_faces(P.face_indices[2], "facesC") with open(os.path.join(GLSL_DIR, "data.frag"), "w") as f: f.write(result)
def anim( coxeter_diagram, trunc_type, extra_relations=(), snub=False, description="polytope-animation", ): """ Call POV-Ray to render the frames and call FFmpeg to generate the movie. """ if len(coxeter_diagram) == 3: if snub: P = models.Snub(coxeter_diagram, extra_relations=extra_relations) else: P = models.Polyhedra(coxeter_diagram, trunc_type, extra_relations) scene_file = "polyhedra_animation.pov" elif len(coxeter_diagram) == 6: P = models.Polychora(coxeter_diagram, trunc_type, extra_relations) scene_file = "polytope_animation.pov" elif len(coxeter_diagram) == 10: P = models.Polytope5D(coxeter_diagram, trunc_type, extra_relations) scene_file = "polytope_animation.pov" else: raise ValueError("Invalid Coxeter diagram: {}".format(coxeter_diagram)) P.build_geometry() # POV-Ray does not support 5d vectors well, so project the vertices in python if isinstance(P, models.Polytope5D): P.proj4d() vert_data, edge_data, face_data = P.get_povray_data() with open(data_file, "w") as f: f.write(POV_TEMPLATE.format(vert_data, edge_data, face_data)) subprocess.call(POV_COMMAND.format(scene_file, description), shell=True) subprocess.call(FFMPEG_COMMAND.format(description, description), shell=True) return P