예제 #1
0
def decide_online_tour_players(c, remote):
    """
    Sig:    Peer ==> array, dictionary
    Pre:    Peer is connected to another peer
    Post:   Array containing list of players on this side of connection, dictionary containing whether \
            players are human or computer controlled
    """
    # Determine number of players
    while True:
        choice = input("How many players on this computer? [" +
                       g.color("G", "1-7") + "](maximum 8 total) ")
        if type(int(choice)) == int:
            choice = int(choice)
            if choice >= 1 and choice <= 7:
                break

    # Send number of players and ensure remote and local don't exceed 8
    c.send(choice)
    print("Confirming number of players...")
    remote_choice = c.receive()
    if remote_choice + choice > 8:
        print("Your total is over 8. Try again")
        decide_online_tour_players(c, remote)

    nr_players = choice
    player_list = []  # Strings of names
    human_dict = {}  # Booleans. Key = player. True = Human, False = NPC
    # Determine names and human/computer controlled
    while True:
        choice = input("How many AI players? [" +
                       g.color("G", "0-" + str(nr_players)) + "] ")
        if type(int(choice)) == int:
            choice = int(choice)
            if choice <= nr_players:
                break
    nr_ai = choice

    # Name human players
    for player in range(nr_players - nr_ai):
        name = input("Name player" + str(player + 1) + ": ")
        player_list.append(name)
        human_dict[name] = True

    # Name AI players
    names = [
        "SKYNET", "MAX HEADROOM", "WATSON", "DEEP THOUGHT", "J.A.R.V.I.S.",
        "R2D2", "MU-TH-UR 6000", "TÄNKANDE AUGUST"
    ]
    for nr in range(nr_ai):
        # This is to ensure that server/client dont create players with the same name
        if remote:
            name = names[nr]
        else:
            name = names[nr + 4]
        player_list.append(name)
        human_dict[name] = False

    return player_list, human_dict
예제 #2
0
def vmd_label(molid,
              key,
              selection="all",
              label_color="white",
              textsize=1.0,
              offset=(0.0, 0.0, 0.0),
              idx_offset=None):
    """
    Labels atoms by index, charge, etc.

        Input:
           > molid       int; index of molecule to label
           > key         str; attribute to label atom by
           > textsize    float; size of label font
           > offset      (1,3)-list; offset to shift the label by
           > selection   str; selected atoms
           > num_offset  int; offset to add to atomic index
    """

    # select atoms to label
    selected_atoms = atomsel.atomsel(selection, molid)

    # complete selection of all atoms in order to label just the ones needed
    complete_selection = atomsel.atomsel("all", molid)
    atom_idxs = selected_atoms.get("index")
    print(len(atom_idxs))

    # get its coordinates
    xs = complete_selection.get("x")
    ys = complete_selection.get("y")
    zs = complete_selection.get("z")
    values = complete_selection.get(key)

    if key == "index":
        if idx_offset is not None:
            values = [i + idx_offset for i in values]

    if key == "charge":
        total_charge = sum(values)
        print("Total charge is {}".format(total_charge))
        del total_charge

    # set a label color
    graphics.color(molid, label_color)

    for atom_idx in atom_idxs:
        label_pos = (xs[atom_idx] + offset[0], ys[atom_idx] + offset[1],
                     zs[atom_idx] + offset[2])

        if key == "index":
            labelformat = "{}"
        else:
            labelformat = "{:2.3f}"

        label_text = labelformat.format(values[atom_idx])
        graphics.text(molid, tuple(label_pos), label_text, textsize)
예제 #3
0
def online_vs():
    """
    Sig:    None
    Pre:    None
    Post:   A game played between against a remote player
    """
    while True:
        name, human = get_online_name()
        choice = input("Are you the first to start the game? [" + g.color("G", "Y") + "]es [" \
                       + g.color("R", "N") + "]no\n[" + g.color("R", "Q") + "]uit ")
        if choice == "Y" or choice == "y":
            # Create peer which will act as server
            c = peer.Peer(True)
            c.accept_client()
            while True:
                # Name, peer, Human, Server
                win = game.online_vs(name, c, human, True)
                win = playOnlineVersusTournament(True, c, name, 'test')
                if win != "DRAW":
                    break
                else:
                    g.make_header("Game draw! Replay game")
            if win == name:
                g.make_header("You've won!")
            else:
                g.make_header("You've lost!")
            c.teardown()
            break

        elif choice == "N" or choice == "n":
            # Create peer which will act as client
            c = peer.Peer(False)
            c.connect_to_server()
            while True:
                # Name, peer, Human, Server
                win = game.online_vs(name, c, human, False)
                if win != "DRAW":
                    break
                else:
                    g.make_header("Game draw! Replay game")
            # Name, peer, Human = True, Server = False
            if win == name:
                g.make_header("You've won!")
            else:
                g.make_header("You've lost!")
            c.teardown()
            break

        elif choice == "Q" or choice == "q":
            sys.exit()

        else:
            print("Invalid choice, try again")
