示例#1
0
    def _addGroupBoxes(self):
        """
        Add various groupboxes to Fuse property manager. 
        """

        self.fuseOptionsGroupBox = PM_GroupBox(self, title="Fuse Options")
        self._loadFuseOptionsGroupBox(self.fuseOptionsGroupBox)

        MovePropertyManager._addGroupBoxes(self)
 def _addGroupBoxes(self):
     """
     Add various groupboxes to Fuse property manager. 
     """
     
     self.fuseOptionsGroupBox = PM_GroupBox( self,
                                      title = "Fuse Options")
     self._loadFuseOptionsGroupBox(self.fuseOptionsGroupBox)
     
     MovePropertyManager._addGroupBoxes(self)
 def __init__(self, parentMode):
     """
     Constructor for Fuse Property manager. 
     @param parentMode: The parent mode for this property manager 
     @type  parentMode: L{fuseChunksmode}
     """
     
     self.parentMode = parentMode
     MovePropertyManager.__init__(self, self.parentMode)
             
     self.activate_translateGroupBox_in_fuse_PM()
示例#4
0
    def __init__(self, command):
        """
        Constructor for Fuse Property manager. 
        @param command: The parent mode for this property manager 
        @type  command: L{fuseChunksmode}
        """

        self.command = command
        MovePropertyManager.__init__(self, self.command)

        self.activate_translateGroupBox_in_fuse_PM()
    def __init__(self, command):
        """
        Constructor for Fuse Property manager.
        @param command: The parent mode for this property manager
        @type  command: L{fuseChunksmode}
        """

        self.command = command
        MovePropertyManager.__init__(self, self.command)

        self.activate_translateGroupBox_in_fuse_PM()
    def init_gui(self):
        if not self.propMgr:
            self.propMgr = MovePropertyManager(self)
            #@bug BUG: following is a workaround for bug 2494
            changes.keep_forever(self.propMgr)

        self.propMgr.show()
        self.updateCommandToolbar(bool_entering=True)

        # connect signals (these all need to be disconnected in restore_gui)
        self.connect_or_disconnect_signals(True)

        self.propMgr.set_move_xyz(0, 0, 0)  # Init X, Y, and Z to zero
        self.propMgr.set_move_delta_xyz(0, 0,
                                        0)  # Init DelX,DelY, DelZ to zero
示例#7
0
    def init_gui(self):
        if not self.propMgr:
            self.propMgr = MovePropertyManager(self)
            #@bug BUG: following is a workaround for bug 2494
            changes.keep_forever(self.propMgr)

        self.propMgr.show()
        self.updateCommandToolbar(bool_entering = True)

        # connect signals (these all need to be disconnected in restore_gui)
        self.connect_or_disconnect_signals(True)

        self.propMgr.set_move_xyz(0, 0, 0) # Init X, Y, and Z to zero
        self.propMgr.set_move_delta_xyz(0,0,0) # Init DelX,DelY, DelZ to zero
