def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('num_balls_on_ring', help='Number of balls on each ring', type=int, nargs='?', default=10) parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() ring_centres = read_coords() if not len(ring_centres): parser.error('no coordinates in input') R = ring_centres[0].mag() dist = find_minimum_separation(ring_centres) a = math.asin(dist / (2 * R)) ball_points, ball_ang = make_ring(R, args.num_balls_on_ring, a) print('ball radius = %.14f' % (2 * R * math.sin(ball_ang / 2)), file=sys.stderr) out = anti_lib.OffFile(args.outfile) out.print_header(len(ring_centres) * len(ball_points), 0) for cent in ring_centres: mat = Mat.rot_from_to(Vec(0, 0, 1), cent) out.print_verts([mat * p for p in ball_points])
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('polygon', help='number of pairs of pentagons (default: 4) ' '(or may be a polygon fraction, e.g. 5/2)', type=anti_lib.read_polygon, nargs='?', default='7') parser.add_argument('-m', '--model_type', help='model type: a - with apex, t - truncated apex', default='t') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon try: points, faces = make_model(pgon, args.model_type) except Exception as e: parser.error(e.args[0]) out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('number_points', help='number of points to distribute on a sphere', type=anti_lib.read_positive_int, nargs='?', default=100) parser.add_argument( '-a', '--angle', help='increment each point placement by a fixed angle instead ' 'of using the Saff and Kuiljaars placement method', type=float) parser.add_argument('-x', '--exclude-poles', help='exclude the pole point circles', action='store_true') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() points = calc_points(args) start = int(args.exclude_poles) end = len(points) - start out = anti_lib.OffFile(args.outfile) out.print_all(points[start:end], [])
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('number_turns', help='number of times the spiral turns around the ' 'axis (default: 10)', type=float, nargs='?', default=10) parser.add_argument('distance_between_points', help='the distance between consequetive points ' '(default: the distance beteen spiral turns)', type=anti_lib.read_positive_float, nargs='?') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() points = calc_points(args) out = anti_lib.OffFile(args.outfile) out.print_all(points, [])
def main(): """Entry point""" epilog = ''' notes: Depends on anti_lib.py. Not all models are constructible. Use of golden trapeziums in polyhedra proposed by Dave Smith - https://hedraweb.wordpress.com/ examples: Pentagonal orthobicupola type gold_bowtie.py 5 1 | antiview Petagramatic elongated gyrobicupola type gold_bowtie.py 5/2 2 | antiview ''' parser = argparse.ArgumentParser(formatter_class=anti_lib.DefFormatter, description=__doc__, epilog=epilog) parser.add_argument('polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D) (default: 5)', default='5', nargs='?', type=anti_lib.read_polygon) parser.add_argument('poly_type', help=''']polyhedron type (default: 0): 0 - like a square barrel polyhedron 1 - orthobicupola 2 - elongated gyrobicupola 3 - inverted bicupola 4 - inverted bifrustum 5 - like a double square barrel polyhedron''', choices=['0', '1', '2', '3', '4', '5'], default='1', nargs='?') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon_fraction if args.poly_type in ['0', '1', '2', '3']: points, faces = cup_model(pgon, args.poly_type) elif args.poly_type == '4': points, faces = bifrustum_model(pgon, args.poly_type) elif args.poly_type == '5': points, faces = antiprism_model(pgon, args.poly_type) else: parser.error('unknown polyhedron type') out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon)
def main(): """Entry point""" epilog = ''' notes: Depends on anti_lib.py. examples: Cuboctahedron barrel.py 4 | antiview Pentagonal square barrel capped with pyramids ("trapezobarrel") barrel.py -t 5 | antiview Pentagonal square barrel with two bands of squares barrel.py -n 2 5 | antiview ''' parser = argparse.ArgumentParser(formatter_class=anti_lib.DefFormatter, description=__doc__, epilog=epilog) parser.add_argument( 'polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D) (default: 6)', default='6', nargs='?', type=anti_lib.read_polygon) parser.add_argument( '-n', '--number-bands', help='number of bands of squares (default: 1)', choices=['1', '2'], default='1') parser.add_argument( '-t', '--trapezo', help='make a "trapezobarrel" by extending the triangles ' 'into kites (like a trapezohedron can be made from ' 'an antiprism)', action='store_true') parser.add_argument( '-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon_fraction if args.number_bands == '1': points, faces = make_1_band_model(pgon, args.trapezo) else: if pgon.N < 2 * pgon.D: parser.error('polyhedron is not constructible (fraction > 1/2)') points, faces = make_2_band_model(pgon, args.trapezo) out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) num_group = parser.add_mutually_exclusive_group() num_group.add_argument( '-n', '--number-circles', help='number of circles of points (default: 6)', type=anti_lib.read_positive_int, default=6) num_group.add_argument( '-p', '--points-list', help='number of points on each circles', type=read_nonnegative_int_list) parser.add_argument( '-d', '--default-number-points', help='number of points to put on a circle if not ' 'otherwise specified (default: maximum number ' 'that fit)', type=anti_lib.read_positive_int, default=-1) parser.add_argument( '-s', '--stagger', help='stagger points between layers', action='store_true') parser.add_argument( '-x', '--exclude-poles', help='exclude the pole point circles', action='store_true') parser.add_argument( '-a', '--aspect-ratio', help='angular aspect ratio (default: 1.0)', type=anti_lib.read_positive_float, default=1.0) parser.add_argument( '-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() if args.points_list: args.number_circles = len(args.points_list) points = calc_points(args) out = anti_lib.OffFile(args.outfile) out.print_all(points, [])
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('number_sides', help='number of sides (default: 6) (or may be a ' 'polygon fraction, e.g. 5/2)', type=anti_lib.read_polygon, nargs='?', default='6') parser.add_argument('pyramid_ht', help='pyramid_height (default: 0.5)', type=float, nargs='?', default=0.5) parser.add_argument('base_ht', help='base_height (default: 0.5)', type=float, nargs='?', default=0.5) parser.add_argument('frequency', help='frequency (default: 5)', type=anti_lib.read_positive_int, nargs='?', default=5) parser.add_argument('-t', '--triangle-only', help='only output one triangle section of the dome', action='store_true') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() if abs(args.pyramid_ht + args.base_ht) < 1e-13: parser.error('base height cannot be the negative of the ' 'pyramid height') (points, faces) = calc_temcor_side(args.number_sides, args.pyramid_ht, args.base_ht, args.frequency) out = anti_lib.OffFile(args.outfile) if args.triangle_only: out.print_all(points, faces) else: out.print_all_pgon(points, faces, args.number_sides, repeat_side=True)
def main(): """Entry point""" epilog = ''' notes: Depends on anti_lib.py. examples: Pentagonal hermaphrodite with equilateral triangles angled at 100 degrees from base eq_antherm.py -a 100 5 | antiview ''' parser = argparse.ArgumentParser(formatter_class=anti_lib.DefFormatter, description=__doc__, epilog=epilog) parser.add_argument( 'polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D) (default: 6)', default='6', nargs='?', type=anti_lib.read_polygon) parser.add_argument( '-a', '--angle', help='dihedral angle at base (default: 90)', type=float, default='90') parser.add_argument( '-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon_fraction dih = radians(args.angle) points, faces = make_equ_antiherm(pgon, dih) out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon) c = sqrt(3)/6 o = pgon.inradius() + c*cos(dih) h = o/tan(dih) + c*sin(dih) print("0,0,%f" % (h), file=sys.stderr)
def main(): """Entry point""" epilog = ''' notes: Depends on anti_lib.py. examples: Oct-tet truss, space-frame lat_grid.py fcc 5 2 | antiview Spherical section of diamond lat_grid.py -s diamond 20 3 | antiview ''' parser = argparse.ArgumentParser(formatter_class=anti_lib.DefFormatter, description=__doc__, epilog=epilog) parser.add_argument( 'lat_type', help=''']Type of lattice or grid (default: sc). The numbers in brackets are suitable strut arguments. sc - Simple Cubic (1, 2, 3) fcc - Face Centred Cubic (2, 4, 6, 12) bcc - Body Centred Cubic (3, 4, 8) hcp - Hexagonal Close Packing (18) rh_dodec - Rhombic Dodecahedra (3, 8) cubo_oct - Cuboctahedron / Octahedron (2) tr_oct - Truncated Octahedron (2) tr_tet_tet - Trunc Tetrahedron/Tetrahedron (2) tr_tet_tr_oct_cubo - Trunc Tet / Trunc Oct / Cuboct (4) diamond - Diamond (3) hcp_diamond - HCP Diamond (27)''', choices=[ 'sc', 'fcc', 'bcc', 'hcp', 'rh_dodec', 'cubo_oct', 'tr_oct', 'tr_tet_tet', 'tr_tet_tr_oct_cubo', 'diamond', 'hcp_diamond' ], nargs='?', default="sc") parser.add_argument('width', help='''width of container cube (default: 6), or radius of contianer sphere''', type=anti_lib.read_positive_int, nargs='?', default=6) parser.add_argument('strut_len_sqd', help='''add struts between pairs of vertices that are separated by the square root of this distance''', type=anti_lib.read_positive_int, nargs='?', default=0) parser.add_argument( '-s', '--sphere-container', help='''container is a sphere (radius 'width') rather than a cube''', action='store_true') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() verts = make_verts(args.lat_type, args.width, not args.sphere_container) edges = make_edges(verts, args.strut_len_sqd) out = anti_lib.OffFile(args.outfile) out.print_all(verts, edges)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('frequency', help='frequency (default: 5)', type=anti_lib.read_positive_int, nargs='?', default=5) parser.add_argument('tiling_ht', help='tiling_height (default: 4)', type=float, nargs='?', default=4) parser.add_argument( '-p', '--projection-height', help='height of projection centre below sphere centre, ' '0.0 - gnomonic projection (default), ' '1.0 - stereographic projection, values with a ' 'magnitude greater than 1 may not be geometrically ' 'realisable if the tiling is wider than the sphere', type=float, default=0.0) parser.add_argument('-t', '--tiling-type', help='type of tiling: t - triangles, s - squares, ' 'x - squares triangulated to centres', choices=['t', 's', 'x'], default='t') parser.add_argument( '-P', '--parallel-project-radius', help='set radius of tiling (<=1) and parallel project onto unit ' 'sphere', type=float) parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() if args.tiling_ht < epsilon: parser.error('tiling height cannot be very small, or negative ') args.tiling_ht = args.tiling_ht + 1 if args.tiling_type == 't': points, faces, R = make_hexagonal_tiling(args.frequency) elif args.tiling_type == 's': points, faces, R = make_sq_tiling(args.frequency) elif args.tiling_type == 'x': points, faces, R = make_sq_x_tiling(args.frequency) rad = args.parallel_project_radius print(rad, file=sys.stderr) if (rad is None): points = project_onto_sphere(points, args.tiling_ht, args.projection_height) elif (rad >= 0.0 and rad <= 1.0): points = parallel_project(points, R, rad) else: parser.error('option -P: radius must be between 0 and 1.0') out = anti_lib.OffFile(args.outfile) out.print_all(points, faces)
def main(): """Entry point""" epilog = ''' notes: Depends on anti_lib.py. Use Antiprism conv_hull to create faces for convex models (larger frequency tetrahdral geodesic spheres tend to be non-convex). examples: Icosahedral Class I F10 geodesic sphere geodesic.py 10 | conv_hull | antiview Octahedral Class 2 geodesic sphere geodesic.py -p o -c 2 10 | conv_hull | antiview Icosahedral Class 3 [3,1] geodesic sphere geodesic.py -c 3,1 | conv_hull | antiview Flat-faced equal-length division tetrahedral model geodesic.py -p t -f -l -c 5,2 | conv_hull -a | antiview -v 0.05 ''' parser = argparse.ArgumentParser(formatter_class=anti_lib.DefFormatter, description=__doc__, epilog=epilog) parser.add_argument( 'repeats', help='number of times the pattern is repeated (default: 1)', type=anti_lib.read_positive_int, nargs='?', default=1) parser.add_argument('-p', '--polyhedron', help='base polyhedron: i - icosahedron (default), ' 'o - octahedron, t - tetrahedron, T - triangle.', choices=['i', 'o', 't', 'T'], default='i') parser.add_argument( '-c', '--class-pattern', help='class of face division, 1 (Class I, default) or ' '2 (Class II), or two numbers separated by a comma to ' 'determine the pattern (Class III generally, but 1,0 is ' 'Class I, 1,1 is Class II, etc).', type=class_type, default=[1, 0, 1]) parser.add_argument( '-f', '--flat-faced', help='keep flat-faced polyhedron rather than projecting ' 'the points onto a sphere.', action='store_true') parser.add_argument( '-l', '--equal-length', help='divide the edges by equal lengths rather than equal angles', action='store_true') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() verts = [] edges = {} faces = [] get_poly(args.polyhedron, verts, edges, faces) (M, N, reps) = args.class_pattern repeats = args.repeats * reps freq = repeats * (M**2 + M * N + N**2) grid = {} grid = make_grid(freq, M, N) points = verts for face in faces: if args.polyhedron == 'T': face_edges = (0, 0, 0) # generate points for all edges else: face_edges = face points[len(points):len(points)] = grid_to_points( grid, freq, args.equal_length, [verts[face[i]] for i in range(3)], face_edges) if not args.flat_faced: points = [p.unit() for p in points] # Project onto sphere out = anti_lib.OffFile(args.outfile) out.print_verts(points)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( 'polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D) (default: 5)', default='5', nargs='?', type=anti_lib.read_polygon) parser.add_argument( 'poly_type', help='polyhedron type: ' '0 - base rhombic tiling, ' '1 - gyroelongated dipyramid, ' '2 - scalenohedron, ' '3 - subscalenohedron ' '4 - inverted subscalenohedron (default: 1)', choices=['0', '1', '2', '3', '4'], default='1') parser.add_argument( '-t', '--twist', help='twist one half of the model by 120 degrees' '(N must be odd)', action='store_true') parser.add_argument( '-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon_fraction if args.twist: msg_start = 'twist: cannot twist model, polygon fraction ' if pgon.parts > 1: parser.error(msg_start + 'is compound') msg = '' if not pgon.N % 2: msg = 'numerator' elif not pgon.D % 2: msg = 'denominator' if msg: parser.error(msg_start + msg + ' is even') if args.poly_type == '3': add_centres = 1 elif args.poly_type == '4': add_centres = -1 else: add_centres = 0 points, rhombi = get_base_points(pgon, add_centres, args.twist) if args.poly_type == '0': faces = rhombi elif args.poly_type == '1': faces = make_gyroelongated_dipyramid_model(rhombi) elif args.poly_type == '2': faces = make_scalahedron_model(rhombi) elif args.poly_type == '3' or args.poly_type == '4': faces = make_subscalahedron_model(rhombi) else: parser.error('unknown polyhedron type') out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon)
def main(): """Entry point""" epilog = ''' notes: Depends on anti_lib.py. examples: octagonal hosohedron rotegrity rotegrity_pretwist.py 8 | antiview ''' parser = argparse.ArgumentParser(formatter_class=anti_lib.DefFormatter, description=__doc__, epilog=epilog) parser.add_argument('polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D) (default: 6)', default='6', nargs='?', type=anti_lib.read_polygon) parser.add_argument('-f', '--fraction', help='end fraction (default: calculated valid value), ' 'only used for 1-layer models', type=float, default=float('nan')) parser.add_argument('-n', '--number-layers', help='number of layers (default: 1)', choices=['1', '2'], default='1') parser.add_argument('-c', '--curved-struts', help='represent struts by a curved sequence of edges', action='store_true') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() number_layers = int(args.number_layers) if number_layers == 2 and not math.isnan(args.fraction): parser.error('option -f cannot be used with option -n 2 ' '(fraction value is fixed)"') pgon = args.polygon_fraction points, faces, end_ang, total_ang = make_model(pgon, args.fraction, number_layers) if not points: parser.error("model is not constructible (try reducing -f value)") use_curves = args.curved_struts invisible = 9999 out = anti_lib.OffFile(args.outfile) if not use_curves: out.print_header(len(points), 5 * len(faces)) out.print_verts(points) for i in range(len(faces)): out.print_face(faces[i], 0, i) for j in range(4): col = i if j else invisible out.print_face([faces[i][j], faces[i][(j + 1) % 4]], 0, col) else: num_seg_pts = 60 out.print_header(num_seg_pts * len(faces), (num_seg_pts - 1) * len(faces)) for i in range(len(faces)): pts = [points[idx] for idx in faces[i]] axis = anti_lib.Vec.cross(pts[1] - pts[0], pts[2] - pts[0]).unit() for j in range(num_seg_pts): rot = anti_lib.Mat.rot_axis_ang( axis, total_ang * j / (num_seg_pts - 1)) out.print_vert(rot * pts[1]) for i in range(len(faces)): start_idx = i * num_seg_pts for j in range(num_seg_pts - 1): out.print_face([start_idx + j, start_idx + j + 1], 0, i) print("end_angle=%19.17f\ntot_angle=%19.17f\nfraction=%19.17f\n" % (end_ang, total_ang, end_ang / total_ang), file=sys.stderr)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('polygon', help='number of sides of polygon (default: 7) ' '(or may be a polygon fraction, e.g. 5/2)', type=anti_lib.read_polygon, nargs='?', default='7') parser.add_argument('turn_angle', help='amount to turn polygon on axis0 in degrees ' '(default (0.0), or a value followed by \'e\', ' 'where 1.0e is half the central angle of an edge, ' 'which produces an edge-connected model (negative ' 'values may have to be specified as, e.g. -a=-1.0e),' 'or a value followed by x, which is like e but with ' 'a half turn offset', type=read_turn_angle, nargs='?', default='0') parser.add_argument('-n', '--number-faces', help='number of faces in output (default: all): ' '0 - none (frame only), ' '2 - cap and adjoining polygon' '4 - two caps and two adjoining connected polygons', type=int, choices=[0, 2, 4], default=-1) parser.add_argument('-F', '--frame', help='include frame elements in output, any from: ' 'r - rhombic tiling edges, ' 'a - rotation axes (default: no elements)', type=frame_type, default='') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon N = pgon.N D = pgon.D parts = pgon.parts # if N % 2 == 0: # parser.error('polygon: %sfraction numerator must be odd' % # ('reduced ' if parts > 1 else '')) if D % 2 == 0: print(os.path.basename(__file__) + ': warning: ' 'polygon: %sfraction denominator should be odd, ' 'model will only connect correctly at certain twist angles' % ('reduced ' if parts > 1 else ''), file=sys.stderr) if abs(N / D) < 3 / 2: parser.error('polygon: the polygon fraction cannot be less than 3/2 ' '(base rhombic tiling is not constructible)') axis_angle = math.acos(1 / math.tan(math.pi * D / N) / math.tan(math.pi * (N - D) / (2 * N))) if args.turn_angle[1] == 'e': # units: half edge central angle turn_angle = args.turn_angle[0] * pgon.angle() / 2 elif args.turn_angle[1] == 'x': # units: half edge central angle turn_angle = math.pi + args.turn_angle[0] * pgon.angle() / 2 else: # units: degrees turn_angle = math.radians(args.turn_angle[0]) turn_angle_test_val = abs( math.fmod(abs(turn_angle), 2 * math.pi) - math.pi) sign_flag = 1 - 2 * (turn_angle_test_val > math.pi / 2) try: (points, faces) = calc_polygons(pgon, turn_angle, axis_angle, sign_flag) except Exception as e: parser.error(e.args[0]) if args.number_faces < 0: num_twist_faces = (2 * N + 2) * parts else: num_twist_faces = args.number_faces * parts num_twist_points = num_twist_faces * N frame_points, frame_faces = make_frame(args.frame, pgon, axis_angle, 10) if num_twist_points + len(frame_points) == 0: parser.error('no output specified, use -f with -n 0 to output a frame') if D % 2 == 0: mat = Mat.rot_axis_ang(Vec(0, 0, 1), math.pi / N) points = [mat * p for p in points] out = anti_lib.OffFile(args.outfile) out.print_header(num_twist_points + 2 * N * len(frame_points), num_twist_faces + 2 * N * len(frame_faces)) if args.number_faces == -1: out.print_verts(rot_reflect_pair(points[:N * parts], pgon, 0, True)) for i in range(N): out.print_verts(rot_reflect_pair(points[N * parts:], pgon, i)) elif args.number_faces == 2: out.print_verts(points) elif args.number_faces == 4: out.print_verts(rot_reflect_pair(points[:N * parts], pgon, 0, True), ) out.print_verts(rot_reflect_pair(points[N * parts:], pgon, 0)) for i in range(N): out.print_verts(rot_reflect_pair(frame_points, pgon, i)) for i in range(num_twist_faces): out.print_face(faces[0], i * N, (i // parts) % 2) for i in range(N): cur_num_points = num_twist_points + 2 * i * len(frame_points) for j in [0, len(frame_points)]: out.print_faces(frame_faces, cur_num_points + j, col=2)
def main(): """Entry point""" epilog = ''' notes: Depends on anti_lib.py. Use poly_kscope to repeat the model. examples: Icosahedral model twister.py I[5,3] | poly_kscope -s I| antiview Twisted icosahedral model with hexagons twister.py I[5,3] 1 2 -a 0.5e | poly_kscope -s I| antiview Dihedral model with frame twister.py D6[6,2] 1 2 -f ra | poly_kscope -s D6 | antiview ''' parser = argparse.ArgumentParser(formatter_class=anti_lib.DefFormatter, description=__doc__, epilog=epilog) parser.add_argument( 'symmetry_axes', help=']Axes given in the form: sym_type[axis1,axis2]id_no\n' ' sym_type: rotational symmetry group, can be T, O, I,\n' ' or can be D followed by an integer (e.g D5)\n' ' axis1,axis2: rotational order of each of the two axes\n' ' id_no (default: 1): integer to select between\n' ' non-equivalent pairs of axes having the same\n' ' symmetry group and rotational orders\n' 'e.g. T[2,3], I[5,2]2, D7[7,2], D11[2,2]4\n' 'Axis pairs are from the following\n' ' T: [3, 3], [3, 2], [2, 2]\n' ' O: [4, 4], [4, 3], [4, 2]x2, [3, 3], [3, 2]x2,\n' ' [2, 2]x2\n' ' I: [5, 5], [5, 3]x2, [5, 2]x3, [3, 3]x2, [3, 2]x4,\n' ' [2, 2]x4\n' ' Dn: [n 2], [2,2]x(n/2 rounded down)\n', type=read_axes, nargs='?', default='O[4,3]') parser.add_argument('multiplier1', help='integer or fractional multiplier for axis 1 ' '(default: 1). If the axis is N/D and the ' 'multiplier is n/d the polygon used will be N*n/d', type=read_axis_multiplier, nargs='?', default="1") parser.add_argument('multiplier2', help='integer or fractional multiplier for axis 2 ' '(default: 1). If the axis is N/D and the ' 'multiplier is n/d the polygon used will be N*n/d', type=read_axis_multiplier, nargs='?', default="1") parser.add_argument('-r', '--ratio', help='ratio of edge lengths (default: 1.0)', type=float, default=1.0) parser.add_argument('-a', '--angle', help='amount to turn polygon on axis0 in degrees ' '(default: 0), or a value followed by \'e\', ' 'where 1.0e is half the central angle of an edge, ' 'which produces an edge-connected model (negative ' 'values may have to be specified as, e.g. -a=-1.0e), ' 'or a value followed by x, which is like e but with ' 'a half turn offset', type=read_turn_angle, default='0') parser.add_argument('-f', '--offset', help='amount to offset the first polygon to avoid ' 'coplanarity with the second polygon, for example ' '0.0001 (default: 0.0)', type=float, default=0.0) parser.add_argument('-F', '--frame', help='include frame elements in output, any from: ' 'r - rhombic tiling edges, ' 'a - rotation axes (default: no elements)', type=frame_type, default='') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() axis_pair = args.symmetry_axes pgons = [] for i, m in enumerate([args.multiplier1, args.multiplier2]): try: pgons.append(anti_lib.Polygon(axis_pair['nfolds'][i] * m.N, m.D)) except Exception as e: parser.error('multiplier%d: ' % (i) + e.args[0]) axes = axis_pair['axes'] if args.angle[1] == 'e': # units: half edge central angle turn_angle = args.angle[0] * pgons[0].angle() / 2 elif args.angle[1] == 'x': # units: half edge central angle turn_angle = math.pi + args.angle[0] * pgons[0].angle() / 2 else: # units: degrees turn_angle = math.radians(args.angle[0]) sin_angle_between_axes = Vec.cross(axes[0], axes[1]).mag() if abs(sin_angle_between_axes) > 1: sin_angle_between_axes = -1 if sin_angle_between_axes < 0 else 1 angle_between_axes = math.asin(sin_angle_between_axes) if (Vec.dot(axes[0], axes[1]) > 0): axes[1] *= -1 try: (points, faces) = calc_polygons(pgons[0], pgons[1], turn_angle, args.ratio, angle_between_axes) except Exception as e: parser.error(e.args[0]) if args.offset: for i in range(len(faces[0])): points[i][2] += args.offset frame_rad = calc_polygons(pgons[0], pgons[1], 0, args.ratio, angle_between_axes)[0][0].mag() frame_points, frame_faces = make_frame(args.frame, angle_between_axes, frame_rad, 10) rot = Mat.rot_from_to2(Vec(0, 0, 1), Vec(1, 0, 0), axes[0], axes[1]) all_points = [rot * point for point in points + frame_points] out = anti_lib.OffFile(args.outfile) out.print_header(len(all_points), len(faces) + len(frame_faces)) out.print_verts(all_points) for i in range(pgons[0].parts + pgons[1].parts): out.print_face(faces[i], 0, int(i < pgons[0].parts)) out.print_faces(frame_faces, len(points), 2)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('number_sides0', help='number of sides of polygon 0 (default: 6) ' '(or may be a polygon fraction, e.g. 5/2)', type=anti_lib.read_polygon, nargs='?', default='6') parser.add_argument('number_sides1', help='number of sides of polygon 0 (default: 5) ' '(or may be a polygon fraction, e.g. 5/2)', type=anti_lib.read_polygon, nargs='?', default='5') parser.add_argument('-A', '--angle_between_axes', help='angle between the two axes (default: 60 degs)', type=float, default=60.0) parser.add_argument('-r', '--ratio', help='ratio of edge lengths (default: 1.0)', type=float, default=1.0) parser.add_argument('-a', '--angle', help='amount to turn polygon on axis0 in degrees ' '(default: 0), or a value followed by \'e\', ' 'where 1.0e is half the central angle of an edge, ' 'which produces an edge-connected model (negative ' 'values may have to be specified as, e.g. -a=-1.0e), ' 'or a value followed by x, which is like e but with ' 'a half turn offset', type=read_turn_angle, default='0') parser.add_argument( '-x', '--x-axis-vert', help='offset of vertex of side polygon to align with x-axis, with 0' 'being the vertex attached to the axial polygon', type=int) parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon0 = args.number_sides0 pgon1 = args.number_sides1 if args.angle[1] == 'e': # units: half edge central angle turn_angle = args.angle[0] * pgon0.angle() / 2 elif args.angle[1] == 'x': # units: half edge central angle turn_angle = math.pi + args.angle[0] * pgon0.angle() / 2 else: # units: degrees turn_angle = math.radians(args.angle[0]) try: (points, faces) = calc_polygons2(pgon0, pgon0.circumradius(), turn_angle, pgon1, args.ratio * pgon1.circumradius(), math.radians(args.angle_between_axes)) except Exception as e: parser.error(e.args[0]) if (args.x_axis_vert is not None): v = pgon0.N + args.x_axis_vert % pgon1.N P = points[v].copy() transl = Mat.transl(Vec(0, 0, -P[2])) # for i in range(len(points)): # points[i][2] -= P[2] rot = Mat.rot_xyz( 0, 0, anti_lib.angle_around_axis(P, Vec(1, 0, 0), Vec(0, 0, 1))) points = [rot * transl * point for point in points] out = anti_lib.OffFile(args.outfile) out.print_all(points, faces)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( 'polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D)', default='3', type=anti_lib.read_polygon) parser.add_argument( 'angle', help='angle to rotate a belt edge from horizontal', type=float, default=0.0) parser.add_argument( '-x', '--cross', help='alternative model type that will make a ' 'cross-antiprism for fractions greater than 1/2', action='store_true') parser.add_argument( '-l', '--left-fill', help='fill holes with triangles using the "right" ' 'diagonal', action='store_true') parser.add_argument( '-r', '--right-fill', help='fill holes with triangles using the "left" ' 'diagonal', action='store_true') parser.add_argument( '-d', '--delete-main-faces', help='delete base polygons and side triangles, ' 'keep all vertices and any faces specified with -l, -r', action='store_true') parser.add_argument( '-p', '--print-info', help='print information about the model to the screen ' '(currently only parameters to make antiprism)', action='store_true') parser.add_argument( '-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon_fraction if args.print_info: print_antiprism_angle(pgon.angle()/2) try: points, faces = make_jitterbug( pgon, math.radians(args.angle), args.cross, args.right_fill, args.left_fill, args.delete_main_faces) except ValueError as e: parser.error(e.args[0]) out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon)
def main(): """Entry point""" parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( 'johnson_no', help='johnson solid number to make the general form of', choices=['88', '89', '90'], nargs='?', default='90') parser.add_argument('polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D)', type=anti_lib.read_polygon, nargs='?', default='3') parser.add_argument('angle', help='angle to rotate a belt edge from horizontal', type=float, nargs='?', default=0.0) parser.add_argument('angle_end', help='if given, do not output the model, but instead ' 'print the free edge length for a range of models ' 'between angle and angle_end. This may be used to ' 'search for, and zero in on, unit edged models.', type=float, nargs='?', default=None) parser.add_argument('steps', help='number of steps in the range of models when ' 'printing the free edge lengths', type=anti_lib.read_positive_int, nargs='?', default=20) parser.add_argument( '-p', '--print-edge', help='print the free edge length to the screen when the ' 'output type is model (otherwise ignore)', action='store_true') parser.add_argument('-f', '--form-flags', help='letters from A, B, C, ... which select an ' 'alternative form at the stages of the calculation ' 'where a choice exists. These will generally "pop" ' 'a vertex type in or outfile. For each model the ' 'available letters and an example vertex popped ' 'are: 88: A-3N, B-4N; 89: A-4N, B-6N, C-5N; ' '90: A-3N, B-N.', default='') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() ang = math.radians(args.angle) pgon = args.polygon_fraction flags = args.form_flags try: if args.angle_end is None: if args.johnson_no == '88': (points, faces) = j88_make_poly(pgon, ang, flags) edge_len = (points[5 * pgon.N] - points[4 * pgon.N]).mag() elif args.johnson_no == '89': (points, faces) = j89_make_poly(pgon, ang, flags) edge_len = (points[6 * pgon.N] - points[4 * pgon.N]).mag() elif args.johnson_no == '90': (points, faces) = j90_make_poly(pgon, ang, flags) B_rot = points[pgon.N].rot_z(-pgon.angle() / 2) edge_len = Vec(0, 2 * B_rot[1], 2 * B_rot[2]).mag() if (args.print_edge): print("free edge length:", edge_len, file=sys.stderr) out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon) else: end_ang = math.radians(args.angle_end) print_increments(args.johnson_no, pgon, ang, end_ang, args.steps, flags, file=args.outfile) except ValueError as e: parser.error(e.args[0])
def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('polygon_fraction', help='number of sides of the base polygon (N), ' 'or a fraction for star polygons (N/D) (default: 12)', default='12', nargs='?', type=anti_lib.read_polygon) parser.add_argument( 'last_level', help='number of levels above (+/-) to finish (default: 100,0)', nargs='?', type=int, default=100) parser.add_argument( 'first_level', help='number of levels above (+/-) to start (default: 0)', nargs='?', type=int, default=0) parser.add_argument('-k', '--kite-angle', help='side angle of kite (default: calculated)', type=float, nargs='?', default=-1.0) parser.add_argument('-l', '--height', help='height of base antiprism (default: calculated)', type=float, nargs='?', default=-1.0) parser.add_argument('-a', '--alignment', help='alignment: p - prism, a - antiprism (default)', choices=['p', 'a'], default='a') parser.add_argument( '-c', '--caps', help='cap types for bottom and top (in that order), two letters ' 'from p (polygon), and a (apex) (default: pa)', choices=['aa', 'ap', 'pa', 'pp'], default='pa') parser.add_argument('-o', '--outfile', help='output file name (default: standard output)', type=argparse.FileType('w'), default=sys.stdout) args = parser.parse_args() pgon = args.polygon_fraction if pgon.D > 1: parser.error('star polygons not currently implemented') pgon_a = pgon.angle() / 2 radius_bottom = 1.0 if args.alignment == 'a': radius_top = radius_bottom if args.height > 0: height_top = args.height / 2 else: height_top = 0.5 * sin(pgon_a) * sqrt(2 - 1 / (cos(pgon_a / 2))**2) height_bottom = -height_top else: radius_top = radius_bottom * cos(pgon_a) if args.height > 0: height_top = args.height else: height_top = radius_bottom * sin(pgon_a) height_bottom = 0.0 if args.kite_angle >= 0.0: ang = args.kite_angle * pi / 180 else: ang = get_default_angle(pgon, radius_top, radius_bottom, height_top - height_bottom) print("calculated angle:" + str(180 / pi * ang), file=sys.stderr) points, faces = make_lamella_dome(pgon, radius_top, height_top, radius_bottom, height_bottom, ang, args.first_level, args.last_level, args.caps) out = anti_lib.OffFile(args.outfile) out.print_all_pgon(points, faces, pgon)