Exemple #1
0
    def sameAsCurrentView(self, view = None):
        """
        Tests if self is the same as I{view}, or the current view if I{view}
        is None (the default).

        @param view: A named view to compare with self. If None (the default),
                     self is compared to the current view (i.e. the 3D graphics
                     area).
        @type  view: L{NamedView}

        @return: True if they are the same. Otherwise, returns False.
        @rtype:  boolean
        """
        # Note: I'm guessing this could be rewritten to be more
        # efficient/concise. For example, it seems possible to implement
        # this using a simple conditional like this:
        #
        # if self == view:
        #    return True
        # else:
        #    return False
        #
        # It occurs to me that the GPLane class should use a NamedView attr
        # along with (or in place of) quat, scale, pov and zoomFactor attrs.
        # That would make this method (and possibly other code) easier to
        # write and understand.
        #
        # Ask Bruce about all this.
        #
        # BTW, this code was originally copied/borrowed from
        # GLPane.animateToView(). Mark 2008-02-03.

        # Make copies of self parameters.
        q1 = Q(self.quat)
        s1 = self.scale
        p1 = V(self.pov[0], self.pov[1], self.pov[2])
        z1 = self.zoomFactor

        if view is None:
            # use the graphics area in which self is displayed
            # (usually the main 3D graphics area; code in this class
            #  has not been reviewed for working in other GLPane_minimal instances)
            view = self.assy.glpane

        # Copy the parameters of view for comparison
        q2 = Q(view.quat)
        s2 = view.scale
        p2 = V(view.pov[0], view.pov[1], view.pov[2])
        z2 = view.zoomFactor

        # Compute the deltas
        deltaq = q2 - q1
        deltap = vlen(p2 - p1)
        deltas = abs(s2 - s1)
        deltaz = abs(z2 - z1)

        if deltaq.angle + deltap + deltas + deltaz == 0:
            return True
        else:
            return False
Exemple #2
0
    def setup_quat_center(self, atomList=None):
        """
        Setup the plane's quat using a list of atoms.

        If no atom list is supplied, the plane is centered in the glpane
        and parallel to the screen.

        @param atomList: A list of atoms.
        @type  atomList: list

        """
        if atomList:
            self.atomPos = []
            for a in atomList:
                self.atomPos += [a.posn()]
            planeNorm = self._getPlaneOrientation(self.atomPos)
            if dot(planeNorm, self.glpane.lineOfSight) < 0:
                planeNorm = -planeNorm
            self.center = add.reduce(self.atomPos) / len(self.atomPos)
            self.quat = Q(V(0.0, 0.0, 1.0), planeNorm)
        else:
            self.center = V(0.0, 0.0, 0.0)
            # Following makes sure that Plane edges are parallel to
            # the 3D workspace borders. Fixes bug 2448
            x, y, z = self.glpane.right, self.glpane.up, self.glpane.out
            self.quat = Q(x, y, z)
            self.quat += Q(self.glpane.right, pi)
Exemple #3
0
 def update(self, px, py, uq = None):
     """
     This should be called in a mouseDrag binding, with window coordinates of the mouse;
     return value is an incremental quat, to be used in conjunction with uq as explained below.
        For trackballing the entire model space (whose orientation is stored in (for example) glpane.quat),
     caller should not pass uq, and should increment glpane.quat by the return value (i.e. glpane.quat += retval).
        For trackballing an object with orientation obj.quat, drawn subject to (for example) glpane.quat,
     caller should pass uq = glpane.quat, and should increment obj.quat by the return value.
     (If caller didn't pass uq in that case, our retval would be suitable for incrementing obj.quat + glpane.quat,
      or glpane.quat alone, but this is not the same as a retval suitable for incrementing obj.quat alone.)
     """
     #bruce 060514 revised this code (should be equivalent to the prior code), added docstring
     #ninad 060906 added 'rotation sensitivity to this formula. the rotation sensitivity will be used
     #while middle drag rotating the model. By default a lower value is set for this and can be adjusted
     #via a user preference. This helps mitigate bug 1856
     newmouse = proj2sphere((px - self.w2) * self.scale * self.mouseSpeedDuringRotation,
                            (self.h2 - py) * self.scale * self.mouseSpeedDuringRotation)
     if self.oldmouse is not None:
         quat = Q(self.oldmouse, newmouse)
         if uq is not None:
             quat = uq + quat - uq
     else:
         print "warning: trackball.update sees oldmouse is None (should not happen)" #bruce 060514
         quat = Q(1,0,0,0)
     self.oldmouse = newmouse
     return quat