class Move_basicCommand(SelectChunks_basicCommand):
    """
    """
    commandName = 'MODIFY'
    default_mode_status_text = "Mode: Move Chunks"
    featurename = "Move Chunks Mode"
    propMgr = None
    pw = None

    command_can_be_suspended = True
    command_should_resume_prevMode = False
    command_has_its_own_gui = True

    def init_gui(self):
        if not self.propMgr:
            self.propMgr = MovePropertyManager(self)
            #@bug BUG: following is a workaround for bug 2494
            changes.keep_forever(self.propMgr)

        self.propMgr.show()
        self.updateCommandToolbar(bool_entering=True)

        # connect signals (these all need to be disconnected in restore_gui)
        self.connect_or_disconnect_signals(True)

        self.propMgr.set_move_xyz(0, 0, 0)  # Init X, Y, and Z to zero
        self.propMgr.set_move_delta_xyz(0, 0,
                                        0)  # Init DelX,DelY, DelZ to zero

    def connect_or_disconnect_signals(self, connect):  # mark 060304.
        if connect:
            change_connect = self.w.connect
        else:
            change_connect = self.w.disconnect

        change_connect(self.exitMoveAction, SIGNAL("triggered()"),
                       self.w.toolsDone)

        self.propMgr.connect_or_disconnect_signals(connect)

    def restore_gui(self):
        # disconnect signals which were connected in init_gui [bruce 050728]
        self.updateCommandToolbar(bool_entering=False)
        self.w.toolsMoveMoleculeAction.setChecked(
            False)  # toggle on the Move Chunks icon
        self.w.rotateComponentsAction.setChecked(False)
        self.connect_or_disconnect_signals(False)
        if self.propMgr:
            self.propMgr.close()

    def NEWER_acceptParamsFromTemporaryMode(self, temporaryModeName, params):
        """
        NOTE: see electMolsMode.acceptParamsFromTemporaryMode for detail
        comment. This needs to be a API method. This is a temporary
        implementation
        """

        if len(params) == 2:
            mouseClickPoints, pivotAtom = params

            #Mouseclick points should contain 2 points. But if user abruptly
            #terminates  the temporary mode, this might not be true. So rotate
            #only when the it has 2 points!

            if len(mouseClickPoints) < 2:
                self.propMgr.rotateAboutPointButton.setChecked(False)
                return

            startPoint = mouseClickPoints[0]
            endPoint = mouseClickPoints[1]
            #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():
                reference_vec, node_junk = pivotAtom.molecule.getAxis_of_self_or_eligible_parent_node(
                )
                del node_junk
            else:
                reference_vec = self.glpane.right

            lineVector = endPoint - startPoint

            quat1 = Q(lineVector, reference_vec)

            print "***angle =", (quat1.angle) * 180 / math.pi
            print "***dot(lineVector, reference_vec)=", dot(
                lineVector, reference_vec)

            if dot(lineVector, reference_vec) < 0:
                theta = math.pi - quat1.angle
            else:
                theta = quat1.angle

            print "*** new angle =", theta * 180 / math.pi

            rot_axis = cross(lineVector, reference_vec)

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

            print "***dot(cross_prod_1, cross_prod_2) =", dot(
                cross_prod_1, cross_prod_2)

            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.o.gl_update()

        self.propMgr.rotateAboutPointButton.setChecked(False)

    def EXPERIMENTAL_acceptParamsFromTemporaryMode(self, temporaryModeName,
                                                   params):
        """
        NOTE: see electMolsMode.acceptParamsFromTemporaryMode for detail
        comment. This needs to be a API method. This is a temporary
        implementation
        """
        DEBUG_ROTATE_ABOUT_POINT = False

        if DEBUG_ROTATE_ABOUT_POINT:
            if len(params) == 2:
                mouseClickPoints, pivotAtom = params

                #Mouseclick points should contain 2 points. But if user abruptly
                #terminates  the temporary mode, this might not be true. So rotate
                #only when the it has 2 points!

                if len(mouseClickPoints) < 2:
                    self.propMgr.rotateAboutPointButton.setChecked(False)
                    return

                startPoint = mouseClickPoints[0]
                endPoint = mouseClickPoints[1]
                #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.o.gl_update()

        self.propMgr.rotateAboutPointButton.setChecked(False)

    def acceptParamsFromTemporaryMode(self, temporaryModeName, params):
        """
        NOTE: see electMolsMode.acceptParamsFromTemporaryMode for detail
        comment. This needs to be a API method. This is a temporary
        implementation
        """
        #Usually params will contain 2 items. But if user abruptly terminates
        #the temporary mode, this might not be true. So move the chunk by offset
        #only when you have got 2 points!  Ninad 2007-10-16
        if len(params) == 2:
            startPoint = params[0]
            endPoint = params[1]
            offset = endPoint - startPoint
            movables = self.graphicsMode.getMovablesForLeftDragging()
            self.assy.translateSpecifiedMovables(offset, movables=movables)

            self.o.gl_update()

        self.propMgr.moveFromToButton.setChecked(False)

        #For Rotate about point tool. May be we should do the following
        #only when the graphics mode is Rotate graphics mode? Okay for now
        #feature implemented just before FNANO 08 . clanup -- Ninad 2008-04-20
        self.propMgr.rotateAboutPointButton.setChecked(False)

    def provideParamsForTemporaryMode(self, temporaryModeName):
        """
        NOTE: See selectMolsMode.provideParamsForTemporaryMode
        for detail comment. This needs to be a API method. This is a temporary
        implementation
        @see: LineMode_GM._drawCursorText
        """

        temporaryModeNames = ("LineMode", "RotateAboutPoint")

        if temporaryModeName in temporaryModeNames:
            #This is the number of mouse clicks that the temporary mode accepts
            mouseClickLimit = 2
            return (mouseClickLimit)

    def rotateAboutPointTemporaryCommand(self, isChecked=False):
        """
        @see: self.moveFromToTemporaryMode
        """
        #@TODO: clean this up. This was written just after Rattlesnake rc2
        #for FNANO presentation -- Ninad 2008-04-17

        commandSequencer = self.commandSequencer
        currentCommand = commandSequencer.currentCommand

        if isChecked:
            self.propMgr.rotateStartCoordLineEdit.setEnabled(isChecked)
            msg = "Click inside the 3D workspace to define two points" \
                "of a line. The selection will be rotated about the first point"\
                " in the direction specified by that line"

            self.propMgr.updateMessage(msg)
            if currentCommand.commandName != "RotateAboutPoint":
                commandSequencer.userEnterTemporaryCommand('RotateAboutPoint')
                return
        else:
            if currentCommand.commandName == "RotateAboutPoint":
                currentCommand.Done(exit_using_done_or_cancel_button=False)
            self.propMgr.rotateStartCoordLineEdit.setEnabled(False)
            self.propMgr.updateMessage()

    def moveFromToTemporaryMode(self, isChecked=False):
        """
        Move the selected entities by the offset vector specified by the
        endpoints of a line. To use this feature, click on 'Move From/To button'
        in the PM and specify the two endpoints from GLPane. The program enters
        a temporary mode while you do that and then uses the data collected
        while in temporary mode (i.e. two endpoints) to move the selection.

        TODO: Note that the endpoints always assume GLPane depth. As of today,
        the temporary mode API knows nothing about the highlighting. Once it
        is implemented,  we can then specify atom centers etc as reference
        points. See comments in LineMode for further details.
        """
        if isChecked:
            self.propMgr.startCoordLineEdit.setEnabled(isChecked)
            msg = "Click inside the 3D workspace to define two endpoints" \
                "of a line. The selection will be moved by the offset "\
                "vector defined by these line endpoints."

            self.propMgr.updateMessage(msg)

            commandSequencer = self.commandSequencer
            currentCommand = commandSequencer.currentCommand

            if currentCommand.commandName != "LineMode":
                commandSequencer.userEnterTemporaryCommand('LineMode')
                return
        else:
            self.propMgr.startCoordLineEdit.setEnabled(False)
            self.propMgr.updateMessage()

    def rotateThetaPlus(self):
        "Rotate the selected chunk(s) by theta (plus)"

        button = self.propMgr.rotateAroundAxisButtonRow.checkedButton()
        if button:
            rotype = str(button.text())
        else:
            env.history.message(
                redmsg("Rotate By Specified Angle: Please press the button \
                                   corresponding to the axis of rotation"))
            return
        theta = self.propMgr.rotateThetaSpinBox.value()
        self.rotateTheta(rotype, theta)

    def rotateThetaMinus(self):
        "Rotate the selected chunk(s) by theta (minus)"
        button = self.propMgr.rotateAroundAxisButtonRow.checkedButton()
        if button:
            rotype = str(button.text())
        else:
            env.history.message(
                redmsg("Rotate By Specified Angle: Please press the button \
                                   corresponding to the axis of rotation"))
            return
        theta = self.propMgr.rotateThetaSpinBox.value() * -1.0
        self.rotateTheta(rotype, theta)

    def rotateTheta(self, rotype, theta):
        """"
        Rotate the selected chunk(s) /jig(s) around the specified axis
        by theta (degrees)
        """

        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return

        if rotype == 'ROTATEX':
            ma = V(1, 0, 0)  # X Axis
        elif rotype == 'ROTATEY':
            ma = V(0, 1, 0)  # Y Axis
        elif rotype == 'ROTATEZ':
            ma = V(0, 0, 1)  # Z Axis
        else:
            print 'modifyMody.rotateTheta: Error.  rotype = ', rotype, ', which is undefined.'
            return

        # wware 20061214: I don't know where the need arose for this factor of 100,
        # but it's necessary to get correct angles.
        #ninad 070322:
        #Will's above comment was for "dy = 100.0 * (pi / 180.0) * theta  # Convert to radians"
        #I agree with this. In fact if I enter angle of  1 degree, it multiplies it by 100!
        #May be it was necessary in Qt3 branch. I am modifying this formula
        #to remove this  multiplication factor of 100 as its giving wrong results
        dy = (math.pi / 180.0) * theta  # Convert to radians
        qrot = Q(ma, dy)  # Quat for rotation delta.

        if self.propMgr.rotateAsUnitCB.isChecked():
            # Rotate the selection as a unit.
            self.assy.rotateSpecifiedMovables(qrot, movables)
        else:
            for item in movables:
                try:
                    item.rot(qrot)
                except AssertionError:
                    print_compact_traceback("Selected movable doesn't have"\
                                            "rot method?")

        self.o.gl_update()

    def transDeltaPlus(self):
        """
        Add X, Y, and Z to the selected chunk(s) current position
        """
        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return
        offset = self.propMgr.get_move_delta_xyz()
        self.assy.translateSpecifiedMovables(offset, movables=movables)
        self.o.gl_update()

    def transDeltaMinus(self):
        """
        Subtract X, Y, and Z from the selected chunk(s) current position
        """
        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return

        offset = self.propMgr.get_move_delta_xyz(Plus=False)
        self.assy.translateSpecifiedMovables(offset, movables=movables)
        self.o.gl_update()

    def moveAbsolute(self):
        """
        Move selected chunk(s), jig(s) to absolute X, Y, and Z by computing
        the bbox center of everything as if they were one big chunk, then move
        everything as a unit.
        """
        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return

        ## Compute bbox for selected chunk(s).

        bbox = BBox()
        for m in movables:
            if hasattr(m, "bbox"):  # Fixes bug 1990. Mark 060702.
                bbox.merge(m.bbox)
        pt1 = bbox.center(
        )  # pt1 = center point for bbox of selected chunk(s).

        pt2 = self.propMgr.get_move_xyz()  # pt2 = X, Y, Z values from PM
        offset = pt2 - pt1  # Compute offset for translating the selection

        self.assy.translateSpecifiedMovables(offset, movables=movables)

        # Print history message about what happened.
        if len(movables) == 1:
            msg = "[%s] moved to [X: %.2f] [Y: %.2f] [Z: %.2f]" % (
                movables[0].name, pt2[0], pt2[1], pt2[2])
        else:
            msg = "Selected chunks/jigs moved by offset [X: %.2f] [Y: %.2f] [Z: %.2f]" % (
                offset[0], offset[1], offset[2])
        env.history.message(msg)
        self.o.gl_update()
        return

    #Command Toolbar related methods to be revised==============================
    def updateCommandToolbar(self, bool_entering=True):  #Ninad 20070618
        """
        Update the command toolbar.
        """
        if bool_entering:
            try:
                action = self.w.toolsMoveRotateActionGroup.checkedAction()
            except:
                print_compact_traceback("bug: no move action checked?")
                action = None
        else:
            action = None

        # object that needs its own flyout toolbar. In this case it is just
        #the mode itself.
        obj = self

        self.w.commandToolbar.updateCommandToolbar(action,
                                                   obj,
                                                   entering=bool_entering)

    def getFlyoutActionList(self):  #Ninad 20070618
        """ Returns a tuple that contains mode spcific actionlists in the
        added in the flyout toolbar of the mode.
        CommandToolbar._createFlyoutToolBar method calls this
        @return: params: A tuple that contains 3 lists:
        (subControlAreaActionList, commandActionLists, allActionsList)"""

        #'allActionsList' returns all actions in the flyout toolbar
        #including the subcontrolArea actions
        allActionsList = []

        #Action List for  subcontrol Area buttons.
        #In this mode, there is really no subcontrol area.
        #We will treat subcontrol area same as 'command area'
        #(subcontrol area buttons will have an empty list as their command area
        #list). We will set  the Comamnd Area palette background color to the
        #subcontrol area.

        subControlAreaActionList = []

        self.exitMoveAction = NE1_QWidgetAction(self.w, win=self.w)
        self.exitMoveAction.setText("Exit Move")
        self.exitMoveAction.setWhatsThis("Exits Move Mode")
        self.exitMoveAction.setCheckable(True)
        self.exitMoveAction.setChecked(True)
        self.exitMoveAction.setIcon(
            geticon("ui/actions/Toolbars/Smart/Exit.png"))
        subControlAreaActionList.append(self.exitMoveAction)

        separator = QtGui.QAction(self.w)
        separator.setSeparator(True)
        subControlAreaActionList.append(separator)

        subControlAreaActionList.append(self.w.toolsMoveMoleculeAction)
        subControlAreaActionList.append(self.w.rotateComponentsAction)
        subControlAreaActionList.append(self.w.modifyAlignCommonAxisAction)

        allActionsList.extend(subControlAreaActionList)

        #Empty actionlist for the 'Command Area'
        commandActionLists = []

        #Append empty 'lists' in 'commandActionLists equal to the
        #number of actions in subControlArea
        for i in range(len(subControlAreaActionList)):
            lst = []
            commandActionLists.append(lst)

        params = (subControlAreaActionList, commandActionLists, allActionsList)

        return params
