def baseframe_from_pam5_data(ss1, gv, ss2):
    """
    Given the positions of the Ss5-Gv5-Ss5 atoms in a PAM5 basepair,
    return the first Ss5's baseframe (and y_m) as a tuple of
    (origin, rel_to_abs_quat, y_m).

    @note: this is correct even if gv is actually an Ax5 position.
    """
    # y axis is parallel to inter-sugar line

    # base plane orientation comes from the other atom, Gv

    # so get x and z axis around that line

    origin = ss1

    y_vector = ss2 - ss1
    y_length = vlen(y_vector)

    ## y_direction = norm(ss2 - ss1)
    y_direction = y_vector / y_length  # optimization

    z_direction = norm(cross(gv - ss1, y_direction))
    # BUG: nothing checks for cross product being too small

    x_direction = norm(cross(y_direction, z_direction))
    # this norm is redundant, but might help with numerical stability

    rel_to_abs_quat = Q(x_direction, y_direction, z_direction)

    y_m = y_length / 2.0

    return (origin, rel_to_abs_quat, y_m)
def baseframe_from_pam3_data(ss1, ax, ss2):
    """
    Given the positions of the Ss3-Ax3-Ss3 atoms in a PAM3 basepair,
    return the first Ss3's baseframe (and y_m) as a tuple of
    (origin, rel_to_abs_quat, y_m).
    """
    yprime_vector = ss2 - ss1
    yprime_length = vlen(yprime_vector)

    y_direction = yprime_vector / yprime_length  # optimization of norm

    z_direction = norm(cross(ax - ss1, y_direction))
    # BUG: nothing checks for cross product being too small

    x_direction = norm(cross(y_direction, z_direction))
    # this norm is redundant, but might help with numerical stability

    rel_to_abs_quat = Q(x_direction, y_direction, z_direction)

    # still need origin, easy since we know SPRIME_D_SDFRAME -- but we do have to rotate that, using the quat

    # rel_to_abs_quat.rot( SPRIME_D_SDFRAME ) # this is Ss5 to Ss3 vector, abs coords

    Ss3_d_abspos = ss1
    Ss5_d_abspos = Ss3_d_abspos - rel_to_abs_quat.rot(SPRIME_D_SDFRAME)

    origin = Ss5_d_abspos

    # y_m = (|S'_u - S'_d| / 2) + y_s'
    y_m = yprime_length / 2.0 + Y_SPRIME

    return (origin, rel_to_abs_quat, y_m)
Example #3
0
 def closest_pt_params_to_ray(self, ray):
     ""
     p2, v2 = ray.params # note: at first I wrote self.params() (using method not attr)
     p1, v1 = self.params
     # do some math, solve for k in p1 + k * v1 = that point (remember that the vecs can be of any length):
     # way 1: express p2-p1 as a weighted sum of v1, v2, cross(v1,v2), then take the v1 term in that sum and add it to p1.
     # way 2: There must be a NumPy function that would just do this in about one step...
     # way 3: or maybe we can mess around with dot(v1,v2) sort of like in corner_analyzer in demo_polygon...
     # way 4: or we could google for "closest points on two lines" or so...
     # way 5: or we could call it the intersection of self with the plane containing p2, and directions v2 and the cross prod,
     # and use a formula in VQT. Yes, that may not be self-contained but it's fastest to code!
     v1n = norm(v1)
     v2n = norm(v2)
     perp0 = cross(v1n, v2n)
     if vlen(perp0) < 0.01:
         ##k btw what if the lines are parallel, in what way should we fail?
         # and for that matter what if they are *almost* parallel so that we're too sensitive -- do we use an env param
         # to decide whether to fail in that case too? If we're an Instance we could do that from self.env... #e
         print "closest_pt_params_to_ray: too sensitive, returning None" ###### teach caller to handle this; let 0.01 be option
         return None
     perpn = norm(perp0)
     perpperp = cross(perpn,v2n)
     inter = planeXline(p2, perpperp, p1, v1n) # intersect plane (as plane point and normal) with line (as point and vector)
     if inter is None:
         print "inter is None (unexpected); data:",p1,v1,p2,v2,perp0
         return None
     # inter is the retval for a variant which just wants the closest point itself, i.e. closest_pt_to_ray
     return dot(inter - p1, v1n) / vlen(v1)
Example #4
0
def baseframe_from_pam5_data(ss1, gv, ss2):
    """
    Given the positions of the Ss5-Gv5-Ss5 atoms in a PAM5 basepair,
    return the first Ss5's baseframe (and y_m) as a tuple of
    (origin, rel_to_abs_quat, y_m).

    @note: this is correct even if gv is actually an Ax5 position.
    """
    # y axis is parallel to inter-sugar line

    # base plane orientation comes from the other atom, Gv

    # so get x and z axis around that line
    
    origin = ss1

    y_vector = ss2 - ss1
    y_length = vlen(y_vector)
    
    ## y_direction = norm(ss2 - ss1)
    y_direction = y_vector / y_length # optimization
    
    z_direction = norm(cross(gv - ss1, y_direction))
        # BUG: nothing checks for cross product being too small

    x_direction = norm(cross(y_direction, z_direction))
        # this norm is redundant, but might help with numerical stability

    rel_to_abs_quat = Q(x_direction, y_direction, z_direction)

    y_m = y_length / 2.0

    return ( origin, rel_to_abs_quat, y_m )
Example #5
0
 def closest_pt_params_to_ray(self, ray):
     ""
     p2, v2 = ray.params  # note: at first I wrote self.params() (using method not attr)
     p1, v1 = self.params
     # do some math, solve for k in p1 + k * v1 = that point (remember that the vecs can be of any length):
     # way 1: express p2-p1 as a weighted sum of v1, v2, cross(v1,v2), then take the v1 term in that sum and add it to p1.
     # way 2: There must be a NumPy function that would just do this in about one step...
     # way 3: or maybe we can mess around with dot(v1,v2) sort of like in corner_analyzer in demo_polygon...
     # way 4: or we could google for "closest points on two lines" or so...
     # way 5: or we could call it the intersection of self with the plane containing p2, and directions v2 and the cross prod,
     # and use a formula in VQT. Yes, that may not be self-contained but it's fastest to code!
     v1n = norm(v1)
     v2n = norm(v2)
     perp0 = cross(v1n, v2n)
     if vlen(perp0) < 0.01:
         ##k btw what if the lines are parallel, in what way should we fail?
         # and for that matter what if they are *almost* parallel so that we're too sensitive -- do we use an env param
         # to decide whether to fail in that case too? If we're an Instance we could do that from self.env... #e
         print "closest_pt_params_to_ray: too sensitive, returning None"  ###### teach caller to handle this; let 0.01 be option
         return None
     perpn = norm(perp0)
     perpperp = cross(perpn, v2n)
     inter = planeXline(
         p2, perpperp, p1, v1n
     )  # intersect plane (as plane point and normal) with line (as point and vector)
     if inter is None:
         print "inter is None (unexpected); data:", p1, v1, p2, v2, perp0
         return None
     # inter is the retval for a variant which just wants the closest point itself, i.e. closest_pt_to_ray
     return dot(inter - p1, v1n) / vlen(v1)
Example #6
0
def baseframe_from_pam3_data(ss1, ax, ss2):
    """
    Given the positions of the Ss3-Ax3-Ss3 atoms in a PAM3 basepair,
    return the first Ss3's baseframe (and y_m) as a tuple of
    (origin, rel_to_abs_quat, y_m).
    """
    yprime_vector = ss2 - ss1
    yprime_length = vlen(yprime_vector)
    
    y_direction = yprime_vector / yprime_length # optimization of norm
    
    z_direction = norm(cross(ax - ss1, y_direction))
        # BUG: nothing checks for cross product being too small

    x_direction = norm(cross(y_direction, z_direction))
        # this norm is redundant, but might help with numerical stability

    rel_to_abs_quat = Q(x_direction, y_direction, z_direction)

    # still need origin, easy since we know SPRIME_D_SDFRAME -- but we do have to rotate that, using the quat

    # rel_to_abs_quat.rot( SPRIME_D_SDFRAME ) # this is Ss5 to Ss3 vector, abs coords

    Ss3_d_abspos = ss1
    Ss5_d_abspos = Ss3_d_abspos - rel_to_abs_quat.rot( SPRIME_D_SDFRAME )

    origin = Ss5_d_abspos

    # y_m = (|S'_u - S'_d| / 2) + y_s'
    y_m = yprime_length / 2.0 + Y_SPRIME

    return ( origin, rel_to_abs_quat, y_m )
Example #7
0
def drawLinearDimension(color,      # what color are we drawing this in
                        right, up,  # screen directions mapped to xyz coords
                        bpos,       # position of the handle for moving the text
                        p0, p1,     # positions of the ends of the dimension
                        text, highlighted=False):
    outOfScreen = cross(right, up)
    bdiff = bpos - 0.5 * (p0 + p1)
    csys = CylindricalCoordinates(p0, p1 - p0, bdiff, right)
    # This works OK until we want to keep the text right side up, then the
    # criterion for right-side-up-ness changes because we've changed 'up'.
    br, bt, bz = csys.rtz(bpos)
    e0 = csys.xyz((br + 0.5, 0, 0))
    e1 = csys.xyz((br + 0.5, 0, 1))
    drawline(color, p0, e0)
    drawline(color, p1, e1)
    v0 = csys.xyz((br, 0, 0))
    v1 = csys.xyz((br, 0, 1))
    if highlighted:
        drawline(color, v0, v1, width=THICKLINEWIDTH)
    else:
        drawline(color, v0, v1)
    # draw arrowheads at the ends
    a1, a2 = 0.25, 1.0 * csys.zinv
    arrow00 = csys.xyz((br + a1, 0, a2))
    arrow01 = csys.xyz((br - a1, 0, a2))
    drawline(color, v0, arrow00)
    drawline(color, v0, arrow01)
    arrow10 = csys.xyz((br + a1, 0, 1-a2))
    arrow11 = csys.xyz((br - a1, 0, 1-a2))
    drawline(color, v1, arrow10)
    drawline(color, v1, arrow11)
    # draw the text for the numerical measurement, make
    # sure it goes from left to right
    xflip = dot(csys.z, right) < 0
    # then make sure it's right side up
    theoreticalRight = (xflip and -csys.z) or csys.z
    theoreticalOutOfScreen = cross(theoreticalRight, bdiff)
    yflip = dot(theoreticalOutOfScreen, outOfScreen) < 0
    if debug_flags.atom_debug:
        print "DEBUG INFO FROM drawLinearDimension"
        print csys
        print theoreticalRight, theoreticalOutOfScreen
        print xflip, yflip
    if yflip:
        def fx(y):
            return br + 1.5 - y / (1. * HEIGHT)
    else:
        def fx(y):
            return br + 0.5 + y / (1. * HEIGHT)
    if xflip:
        def fz(x):
            return 0.9 - csys.zinv * x / (1. * WIDTH)
    else:
        def fz(x):
            return 0.1 + csys.zinv * x / (1. * WIDTH)
    def tfm(x, y, fx=fx, fz=fz):
        return csys.xyz((fx(y), 0, fz(x)))
    f3d = Font3D()
    f3d.drawString(text, tfm=tfm, color=color)
