Exemplo n.º 1
0
def calc_temcor_side(pgon, pyramid_ht, base_ht, freq):
    freq += 1
    inrad = pgon.inradius()
    axis = Vec(-inrad, 0, pyramid_ht)           # axis to rotate plane around
    A = Vec(0, 0, base_ht + pyramid_ht)         # apex
    B = Vec(inrad, 0.5, base_ht)                # base polygon vertex

    n0 = Vec.cross(A, B).unit()

    edge_ang = anti_lib.angle_around_axis(Vec(B[0], 0, B[2]), B, axis)
    ang_inc = edge_ang/freq

    points = []
    faces = []
    for i in range(freq):
        n_inc = Mat.rot_axis_ang(axis, i*ang_inc) * Vec(0, 1, 0)
        edge_v = Vec.cross(n_inc, n0).unit()
        last_idx = i*(i-1)//2
        new_idx = i*(i+1)//2
        for j in range(i + 1):
            v = Mat.rot_axis_ang(axis, -2*j*ang_inc) * edge_v
            points.append(v)
            if new_idx and j < i:
                faces.append([new_idx+j, new_idx+j+1, last_idx+j])
            if j < i-1:
                faces.append([new_idx+j+1, last_idx+j+1, last_idx+j])

    return (points, faces)
Exemplo n.º 2
0
def calc_temcor_side(pgon, pyramid_ht, base_ht, freq):
    freq += 1
    inrad = pgon.inradius()
    axis = Vec(-inrad, 0, pyramid_ht)  # axis to rotate plane around
    A = Vec(0, 0, base_ht + pyramid_ht)  # apex
    B = Vec(inrad, 0.5, base_ht)  # base polygon vertex

    n0 = Vec.cross(A, B).unit()

    edge_ang = anti_lib.angle_around_axis(Vec(B[0], 0, B[2]), B, axis)
    ang_inc = edge_ang / freq

    points = []
    faces = []
    for i in range(freq):
        n_inc = Mat.rot_axis_ang(axis, i * ang_inc) * Vec(0, 1, 0)
        edge_v = Vec.cross(n_inc, n0).unit()
        last_idx = i * (i - 1) // 2
        new_idx = i * (i + 1) // 2
        for j in range(i + 1):
            v = Mat.rot_axis_ang(axis, -2 * j * ang_inc) * edge_v
            points.append(v)
            if new_idx and j < i:
                faces.append([new_idx + j, new_idx + j + 1, last_idx + j])
            if j < i - 1:
                faces.append([new_idx + j + 1, last_idx + j + 1, last_idx + j])

    return (points, faces)
Exemplo n.º 3
0
def make_arc(v0, v1, num_segs, start_idx):
    axis = Vec.cross(v0, v1).unit()
    ang = anti_lib.angle_around_axis(v0, v1, axis)
    points = [v0]
    faces = []
    mat = Mat.rot_axis_ang(axis, ang / num_segs)
    for i in range(num_segs):
        # accumulated error
        points.append(mat * points[-1])
        faces.append([start_idx + i, start_idx + i + 1])
    return points, faces
Exemplo n.º 4
0
def make_arc(v0, v1, num_segs, start_idx):
    axis = Vec.cross(v0, v1).unit()
    ang = anti_lib.angle_around_axis(v0, v1, axis)
    points = [v0]
    faces = []
    mat = Mat.rot_axis_ang(axis, ang/num_segs)
    for i in range(num_segs):
        # accumulated error
        points.append(mat * points[-1])
        faces.append([start_idx + i, start_idx + i+1])
    return points, faces
Exemplo n.º 5
0
def touching_spheres(R, p0, r0, p1, r1, p2, r2):
    # Add R to the radii, the intersection points of the three sheres are
    # the centres of the touching ball(s)
    r0 += R
    r1 += R
    r2 += R

    # find centre of circle nd readius where first two spheres intersect
    pc1, rc1 = sphere_intersection(p0, r0, p1, r1)
    if pc1 is None:
        return None, None

    # the second circle is defined by th plane of first circle intersecting
    # the third sphere
    # find centre of second circle
    p2_pc1 = pc1 - p2
    p0_p1 = p1 - p0
    unit_p0_p1 = p0_p1.unit()
    len_p2_pc2 = Vec.dot(p2_pc1, unit_p0_p1)

    # is circle outside of third sphere
    if not (r2 > len_p2_pc2 > -r2):
        return None, None

    p2_pc2 = unit_p0_p1 * len_p2_pc2
    pc2 = p2 + p2_pc2

    rc2 = math.sqrt(r2**2 - len_p2_pc2**2)

    # find pt - intersection of plane of sphere centres and line joining
    # touching spheres, and R distance pt to a touching sphere centre.
    pt, R = sphere_intersection(pc1, rc1, pc2, rc2)
    if pt is None:
        return None, None

    # make a vector length R perpendicular to the plane of the sphere centres
    R_norm = Vec.cross(p1 - p0, p2 - p0)
    len_R_norm = R_norm.mag()
    if not len_R_norm:
        return None, None

    R_norm = R_norm * R/len_R_norm

    return pt + R_norm, pt - R_norm
Exemplo n.º 6
0
def get_three_line_vert(A0, A1, B0, B1, ridge_down):
    A_edge = A1 - A0
    B_edge = B0 - A0
    cos_gamma = Vec.dot(A_edge.unit(), B_edge.unit())
    if abs(cos_gamma) > 1:
        cos_gamma /= abs(cos_gamma)
    gamma = acos(cos_gamma)
    d = (edge/2)*tan(gamma/2)
    h2 = 3*edge/4 - d**2
    if h2 < -epsilon:
        raise ValueError(
            'Not possible to calculate a three-line-fill triangle')
    h = (1 - 2*ridge_down) * sqrt(h2)

    A_mid = (A0 + A1) / 2
    B_mid = (B0 + B1) / 2
    mid_dir = (B_mid - A_mid).unit()
    norm = Vec.cross(B_edge, A_edge).unit()
    P_from_A_mid = mid_dir*d + norm*h
    return A_mid + P_from_A_mid
Exemplo n.º 7
0
def get_three_line_vert(A0, A1, B0, B1, ridge_down):
    A_edge = A1 - A0
    B_edge = B0 - A0
    cos_gamma = Vec.dot(A_edge.unit(), B_edge.unit())
    if abs(cos_gamma) > 1:
        cos_gamma /= abs(cos_gamma)
    gamma = acos(cos_gamma)
    d = (edge / 2) * tan(gamma / 2)
    h2 = 3 * edge / 4 - d**2
    if h2 < -epsilon:
        raise ValueError(
            'Not possible to calculate a three-line-fill triangle')
    h = (1 - 2 * ridge_down) * sqrt(h2)

    A_mid = (A0 + A1) / 2
    B_mid = (B0 + B1) / 2
    mid_dir = (B_mid - A_mid).unit()
    norm = Vec.cross(B_edge, A_edge).unit()
    P_from_A_mid = mid_dir * d + norm * h
    return A_mid + P_from_A_mid
Exemplo n.º 8
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)
Exemplo n.º 9
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)