예제 #4
0
def draw_dotted_line(molid,
                     start,
                     end,
                     sradius=0.01,
                     drawcolor="blue",
                     sdist=0.1,
                     vmd_material="Basic1Pantone"):
    """
    Draw a dotted line between two pints 'start' and 'end'.

    Parameters
    ----------
    molid : int
        id of the molecule to draw the arrow to

    start : np-array; (1,3)-tuple
        starting coordinates

    end : np-array; (1,3)-tuple
        ending coordinates

    sradius : float
        radii of the dots

    drawcolor : str
        color of the dots

    sdist : float
        distance between points

    """
    graphics.material(molid, vmd_material)
    graphics.color(molid, drawcolor)

    # vector between start and end
    p_vector = end - start
    length_p_vector = np.linalg.norm(p_vector)

    # normed p_vector
    normed_p_vector = p_vector / length_p_vector

    # number of points
    num_points = int(length_p_vector / sdist)

    # first sphere
    for pt in range(num_points):
        csphere = start + normed_p_vector * sdist * pt
        graphics.sphere(molid, center=tuple(csphere), radius=sradius)
예제 #5
0
def get_online_name():
    """
    Sig:    None
    Pre:    None
    Post:   Name, and boolean corresponding to whether player is human or NPC
    """
    name = input("Input your name: ")
    while True:
        human = input("Are you a human player? [" + g.color("G", "Y") + "/" +
                      g.color("R", "N") + "]")
        if human == "Y" or human == "y":
            human = True
            break
        if human == "n" or human == "n":
            human = False
            break

    return name, human
예제 #6
0
def decide_offline_tour_players():
    player_list = []  # Strings of names
    human_dict = {}  # Booleans. Key = player. True = Human, False = NPC
    # Decide nr players
    while True:
        choice = input("How many players? [" + g.color("G", "3-8") + "] ")
        if type(int(choice)) == int:
            choice = int(choice)
            if choice > 2 and choice < 9:
                break
    nr_players = choice

    # Decide nr AI players
    while True:
        choice = input("How many AI players? [" +
                       g.color("G", "0-" + str(nr_players)) + "] ")
        if type(int(choice)) == int:
            choice = int(choice)
            if choice <= nr_players:
                break
    nr_ai = choice

    # Name human players
    for player in range(nr_players - nr_ai):
        name = input("Name player" + str(player + 1) + ": ")
        player_list.append(name)
        human_dict[name] = True

    # Name AI players
    names = [
        "SKYNET", "MAX HEADROOM", "WATSON", "DEEP THOUGHT", "J.A.R.V.I.S.",
        "R2D2", "MU-TH-UR 6000", "TÄNKANDE AUGUST"
    ]
    for nr in range(nr_ai):
        name = names[nr]
        player_list.append(name)
        human_dict[name] = False

    return player_list, human_dict
예제 #7
0
def online_tour_play():
    """
    Sig:    None
    Pre:    None
    Post:   A tournament played between local, and remote players. And/or termination of program
    """
    g.make_header("Tournament play!")

    while True:
        choice = input("Are you the first to start the game? [" + g.color("G", "Y") + "]es ["\
                       + g.color("R", "N") + "]no\n[" + g.color("R", "Q") + "]uit ")
        if choice == "Y" or choice == "y":
            server_side_tournament()

        elif choice == "N" or choice == "n":
            client_side_tournament()

        elif choice == "Q" or choice == "q":
            sys.exit()

        else:
            print("Invalid choice, try again")
예제 #8
0
def get_local_names():
    """
    Sig:    None
    Pre:    None
    Post:   List of names, and list of booleans corresponding to whether player is human or NPC
    """
    players = []
    humans = []

    for i in range(2):
        name = input("Name player " + str(i + 1) + ": ")
        while True:
            human = input("Is this a human player? [" + g.color("G", "Y") +
                          "/" + g.color("R", "N") + "]")
            if human == "Y" or human == "y":
                human = True
                break
            if human == "n" or human == "n":
                human = False
                break
        players.append(name)
        humans.append(human)

    return players, humans