Example #8
0
    def recompute_geom_from_quats(self):  # non-ring class
        """
        [not a ring; various possible end situations]
        """
        out = self.out
        up = self.up
        atoms = self.lista
        bonds = self.listb
        # (I wish I could rename these attrs to "atoms" and "bonds",
        #  but self.atoms conflicts with the Jig attr, and self.chain_atoms is too long.)
        # default values:
        self.bm1R_pvec = "not needed"  # and bug if used, we hope, unless we later change this value
        self.twist = None
        # Figure out p vectors for atom[0]-end (left end) of bond[0], and atom[-1]-end (right end) of bond[-1].
        # If both are determined from outside this chain (i.e. if the subrs here don't return None),
        # or if we are a ring (so they are forced to be the same, except for the projection due to bond bending at the ring-joining atom),
        # then [using self.recompute_geom_both_ends_constrained()] they must be made to match (up to an arbitrary sign),
        # using a combination of some twist (to be computed here) along each bond,
        # plus a projection and (in some cases, depending on bond types i think -- see self.twist90)
        # 90-degree turn at each bond-bond connection;
        # the projection part for all the bond-bond connections is already accumulated in self.chain_quat_cum.

        # note: the following p-vec retvals are in abs coords, as they should be
        #e rename the funcs, since they are not only for sp2, but for any atom that ends our chain of pi bonds
        pvec1 = p_vector_from_sp2_atom(atoms[0], bonds[0], out=out,
                                       up=up)  # might be None
        pvec2 = p_vector_from_sp2_atom(
            atoms[-1], bonds[-1], out=out, up=up
        )  # ideally, close to negative or positive of pvec1 ###@@@ handle neg
        # handle one being None (use other one to determine the twist) or both being None (use arb vectors)
        if pvec1 is None:
            if pvec2 is None:
                # use arbitrary vectors on left end of bonds[0], perp to bond and to out; compute differently if bond axis ~= out
                axis = self.axes[0]
                pvec = cross(out, axis)
                lenpvec = vlen(pvec)
                if lenpvec < 0.01:
                    # bond axis is approx parallel to out
                    pvec = cross(up, axis)
                    lenpvec = vlen(
                        pvec
                    )  # won't be too small -- bond can't be parallel to both up and out
                pvec /= lenpvec
                self.b0L_pvec = pvec
            else:
                # pvec2 is defined, pvec1 is not. Need to transport pvec2 back to coords of pvec1
                # so our standard code (pvec_i, which wants pvec1, i.e. self.b0L_pvec) can be used.
                self.b0L_pvec = self.chain_quat_cum.unrot(pvec2)
        else:
            if pvec2 is None:
                self.b0L_pvec = pvec1
            else:
                # both vectors not None -- use recompute_geom_both_ends_constrained
                self.b0L_pvec = pvec1
                self.bm1R_pvec = pvec2
                self.recompute_geom_both_ends_constrained()
        return  # from non-ring recompute_geom_from_quats
Example #9
0
    def rotateAboutPoint(self):
        """
        Rotates the selected entities along the specified vector, about the
        specified pivot point (pivot point it the starting point of the
        drawn vector.
        """
        
        if len(self.mouseClickPoints) != self.mouseClickLimit:
            print_compact_stack("Rotate about point bug: mouseclick points != mouseclicklimit: ")
            return
            
        
        pivotPoint = self.mouseClickPoints[0]
        ref_vec_endPoint = self.mouseClickPoints[1]
        rot_vec_endPoint = self.mouseClickPoints[2]
        
        reference_vec = norm(ref_vec_endPoint - pivotPoint)
        
        lineVector = norm(rot_vec_endPoint - pivotPoint)
                           
            
        #lineVector = endPoint - startPoint

        quat1 = Q(lineVector, reference_vec)
                
        #DEBUG Disabled temporarily . will not be used
        if dot(lineVector, reference_vec) < 0:
            theta = math.pi - quat1.angle
        else:
            theta = quat1.angle

        #TEST_DEBUG-- Works fine
        theta = quat1.angle

        rot_axis = cross(lineVector, reference_vec)
        
        
        if dot(lineVector, reference_vec) < 0:
            rot_axis = - rot_axis

        cross_prod_1 = norm(cross(reference_vec, rot_axis))
        cross_prod_2 = norm(cross(lineVector, rot_axis))

        if dot(cross_prod_1, cross_prod_2) < 0:
            quat2 = Q(rot_axis, theta)
        else:
            quat2 = Q(rot_axis, - theta)

        movables = self.graphicsMode.getMovablesForLeftDragging()
        self.assy.rotateSpecifiedMovables(
            quat2,
            movables = movables,
            commonCenter = pivotPoint)

        self.glpane.gl_update()
        return
Example #10
0
def calc_torsion_angle(atom_list):
    """
    Calculates torsional angle defined by four atoms, A1-A2-A3-A4,
    Return torsional angle value between atoms A2 and A3.
    
    @param atom_list: list of four atoms describing the torsion bond
    @type atom_list: list
    
    @return: value of the torsional angle (float)
    """
    # Note: this appears to be very general and perhaps ought to be moved to a more
    # general place (someday), perhaps VQT.py or nearby. [bruce 080828 comment]
    
    from numpy.oldnumeric import dot
    from math import atan2, pi, sqrt
    from geometry.VQT import cross
    
    if len(atom_list) != 4:
        # The list has to have four members.
        return 0.0
    
    # Calculate pairwise distances
    v12 = atom_list[0].posn() - atom_list[1].posn()
    v43 = atom_list[3].posn() - atom_list[2].posn()
    v23 = atom_list[1].posn() - atom_list[2].posn()

    # p is a vector perpendicular to the plane defined by atoms 1,2,3
    # p is perpendicular to v23_v12 plane
    p = cross(v23, v12)
    
    # x is a vector perpendicular to the plane defined by atoms 2,3,4.
    # x is perpendicular to v23_v43 plane
    x = cross(v23, v43)
    
    # y is perpendicular to v23_x plane
    y = cross(v23, x)
    
    # Calculate lengths of the x, y vectors.
    u1 = dot(x, x)
    v1 = dot(y, y)
    
    if u1 < 0.0 or \
       v1 < 0.0:
        return 360.0
    
    u2 = dot(p, x) / sqrt(u1)
    v2 = dot(p, y) / sqrt(v1)
    
    if u2 != 0.0 and \
       v2 != 0.0:
        # calculate the angle
        return atan2(v2, u2) * (180.0 / pi)
    else:
        return 360.0
    def rotateAboutPoint(self):
        """
        Rotates the selected entities along the specified vector, about the
        specified pivot point (pivot point it the starting point of the
        drawn vector.
        """
        startPoint = self.mouseClickPoints[0]
        endPoint = self.mouseClickPoints[1]
        pivotAtom = self.graphicsMode.pivotAtom
        #initial assignment of reference_vec. The selected movables will be
        #rotated by the angle between this vector and the lineVector
        reference_vec = self.glpane.right
        if isinstance(pivotAtom, Atom) and not pivotAtom.molecule.isNullChunk():
            mol = pivotAtom.molecule
            reference_vec, node_junk = mol.getAxis_of_self_or_eligible_parent_node(
                atomAtVectorOrigin = pivotAtom)
            del node_junk
        else:
            reference_vec = self.glpane.right

        lineVector = endPoint - startPoint

        quat1 = Q(lineVector, reference_vec)

        #DEBUG Disabled temporarily . will not be used
        ##if dot(lineVector, reference_vec) < 0:
            ##theta = math.pi - quat1.angle
        ##else:
            ##theta = quat1.angle

        #TEST_DEBUG-- Works fine
        theta = quat1.angle

        rot_axis = cross(lineVector, reference_vec)

        if dot(lineVector, reference_vec) < 0:
            rot_axis = - rot_axis

        cross_prod_1 = norm(cross(reference_vec, rot_axis))
        cross_prod_2 = norm(cross(lineVector, rot_axis))

        if dot(cross_prod_1, cross_prod_2) < 0:
            quat2 = Q(rot_axis,  theta)
        else:
            quat2 = Q(rot_axis,  - theta)


        movables = self.graphicsMode.getMovablesForLeftDragging()
        self.assy.rotateSpecifiedMovables(
            quat2,
            movables = movables,
            commonCenter = startPoint)

        self.glpane.gl_update()
Example #12
0
    def rotateAboutPoint(self):
        """
        Rotates the selected entities along the specified vector, about the
        specified pivot point (pivot point it the starting point of the
        drawn vector.
        """

        if len(self.mouseClickPoints) != self.mouseClickLimit:
            print_compact_stack(
                "Rotate about point bug: mouseclick points != mouseclicklimit: "
            )
            return

        pivotPoint = self.mouseClickPoints[0]
        ref_vec_endPoint = self.mouseClickPoints[1]
        rot_vec_endPoint = self.mouseClickPoints[2]

        reference_vec = norm(ref_vec_endPoint - pivotPoint)

        lineVector = norm(rot_vec_endPoint - pivotPoint)

        #lineVector = endPoint - startPoint

        quat1 = Q(lineVector, reference_vec)

        #DEBUG Disabled temporarily . will not be used
        if dot(lineVector, reference_vec) < 0:
            theta = math.pi - quat1.angle
        else:
            theta = quat1.angle

        #TEST_DEBUG-- Works fine
        theta = quat1.angle

        rot_axis = cross(lineVector, reference_vec)

        if dot(lineVector, reference_vec) < 0:
            rot_axis = -rot_axis

        cross_prod_1 = norm(cross(reference_vec, rot_axis))
        cross_prod_2 = norm(cross(lineVector, rot_axis))

        if dot(cross_prod_1, cross_prod_2) < 0:
            quat2 = Q(rot_axis, theta)
        else:
            quat2 = Q(rot_axis, -theta)

        movables = self.graphicsMode.getMovablesForLeftDragging()
        self.assy.rotateSpecifiedMovables(quat2,
                                          movables=movables,
                                          commonCenter=pivotPoint)

        self.glpane.gl_update()
        return