Exemple #4
0
 def pvecs_i(self, i, abs_coords=False):
     """
     Use last recomputed geom to get the 2 pvecs for bond i...
     in the coordsys of the bond, or always abs if flag is passed.
     WARNING: pvec order matches atom order in lista, maybe not in bond.
     """
     biL_pvec = biR_pvec = self.quats_cum[i].rot(
         self.b0L_pvec)  # not yet twisted
     axis = self.axes[i]
     ##        if self.twist90 and i % 2 == 1:
     ##            biL_pvec = norm(cross(biL_pvec, axis))
     ##            biR_pvec = norm(cross(biR_pvec, axis))
     twist = self.twist  # this is the twist angle (in radians), for each bond; or None or 0 or 0.0 for no twist
     if twist:
         # twist that much times i and i+1 for L and R, respectively, around axes[i]
         theta = twist
         quatL = Q(axis, theta * (i))
         quatR = Q(axis, theta * (i + 1))
         biL_pvec = quatL.rot(biL_pvec)
         biR_pvec = quatR.rot(biR_pvec)
     if not abs_coords:
         # put into bond coords (which might be the same as abs coords)
         bond = self.listb[i]
         quat = bond.bond_to_abs_coords_quat()
         biL_pvec = quat.unrot(biL_pvec)
         biR_pvec = quat.unrot(biR_pvec)
     return biL_pvec, biR_pvec  # warning: these two vectors might be the same object
Exemple #5
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
    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()
    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)
Exemple #8
0
def animate_TCs():
    # Animate TCs, rotating them slowly.

    # Note: as of 090223 and before, this works in DL case but not in shader
    # case, because coordinate updates after TCs are modified are nim in
    # shader case (I think). [bruce 090223 comment]

    slow = 10.0  # Seconds.
    angle = 2 * pi * fmod(time.time(), slow) / slow
    # Leave the first one as identity, and rotate the others in
    # opposite directions around the X axis.
    TCs[1].setRotateTranslate(Q(V(1, 0, 0), angle * 2), V(0, 0, 0))
    TCs[2].setRotateTranslate(Q(V(1, 0, 0), -angle), V(0, 0, 0))
    return
Exemple #9
0
 def viewIsometric(self):
     """
     This sets the view to isometric. For isometric view, it needs
     rotation around the vertical axis by pi/4 *followed* by rotation
     around horizontal axis by asin(tan(pi/6) - ninad060810
     """
     # This is not yet called from the MainWindow. Need UI for this.
     # Also need code review -ninad060810
     cmd = greenmsg("Isometric View: ")
     info = 'Current view is Isometric View'
     env.history.message(cmd + info)
     self.quatX = Q(V(1,0,0), math.asin(math.tan(math.pi/6)))
     self.quatY = Q(V(0,1,0), -math.pi/4)
     self.glpane.rotateView(self.quatY+self.quatX)