예제 #9
0
def menu_options():
    """
    Sig:    None
    Pre:    None
    Post:   A played game or tournament in the case of user choosing so, and termination of program
    """
    playing = True
    while playing:
        g.make_header("Welcome to <game>!")
        print("You have the following options:\n 1[" + g.color("G", "v")\
              + "]s1\n["  + g.color("G", "T") + "]ournament\n[" + g.color("R", "Q") + "]uit ")
        choice = input("Please make your " + g.color("G", "choice: "))

        # 1 vs 1 game
        if choice == "V" or choice == "v":
            while True:
                print("Do you wish to play [" + g.color("G", "L") + "]ocal or [" + g.color("G", "O") + "]nline?\n["\
                      + g.color("R", "R") + "]eturn to previous options\n[" + g.color("R", "Q") + "]uit ")
                choice = input("Please make your " + g.color("G", "choice: "))

                # Local game
                if choice == "L" or choice == "l":
                    local_vs()
                    playing = False
                    break

                # Online game
                elif choice == "O" or choice == "o":
                    online_vs()
                    playing = False
                    break

                elif choice == "R" or choice == "r":
                    break

                elif choice == "Q" or choice == "q":
                    sys.exit()

                else:
                    print("Invalid choice, try again")

        # Tournament game
        elif choice == "T" or choice == "t":
            while True:
                print("Do you wish to play [" + g.color("G", "L") + "]ocal or [" + g.color("G", "O") + "]nline?\n["\
                      + g.color("R", "R") + "]eturn to previous options\n[" + g.color("R", "Q") + "]uit ")
                choice = input("Please make your " + g.color("G", "choice: "))

                # Local tournament
                if choice == "L" or choice == "l":
                    local_tour_play()
                    playing = False
                    break

                # Online tournament
                elif choice == "O" or choice == "o":
                    online_tour_play()
                    playing = False
                    break

                elif choice == "R" or choice == "r":
                    break

                elif choice == "Q" or choice == "q":
                    sys.exit()

                else:
                    print("Invalid choice, try again")

        elif choice == "Q" or choice == "q":
            sys.exit()

        else:
            print("Invalid choice, try again")
예제 #10
0
def draw_circle(molid,
                rotaxis,
                center,
                angle=360,
                drawcolor="blue",
                circle_radius=0.2,
                vmd_material="Basic1Pantone",
                cylinder_radius=0.01,
                cone_radius=0.02,
                cone_length=10):
    """
    Draw a circle around center using a rotational axis.

    Parameters
    ----------
    molid : int
    frame_id : int

    rotaxis : numpy-array {float float float}
        rotational axis

    center : numpy-array {float float float}
        center to rotate around

    angle : float or int
        angle to rotate about in degrees

    color : str
        color of the circle

    circle_radius : float
        circle_radius of the circle

    resolution : int
        vectors the circle consists of

    """
    # change color and material of circle
    graphics.color(molid, drawcolor)
    graphics.material(molid, vmd_material)

    # norm rotational axis
    rotaxis /= np.linalg.norm(rotaxis)

    # create and scale first vector according to given radius
    normal1 = np.cross(rotaxis, center)
    normal1 /= np.linalg.norm(normal1)
    normal1 *= circle_radius

    vector_start = normal1

    # double angle for more points
    angle *= 2

    for cangle in range(angle - cone_length):
        #print(cangle)
        # convert angle to radians
        cangle = np.radians(cangle / 2)
        #print(cangle)

        # define quaternion according to current angle
        quaternion = Quaternion(axis=rotaxis, angle=cangle)

        # define end of vector
        vector_end = quaternion.rotate(normal1)
        #vector_end /= np.linalg.norm(vector_end)
        #vector_end *= radius

        graphics.cylinder(molid,
                          tuple(center + vector_start),
                          tuple(center + vector_end),
                          radius=cylinder_radius,
                          resolution=20,
                          filled=1)
        #graphics.sphere(molid, tuple(center + vector_start), radius=0.02)

        # new starting point is old ending
        vector_start = vector_end

    # draw an arrow beginning 5 degrees before the last angle
    vector_start = vector_end

    quaternion = Quaternion(axis=rotaxis,
                            angle=np.radians(angle / 2 + cone_length))
    vector_end = quaternion.rotate(normal1)

    graphics.cone(molid,
                  tuple(center + vector_start),
                  tuple(center + vector_end),
                  radius=cone_radius,
                  resolution=20)