Example #13
0
 def walk_great_circle(P, Q, D, R=radius):
     """Given two points P and Q on or near the surface of the
     sphere, use P and Q to define a great circle. Then walk along
     that great circle starting at P and going in the direction of
     Q, and traveling far enough the chord is of length D. P and Q
     are not required to lie exactly on the sphere's surface.
     """
     dP, dQ = P - sphere_center, Q - sphere_center
     dPs = cross(cross(dP, dQ), dP)
     cpart, spart = norm(dP), norm(dPs)
     theta = 2 * asin(0.5 * D / R)
     return sphere_center + R * (cpart * cos(theta) + spart * sin(theta))
 def walk_great_circle(P, Q, D, R=radius):
     """Given two points P and Q on or near the surface of the
     sphere, use P and Q to define a great circle. Then walk along
     that great circle starting at P and going in the direction of
     Q, and traveling far enough the chord is of length D. P and Q
     are not required to lie exactly on the sphere's surface.
     """
     dP, dQ = P - sphere_center, Q - sphere_center
     dPs = cross(cross(dP, dQ), dP)
     cpart, spart = norm(dP), norm(dPs)
     theta = 2 * asin(0.5 * D / R)
     return sphere_center + R * (cpart * cos(theta) + spart * sin(theta))
Example #15
0
 def recompute_geom_from_quats(self): # non-ring class
     """
     [not a ring; various possible end situations]
     """
     out = self.out
     up = self.up
     atoms = self.lista
     bonds = self.listb
         # (I wish I could rename these attrs to "atoms" and "bonds",
         #  but self.atoms conflicts with the Jig attr, and self.chain_atoms is too long.)
     # default values:
     self.bm1R_pvec = "not needed" # and bug if used, we hope, unless we later change this value
     self.twist = None
     # Figure out p vectors for atom[0]-end (left end) of bond[0], and atom[-1]-end (right end) of bond[-1].
     # If both are determined from outside this chain (i.e. if the subrs here don't return None),
     # or if we are a ring (so they are forced to be the same, except for the projection due to bond bending at the ring-joining atom),
     # then [using self.recompute_geom_both_ends_constrained()] they must be made to match (up to an arbitrary sign),
     # using a combination of some twist (to be computed here) along each bond,
     # plus a projection and (in some cases, depending on bond types i think -- see self.twist90)
     # 90-degree turn at each bond-bond connection;
     # the projection part for all the bond-bond connections is already accumulated in self.chain_quat_cum.
     
     # note: the following p-vec retvals are in abs coords, as they should be
     #e rename the funcs, since they are not only for sp2, but for any atom that ends our chain of pi bonds
     pvec1 = p_vector_from_sp2_atom(atoms[0], bonds[0], out = out, up = up) # might be None
     pvec2 = p_vector_from_sp2_atom(atoms[-1], bonds[-1], out = out, up = up) # ideally, close to negative or positive of pvec1 ###@@@ handle neg
     # handle one being None (use other one to determine the twist) or both being None (use arb vectors)
     if pvec1 is None:
         if pvec2 is None:
             # use arbitrary vectors on left end of bonds[0], perp to bond and to out; compute differently if bond axis ~= out
             axis = self.axes[0]
             pvec = cross(out, axis)
             lenpvec = vlen(pvec)
             if lenpvec < 0.01:
                 # bond axis is approx parallel to out
                 pvec = cross(up, axis)
                 lenpvec = vlen(pvec) # won't be too small -- bond can't be parallel to both up and out
             pvec /= lenpvec
             self.b0L_pvec = pvec
         else:
             # pvec2 is defined, pvec1 is not. Need to transport pvec2 back to coords of pvec1
             # so our standard code (pvec_i, which wants pvec1, i.e. self.b0L_pvec) can be used.
             self.b0L_pvec = self.chain_quat_cum.unrot(pvec2)
     else:
         if pvec2 is None:
             self.b0L_pvec = pvec1
         else:
             # both vectors not None -- use recompute_geom_both_ends_constrained
             self.b0L_pvec = pvec1
             self.bm1R_pvec = pvec2
             self.recompute_geom_both_ends_constrained()
     return # from non-ring recompute_geom_from_quats
Example #16
0
def p_vector_from_3_bonds(atom, bond, out=DFLT_OUT, up=DFLT_UP):
    """
    Given an sp2 atom with 3 bonds, and one of those bonds which we assume has pi orbitals in it,
    return a unit vector from atom along its p orbital, guaranteed perpendicular to bond,
    for purposes of drawing the pi orbital component of bond.
    Note that it's arbitrary whether we return a given vector or its opposite.
    [##e should we fix that, using out and up? I don't think we can in a continuous way, so don't bother.]
       We don't verify the atom is sp2, since we don't need to for this code to work,
    though our result would probably not make sense otherwise.
    """
    others = map(lambda bond: bond.other(atom), atom.bonds)
    assert len(others) == 3
    other1 = bond.other(atom)
    others.remove(other1)
    other2, other3 = others
    apos = atom.posn()
    v1 = other1.posn() - apos
    # if v1 has 0 length, we should return some default value here; this might sometimes happen so I better handle it.
    # actually i'm not sure the remaining code would fail in this case! If not, I might revise this.
    if vlen(v1) < 0.01:  # in angstroms
        return +up
    v2 = other2.posn() - apos
    v3 = other3.posn() - apos
    # projecting along v1, we hope v2 and v3 are opposite, and then we return something perpendicular to them.
    # if one is zero, just be perp. to the other one alone.
    # (If both zero? Present code returns near-0. Should never happen, but fix. #e)
    # otherwise if they are not opposite, use perps to each one, "averaged",
    # which means (for normalized vectors), normalize the larger of the sum or difference
    # (equivalent to clustering them in the way (of choice of sign for each) that spans the smallest angle).
    # Optim: no need to project them before taking cross products to get the perps to use.
    ## v2 -= v1 * dot(v2,v1)
    ## v3 -= v1 * dot(v3,v1)
    v2p = cross(v2, v1)
    v3p = cross(v3, v1)
    lenv2p = vlen(v2p)
    if lenv2p < 0.01:
        return norm(v3p)
    v2p /= lenv2p
    lenv3p = vlen(v3p)
    if lenv3p < 0.01:
        return v2p  # normalized above
    v3p /= lenv3p
    r1 = v2p + v3p
    r2 = v2p - v3p
    lenr1 = vlen(r1)
    lenr2 = vlen(r2)
    if lenr1 > lenr2:
        return r1 / lenr1
    else:
        return r2 / lenr2
    pass
Example #17
0
def p_vector_from_3_bonds(atom, bond, out = DFLT_OUT, up = DFLT_UP):
    """
    Given an sp2 atom with 3 bonds, and one of those bonds which we assume has pi orbitals in it,
    return a unit vector from atom along its p orbital, guaranteed perpendicular to bond,
    for purposes of drawing the pi orbital component of bond.
    Note that it's arbitrary whether we return a given vector or its opposite.
    [##e should we fix that, using out and up? I don't think we can in a continuous way, so don't bother.]
       We don't verify the atom is sp2, since we don't need to for this code to work,
    though our result would probably not make sense otherwise.
    """
    others = map( lambda bond: bond.other(atom), atom.bonds)
    assert len(others) == 3
    other1 = bond.other(atom)
    others.remove(other1)
    other2, other3 = others
    apos = atom.posn()
    v1 = other1.posn() - apos
    # if v1 has 0 length, we should return some default value here; this might sometimes happen so I better handle it.
    # actually i'm not sure the remaining code would fail in this case! If not, I might revise this.
    if vlen(v1) < 0.01: # in angstroms
        return + up
    v2 = other2.posn() - apos
    v3 = other3.posn() - apos
    # projecting along v1, we hope v2 and v3 are opposite, and then we return something perpendicular to them.
    # if one is zero, just be perp. to the other one alone.
    # (If both zero? Present code returns near-0. Should never happen, but fix. #e)
    # otherwise if they are not opposite, use perps to each one, "averaged",
    # which means (for normalized vectors), normalize the larger of the sum or difference
    # (equivalent to clustering them in the way (of choice of sign for each) that spans the smallest angle).
    # Optim: no need to project them before taking cross products to get the perps to use.
    ## v2 -= v1 * dot(v2,v1)
    ## v3 -= v1 * dot(v3,v1)
    v2p = cross(v2,v1)
    v3p = cross(v3,v1)
    lenv2p = vlen(v2p)
    if lenv2p < 0.01:
        return norm(v3p)
    v2p /= lenv2p
    lenv3p = vlen(v3p)
    if lenv3p < 0.01:
        return v2p # normalized above
    v3p /= lenv3p
    r1 = v2p + v3p
    r2 = v2p - v3p
    lenr1 = vlen(r1)
    lenr2 = vlen(r2)
    if lenr1 > lenr2:
        return r1/lenr1
    else:
        return r2/lenr2
    pass
Example #18
0
 def get_dihedral(self):
     """
     Returns the dihedral between two atoms (nuclei)
     """
     wx = self.atoms[0].posn() - self.atoms[1].posn()
     yx = self.atoms[2].posn() - self.atoms[1].posn()
     xy = -yx
     zy = self.atoms[3].posn() - self.atoms[2].posn()
     u = cross(wx, yx)
     v = cross(xy, zy)
     if dot(zy, u) < 0:  # angles go from -180 to 180, wware 051101
         return -angleBetween(u, v)  # use new acos(dot) func, wware 051103
     else:
         return angleBetween(u, v)
Example #19
0
 def get_dihedral(self):
     """
     Returns the dihedral between two atoms (nuclei)
     """
     wx = self.atoms[0].posn()-self.atoms[1].posn()
     yx = self.atoms[2].posn()-self.atoms[1].posn()
     xy = -yx
     zy = self.atoms[3].posn()-self.atoms[2].posn()
     u = cross(wx, yx)
     v = cross(xy, zy)
     if dot(zy, u) < 0:   # angles go from -180 to 180, wware 051101
         return -angleBetween(u, v)  # use new acos(dot) func, wware 051103
     else:
         return angleBetween(u, v)
