예제 #1
0
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])
예제 #2
0
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)
예제 #3
0
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], [])
예제 #4
0
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, [])
예제 #5
0
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)
예제 #6
0
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)
예제 #7
0
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, [])
예제 #8
0
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)
예제 #9
0
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)
예제 #10
0
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)
예제 #11
0
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)
예제 #12
0
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)
예제 #13
0
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)
예제 #14
0
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)
예제 #15
0
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)
예제 #16
0
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)
예제 #17
0
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)
예제 #18
0
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)
예제 #19
0
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])
예제 #20
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)