예제 #11
0
def draw_double_bonds(molid,
                      frame_id,
                      bonds,
                      radius=0.02,
                      filled=True,
                      vmd_material="Basic1Pantone"):
    """
    Draw double bonds using cylinders given a dictionary with according bonds.

    Parameters
    ----------
    molid : int
        molecule id to draw the cylinder in
    frame_id : int
        id of the frame to use the coordinates from
    bonds : list {list {int, int, int, int}, list {int, int, int, int}, ...}
        first two integers of each sublist form the bond, the others form
        the vector which forms the plane in which the double will be located
    """

    # TODO: since a double bond is always in a plane, both neighbor bonds
    # TODO: are also in that plane, therefor a plane can always easily
    #       be defined without explicitly naming the neighbors
    selection_str = "index {}"
    element_colors = color.get_colormap("Element")
    graphics.material(molid, vmd_material)

    for cbond in bonds:
        selection_str1 = selection_str.format(cbond[0])
        selection_str2 = selection_str.format(cbond[1])
        selection_str3 = selection_str.format(cbond[2])
        selection_str4 = selection_str.format(cbond[3])

        # get vector which is the bond
        vt1_coords = vmd_coords_numpy_arrays(molid, frame_id, selection_str1)
        vt2_coords = vmd_coords_numpy_arrays(molid, frame_id, selection_str2)
        #print(vt1_coords)
        bond = vt2_coords - vt1_coords

        # get vector forms the plane with bond vector
        vt3_coords = vmd_coords_numpy_arrays(molid, frame_id, selection_str3)
        vt4_coords = vmd_coords_numpy_arrays(molid, frame_id, selection_str4)
        bond_neigh = vt4_coords - vt3_coords

        # get normal to bond vector and neighbor vector
        normal1 = np.cross(bond_neigh, bond)
        normal1 /= np.linalg.norm(normal1)

        # get normal to normal of bond and bond neigh
        # and bond - this is the desired shift vector for the bond
        normal2 = np.cross(bond, normal1)
        normal2 /= np.linalg.norm(normal2)

        # draw double bond
        tail_bond2 = vt1_coords + normal2 * 0.1
        head_bond2 = vt2_coords + normal2 * 0.1

        # center between tail and head (for coloring)
        center = bond / 2 + vt1_coords + normal2 * 0.1

        # get color of atoms
        selection1 = atomsel.atomsel(selection_str1)
        selection2 = atomsel.atomsel(selection_str2)

        # get element name
        atom1_element = selection1.get("element")[0]
        atom2_element = selection2.get("element")[0]

        # get element color
        atom1_color = element_colors[atom1_element]
        atom2_color = element_colors[atom2_element]

        # draw double bond - atom 1 to center using corresponding color
        graphics.color(molid, atom1_color)
        graphics.cylinder(molid,
                          tuple(tail_bond2),
                          tuple(center),
                          radius=radius,
                          filled=filled)

        # draw double bond - center to atom 2 using corresponding color
        graphics.color(molid, atom2_color)
        graphics.cylinder(molid,
                          tuple(center),
                          tuple(head_bond2),
                          radius=radius,
                          filled=filled)
예제 #12
0
def vmd_draw_box(lines,
                 molid=0,
                 vmd_material="Basic1Pantone",
                 drawcolor="blue",
                 lstyle="solid",
                 lwidth=1,
                 lfreq=15):
    """
    Draw the unit cell in molid.

    This function takes the output from the lines_to_draw function.

    Parameters
    ----------
    molid : int, optional
        id of loaded molecule in vmd

    lines : {list{list, list}, list{list, list}}
        all lines with starting and endpoints that are to be drawn;
        this is the output from the lines_to_draw function

    lstyle : str; 'solid' or 'dashed' or '--'
        draw dashed lines or own dashed lines

    lwidth : int
        width of the line

    lfreq : int
        frequency a line shall be drawn, which is lfreq / 2 since every
        second line is skipped

    """
    #all_molids = molecule.listall()

    graphics.material(molid, vmd_material)
    graphics.color(molid, drawcolor)

    for ucell_line in lines:
        #print(ucell_line)

        # use a more rough dashing than the built-in one
        if lstyle == "--":
            # divide current line into sublines
            pstart = ucell_line[0]

            # get the subline and norm it
            subline = ucell_line[1] - ucell_line[0]
            subline /= lfreq

            for cntr in range(lfreq):
                pstop = pstart + subline

                if cntr % 2 == 0:
                    #print(cntr)
                    graphics.line(molid,
                                  tuple(pstart),
                                  tuple(pstop),
                                  style="solid",
                                  width=lwidth)

                pstart = pstop
        else:
            graphics.line(molid,
                          tuple(ucell_line[0]),
                          tuple(ucell_line[1]),
                          style=lstyle,
                          width=lwidth)