Example #20
0
 def on_press(self):
     point = self.current_event_mousepoint(
     )  # the touched point on the visible object (hitpoint)
     # (this method is defined in the Highlightable which is self.delegate)
     self.oldpoint = self.startpoint = point
     # decide type of drag now, so it's clearly constant during drag, and so decision code is only in one place.
     # (but note that some modkey meanings might require that changes to them during the same drag are detected [nim].)
     if self._delegate.altkey:
         self._this_drag = 'free x-y rotate'
         #e more options later, and/or more flags like this (maybe some should be booleans)
         ###e or better, set up a function or object which turns later points into their effects... hmm, a DragCommand instance!
         ##e or should that be renamed DragOperation??
         self._screenrect = (ll, lr, ur,
                             ul) = self.screenrect(self.startpoint)
         # these points should be valid in our delegate's coords == self's coords
         self._dx = _dx = norm(lr - ll)
         self._dy = _dy = norm(ur - lr)
         self._dz = cross(
             _dx, _dy
         )  # towards the eye (if view is ortho) (but alg is correct whether or not it is, i think)
         ###k check cross direction sign
         self._scale = min(vlen(lr - ll), vlen(ur - lr)) * 0.4
         # New motion UI suggests that 40% of that distance means 180 degrees of rotation.
         # We'll draw an axis whose length is chosen so that dragging on a sphere of that size
         # would have the same effect. (Maybe.)
         self._objcenter = self._delegate.center
         self.startrot = +self.rotation
     else:
         self._this_drag = 'free x-y translate'
     if debug070209:
         self.ndrags = 0
     return
Example #21
0
 def on_press(self):
     point = self.current_event_mousepoint() # the touched point on the visible object (hitpoint)
         # (this method is defined in the Highlightable which is self.delegate)
     self.oldpoint = self.startpoint = point
     # decide type of drag now, so it's clearly constant during drag, and so decision code is only in one place.
     # (but note that some modkey meanings might require that changes to them during the same drag are detected [nim].)
     if self._delegate.altkey:
         self._this_drag = 'free x-y rotate'
             #e more options later, and/or more flags like this (maybe some should be booleans)
             ###e or better, set up a function or object which turns later points into their effects... hmm, a DragCommand instance!
             ##e or should that be renamed DragOperation??
         self._screenrect = (ll, lr, ur, ul) = self.screenrect( self.startpoint)
             # these points should be valid in our delegate's coords == self's coords
         self._dx = _dx = norm(lr - ll)
         self._dy = _dy = norm(ur - lr)
         self._dz = cross(_dx, _dy) # towards the eye (if view is ortho) (but alg is correct whether or not it is, i think)
             ###k check cross direction sign
         self._scale = min(vlen(lr - ll), vlen(ur - lr)) * 0.4
             # New motion UI suggests that 40% of that distance means 180 degrees of rotation.
             # We'll draw an axis whose length is chosen so that dragging on a sphere of that size
             # would have the same effect. (Maybe.)
         self._objcenter = self._delegate.center
         self.startrot = + self.rotation
     else:
         self._this_drag = 'free x-y translate'
     if debug070209:
         self.ndrags = 0
     return
Example #22
0
def arb_perp_unit_vector(vec):
    """
    Given a nonzero vector, return an arbitrary unit vector
    perpendicular to it.
    """
    vec2 = arb_non_parallel_vector(vec)
    return norm(cross(vec, vec2))
Example #23
0
def arb_perp_unit_vector(vec):
    """
    Given a nonzero vector, return an arbitrary unit vector
    perpendicular to it.
    """
    vec2 = arb_non_parallel_vector(vec)
    return norm(cross(vec, vec2))
Example #24
0
    def on_drag(self):
        # Note: we can assume this is a "real drag", since the caller (ultimately a selectMode method in testmode, as of 070209)
        # is tracking mouse motion and not calling this until it becomes large enough, as the debug070209 prints show.
        oldpoint = self.oldpoint  # was saved by prior on_drag or by on_press
        point = self.current_event_mousepoint(plane=self.startpoint)
        if debug070209:
            self.ndrags += 1


##            if (self.ndrags == 1) or 1:
##                print "drag event %d, model distance = %r, pixel dist not computed" % (self.ndrags, vlen(oldpoint - point),)
        if self._this_drag == 'free x-y rotate':
            # rotate using New motion UI
            #  [probably works for this specific kind of rotation, one of 4 that UI proposes;
            #   doesn't yet have fancy cursors or during-rotation graphics; add those only after it's a DragCommand]
            # two implem choices:
            # 1. know the eye direction and the screen dims in plane of startpoint, in model coords; compute in model coords
            # 2. get the mouse positions (startpoint and point) and screen dims in window x,y coords, compute rotation in eye coords,
            #   but remember to reorient it to correspond with model if model coords are rotated already.
            # Not sure which one is better.
            #   In general, placing user into model coords (or more precisely, into object local coords) seems more general --
            # for example, what if there were several interacting users, each visible to the others?
            # We'd want each user's eye & screen to be visible! (Maybe even an image of their face & screen, properly scaled and aligned?)
            # And we'd want their posns to be used in the computations here, all in model coords.
            # (Even if zoom had occurred, which means, even the user's *size* is quite variable!)
            #   I need "user in model coords" for other reasons too, so ok, I'll do it that way.
            #
            # [Hey, I might as well fix the bug in current_event_mousepoint which fakes the center of view, at the same time.
            # (I can't remember its details right now, but I think it assumed the local origin was the cov, which is obviously wrong.)
            # (But I didn't look at that code or fix that bug now.)]
            vec = point - self.startpoint
            uvec = norm(vec)  #k needed??
            axisvec = cross(
                self._dz, uvec
            )  # unit length (suitable for glRotate -- but we need to use it to make a quat!)
            axisvec = norm(
                axisvec)  # just to be sure (or to reduce numerical errors)
            scale = self._scale
            draw_axisvec = axisvec * scale  #e times some other length constant too?
            center = self._objcenter
            self.axisends = (center - axisvec, center + axisvec
                             )  # draw a rotation axis here ###e
            self.degrees = degrees = vlen(
                vec
            ) / scale * 180.0  # draw a textual indicator with degrees (and axisvec angle too) ###e
            ###e or print that info into sbar? or somewhere fixed in glpane? or in glpane near mouse?
            # now set self.rotation to a quat made from axisvec and degrees
            theta = degrees / 360.0 * 2 * pi
            # print "axisvec %r, degrees %r, theta %r" % (axisvec ,degrees,theta)
            rot = Q(axisvec, theta)
            self.rotation = self.startrot + rot  # note use of self.startrot rather than self.rotation on rhs
            # avoid += to make sure it gets changed-tracked -- and since it would be the wrong op!

        elif self._this_drag == 'free x-y translate':
            self._cmd_drag_from_to(
                oldpoint, point)  # use Draggable interface cmd on self
        else:
            assert 0
        self.oldpoint = point
        return
Example #25
0
    def _getPlaneOrientation(self, atomPos):
        """
        """
        assert len(atomPos) >= 3
        v1 = atomPos[-2] - atomPos[-1]
        v2 = atomPos[-3] - atomPos[-1]

        return cross(v1, v2)
Example #26
0
def arb_ortho_pair(vec): #k not presently used # see also some related code in pi_vectors()
    """
    Given a nonzero vector, return an arbitrary pair of unit vectors
    perpendicular to it and to each other.
    """
    res1 = arb_perp_unit_vector(vec)
    res2 = norm(cross(vec, res1))
    return res1, res2
Example #27
0
    def _getPlaneOrientation(self, atomPos):
        """
        """
        assert len(atomPos) >= 3
        v1 = atomPos[-2] - atomPos[-1]
        v2 = atomPos[-3] - atomPos[-1]

        return cross(v1, v2)
Example #28
0
 def _C_width_direction(self):
     """
     compute self.width_direction
     """
     # Note: to do this with a formula expr instead
     # would require cross_Expr to be defined,
     # and glpane.lineOfSight to be tracked.
     return cross( self.direction, self.env.glpane.lineOfSight )
Example #29
0
def arb_ortho_pair(vec): #k not presently used # see also some related code in pi_vectors()
    """
    Given a nonzero vector, return an arbitrary pair of unit vectors
    perpendicular to it and to each other.
    """
    res1 = arb_perp_unit_vector(vec)
    res2 = norm(cross(vec, res1))
    return res1, res2
Example #30
0
def pi_info_from_abs_pvecs( bond, bond_axis, pvec1, pvec2, abs_coords = False):
    """
    #doc;
    bond_axis (passed only as an optim) and pvecs are in abs coords; retval is in bond coords unless abs_coords is true
    """
    a1py = pvec1
    a2py = pvec2
    a1pz = norm(cross(bond_axis, pvec1))
    a2pz = norm(cross(bond_axis, pvec2))
    ord_pi_y, ord_pi_z = pi_orders(bond)
    if not abs_coords:
        # put into bond coords (which might be the same as abs coords)
        quat = bond.bond_to_abs_coords_quat()
        a1py = quat.unrot(a1py)
        a2py = quat.unrot(a2py)
        a1pz = quat.unrot(a1pz)
        a2pz = quat.unrot(a2pz)
    return ((a1py, a1pz), (a2py, a2pz), ord_pi_y, ord_pi_z)
Example #31
0
def pi_info_from_abs_pvecs(bond, bond_axis, pvec1, pvec2, abs_coords=False):
    """
    #doc;
    bond_axis (passed only as an optim) and pvecs are in abs coords; retval is in bond coords unless abs_coords is true
    """
    a1py = pvec1
    a2py = pvec2
    a1pz = norm(cross(bond_axis, pvec1))
    a2pz = norm(cross(bond_axis, pvec2))
    ord_pi_y, ord_pi_z = pi_orders(bond)
    if not abs_coords:
        # put into bond coords (which might be the same as abs coords)
        quat = bond.bond_to_abs_coords_quat()
        a1py = quat.unrot(a1py)
        a2py = quat.unrot(a2py)
        a1pz = quat.unrot(a1pz)
        a2pz = quat.unrot(a2pz)
    return ((a1py, a1pz), (a2py, a2pz), ord_pi_y, ord_pi_z)