示例#9
0
class Move_basicCommand(SelectChunks_basicCommand):
    """
    """
    commandName = 'MODIFY'
    default_mode_status_text = "Mode: Move Chunks"
    featurename = "Move Chunks Mode"
    propMgr = None
    pw = None

    command_can_be_suspended = True
    command_should_resume_prevMode = False
    command_has_its_own_gui = True

    def init_gui(self):
        if not self.propMgr:
            self.propMgr = MovePropertyManager(self)
            #@bug BUG: following is a workaround for bug 2494
            changes.keep_forever(self.propMgr)

        self.propMgr.show()
        self.updateCommandToolbar(bool_entering = True)

        # connect signals (these all need to be disconnected in restore_gui)
        self.connect_or_disconnect_signals(True)

        self.propMgr.set_move_xyz(0, 0, 0) # Init X, Y, and Z to zero
        self.propMgr.set_move_delta_xyz(0,0,0) # Init DelX,DelY, DelZ to zero

    def connect_or_disconnect_signals(self, connect): # mark 060304.
        if connect:
            change_connect = self.w.connect
        else:
            change_connect = self.w.disconnect

        change_connect(self.exitMoveAction, SIGNAL("triggered()"),
                       self.w.toolsDone)

        self.propMgr.connect_or_disconnect_signals(connect)

    def restore_gui(self):
        # disconnect signals which were connected in init_gui [bruce 050728]
        self.updateCommandToolbar(bool_entering = False)
        self.w.toolsMoveMoleculeAction.setChecked(False) # toggle on the Move Chunks icon
        self.w.rotateComponentsAction.setChecked(False)
        self.connect_or_disconnect_signals(False)
        if self.propMgr:
            self.propMgr.close()

    def NEWER_acceptParamsFromTemporaryMode(self, temporaryModeName, params):
        """
        NOTE: see electMolsMode.acceptParamsFromTemporaryMode for detail
        comment. This needs to be a API method. This is a temporary
        implementation
        """

        if len(params) == 2:
            mouseClickPoints, pivotAtom = params

            #Mouseclick points should contain 2 points. But if user abruptly
            #terminates  the temporary mode, this might not be true. So rotate
            #only when the it has 2 points!

            if len(mouseClickPoints) < 2:
                self.propMgr.rotateAboutPointButton.setChecked(False)
                return


            startPoint = mouseClickPoints[0]
            endPoint = mouseClickPoints[1]
            #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() :
                reference_vec, node_junk = pivotAtom.molecule.getAxis_of_self_or_eligible_parent_node()
                del node_junk
            else:
                reference_vec = self.glpane.right

            lineVector = endPoint - startPoint

            quat1 = Q(lineVector, reference_vec)

            print "***angle =", (quat1.angle)*180/math.pi
            print "***dot(lineVector, reference_vec)=", dot(lineVector, reference_vec)

            if dot(lineVector, reference_vec) < 0:
                theta = math.pi - quat1.angle
            else:
                theta = quat1.angle

            print "*** new angle =", theta*180/math.pi


            rot_axis = cross(lineVector, reference_vec)

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

            print "***dot(cross_prod_1, cross_prod_2) =", dot(cross_prod_1, cross_prod_2)

            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.o.gl_update()

        self.propMgr.rotateAboutPointButton.setChecked(False)

    def EXPERIMENTAL_acceptParamsFromTemporaryMode(self, temporaryModeName, params):
        """
        NOTE: see electMolsMode.acceptParamsFromTemporaryMode for detail
        comment. This needs to be a API method. This is a temporary
        implementation
        """
        DEBUG_ROTATE_ABOUT_POINT = False

        if DEBUG_ROTATE_ABOUT_POINT:
            if len(params) == 2:
                mouseClickPoints, pivotAtom = params

                #Mouseclick points should contain 2 points. But if user abruptly
                #terminates  the temporary mode, this might not be true. So rotate
                #only when the it has 2 points!

                if len(mouseClickPoints) < 2:
                    self.propMgr.rotateAboutPointButton.setChecked(False)
                    return


                startPoint = mouseClickPoints[0]
                endPoint = mouseClickPoints[1]
                #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.o.gl_update()

        self.propMgr.rotateAboutPointButton.setChecked(False)

    def acceptParamsFromTemporaryMode(self, temporaryModeName, params):
        """
        NOTE: see electMolsMode.acceptParamsFromTemporaryMode for detail
        comment. This needs to be a API method. This is a temporary
        implementation
        """
        #Usually params will contain 2 items. But if user abruptly terminates
        #the temporary mode, this might not be true. So move the chunk by offset
        #only when you have got 2 points!  Ninad 2007-10-16
        if len(params) == 2:
            startPoint = params[0]
            endPoint = params[1]
            offset = endPoint - startPoint
            movables = self.graphicsMode.getMovablesForLeftDragging()
            self.assy.translateSpecifiedMovables(offset,
                                                 movables = movables)

            self.o.gl_update()

        self.propMgr.moveFromToButton.setChecked(False)

        #For Rotate about point tool. May be we should do the following
        #only when the graphics mode is Rotate graphics mode? Okay for now
        #feature implemented just before FNANO 08 . clanup -- Ninad 2008-04-20
        self.propMgr.rotateAboutPointButton.setChecked(False)

    def provideParamsForTemporaryMode(self, temporaryModeName):
        """
        NOTE: See selectMolsMode.provideParamsForTemporaryMode
        for detail comment. This needs to be a API method. This is a temporary
        implementation
        @see: LineMode_GM._drawCursorText
        """

        temporaryModeNames = ("LineMode", "RotateAboutPoint")

        if temporaryModeName in temporaryModeNames:
            #This is the number of mouse clicks that the temporary mode accepts
            mouseClickLimit = 2
            return (mouseClickLimit)

    def rotateAboutPointTemporaryCommand(self, isChecked = False):
        """
        @see: self.moveFromToTemporaryMode
        """
        #@TODO: clean this up. This was written just after Rattlesnake rc2
        #for FNANO presentation -- Ninad 2008-04-17

        commandSequencer = self.commandSequencer
        currentCommand = commandSequencer.currentCommand

        if isChecked:
            self.propMgr.rotateStartCoordLineEdit.setEnabled(isChecked)
            msg = "Click inside the 3D workspace to define two points" \
                "of a line. The selection will be rotated about the first point"\
                " in the direction specified by that line"


            self.propMgr.updateMessage(msg)
            if currentCommand.commandName != "RotateAboutPoint":
                commandSequencer.userEnterTemporaryCommand(
                    'RotateAboutPoint')
                return
        else:
            if currentCommand.commandName == "RotateAboutPoint":
                currentCommand.Done(exit_using_done_or_cancel_button = False)
            self.propMgr.rotateStartCoordLineEdit.setEnabled(False)
            self.propMgr.updateMessage()



    def moveFromToTemporaryMode(self, isChecked = False):
        """
        Move the selected entities by the offset vector specified by the
        endpoints of a line. To use this feature, click on 'Move From/To button'
        in the PM and specify the two endpoints from GLPane. The program enters
        a temporary mode while you do that and then uses the data collected
        while in temporary mode (i.e. two endpoints) to move the selection.

        TODO: Note that the endpoints always assume GLPane depth. As of today,
        the temporary mode API knows nothing about the highlighting. Once it
        is implemented,  we can then specify atom centers etc as reference
        points. See comments in LineMode for further details.
        """
        if isChecked:
            self.propMgr.startCoordLineEdit.setEnabled(isChecked)
            msg = "Click inside the 3D workspace to define two endpoints" \
                "of a line. The selection will be moved by the offset "\
                "vector defined by these line endpoints."

            self.propMgr.updateMessage(msg)

            commandSequencer = self.commandSequencer
            currentCommand = commandSequencer.currentCommand

            if currentCommand.commandName != "LineMode":
                commandSequencer.userEnterTemporaryCommand(
                    'LineMode')
                return
        else:
            self.propMgr.startCoordLineEdit.setEnabled(False)
            self.propMgr.updateMessage()

    def rotateThetaPlus(self):
        "Rotate the selected chunk(s) by theta (plus)"

        button = self.propMgr.rotateAroundAxisButtonRow.checkedButton()
        if button:
            rotype = str(button.text())
        else:
            env.history.message(redmsg("Rotate By Specified Angle: Please press the button \
                                   corresponding to the axis of rotation"))
            return
        theta = self.propMgr.rotateThetaSpinBox.value()
        self.rotateTheta( rotype, theta)

    def rotateThetaMinus(self):
        "Rotate the selected chunk(s) by theta (minus)"
        button = self.propMgr.rotateAroundAxisButtonRow.checkedButton()
        if button:
            rotype = str(button.text())
        else:
            env.history.message(redmsg("Rotate By Specified Angle: Please press the button \
                                   corresponding to the axis of rotation"))
            return
        theta = self.propMgr.rotateThetaSpinBox.value() * -1.0
        self.rotateTheta( rotype, theta)

    def rotateTheta(self, rotype, theta):
        """"
        Rotate the selected chunk(s) /jig(s) around the specified axis
        by theta (degrees)
        """

        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return

        if rotype == 'ROTATEX':
            ma = V(1,0,0) # X Axis
        elif rotype == 'ROTATEY':
            ma = V(0,1,0) # Y Axis
        elif rotype == 'ROTATEZ':
            ma = V(0,0,1) # Z Axis
        else:
            print 'modifyMody.rotateTheta: Error.  rotype = ', rotype, ', which is undefined.'
            return

        # wware 20061214: I don't know where the need arose for this factor of 100,
        # but it's necessary to get correct angles.
        #ninad 070322:
        #Will's above comment was for "dy = 100.0 * (pi / 180.0) * theta  # Convert to radians"
        #I agree with this. In fact if I enter angle of  1 degree, it multiplies it by 100!
        #May be it was necessary in Qt3 branch. I am modifying this formula
        #to remove this  multiplication factor of 100 as its giving wrong results
        dy =  (math.pi / 180.0) * theta  # Convert to radians
        qrot = Q(ma,dy) # Quat for rotation delta.

        if self.propMgr.rotateAsUnitCB.isChecked():
            # Rotate the selection as a unit.
            self.assy.rotateSpecifiedMovables(qrot,
                                              movables)
        else:
            for item in movables:
                try:
                    item.rot(qrot)
                except AssertionError:
                    print_compact_traceback("Selected movable doesn't have"\
                                            "rot method?")

        self.o.gl_update()

    def transDeltaPlus(self):
        """
        Add X, Y, and Z to the selected chunk(s) current position
        """
        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return
        offset = self.propMgr.get_move_delta_xyz()
        self.assy.translateSpecifiedMovables(offset,
                                             movables = movables)
        self.o.gl_update()

    def transDeltaMinus(self):
        """
        Subtract X, Y, and Z from the selected chunk(s) current position
        """
        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return

        offset = self.propMgr.get_move_delta_xyz(Plus=False)
        self.assy.translateSpecifiedMovables(offset,
                                             movables = movables)
        self.o.gl_update()

    def moveAbsolute(self):
        """
        Move selected chunk(s), jig(s) to absolute X, Y, and Z by computing
        the bbox center of everything as if they were one big chunk, then move
        everything as a unit.
        """
        movables = self.graphicsMode.getMovablesForLeftDragging()
        if not movables:
            env.history.message(redmsg("No chunks or movable jigs selected."))
            return

        ## Compute bbox for selected chunk(s).

        bbox = BBox()
        for m in movables:
            if hasattr(m, "bbox"): # Fixes bug 1990. Mark 060702.
                bbox.merge(m.bbox)
        pt1 = bbox.center() # pt1 = center point for bbox of selected chunk(s).

        pt2 = self.propMgr.get_move_xyz() # pt2 = X, Y, Z values from PM
        offset = pt2 - pt1 # Compute offset for translating the selection

        self.assy.translateSpecifiedMovables(offset,
                                             movables = movables)

        # Print history message about what happened.
        if len(movables) == 1:
            msg = "[%s] moved to [X: %.2f] [Y: %.2f] [Z: %.2f]" % (movables[0].name, pt2[0], pt2[1], pt2[2])
        else:
            msg = "Selected chunks/jigs moved by offset [X: %.2f] [Y: %.2f] [Z: %.2f]" % (offset[0], offset[1], offset[2])
        env.history.message(msg)
        self.o.gl_update()
        return

    #Command Toolbar related methods to be revised==============================
    def updateCommandToolbar(self, bool_entering = True):#Ninad 20070618
        """
        Update the command toolbar.
        """
        if bool_entering:
            try:
                action = self.w.toolsMoveRotateActionGroup.checkedAction()
            except:
                print_compact_traceback("bug: no move action checked?")
                action = None
        else:
            action = None

        # object that needs its own flyout toolbar. In this case it is just
        #the mode itself.
        obj = self

        self.w.commandToolbar.updateCommandToolbar(action,
                                                   obj,
                                                   entering = bool_entering)

    def getFlyoutActionList(self): #Ninad 20070618
        """ Returns a tuple that contains mode spcific actionlists in the
        added in the flyout toolbar of the mode.
        CommandToolbar._createFlyoutToolBar method calls this
        @return: params: A tuple that contains 3 lists:
        (subControlAreaActionList, commandActionLists, allActionsList)"""

        #'allActionsList' returns all actions in the flyout toolbar
        #including the subcontrolArea actions
        allActionsList = []

        #Action List for  subcontrol Area buttons.
        #In this mode, there is really no subcontrol area.
        #We will treat subcontrol area same as 'command area'
        #(subcontrol area buttons will have an empty list as their command area
        #list). We will set  the Comamnd Area palette background color to the
        #subcontrol area.

        subControlAreaActionList =[]

        self.exitMoveAction = NE1_QWidgetAction(self.w, 
                                                  win = self.w)
        self.exitMoveAction.setText("Exit Move")
        self.exitMoveAction.setWhatsThis("Exits Move Mode")
        self.exitMoveAction.setCheckable(True)
        self.exitMoveAction.setChecked(True)
        self.exitMoveAction.setIcon(
            geticon("ui/actions/Toolbars/Smart/Exit.png"))
        subControlAreaActionList.append(self.exitMoveAction)

        separator = QtGui.QAction(self.w)
        separator.setSeparator(True)
        subControlAreaActionList.append(separator)

        subControlAreaActionList.append(self.w.toolsMoveMoleculeAction)
        subControlAreaActionList.append(self.w.rotateComponentsAction)
        subControlAreaActionList.append(self.w.modifyAlignCommonAxisAction)

        allActionsList.extend(subControlAreaActionList)

        #Empty actionlist for the 'Command Area'
        commandActionLists = []

        #Append empty 'lists' in 'commandActionLists equal to the
        #number of actions in subControlArea
        for i in range(len(subControlAreaActionList)):
            lst = []
            commandActionLists.append(lst)

        params = (subControlAreaActionList, commandActionLists, allActionsList)

        return params