예제 #13
0
def vmd_draw_angle(molid,
                   frame,
                   atomids=None,
                   atm_coords=None,
                   canvas=False,
                   resolution=200,
                   radius=0.5,
                   drawcolor="blue",
                   cylinder_radius=0.01):
    """
    Draws part of a circle to visualize the measured angle.

        Input:
            > moldid     int; index of molecule to draw the angle for
            > frame      int; frame number to draw the angle for
            > atomids    tuple; all three atom ids with second one as angular
                         point
            > canvas     boolean; draw a canvas between bow and angle axis
            > resolution int; number of cylinders and spheres that form the angle

    """
    if atomids is not None:
        id1, id2, id3 = atomids
        # select all atoms
        sel = atomsel.atomsel("all", molid, frame)
        # get coordinates
        x = sel.get("x")
        y = sel.get("y")
        z = sel.get("z")
        # get rotational axis
        atm1Crds = np.array([x[id1], y[id1], z[id1]])
        atm2Crds = np.array([x[id2], y[id2], z[id2]])
        atm3Crds = np.array([x[id3], y[id3], z[id3]])
    elif atm_coords is not None:
        atm1Crds, atm2Crds, atm3Crds = atm_coords
    else:
        raise Warning(
            "At least atomic coordinates or atom ids have to be provided!")

    # draw bows in the current molecule, transparent canvas in a new molecule
    if canvas is True:
        molecule.new("angle canvas")
        graphics_id = molecule.num() - 1  # ids start with 0
    else:
        graphics_id = molid

    graphics.color(graphics_id, drawcolor)

    #pdb.set_trace()
    # define angle and rotational axis
    vt1 = atm1Crds - atm2Crds
    vt2 = atm3Crds - atm2Crds
    vtRot = np.cross(vt1, vt2)

    # unit vectors for quaternions
    vt1 /= np.linalg.norm(vt1)
    vt2 /= np.linalg.norm(vt2)
    vtRot /= np.linalg.norm(vtRot)

    # define angle offset
    max_angle = np.arccos(np.dot(
        vt1, vt2))  # denominator is 1 since vectors are normed
    print("Measured angles: {}".format(np.degrees(max_angle)))
    angle_offset = np.pi / resolution

    vt1 *= radius
    vt2 *= radius

    for cntr, theta in enumerate(np.arange(0, max_angle, angle_offset)):
        # previous vector
        if cntr == 0:
            vt_pre = vt1 + atm2Crds

        # define quaternion
        q = Quaternion(axis=vtRot, angle=theta)
        #print(q)

        # rotate vector
        vt_cur = q.rotate(vt1)
        vt_cur += atm2Crds

        if canvas is True and cntr != 0:
            graphics.triangle(graphics_id, tuple(vt_pre), tuple(atm2Crds),
                              tuple(vt_cur))
        else:
            graphics.cylinder(graphics_id,
                              tuple(vt_pre),
                              tuple(vt_cur),
                              radius=cylinder_radius,
                              resolution=20,
                              filled=1)
        vt_pre = vt_cur

    if canvas is True:
        graphics.triangle(graphics_id, tuple(vt_pre), tuple(atm2Crds),
                          tuple(vt2 + atm2Crds))
        graphics.material(graphics_id, "Transparent")
    else:
        graphics.cylinder(graphics_id,
                          tuple(vt_pre),
                          tuple(vt2 + atm2Crds),
                          radius=cylinder_radius,
                          resolution=20,
                          filled=1)