Example #32
0
    def __init__(self,
                 xpos=0,
                 ypos=0,
                 right=None,
                 up=None,
                 rot90=False,
                 glBegin=False):

        self.glBegin = glBegin
        if right is not None and up is not None:
            # The out-of-screen direction for text should always agree with
            # the "real" out-of-screen direction.
            self.outOfScreen = cross(right, up)

            if rot90:
                self.xflip = xflip = right[1] < 0.0
            else:
                self.xflip = xflip = right[0] < 0.0

            xgap = WIDTH
            halfheight = 0.5 * HEIGHT

            if xflip:
                xgap *= -SCALE

                def fx(x):
                    return SCALE * (WIDTH - 1 - x)
            else:
                xgap *= SCALE

                def fx(x):
                    return SCALE * x

            if rot90:
                ypos += xgap
                xpos -= halfheight * SCALE

                def tfm(x, y, yoff1, yflip):
                    if yflip:
                        y1 = SCALE * (HEIGHT - 1 - y)
                    else:
                        y1 = SCALE * y
                    return Numeric.array(
                        (xpos + yoff1 + y1, ypos + fx(x), 0.0))
            else:
                xpos += xgap
                ypos -= halfheight * SCALE

                def tfm(x, y, yoff1, yflip):
                    if yflip:
                        y1 = SCALE * (HEIGHT - 1 - y)
                    else:
                        y1 = SCALE * y
                    return Numeric.array(
                        (xpos + fx(x), ypos + yoff1 + y1, 0.0))

            self.tfm = tfm
Example #33
0
def _constrainHandleToAngle(pos, p0, p1, p2):
    """
    This works in two steps.
    (1) Project pos onto the plane defined by (p0, p1, p2).
    (2) Confine the projected point to lie within the angular arc.
    """
    u = pos - p1
    z0 = norm(p0 - p1)
    z2 = norm(p2 - p1)
    oop = norm(cross(z0, z2))
    u = u - dot(oop, u) * oop
    # clip the point so it lies within the angle
    if dot(cross(z0, u), oop) < 0:
        # Clip on the z0 side of the angle.
        u = vlen(u) * z0
    elif dot(cross(u, z2), oop) < 0:
        # Clip on the z2 side of the angle.
        u = vlen(u) * z2
    return p1 + u
Example #34
0
def _constrainHandleToAngle(pos, p0, p1, p2):
    """
    This works in two steps.
    (1) Project pos onto the plane defined by (p0, p1, p2).
    (2) Confine the projected point to lie within the angular arc.
    """
    u = pos - p1
    z0 = norm(p0 - p1)
    z2 = norm(p2 - p1)
    oop = norm(cross(z0, z2))
    u = u - dot(oop, u) * oop
    # clip the point so it lies within the angle
    if dot(cross(z0, u), oop) < 0:
        # Clip on the z0 side of the angle.
        u = vlen(u) * z0
    elif dot(cross(u, z2), oop) < 0:
        # Clip on the z2 side of the angle.
        u = vlen(u) * z2
    return p1 + u
Example #35
0
    def _orient(self, cntChunk, pt1, pt2):
        """
        Orients the CNT I{cntChunk} based on two points. I{pt1} is
        the first endpoint (origin) of the nanotube. The vector I{pt1}, I{pt2}
        defines the direction and central axis of the nanotube.
        
        @param pt1: The starting endpoint (origin) of the nanotube.
        @type  pt1: L{V}
        
        @param pt2: The second point of a vector defining the direction
                    and central axis of the nanotube.
        @type  pt2: L{V}
        """

        a = V(0.0, 0.0, -1.0)
        # <a> is the unit vector pointing down the center axis of the default
        # DNA structure which is aligned along the Z axis.
        bLine = pt2 - pt1
        bLength = vlen(bLine)
        b = bLine / bLength
        # <b> is the unit vector parallel to the line (i.e. pt1, pt2).
        axis = cross(a, b)
        # <axis> is the axis of rotation.
        theta = angleBetween(a, b)
        # <theta> is the angle (in degress) to rotate about <axis>.
        scalar = bLength * 0.5
        rawOffset = b * scalar

        if 0:  # Debugging code.
            print ""
            print "uVector  a = ", a
            print "uVector  b = ", b
            print "cross(a,b) =", axis
            print "theta      =", theta
            print "cntRise   =", self.getCntRise()
            print "# of cells =", self.getNumberOfCells()
            print "scalar     =", scalar
            print "rawOffset  =", rawOffset

        if theta == 0.0 or theta == 180.0:
            axis = V(0, 1, 0)
            # print "Now cross(a,b) =", axis

        rot = (pi / 180.0) * theta  # Convert to radians
        qrot = Q(axis, rot)  # Quat for rotation delta.

        # Move and rotate the nanotube into final orientation.
        cntChunk.move(
            qrot.rot(cntChunk.center) - cntChunk.center + rawOffset + pt1)
        cntChunk.rot(qrot)

        # Bruce suggested I add this. It works here, but not if its
        # before move() and rot() above. Mark 2008-04-11
        cntChunk.full_inval_and_update()
        return
Example #36
0
def pi_vectors(
        bond,
        out=DFLT_OUT,
        up=DFLT_UP,
        abs_coords=False):  # rename -- pi_info for pi bond in degen sp chain
    # see also PiBondSpChain.get_pi_info
    """
    Given a bond involving some pi orbitals, return the 4-tuple ((a1py, a1pz), (a2py, a2pz), ord_pi_y, ord_pi_z),
    where a1py and a1pz are orthogonal vectors from atom1 giving the direction of its p orbitals for use in drawing
    this bond (for twisted bonds, the details of these might be determined more by graphic design issues than by the
    shapes of the real pi orbitals of the bond, though the goal is to approximate those);
    where a2py and a2pz are the same for atom2 (note that a2py might not be parallel to a1py for twisted bonds);
    and where ord_pi_y and ord_pi_z are order estimates (between 0.0 and 1.0 inclusive) for use in drawing the bond,
    for the pi_y and pi_z orbitals respectively. Note that the choice of how to name the two pi orbitals (pi_y, pi_z)
    is arbitrary and up to this function.
       All returned vectors are in the coordinate system of bond, unless abs_coords is true.
       This should not be called for pi bonds which are part of an "sp chain",
    but it should be equivalent to the code that would be used for a 1-bond sp-chain
    (i.e. it's an optimization of that code, PiBondSpChain.get_pi_info, for that case).
    """
    atom1 = bond.atom1
    atom2 = bond.atom2
    bond_axis = atom2.posn() - atom1.posn()  #k not always needed i think
    # following subrs should be renamed, since we routinely call them for sp atoms,
    # e.g. in -C#C- where outer bonds are not potential pi bonds
    pvec1 = p_vector_from_sp2_atom(atom1, bond, out=out,
                                   up=up)  # might be None
    pvec2 = p_vector_from_sp2_atom(
        atom2, bond, out=out,
        up=up)  # ideally, close to negative or positive of pvec1
    # handle one being None (use other one in place of it) or both being None (use arb vectors)
    if pvec1 is None:
        if pvec2 is None:
            # use arbitrary vectors perp to the bond; compute differently if bond_axis ~= out [###@@@ make this a subr? dup code?]
            pvec = cross(out, bond_axis)
            lenpvec = vlen(pvec)
            if lenpvec < 0.01:
                pvec = up
            else:
                pvec /= lenpvec
            pvec1 = pvec2 = pvec
        else:
            pvec1 = pvec2
    else:
        if pvec2 is None:
            pvec2 = pvec1
        else:
            # both vectors not None -- use them, but negate pvec2 if this makes them more aligned
            if dot(pvec1, pvec2) < 0:
                pvec2 = -pvec2
    return pi_info_from_abs_pvecs(bond,
                                  bond_axis,
                                  pvec1,
                                  pvec2,
                                  abs_coords=abs_coords)
Example #37
0
 def _orient(self, cntChunk, pt1, pt2):
     """
     Orients the CNT I{cntChunk} based on two points. I{pt1} is
     the first endpoint (origin) of the nanotube. The vector I{pt1}, I{pt2}
     defines the direction and central axis of the nanotube.
     
     @param pt1: The starting endpoint (origin) of the nanotube.
     @type  pt1: L{V}
     
     @param pt2: The second point of a vector defining the direction
                 and central axis of the nanotube.
     @type  pt2: L{V}
     """
     
     a = V(0.0, 0.0, -1.0)
     # <a> is the unit vector pointing down the center axis of the default
     # DNA structure which is aligned along the Z axis.
     bLine = pt2 - pt1
     bLength = vlen(bLine)
     b = bLine/bLength
     # <b> is the unit vector parallel to the line (i.e. pt1, pt2).
     axis = cross(a, b)
     # <axis> is the axis of rotation.
     theta = angleBetween(a, b)
     # <theta> is the angle (in degress) to rotate about <axis>.
     scalar = bLength * 0.5
     rawOffset = b * scalar
     
     if 0: # Debugging code.
         print ""
         print "uVector  a = ", a
         print "uVector  b = ", b
         print "cross(a,b) =", axis
         print "theta      =", theta
         print "cntRise   =", self.getCntRise()
         print "# of cells =", self.getNumberOfCells()
         print "scalar     =", scalar
         print "rawOffset  =", rawOffset
     
     if theta == 0.0 or theta == 180.0:
         axis = V(0, 1, 0)
         # print "Now cross(a,b) =", axis
         
     rot =  (pi / 180.0) * theta  # Convert to radians
     qrot = Q(axis, rot) # Quat for rotation delta.
     
     # Move and rotate the nanotube into final orientation.
     cntChunk.move(qrot.rot(cntChunk.center) - cntChunk.center + rawOffset + pt1)
     cntChunk.rot(qrot)
     
     # Bruce suggested I add this. It works here, but not if its 
     # before move() and rot() above. Mark 2008-04-11
     cntChunk.full_inval_and_update()
     return