Exemple #10
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)
Exemple #11
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
Exemple #12
0
def bonded_atoms_summary(
    bond, quat=Q(1, 0, 0, 0)
):  #bruce 050705; direction feature, bruce 070414. ###e SHOULD CALL bond_left_atom
    """
    Given a bond, and an optional quat describing the orientation it's shown in,
    order the atoms left to right based on that quat,
    and return a text string summarizing the bond
    in the form C26(sp2) <-2-> C34(sp3) or so,
    leaving out the < or > if the bond has a direction.
    """
    a1 = bond.atom1
    a2 = bond.atom2
    direction = bond._direction
    vec = a2.posn() - a1.posn()
    vec = quat.rot(vec)
    if vec[0] < 0.0:
        a1, a2 = a2, a1
        direction = -direction
    a1s = describe_atom_and_atomtype(a1)
    a2s = describe_atom_and_atomtype(a2)
    bondletter = bond_letter_from_v6(bond.v6)
    if bondletter == '1':
        bondletter = ''
    arrows = _bond_arrows.get(direction, ("<-", " (invalid direction) ->"))
    return "%s %s%s%s %s" % (a1s, arrows[0], bondletter, arrows[1], a2s)
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)
Exemple #14
0
 def getRotateTranslate(self):
     """
     @return: self's transform value, as the tuple (quat, vec), representing
              the translation 3-vector vec composed with the rotation
              quaternion quat (rotation to be done first).
     @rtype: (quat, vec) where quat is of class Q, and vec is a length-3
             sequence of undocumented type.
     
     If self is being used to transform a 3d model, the rotation should be
     applied to the model first, to orient it around its presumed center;
     then the translation, to position the rotated model with its center in
     the desired location. This means that the opposite order should be used
     to apply them to the GL matrices (which give the coordinate system for
     drawing), i.e. first glTranslatef, then glRotatef.
     """
     # With no scales, skews, or perspective the right column is [0, 0, 0,
     # 1].  The upper right 3x3 is a rotation matrix giving the orientation
     ####         ^^^^^
     #### REVIEW: should this 'right' be 'left'?
     #### [bruce 090203 comment]
     # of the new right-handed orthonormal local coordinate frame, and the
     # left-bottom-row 3-vector is the translation that positions the origin
     # of that frame.
     quat = Q(self.transform[0, 0:3], self.transform[1, 0:3],
              self.transform[2, 0:3])
     vec = self.transform[3, 0:3]
     return (quat, vec)
    def _fitInWindow(self):
        if not self.model:
            return

        self.quat = Q(1, 0, 0, 0)

        if isinstance(self.model, Chunk):
            self.model._recompute_bbox()
            bbox = self.model.bbox
        else:  ## Assembly
            part = self.model.part
            bbox = part.bbox
        self.scale = bbox.scale()

        if isinstance(self.width, int):
            width = self.width
        else:
            width = float(self.width())
        if isinstance(self.height, int):
            height = self.height
        else:
            height = float(self.height())

        aspect = width / height

        ##aspect = float(self.width) / self.height
        if aspect < 1.0:
            self.scale /= aspect
        center = bbox.center()
        self.pov = V(-center[0], -center[1], -center[2])
Exemple #16
0
    def __init__(self, assy, name, scale, pov, zoomFactor, wxyz):
        """
        @param pov: the inverse of the "center of view" in model coordinates
        @type pov: position vector (Numeric.array of 3 ints or floats, as made
                   by V(x,y,z))

        @param wxyz: orientation of view
        @type wxyz: a Quaternion (class VQT.Q), or a sequence of 4 floats
                    which can be passed to that class to make one, e.g.
                    Q(W, x, y, z) is the quaternion with axis vector x,y,z
                    and sin(theta/2) = W
        """
        self.const_pixmap = imagename_to_pixmap("modeltree/NamedView.png")
        if not name:
            name = gensym("%s" % self.sym, assy)
        Node.__init__(self, assy, name)
        self.scale = scale
        assert type(pov) is type(V(1, 0, 0))
        self.pov = V(pov[0], pov[1], pov[2])
        self.zoomFactor = zoomFactor
        self.quat = Q(wxyz)
            #bruce 050518/080303 comment: wxyz is passed as an array of 4 floats
            # (in same order as in mmp file's csys record), when parsing
            # csys mmp records, or with wxyz a quat in other places.
        return