예제 #14
0
def vmd_draw_arrow(molid,
                   start,
                   end,
                   cylinder_radius=0.4,
                   cone_radius=1.0,
                   cone_length=0.15,
                   resolution=50,
                   double_arrow=False,
                   vmd_material="Basic1Pantone",
                   drawcolor="blue",
                   lstyle="solid"):
    """
    Draws an arrow from start to end using the arrow color and a certain radius
    for the cylinder and the cone (top).
    Draw cylinder of 90 % of the max length and the tip from 75 % of the total
    arrow length.

    Input:
        > molid             int; id of the molecule to draw the arrow to
        > start             np-array; (1,3)-tuple with starting coordinates
        > end               np-array; (1,3)-tuple with ending coordinates
        > cylinder_radius   float; radius of the arrow base
        > cone_radius       float; radius of the cone

    lstyle : str; solid | dashed
        draw a solid (default) or dashed arrow
    """
    graphics.material(molid, vmd_material)
    graphics.color(molid, drawcolor)
    p_vector = end - start

    # shift starting point of the vector by cone_length towards the end point
    if double_arrow is True:
        # shorten vector so there is place for the cone at the starting point
        p_start = start + p_vector * cone_length
    else:
        p_start = start

    # shorten vector so there is place for the cone at the ending point
    p_end = start + p_vector * (1 - cone_length)
    graphics.cone(molid,
                  tuple(p_end),
                  tuple(end),
                  radius=cone_radius,
                  resolution=resolution)
    graphics.cone(molid,
                  tuple(p_start),
                  tuple(start),
                  radius=cone_radius,
                  resolution=resolution)

    if lstyle == "solid":
        graphics.cylinder(molid,
                          tuple(p_start),
                          tuple(p_end),
                          radius=cylinder_radius,
                          resolution=resolution)
    elif lstyle == "dashed":
        # length of a single cylinder
        len_cylinder = 0.08

        # normed length of the vector between the cones
        p_vector_len = np.linalg.norm(p_start - p_end)

        # number of cylinders that fit between the cones with len_cylinder length
        ncylinders = int(p_vector_len // len_cylinder)
        p_vector_unit = (p_end - p_start) / p_vector_len

        # define the intermediate vector
        inter_end = [0, 0, 0]

        # draw vectors ncylinders times
        for i in range(ncylinders):
            inter_end = p_start + p_vector_unit * len_cylinder

            if i % 2 == 0:
                graphics.cylinder(molid,
                                  tuple(p_start),
                                  tuple(inter_end),
                                  radius=cylinder_radius,
                                  resolution=resolution)
                #pdb.set_trace()

            p_start = inter_end
    else:
        pass
예제 #15
0
def draw_torsion(molid,
                 frame,
                 atomids,
                 canvas=False,
                 resolution=50,
                 radius=0.5,
                 drawcolor="blue"):
    """
    """
    id1, id2, id3, id4 = atomids

    # draw bows in the current molecule, transparent canvas in a new molecule
    if canvas is True:
        molecule.new("angle canvas")
        graphics_id = molecule.num() - 1  # ids start with 0
    else:
        graphics_id = molid

    graphics.color(graphics_id, drawcolor)

    # select all atoms
    sel = atomsel.atomsel("all", molid, frame)

    # get coordinates
    x = sel.get("x")
    y = sel.get("y")
    z = sel.get("z")

    # get rotational axis
    atm1Crds = np.array([x[id1], y[id1], z[id1]])
    atm2Crds = np.array([x[id2], y[id2], z[id2]])
    atm3Crds = np.array([x[id3], y[id3], z[id3]])
    atm4Crds = np.array([x[id4], y[id4], z[id4]])

    # define angle and rotational axis
    #vt1    = atm1Crds - atm2Crds
    #vt2    = atm3Crds - atm2Crds
    #vtRot  = np.cross(vt1, vt2)

    # unit vectors for quaternions
    #vt1   /= np.linalg.norm(vt1)
    #vt2   /= np.linalg.norm(vt2)
    #vtRot /= np.linalg.norm(vtRot)
    #print(atm1Crds)
    _, cp1, cp2 = ag_geometry.get_dihedral(atm1Crds,
                                           atm2Crds,
                                           atm3Crds,
                                           atm4Crds,
                                           return_cross=True)

    # draw vectors between id2 and id3, therefor get the relevant vector
    center_pt = atm2Crds + (atm3Crds - atm2Crds) * 0.5
    cp1 += center_pt
    cp2 += center_pt
    vmd_draw_angle(molid,
                   frame,
                   atm_coords=[cp1, center_pt, cp2],
                   canvas=False,
                   resolution=resolution,
                   radius=radius,
                   drawcolor="blue")