Example #38
0
 def drawString(self, str, yoff=1.0, color=None, tfm=None,
                _font_X=_font['X']):
     n = len(str)
     if not self.glBegin:
         assert color is not None
     if hasattr(self, 'tfm'):
         assert tfm is None
         if self.xflip:
             def fi(i): return i - (n + 1)
         else:
             def fi(i): return i
         # figure out what the yflip should be
         p0 = self.tfm(0, 0, yoff, False)
         textOutOfScreen = cross(self.tfm(1, 0, yoff, False) - p0,
                                 self.tfm(0, 1, yoff, False) - p0)
         yflip = dot(textOutOfScreen, self.outOfScreen) < 0.0
         def tfmgen(i):
             def tfm2(x, y):
                 return self.tfm(x + (WIDTH+1) * fi(i), y, yoff, yflip)
             return tfm2
     else:
         assert tfm is not None
         def tfmgen(i):
             def tfm2(x, y):
                 return tfm(x + i * (WIDTH+1), y)
             return tfm2
     for i in range(n):
         # A pen-stroke is a tuple of 2D vectors with integer
         # coordinates. Each character is represented as a stroke,
         # or a tuple of strokes e.g. '+' or 'X' or '#'.
         def drawSequence(seq, tfm=tfmgen(i)):
             if len(seq) == 0:
                 return  # a space character has an empty sequence
             if type(seq[0][0]) is not types.IntType:
                 # handle multi-stroke characters
                 for x in seq:
                     drawSequence(x)
                 return
             seq = map(lambda tpl: apply(tfm,tpl), seq)
             for i in range(len(seq) - 1):
                 pos1, pos2 = seq[i], seq[i+1]
                 if self.glBegin:
                     # This is what we do for grid planes, where "somebody"
                     # is drawGPGrid in drawers.py.
                     # Somebody has already taken care of glBegin(GL_LINES).
                     # TODO: explain this in docstring.
                     glVertex(pos1[0], pos1[1], pos1[2])
                     glVertex(pos2[0], pos2[1], pos2[2])
                     # Somebody has already taken care of glEnd().
                 else:
                     # This is what we do for dimensions.
                     drawline(color, seq[i], seq[i+1])
         drawSequence(_font.get(str[i], _font_X))
     return
Example #39
0
 def drawString(self, str, yoff=1.0, color=None, tfm=None,
                _font_X=_font['X']):
     n = len(str)
     if not self.glBegin:
         assert color is not None
     if hasattr(self, 'tfm'):
         assert tfm is None
         if self.xflip:
             def fi(i): return i - (n + 1)
         else:
             def fi(i): return i
         # figure out what the yflip should be
         p0 = self.tfm(0, 0, yoff, False)
         textOutOfScreen = cross(self.tfm(1, 0, yoff, False) - p0,
                                 self.tfm(0, 1, yoff, False) - p0)
         yflip = dot(textOutOfScreen, self.outOfScreen) < 0.0
         def tfmgen(i):
             def tfm2(x, y):
                 return self.tfm(x + (WIDTH+1) * fi(i), y, yoff, yflip)
             return tfm2
     else:
         assert tfm is not None
         def tfmgen(i):
             def tfm2(x, y):
                 return tfm(x + i * (WIDTH+1), y)
             return tfm2
     for i in range(n):
         # A pen-stroke is a tuple of 2D vectors with integer
         # coordinates. Each character is represented as a stroke,
         # or a tuple of strokes e.g. '+' or 'X' or '#'.
         def drawSequence(seq, tfm=tfmgen(i)):
             if len(seq) == 0:
                 return  # a space character has an empty sequence
             if type(seq[0][0]) is not types.IntType:
                 # handle multi-stroke characters
                 for x in seq:
                     drawSequence(x)
                 return
             seq = map(lambda tpl: apply(tfm,tpl), seq)
             for i in range(len(seq) - 1):
                 pos1, pos2 = seq[i], seq[i+1]
                 if self.glBegin:
                     # This is what we do for grid planes, where "somebody"
                     # is drawGPGrid in drawers.py.
                     # Somebody has already taken care of glBegin(GL_LINES).
                     # TODO: explain this in docstring.
                     glVertex(pos1[0], pos1[1], pos1[2])
                     glVertex(pos2[0], pos2[1], pos2[2])
                     # Somebody has already taken care of glEnd().
                 else:
                     # This is what we do for dimensions.
                     drawline(color, seq[i], seq[i+1])
         drawSequence(_font.get(str[i], _font_X))
     return
def matrix_putting_axis_at_z(axis): #bruce 060608
    """
    Return an orthonormal matrix which can be used (via dot(points, matrix) for a Numeric array of 3d points)
    to transform points so that axis transforms to the z axis.
    (Not sure if it has determinant 1 or -1. If you're sure, change it to always be determinant 1.)
    """
    # this code was modified from ops_select.py's findAtomUnderMouse, as it prepares to call Chunk.findAtomUnderMouse
    z = norm(axis)
    x = arbitrary_perpendicular(axis)
    y = cross(z,x)
    matrix = transpose(V(x,y,z))
    return matrix
def matrix_putting_axis_at_z(axis):  #bruce 060608
    """
    Return an orthonormal matrix which can be used (via dot(points, matrix) for a Numeric array of 3d points)
    to transform points so that axis transforms to the z axis.
    (Not sure if it has determinant 1 or -1. If you're sure, change it to always be determinant 1.)
    """
    # this code was modified from ops_select.py's findAtomUnderMouse, as it prepares to call Chunk.findAtomUnderMouse
    z = norm(axis)
    x = arbitrary_perpendicular(axis)
    y = cross(z, x)
    matrix = transpose(V(x, y, z))
    return matrix
    def _orient_to_position_first_strandA_base_in_axis_plane(
            self, baseList, end1, end2):
        """
        The self._orient method orients the DNA duplex parallel to the screen
        (lengthwise) but it doesn't ensure align the vector
        through the strand end atom on StrandA and the corresponding axis end 
        atom  (at end1) , parallel to the screen. 

        This function does that ( it has some rare bugs which trigger where it
        doesn't do its job but overall works okay )

        What it does: After self._orient() is done orienting, it finds a Quat 
        that rotates between the 'desired vector' between strand and axis ends at
        end1(aligned to the screen)  and the actual vector based on the current
        positions of these atoms.  Using this quat we rotate all the chunks 
        (as a unit) around a common center.

        @BUG: The last part 'rotating as a unit' uses a readymade method in 
        ops_motion.py -- 'rotateSpecifiedMovables' . This method itself may have
        some bugs because the axis of the dna duplex is slightly offset to the
        original axis. 

        @see: self._determine_axis_and_strandA_endAtoms_at_end_1()
        @see: self.make()
        """

        #the vector between the two end points. these are more likely
        #points clicked by the user while creating dna duplex using endpoints
        #of a line. In genral, end1 and end2 are obtained from self.make()
        b = norm(end2 - end1)

        axis_strand_vector = (self.strandA_atom_end1.posn() - \
                              self.axis_atom_end1.posn())

        vectorAlongLadderStep = cross(-self.assy.o.lineOfSight, b)
        unitVectorAlongLadderStep = norm(vectorAlongLadderStep)

        self.final_pos_strand_end_atom = \
            self.axis_atom_end1.posn() + \
            vlen(axis_strand_vector)*unitVectorAlongLadderStep

        expected_vec = self.final_pos_strand_end_atom - self.axis_atom_end1.posn(
        )

        q_new = Q(axis_strand_vector, expected_vec)

        if dot(axis_strand_vector, self.assy.o.lineOfSight) < 0:
            q_new2 = Q(b, -q_new.angle)
        else:
            q_new2 = Q(b, q_new.angle)

        self.assy.rotateSpecifiedMovables(q_new2, baseList, end1)
 def _orientRawDnaGroup(self, rawDnaGroup, pt1, pt2):
     """
     Orients the raw DNA group based on two endpoints.
     
     @param rawDnaGroup: The raw DNA group created by make().
     @type  rawDnaGroup: L{Group}
     
     @param pt1: The first endpoint of the DNA strand.
     @type  pt1: L{V}
     
     @param pt2: The second endpoint of the DNA strand.
     @type  pt2: L{V}
     
     @attention: Only works for PAM5 models.
     """
     
     a = V(0.0, 0.0, -1.0)
     # <a> is the unit vector pointing down the center axis of the default
     # rawDnaGroup structure which is aligned along the Z axis.
     bLine = pt2 - pt1
     bLength = vlen(bLine)
     b = bLine/bLength
     # <b> is the unit vector parallel to the line (i.e. pt1, pt2).
     axis = cross(a, b)
     # <axis> is the axis of rotation.
     theta = angleBetween(a, b)
     # <theta> is the angle (in degress) to rotate about <axis>.
     scalar = self.dna.getBaseRise() * self.getSequenceLength() * 0.5
     rawOffset = b * scalar
     
     if 0: # Debugging code.
         print ""
         print "uVector  a = ", a
         print "uVector  b = ", b
         print "cross(a,b) =", axis
         print "theta      =", theta
         print "baserise   =", self.dna.getBaseRise()
         print "seqLength  =", self.getSequenceLength()
         print "scalar     =", scalar
         print "rawOffset  =", rawOffset
     
     if theta == 0.0 or theta == 180.0:
         axis = V(0, 1, 0)
         # print "Now cross(a,b) =", axis
         
     rot =  (pi / 180.0) * theta  # Convert to radians
     qrot = Q(axis, rot) # Quat for rotation delta.
     
     # Move and rotate the base chunks into final orientation.
     for m in rawDnaGroup.members:
         m.move(qrot.rot(m.center) - m.center + rawOffset + pt1)
         m.rot(qrot)
Example #44
0
    def on_drag(self):
        # Note: we can assume this is a "real drag", since the caller (ultimately a selectMode method in testmode, as of 070209)
        # is tracking mouse motion and not calling this until it becomes large enough, as the debug070209 prints show.
        oldpoint = self.oldpoint # was saved by prior on_drag or by on_press
        point = self.current_event_mousepoint(plane = self.startpoint)
        if debug070209:
            self.ndrags += 1