Exemple #17
0
def drawFilledCircle(color, center, radius, normal):
    """
    Scale, rotate/translate the unit circle properly.
    Added a filled circle variant, piotr 080405
    """
    glMatrixMode(GL_MODELVIEW)
    glPushMatrix()
    glColor3fv(color)
    glDisable(GL_LIGHTING)

    glTranslatef(center[0], center[1], center[2])
    rQ = Q(V(0, 0, 1), normal)
    rotAngle = rQ.angle * 180.0 / pi

    #This may cause problems as proved before in Linear motor display.
    #rotation around (0, 0, 0)
    #if vlen(V(rQ.x, rQ.y, rQ.z)) < 0.00005:
    #      rQ.x = 1.0

    glRotatef(rotAngle, rQ.x, rQ.y, rQ.z)
    glScalef(radius, radius, 1.0)
    glCallList(drawing_globals.filledCircleList)
    glEnable(GL_LIGHTING)
    glPopMatrix()
    return
Exemple #18
0
    def viewParallelTo(self):
        """
        Set view parallel to the vector defined by 2 selected atoms.
        """
        cmd = greenmsg("Set View Parallel To: ")

        atoms = self.assy.selatoms_list()

        if len(atoms) != 2:
            msg = redmsg("You must select 2 atoms.")
            env.history.message(cmd + msg)
            return

        v = norm(atoms[0].posn()-atoms[1].posn())

        if vlen(v) < 0.0001: # Atoms are on top of each other.
            info = 'The selected atoms are on top of each other.  No change in view.'
            env.history.message(cmd + info)
            return

        # If vec is pointing into the screen, negate (reverse) vec.
        if dot(v, self.glpane.lineOfSight) > 0:
            v = -v

        # Compute the destination quat (q2).
        q2 = Q(V(0,0,1), v)
        q2 = q2.conj()

        self.glpane.rotateView(q2)

        info = 'View set parallel to the vector defined by the 2 selected atoms.'
        env.history.message(cmd + info)
Exemple #19
0
    def _initialize_view_attributes(self):  #bruce 090220 split this out
        """
        Initialize the current view attributes
        """
        # note: these are sometimes saved in or loaded from
        # the currently displayed part or its mmp file

        # rotation
        self.quat = Q(1, 0, 0, 0)

        # point of view (i.e. negative of center of view)
        self.pov = V(0.0, 0.0, 0.0)

        # half-height of window in Angstroms (reset by certain view-changing operations)
        self.scale = float(env.prefs[startup_GLPane_scale_prefs_key])

        # zoom factor
        self.zoomFactor = 1.0
        # Note: I believe (both now, and in a comment dated 060829 which is
        # now being removed from GLPane.py) that nothing ever sets
        # self.zoomFactor to anything other than 1.0, though there is code
        # which could do this in theory. I think zoomFactor was added as
        # one way to implement zoomToArea, but another way (changing scale)
        # was chosen, which makes zoomFactor useless. Someday we should
        # consider removing it, unless we think it might be useful for
        # something in the future. [bruce 080910 comment]
        return
Exemple #20
0
 def _mirrorChunk(self, chunkToMirror):
     """
     Converts the given chunk into its own mirror. 
     
     @param chunkToMirror: The chunk that needs to be converted into its own
            mirror chunk. 
     @type  chunkToMirror: instance of class Chunk
     @see:  self.Mirror
     """
     m = chunkToMirror
     # ninad060813 Following gives an orthogonal distance between the 
     #chunk center and mirror plane.
     self.mirrorDistance, self.wid = orthodist(m.center, 
                                               self.mirrorAxis, 
                                               self.mirrorJigs[0].center) 
     # @@@@ ninad060813 This moves the mirror chunk on the other side of 
     # the mirror plane. It surely moves the chunk along the axis of the 
     # mirror plane but I am still unsure if this *always* moves the 
     # chunk on the other side of the mirror. 
     #Probably the 'orthodist' function has helped me here?? 
     m.move(2*(self.mirrorDistance)*self.mirrorAxis)
     
     m.stretch(-1.0)
     m.rot(Q(self.mirrorAxis, pi))
     return
Exemple #21
0
 def _mirrorJig(self, jigToMirror):
     """
     Converts the given jig into its own mirror. If the jig is a motor, 
     it also reverses its direction.
     @param jigToMirror: The jig that needs to be converted into its own
            mirror jig. 
     @type  jigToMirror: instance of class Jig
     @see:  self.Mirror
     """
     j = jigToMirror
     # ninad060813 This gives an orthogonal distance between the chunk 
     # center and mirror plane.
     
     #Fixed bug 2503. 
     if not (isinstance(j, Motor) or isinstance(j, ESPImage)):
         return
     
     self.mirrorDistance, self.wid = orthodist(j.center, self.mirrorAxis, 
                                               self.mirrorJigs[0].center)         
     j.move(2*(self.mirrorDistance)*self.mirrorAxis)
     
     j.rot(Q(self.mirrorAxis, pi))
     
     #Reverse the direction of Linear and Rotary motor for correct 
     #mirror operation
     if isinstance(j, Motor):
         j.reverse_direction()
     return
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)
Exemple #23
0
    def __init__(self, elem, name, formalCharge, electronsNeeded,
                 electronsProvided, covalentRadius, bondvectors):
        """
        #doc...
        Set some public members, including element, name, fullname,
        numbonds, valence, rcovalent, bondvectors, base, and quats.
        Also spX, openbond; and for some elements, num_lonepairs (etc),
        num_pi_electrons.
        """
        self.element = elem

        # electronsProvided + formalCharge should equal group number

        # these are shared from another atom (half of an order 1 covalent bond)
        electronsShared = electronsNeeded - electronsProvided

        self.valence = electronsShared  # total bond order for all bonds to this atomtype
        self.name = name = name or "?"
        # default name won't show up except for bugs, provided it's only used for elements with only one atomtype
        self.fullname = elem.name + '/' + self.name  #ok? [see also self.fullname_for_msg()]
        self.openbond = (elem.eltnum == 0)
        if name.startswith("sp3") or name == "?":
            spX = 3
        elif name.startswith("sp2"):  # including sp2 and sp2(graphitic)
            spX = 2
        elif name.startswith("sp") and (name == "sp" or not name[2].isdigit()):
            spX = 1
        else:
            print "warning: bug: atomtype name in %r does not start with sp, sp2, or sp3; assuming sp3 in bonds code" % self.fullname
            spX = 3
        self.spX = spX
        if 0 and debug_flags.atom_debug and (spX != 3 or self.openbond):
            print "atom_debug: fyi: %r has spX == %d" % (self.fullname, spX)
        self.rcovalent = covalentRadius

        self.base = None
        self.quats = [
        ]  # ends up one shorter than self.numbonds [bruce 041217]
        if (bondvectors != None):
            # number of distinct bonds to different other atoms (a
            # double bond is counted as 1)
            self.numbonds = len(bondvectors)

            s = bondvectors[0]
            self.base = s
            for v in bondvectors[1:]:
                self.quats += [Q(s, v)]
        else:
            self.numbonds = 0

        if (bondvectors != None):
            self.bondvectors = bondvectors
        else:
            self.bondvectors = []

        self.charge = formalCharge
        #self._init_electronic_structure() # this uses self.numbonds, so don't call it too early
        self._init_permitted_v6_list()
        return  # from __init__
Exemple #24
0
    def __init_quat_center(self, list):

        for a in list:  #[:3]:
            self.atomPos += [a.posn()]

        planeNorm = self._getPlaneOrientation(self.atomPos)
        self.quat = Q(V(0.0, 0.0, 1.0), planeNorm)
        self.center = add.reduce(self.atomPos) / len(self.atomPos)