##            if (self.ndrags == 1) or 1:
##                print "drag event %d, model distance = %r, pixel dist not computed" % (self.ndrags, vlen(oldpoint - point),)
        if self._this_drag == 'free x-y rotate':
            # rotate using New motion UI
            #  [probably works for this specific kind of rotation, one of 4 that UI proposes;
            #   doesn't yet have fancy cursors or during-rotation graphics; add those only after it's a DragCommand]
            # two implem choices:
            # 1. know the eye direction and the screen dims in plane of startpoint, in model coords; compute in model coords
            # 2. get the mouse positions (startpoint and point) and screen dims in window x,y coords, compute rotation in eye coords,
            #   but remember to reorient it to correspond with model if model coords are rotated already.
            # Not sure which one is better.
            #   In general, placing user into model coords (or more precisely, into object local coords) seems more general --
            # for example, what if there were several interacting users, each visible to the others?
            # We'd want each user's eye & screen to be visible! (Maybe even an image of their face & screen, properly scaled and aligned?)
            # And we'd want their posns to be used in the computations here, all in model coords.
            # (Even if zoom had occurred, which means, even the user's *size* is quite variable!)
            #   I need "user in model coords" for other reasons too, so ok, I'll do it that way.
            #
            # [Hey, I might as well fix the bug in current_event_mousepoint which fakes the center of view, at the same time.
            # (I can't remember its details right now, but I think it assumed the local origin was the cov, which is obviously wrong.)
            # (But I didn't look at that code or fix that bug now.)]
            vec = point - self.startpoint
            uvec = norm(vec) #k needed??
            axisvec = cross(self._dz, uvec) # unit length (suitable for glRotate -- but we need to use it to make a quat!)
            axisvec = norm(axisvec) # just to be sure (or to reduce numerical errors)
            scale = self._scale
            draw_axisvec = axisvec * scale #e times some other length constant too?
            center = self._objcenter
            self.axisends = (center - axisvec, center + axisvec) # draw a rotation axis here ###e
            self.degrees = degrees = vlen(vec) / scale * 180.0 # draw a textual indicator with degrees (and axisvec angle too) ###e
                ###e or print that info into sbar? or somewhere fixed in glpane? or in glpane near mouse?
            # now set self.rotation to a quat made from axisvec and degrees
            theta = degrees / 360.0 * 2 * pi
            # print "axisvec %r, degrees %r, theta %r" % (axisvec ,degrees,theta)
            rot = Q(axisvec, theta)
            self.rotation = self.startrot + rot # note use of self.startrot rather than self.rotation on rhs
                # avoid += to make sure it gets changed-tracked -- and since it would be the wrong op!

        elif self._this_drag == 'free x-y translate':
            self._cmd_drag_from_to( oldpoint, point) # use Draggable interface cmd on self
        else:
            assert 0
        self.oldpoint = point
        return
    def _orient_to_position_first_strandA_base_in_axis_plane(self, baseList, end1, end2):
        """
        The self._orient method orients the DNA duplex parallel to the screen
        (lengthwise) but it doesn't ensure align the vector
        through the strand end atom on StrandA and the corresponding axis end 
        atom  (at end1) , parallel to the screen. 

        This function does that ( it has some rare bugs which trigger where it
        doesn't do its job but overall works okay )

        What it does: After self._orient() is done orienting, it finds a Quat 
        that rotates between the 'desired vector' between strand and axis ends at
        end1(aligned to the screen)  and the actual vector based on the current
        positions of these atoms.  Using this quat we rotate all the chunks 
        (as a unit) around a common center.

        @BUG: The last part 'rotating as a unit' uses a readymade method in 
        ops_motion.py -- 'rotateSpecifiedMovables' . This method itself may have
        some bugs because the axis of the dna duplex is slightly offset to the
        original axis. 

        @see: self._determine_axis_and_strandA_endAtoms_at_end_1()
        @see: self.make()
        """

        #the vector between the two end points. these are more likely
        #points clicked by the user while creating dna duplex using endpoints
        #of a line. In genral, end1 and end2 are obtained from self.make()
        b = norm(end2 - end1)        

        axis_strand_vector = (self.strandA_atom_end1.posn() - \
                              self.axis_atom_end1.posn())

        vectorAlongLadderStep =  cross(-self.assy.o.lineOfSight, b)
        unitVectorAlongLadderStep = norm(vectorAlongLadderStep)

        self.final_pos_strand_end_atom = \
            self.axis_atom_end1.posn() + \
            vlen(axis_strand_vector)*unitVectorAlongLadderStep

        expected_vec = self.final_pos_strand_end_atom - self.axis_atom_end1.posn()

        q_new = Q(axis_strand_vector, expected_vec)

        if dot(axis_strand_vector, self.assy.o.lineOfSight) < 0:            
            q_new2 = Q(b, -q_new.angle)
        else:     
            q_new2 = Q(b, q_new.angle) 


        self.assy.rotateSpecifiedMovables(q_new2, baseList, end1)
Example #46
0
    def _orient(self, chunk, pt1, pt2):
        """
        Orients the Peptide I{chunk} based on two points. I{pt1} is
        the first endpoint (origin) of the Peptide. The vector I{pt1}, I{pt2}
        defines the direction and central axis of the Peptide.

        piotr 080801: I copied this method from Nanotube Builder.

        @param pt1: The starting endpoint (origin) of the Peptide.
        @type  pt1: L{V}

        @param pt2: The second point of a vector defining the direction
                    and central axis of the Peptide.
        @type  pt2: L{V}
        """

        a = V(0.0, 0.0, -1.0)
        # <a> is the unit vector pointing down the center axis of the default
        # structure which is aligned along the Z axis.
        bLine = pt2 - pt1
        bLength = vlen(bLine)
        if bLength == 0:
            return
        b = bLine / bLength
        # <b> is the unit vector parallel to the line (i.e. pt1, pt2).
        axis = cross(a, b)
        # <axis> is the axis of rotation.
        theta = angleBetween(a, b)
        # <theta> is the angle (in degress) to rotate about <axis>.
        scalar = bLength * 0.5
        rawOffset = b * scalar

        if theta == 0.0 or theta == 180.0:
            axis = V(0, 1, 0)
            # print "Now cross(a,b) =", axis

        rot = (pi / 180.0) * theta  # Convert to radians
        qrot = Q(axis, rot)  # Quat for rotation delta.

        # Move and rotate the Peptide into final orientation.

        chunk.move(-chunk.center)

        chunk.rot(qrot)

        # Bruce suggested I add this. It works here, but not if its
        # before move() and rot() above. Mark 2008-04-11
        chunk.full_inval_and_update()
        return
    def _orient(self, chunk, pt1, pt2):
        """
        Orients the Peptide I{chunk} based on two points. I{pt1} is
        the first endpoint (origin) of the Peptide. The vector I{pt1}, I{pt2}
        defines the direction and central axis of the Peptide.

        piotr 080801: I copied this method from Nanotube Builder.

        @param pt1: The starting endpoint (origin) of the Peptide.
        @type  pt1: L{V}

        @param pt2: The second point of a vector defining the direction
                    and central axis of the Peptide.
        @type  pt2: L{V}
        """

        a = V(0.0, 0.0, -1.0)
        # <a> is the unit vector pointing down the center axis of the default
        # structure which is aligned along the Z axis.
        bLine = pt2 - pt1
        bLength = vlen(bLine)
        if bLength == 0:
            return
        b = bLine / bLength
        # <b> is the unit vector parallel to the line (i.e. pt1, pt2).
        axis = cross(a, b)
        # <axis> is the axis of rotation.
        theta = angleBetween(a, b)
        # <theta> is the angle (in degress) to rotate about <axis>.
        scalar = bLength * 0.5
        rawOffset = b * scalar

        if theta == 0.0 or theta == 180.0:
            axis = V(0, 1, 0)
            # print "Now cross(a,b) =", axis

        rot =  (pi / 180.0) * theta  # Convert to radians
        qrot = Q(axis, rot) # Quat for rotation delta.

        # Move and rotate the Peptide into final orientation.

        chunk.move(-chunk.center)

        chunk.rot(qrot)

        # Bruce suggested I add this. It works here, but not if its
        # before move() and rot() above. Mark 2008-04-11
        chunk.full_inval_and_update()
        return
    def updateHandlePositions(self):
        """
        Update handle positions and also update the resize handle radii and
        their 'stopper' lengths.
        @see: self._update_resizeHandle_radius()
        @see: self._update_resizeHandle_stopper_length()
        @see: EditNanotube_GraphicsMode._drawHandles()
        """
        self.handlePoint1 = None  # Needed!
        self.handlePoint2 = None

        #TODO: Call this method less often by implementing model_changed
        #see bug 2729 for a planned optimization
        self.cylinderWidth = CYLINDER_WIDTH_DEFAULT_VALUE
        self.cylinderWidth2 = CYLINDER_WIDTH_DEFAULT_VALUE

        self._update_resizeHandle_radius()

        handlePoint1, handlePoint2 = self.struct.nanotube.getEndPoints()

        if 0:  # Debug prints
            print "updateHandlePositions(): handlePoint1=", handlePoint1
            print "updateHandlePositions(): handlePoint2=", handlePoint2

        if handlePoint1 is not None and handlePoint2 is not None:
            # (that condition is bugfix for deleted axis segment, bruce 080213)

            self.handlePoint1, self.handlePoint2 = handlePoint1, handlePoint2

            #Update the 'stopper'  length where the resize handle being dragged
            #should stop. See self._update_resizeHandle_stopper_length()
            #for more details
            self._update_resizeHandle_stopper_length()

            if DEBUG_ROTATION_HANDLES:
                self.rotation_distance1 = CYLINDER_WIDTH_DEFAULT_VALUE
                self.rotation_distance2 = CYLINDER_WIDTH_DEFAULT_VALUE
                #Following computes the base points for rotation handles.
                #to be revised -- Ninad 2008-02-13
                unitVectorAlongAxis = norm(self.handlePoint1 -
                                           self.handlePoint2)

                v = cross(self.glpane.lineOfSight, unitVectorAlongAxis)

                self.rotationHandleBasePoint1 = self.handlePoint1 + norm(
                    v) * 4.0
                self.rotationHandleBasePoint2 = self.handlePoint2 + norm(
                    v) * 4.0
        return