Exemple #25
0
 def viewRotate180(self):
     """
     Set view to the opposite of current view.
     """
     cmd = greenmsg("Opposite View: ")
     info = 'Current view opposite to the previous view'
     env.history.message(cmd + info)
     self.glpane.rotateView(self.glpane.quat + Q(V(0,1,0), math.pi))
Exemple #26
0
 def viewRotateMinus90(self): # Added by Mark. 051013.
     """
     Decrement the current view by 90 degrees around the vertical axis.
     """
     cmd = greenmsg("Rotate View -90 : ")
     info = 'View decremented by 90 degrees'
     env.history.message(cmd + info)
     self.glpane.rotateView(self.glpane.quat + Q(V(0,1,0), -math.pi/2))
Exemple #27
0
    def resetView(self):
        """
        Reset the view.

        Subclass can override this method with different <scale>, so call
        this version in the overridden version.
        """
        self.pov = V(0.0, 0.0, 0.0)
        self.quat = Q(1, 0, 0, 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
Exemple #29
0
    def viewNormalTo(self): # 
        """
        Set view to the normal vector of the plane defined by 3 or more
        selected atoms or a jig's (Motor or RectGadget) axis.
        """
        cmd = greenmsg("Set View Normal To: ")

        chunks = self.assy.selmols
        jigs = self.assy.getSelectedJigs()
        atoms = self.assy.selatoms_list()

        #following fixes bug 1748 ninad 061003. 
        if len(chunks) > 0 and len(atoms) == 0:
            # Even though chunks have an axis, it is not necessarily the same
            # axis attr stored in the chunk.  Get the chunks atoms and let
            # compute_heuristic_axis() recompute them.
            for c in range(len(chunks)):
                atoms += chunks[c].atoms.values()
        elif len(jigs) == 1 and len(atoms) == 0:
            # Warning: RectGadgets have no atoms.  We handle this special case below.
            atoms = jigs[0].atoms 
        elif len(atoms) < 3:
            # There is a problem when allowing only 2 selected atoms. 
            # Changing requirement to 3 atoms fixes bug 1418. mark 060322
            msg = redmsg("Please select some atoms, jigs, and/or chunks, covering at least 3 atoms")
            print "ops_view.py len(atoms) = ", len(atoms)
            env.history.message(cmd + msg)
            return

        # This check is needed for jigs that have no atoms.  Currently, this 
        # is the case for RectGadgets (ESP Image and Grid Plane) only.
        if len(atoms):
            pos = A( map( lambda a: a.posn(), atoms ) )
            nears = [ self.glpane.out, self.glpane.up ]
            axis = compute_heuristic_axis( pos, 'normal', already_centered = False, nears = nears, dflt = None )
        else: # We have a jig with no atoms.
            axis = jigs[0].getaxis() # Get the jig's axis.
            # If axis is pointing into the screen, negate (reverse) axis.
            if dot(axis, self.glpane.lineOfSight) > 0:
                axis = -axis

        if not axis:
            msg = orangemsg( "Warning: Normal axis could not be determined. No change in view." )
            env.history.message(cmd + msg)
            return

        # Compute the destination quat (q2).
        q2 = Q(V(0,0,1), axis)
        q2 = q2.conj()

        self.glpane.rotateView(q2)

        info = 'View set to normal vector of the plane defined by the selected atoms.'
        env.history.message(cmd + info)
    def __init__(self, assy, atomlist = []): #bruce 050526 added optional atomlist arg
        assert atomlist == [] # whether from default arg value or from caller -- for now
        Jig.__init__(self, assy, atomlist)

        self.quat = Q(1, 0, 0, 0)
            # is self.quat ever set to other values? if not, remove it; if so, add it to mutable_attrs. [bruce 060228 comment]
        
        #The motor is usually drawn as an opaque object. However when it is
        #being previewed, it is drawn as a transparent object - Ninad 2007-10-09
        self.previewOpacity = 0.4
        self.defaultOpacity = 1.0
        self.opacity = self.defaultOpacity