Example #49
0
    def _orient_for_modify(self, end1, end2):
        """
        Do the final orientation of the newly generated dna, around its own
        axis so that the axis and strand atoms on this new dna are
        fusable with the resize end on the original dna.
        @param end1: end1 of new dna (segment) generated
        @param end2: end2 of new dna (segment) generated
        """

        b = norm(end2 - end1)
        new_ladder = self.axis_atom_end1.molecule.ladder

        chunkListForRotation = new_ladder.all_chunks()

        endBaseAtomList = new_ladder.get_endBaseAtoms_containing_atom(
            self.axis_atom_end1)

        endStrandbaseAtoms = (endBaseAtomList[0], endBaseAtomList[2])

        self.strandA_atom_end1 = None
        #TODO: REVIEW / REFACTOR THIS and DOC
        for atm in endStrandbaseAtoms:
            if atm is not None:
                self.strandA_atom_end1 = atm
                self._set_bond_direction_on_new_strand(atm)


        axis_strand_vector = (self.strandA_atom_end1.posn() - \
                              self.axis_atom_end1.posn())


        vectorAlongLadderStep =  self._resizeEndStrand1Atom.posn() - \
                              self._resizeEndAxisAtom.posn()

        unitVectorAlongLadderStep = norm(vectorAlongLadderStep)

        self.final_pos_strand_end_atom = \
            self.axis_atom_end1.posn() + \
            vlen(axis_strand_vector)*unitVectorAlongLadderStep

        q_new = Q(axis_strand_vector, vectorAlongLadderStep)

        if dot(axis_strand_vector, cross(vectorAlongLadderStep, b)) < 0:
            q_new2 = Q(b, -q_new.angle)
        else:
            q_new2 = Q(b, q_new.angle)

        self.assy.rotateSpecifiedMovables(q_new2, chunkListForRotation, end1)
    def _orient_for_modify(self, end1, end2):
        """
        Do the final orientation of the newly generated dna, around its own
        axis so that the axis and strand atoms on this new dna are
        fusable with the resize end on the original dna.
        @param end1: end1 of new dna (segment) generated
        @param end2: end2 of new dna (segment) generated
        """

        b = norm(end2 - end1)
        new_ladder =   self.axis_atom_end1.molecule.ladder

        chunkListForRotation = new_ladder.all_chunks()

        endBaseAtomList  = new_ladder.get_endBaseAtoms_containing_atom(self.axis_atom_end1)

        endStrandbaseAtoms = (endBaseAtomList[0], endBaseAtomList[2])

        self.strandA_atom_end1 = None
        #TODO: REVIEW / REFACTOR THIS and DOC
        for atm in endStrandbaseAtoms:
            if atm is not None:
                self.strandA_atom_end1 = atm
                self._set_bond_direction_on_new_strand(atm)


        axis_strand_vector = (self.strandA_atom_end1.posn() - \
                              self.axis_atom_end1.posn())


        vectorAlongLadderStep =  self._resizeEndStrand1Atom.posn() - \
                              self._resizeEndAxisAtom.posn()

        unitVectorAlongLadderStep = norm(vectorAlongLadderStep)

        self.final_pos_strand_end_atom = \
            self.axis_atom_end1.posn() + \
            vlen(axis_strand_vector)*unitVectorAlongLadderStep

        q_new = Q(axis_strand_vector, vectorAlongLadderStep)

        if dot(axis_strand_vector, cross(vectorAlongLadderStep, b)) < 0:
            q_new2 = Q(b, -q_new.angle)
        else:
            q_new2 = Q(b, q_new.angle)

        self.assy.rotateSpecifiedMovables(q_new2, chunkListForRotation, end1)
Example #51
0
 def __init__(self, point0, z, uhint, uhint2):
     # u and v and zn are unit vectors
     # z is NOT a unit vector
     self.p0 = point0
     self.p1 = point1 = point0 + z
     self.z = z
     zlen = vlen(z)
     if zlen < 1.0e-6:
         raise ZeroLengthCylinder()
     self.zinv = 1.0 / zlen
     self.zn = zn = norm(z)
     u = norm(uhint - (dot(uhint, z) / zlen**2) * z)
     if vlen(u) < 1.0e-4:
         u = norm(uhint2 - (dot(uhint2, z) / zlen**2) * z)
     v = cross(zn, u)
     self.u = u
     self.v = v
Example #52
0
 def __init__(self, point0, z, uhint, uhint2):
     # u and v and zn are unit vectors
     # z is NOT a unit vector
     self.p0 = point0
     self.p1 = point1 = point0 + z
     self.z = z
     zlen = vlen(z)
     if zlen < 1.0e-6:
         raise ZeroLengthCylinder()
     self.zinv = 1.0 / zlen
     self.zn = zn = norm(z)
     u = norm(uhint - (dot(uhint, z) / zlen**2) * z)
     if vlen(u) < 1.0e-4:
         u = norm(uhint2 - (dot(uhint2, z) / zlen**2) * z)
     v = cross(zn, u)
     self.u = u
     self.v = v
    def updateHandlePositions(self):
        """
        Update handle positions and also update the resize handle radii and
        their 'stopper' lengths. 
        @see: self._update_resizeHandle_radius()
        @see: self._update_resizeHandle_stopper_length()
        @see: NanotubeSegment_GraphicsMode._drawHandles()
        """
        self.handlePoint1 = None # Needed!
        self.handlePoint2 = None

        #TODO: Call this method less often by implementing model_changed
        #see bug 2729 for a planned optimization
        self.cylinderWidth = CYLINDER_WIDTH_DEFAULT_VALUE
        self.cylinderWidth2 = CYLINDER_WIDTH_DEFAULT_VALUE      

        self._update_resizeHandle_radius()

        handlePoint1, handlePoint2 = self.struct.nanotube.getEndPoints()

        if 0: # Debug prints
            print "updateHandlePositions(): handlePoint1=", handlePoint1
            print "updateHandlePositions(): handlePoint2=", handlePoint2

        if handlePoint1 is not None and handlePoint2 is not None:
            # (that condition is bugfix for deleted axis segment, bruce 080213)

            self.handlePoint1, self.handlePoint2 = handlePoint1, handlePoint2            

            #Update the 'stopper'  length where the resize handle being dragged 
            #should stop. See self._update_resizeHandle_stopper_length()
            #for more details
            self._update_resizeHandle_stopper_length()            

            if DEBUG_ROTATION_HANDLES:
                self.rotation_distance1 = CYLINDER_WIDTH_DEFAULT_VALUE
                self.rotation_distance2 = CYLINDER_WIDTH_DEFAULT_VALUE
                #Following computes the base points for rotation handles. 
                #to be revised -- Ninad 2008-02-13
                unitVectorAlongAxis = norm(self.handlePoint1 - self.handlePoint2)

                v  = cross(self.glpane.lineOfSight, unitVectorAlongAxis)

                self.rotationHandleBasePoint1 = self.handlePoint1 + norm(v) * 4.0  
                self.rotationHandleBasePoint2 = self.handlePoint2 + norm(v) * 4.0
        return
Example #54
0
def pi_vectors(bond, out = DFLT_OUT, up = DFLT_UP, abs_coords = False): # rename -- pi_info for pi bond in degen sp chain
    # see also PiBondSpChain.get_pi_info
    """
    Given a bond involving some pi orbitals, return the 4-tuple ((a1py, a1pz), (a2py, a2pz), ord_pi_y, ord_pi_z),
    where a1py and a1pz are orthogonal vectors from atom1 giving the direction of its p orbitals for use in drawing
    this bond (for twisted bonds, the details of these might be determined more by graphic design issues than by the
    shapes of the real pi orbitals of the bond, though the goal is to approximate those);
    where a2py and a2pz are the same for atom2 (note that a2py might not be parallel to a1py for twisted bonds);
    and where ord_pi_y and ord_pi_z are order estimates (between 0.0 and 1.0 inclusive) for use in drawing the bond,
    for the pi_y and pi_z orbitals respectively. Note that the choice of how to name the two pi orbitals (pi_y, pi_z)
    is arbitrary and up to this function.
       All returned vectors are in the coordinate system of bond, unless abs_coords is true.
       This should not be called for pi bonds which are part of an "sp chain",
    but it should be equivalent to the code that would be used for a 1-bond sp-chain
    (i.e. it's an optimization of that code, PiBondSpChain.get_pi_info, for that case).
    """
    atom1 = bond.atom1
    atom2 = bond.atom2
    bond_axis = atom2.posn() - atom1.posn() #k not always needed i think
    # following subrs should be renamed, since we routinely call them for sp atoms,
    # e.g. in -C#C- where outer bonds are not potential pi bonds
    pvec1 = p_vector_from_sp2_atom(atom1, bond, out = out, up = up) # might be None
    pvec2 = p_vector_from_sp2_atom(atom2, bond, out = out, up = up) # ideally, close to negative or positive of pvec1
    # handle one being None (use other one in place of it) or both being None (use arb vectors)
    if pvec1 is None:
        if pvec2 is None:
            # use arbitrary vectors perp to the bond; compute differently if bond_axis ~= out [###@@@ make this a subr? dup code?]
            pvec = cross(out, bond_axis)
            lenpvec = vlen(pvec)
            if lenpvec < 0.01:
                pvec = up
            else:
                pvec /= lenpvec
            pvec1 = pvec2 = pvec
        else:
            pvec1 = pvec2
    else:
        if pvec2 is None:
            pvec2 = pvec1
        else:
            # both vectors not None -- use them, but negate pvec2 if this makes them more aligned
            if dot(pvec1, pvec2) < 0:
                pvec2 = - pvec2
    return pi_info_from_abs_pvecs( bond, bond_axis, pvec1, pvec2, abs_coords = abs_coords) 
Example #55
0
    def __init__(self, xpos=0, ypos=0, right=None, up=None,
                 rot90=False, glBegin=False):

        self.glBegin = glBegin
        if right is not None and up is not None:
            # The out-of-screen direction for text should always agree with
            # the "real" out-of-screen direction.
            self.outOfScreen = cross(right, up)

            if rot90:
                self.xflip = xflip = right[1] < 0.0
            else:
                self.xflip = xflip = right[0] < 0.0

            xgap = WIDTH
            halfheight = 0.5 * HEIGHT

            if xflip:
                xgap *= -SCALE
                def fx(x): return SCALE * (WIDTH - 1 - x)
            else:
                xgap *= SCALE
                def fx(x): return SCALE * x

            if rot90:
                ypos += xgap
                xpos -= halfheight * SCALE
                def tfm(x, y, yoff1, yflip):
                    if yflip:
                        y1 = SCALE * (HEIGHT - 1 - y)
                    else:
                        y1 = SCALE * y
                    return Numeric.array((xpos + yoff1 + y1, ypos + fx(x), 0.0))
            else:
                xpos += xgap
                ypos -= halfheight * SCALE
                def tfm(x, y, yoff1, yflip):
                    if yflip:
                        y1 = SCALE * (HEIGHT - 1 - y)
                    else:
                        y1 = SCALE * y
                    return Numeric.array((xpos + fx(x), ypos + yoff1 + y1, 0.0))
            self.tfm = tfm
Example #56
0
 def SurfaceNormals(self):
     """calculate surface normals for all points"""
     normals = []
     for i in range(len(self.points)):
         normals.append(V(0.0, 0.0, 0.0))
     for i in range(len(self.trias)):
         t = self.trias[i]
         p0 = self.points[t[0]]
         p1 = self.points[t[1]]
         p2 = self.points[t[2]]
         v0 = V(p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2])
         v1 = V(p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2])
         n = cross(v0, v1)
         normals[t[0]] += n
         normals[t[1]] += n
         normals[t[2]] += n
     self.normals = []
     for n in normals:
         self.normals.append((n[0], n[1], n[2]))
     return self.normals