def numberOfBasesChanged(self, numberOfBases): """ Slot for the B{Number of Bases} spinbox. """ duplexRise = self.duplexRiseDoubleSpinBox.value() # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, duplexRise=duplexRise)) + " Angstroms" self.duplexLengthLineEdit.setText(text) return
def numberOfBasesChanged(self, numberOfBases): """ Slot for the B{Number of Bases} spinbox. """ # Update the Duplex Length lineEdit widget. text = str(getDuplexLength(self._conformation, numberOfBases, self._duplexRise)) \ + " Angstroms" self.duplexLengthLineEdit.setText(text) return
def _get_resizeEnd_final_position(self, ladderEndAxisAtom, numberOfBases, duplexRise): final_position = None if self.grabbedHandle: final_position = self.grabbedHandle.currentPosition else: other_axisEndAtom = self.struct.getOtherAxisEndAtom(ladderEndAxisAtom) axis_vector = ladderEndAxisAtom.posn() - other_axisEndAtom.posn() segment_length_to_add = getDuplexLength("B-DNA", numberOfBases, duplexRise=duplexRise) final_position = ladderEndAxisAtom.posn() + norm(axis_vector) * segment_length_to_add return final_position
def _get_resizeEnd_final_position(self, ladderEndAxisAtom, numberOfBases, duplexRise): final_position = None if self.grabbedHandle: final_position = self.grabbedHandle.currentPosition else: other_axisEndAtom = self.struct.getOtherAxisEndAtom( ladderEndAxisAtom) axis_vector = ladderEndAxisAtom.posn() - other_axisEndAtom.posn() segment_length_to_add = getDuplexLength('B-DNA', numberOfBases, duplexRise=duplexRise) final_position = ladderEndAxisAtom.posn( ) + norm(axis_vector) * segment_length_to_add return final_position
def __init__(self, command): """ Constructor for the DNA Duplex property manager. """ self.endPoint1 = None self.endPoint2 = None self._conformation = "B-DNA" self._numberOfBases = 0 self._basesPerTurn = getDuplexBasesPerTurn(self._conformation) self._duplexRise = getDuplexRise(self._conformation) self._duplexLength = getDuplexLength(self._conformation, self._numberOfBases) _superclass.__init__(self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON)
def _get_resizeEnd_final_position(self, resizeEndAxisAtom, numberOfBases, duplexRise): final_position = None if self.grabbedHandle: final_position = self.grabbedHandle.currentPosition else: dnaSegment = resizeEndAxisAtom.molecule.parent_node_of_class(self.assy.DnaSegment) other_axisEndAtom = dnaSegment.getOtherAxisEndAtom(resizeEndAxisAtom) axis_vector = resizeEndAxisAtom.posn() - other_axisEndAtom.posn() segment_length_to_add = getDuplexLength('B-DNA', numberOfBases, duplexRise = duplexRise) final_position = resizeEndAxisAtom.posn() + norm(axis_vector)*segment_length_to_add return final_position
def _get_resizeEnd_final_position(self, ladderEndAxisAtom, numberOfBases, duplexRise): """ Returns the final position of the resize end. Note that we can not use the grabbedHandle's currentPosition as the final position because resize handle is placed at an 'average' position. So we must compute the correct vector using the 'self.currentStruct' """ final_position = None other_axisEndAtom = self.struct.getOtherAxisEndAtom(ladderEndAxisAtom) if other_axisEndAtom is None: return None axis_vector = ladderEndAxisAtom.posn() - other_axisEndAtom.posn() segment_length_to_add = getDuplexLength('B-DNA', numberOfBases, duplexRise = duplexRise) signFactor = + 1 ##if self.grabbedHandle is not None: ##vec = self.grabbedHandle.currentPosition - \ ## self.grabbedHandle.fixedEndOfStructure ##if dot(vec, axis_vector) < 0: ##signFactor = -1 ##else: ##signFactor = +1 axis_vector = axis_vector * signFactor final_position = ladderEndAxisAtom.posn() + \ norm(axis_vector)*segment_length_to_add return final_position
def __init__( self, command ): """ Constructor for the DNA Duplex property manager. """ self.endPoint1 = None self.endPoint2 = None self._conformation = "B-DNA" self._numberOfBases = 0 self._basesPerTurn = getDuplexBasesPerTurn(self._conformation) self._duplexRise = getDuplexRise(self._conformation) self._duplexLength = getDuplexLength(self._conformation, self._numberOfBases) _superclass.__init__( self, command) self.showTopRowButtons( PM_DONE_BUTTON | \ PM_CANCEL_BUTTON | \ PM_WHATS_THIS_BUTTON)
def _update_resizeHandle_stopper_length(self): """ Update the limiting length at which the resize handle being dragged should 'stop' without proceeding further in the drag direction. The segment resize handle stops when you are dragging it towards the other resizeend and the distance between the two ends reaches two duplexes. The self._resizeHandle_stopper_length computed in this method is used as a lower limit of the 'range' option provided in declaration of resize handle objects (see class definition for the details) @see: self.updateHandlePositions() """ total_length = vlen(self.handlePoint1 - self.handlePoint2) duplexRise = self.struct.getDuplexRise() # Length of the duplex for 2 base pairs two_bases_length = getDuplexLength("B-DNA", 2, duplexRise=duplexRise) self._resizeHandle_stopper_length = -total_length + two_bases_length
def _update_resizeHandle_stopper_length(self): """ Update the limiting length at which the resize handle being dragged should 'stop' without proceeding further in the drag direction. The segment resize handle stops when you are dragging it towards the other resizeend and the distance between the two ends reaches two duplexes. The self._resizeHandle_stopper_length computed in this method is used as a lower limit of the 'range' option provided in declaration of resize handle objects (see class definition for the details) @see: self.updateHandlePositions() """ total_length = vlen(self.handlePoint1 - self.handlePoint2) duplexRise = self.struct.getDuplexRise() #Length of the duplex for 2 base pairs two_bases_length = getDuplexLength('B-DNA', 2, duplexRise=duplexRise) self._resizeHandle_stopper_length = -total_length + two_bases_length
def _get_resizeEnd_final_position(self, ladderEndAxisAtom, numberOfBases, duplexRise): """ Returns the final position of the resize end. Note that we can not use the grabbedHandle's currentPosition as the final position because resize handle is placed at an 'average' position. So we must compute the correct vector using the 'self.currentStruct' """ final_position = None other_axisEndAtom = self.struct.getOtherAxisEndAtom(ladderEndAxisAtom) if other_axisEndAtom is None: return None axis_vector = ladderEndAxisAtom.posn() - other_axisEndAtom.posn() segment_length_to_add = getDuplexLength('B-DNA', numberOfBases, duplexRise=duplexRise) signFactor = +1 ##if self.grabbedHandle is not None: ##vec = self.grabbedHandle.currentPosition - \ ## self.grabbedHandle.fixedEndOfStructure ##if dot(vec, axis_vector) < 0: ##signFactor = -1 ##else: ##signFactor = +1 axis_vector = axis_vector * signFactor final_position = ladderEndAxisAtom.posn() + \ norm(axis_vector)*segment_length_to_add return final_position
def _createSegment(self): """ Creates and returns the structure (in this case a L{Group} object that contains the DNA strand and axis chunks. @return : group containing that contains the DNA strand and axis chunks. @rtype: L{Group} @note: This needs to return a DNA object once that model is implemented """ params = self._gatherParameters() # No error checking in build_struct, do all your error # checking in gather_parameters numberOfBases, \ dnaForm, \ dnaModel, \ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2 = params if numberOfBases < 2: #Don't create a duplex with only one or 0 bases! #Reset a few variables. This should be done by calling a separate #method on command (there is similar code in self.createStructures) #as well. self.mouseClickPoints = [] self.graphicsMode.resetVariables() msg = redmsg("Cannot preview/insert a DNA duplex with less than 2 base pairs.") self.propMgr.updateMessage(msg) self.dna = None # Fixes bug 2530. Mark 2007-09-02 return None else: msg = "Specify two points in the 3D Graphics Area to define the "\ "endpoints of the DNA duplex" self.propMgr.updateMessage(msg) #If user enters the number of basepairs and hits preview i.e. endPoint1 #and endPoint2 are not entered by the user and thus have default value #of V(0, 0, 0), then enter the endPoint1 as V(0, 0, 0) and compute #endPoint2 using the duplex length. #Do not use '==' equality check on vectors! its a bug. Use same_vals # or Veq instead. if Veq(endPoint1 , endPoint2) and Veq(endPoint1, V(0, 0, 0)): endPoint2 = endPoint1 + \ self.win.glpane.right * \ getDuplexLength('B-DNA', numberOfBases) if dnaForm == 'B-DNA': if dnaModel == 'PAM3': dna = B_Dna_PAM3() elif dnaModel == 'PAM5': dna = B_Dna_PAM5() else: print "bug: unknown dnaModel type: ", dnaModel else: raise PluginBug("Unsupported DNA Form: " + dnaForm) self.dna = dna # needed for done msg # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name # Create the model tree group node. # Make sure that the 'topnode' of this part is a Group (under which the # DNa group will be placed), if the topnode is not a group, make it a # a 'Group' (applicable to Clipboard parts).See part.py # --Part.ensure_toplevel_group method. This is an important line # and it fixes bug 2585 self.win.assy.part.ensure_toplevel_group() if self._parentDnaGroup is None: print_compact_stack("bug: Parent DnaGroup in DnaDuplex_EditCommand"\ "is None. This means the previous command "\ "was not 'BuildDna_EditCommand' Ignoring for now") if self._fallbackDnaGroup is None: self._createFallbackDnaGroup() dnaGroup = self._fallbackDnaGroup else: dnaGroup = self._parentDnaGroup dnaSegment = DnaSegment(self.name, self.win.assy, dnaGroup, editCommand = self ) try: # Make the DNA duplex. <dnaGroup> will contain three chunks: # - Strand1 # - Strand2 # - Axis dna.make(dnaSegment, numberOfBases, basesPerTurn, duplexRise, endPoint1, endPoint2) #set some properties such as duplexRise and number of bases per turn #This information will be stored on the DnaSegment object so that #it can be retrieved while editing this object. #This works with or without dna_updater. Now the question is #should these props be assigned to the DnaSegment in #dnaDuplex.make() itself ? This needs to be answered while modifying #make() method to fit in the dna data model. --Ninad 2008-03-05 #WARNING 2008-03-05: Since self._modifyStructure calls #self._createStructure() (which in turn calls self._createSegment() #in this case) If in the near future, we actually permit modifying a #structure (such as dna) without actually recreating the whole #structre, then the following properties must be set in #self._modifyStructure as well. Needs more thought. props = (duplexRise, basesPerTurn) dnaSegment.setProps(props) return dnaSegment except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 dnaSegment.kill_with_contents() raise PluginBug("Internal error while trying to create DNA duplex.")
def getCursorText(self): """ This is used as a callback method in DnaLine mode @see: DnaLineMode.setParams, DnaLineMode_GM.Draw """ # @TODO: Refactor this. Similar code exists in # DnaStrand_EditCommand.getCursorText() -- Ninad 2008-04-12 if self.grabbedHandle is None: return currentPosition = self.grabbedHandle.currentPosition fixedEndOfStructure = self.grabbedHandle.fixedEndOfStructure duplexRise = self.struct.getDuplexRise() ############# raw_numberOfBasePairsToAddOrRemove = self._determine_numberOfBasePairs_to_change() # Following fixes bugs like 2904 and 2906 # Note that we are using numberOfBasePairsToAddOrRemove in self._modifyStructure() # if self._determine_numberOfBasePairs_to_change() returns the number of basepairs # to add, it returns 1 more than the actual number of basepairs. Because # while creating the dna, it removes the first base pair of the newly created # dna. So, for cursor text and for PM spinbox, we should make adjustments to the # raw_numberOfBasePairsToAddOrRemove so that it reflects the correct value # in the spinbox and in the PM if raw_numberOfBasePairsToAddOrRemove > 1: numberOfBasePairsToAddOrRemove = raw_numberOfBasePairsToAddOrRemove - 1 else: numberOfBasePairsToAddOrRemove = raw_numberOfBasePairsToAddOrRemove current_numberOfBasePairs = self.struct.getNumberOfBasePairs() numberOfBasePairs = current_numberOfBasePairs + numberOfBasePairsToAddOrRemove if hasattr(self.propMgr, "numberOfBasePairsSpinBox"): # @TODO: The following updates the PM as the cursor moves. # Need to rename this method so that you that it also does more things # than just to return a textString -- Ninad 2007-12-20 self.propMgr.numberOfBasePairsSpinBox.setValue(numberOfBasePairs) text = "" textColor = env.prefs[cursorTextColor_prefs_key] # Mark 2008-08-28 if not env.prefs[dnaSegmentEditCommand_showCursorTextCheckBox_prefs_key]: return text, textColor # @@TODO: refactor. # this duplex length canculation fixes bug 2906 duplexLength = getDuplexLength("B-DNA", numberOfBasePairs, duplexRise=duplexRise) # Cursor text strings -- duplexLengthString = str(round(duplexLength, 3)) numberOfBasePairsString = self._getCursorText_numberOfBasePairs(numberOfBasePairs) duplexLengthString = self._getCursorText_length(duplexLength) changedBasePairsString = self._getCursorText_changedBasePairs(numberOfBasePairs) # Add commas (to be refactored) commaString = ", " text = numberOfBasePairsString if text and changedBasePairsString: text += " " # commaString not needed here. Mark 2008-07-03 text += changedBasePairsString if text and duplexLengthString: text += commaString text += duplexLengthString return (text, textColor)
def _createStructure(self): """ Creates and returns the structure (in this case a L{Group} object that contains the DNA strand and axis chunks. @return : group containing that contains the DNA strand and axis chunks. @rtype: L{Group} @note: This needs to return a DNA object once that model is implemented """ params = self._gatherParameters() # No error checking in build_struct, do all your error # checking in gather_parameters number_of_basePairs_from_struct, numberOfBases, dnaForm, dnaModel, basesPerTurn, duplexRise, endPoint1, endPoint2, color_junk = ( params ) # Note: color_junk is not used. Ideally it should do struct.setColor(color) # but the color combobox in the PM directly sets the color of the # structure to the specified one when the current index in the combobx # changes # If user enters the number of basepairs and hits preview i.e. endPoint1 # and endPoint2 are not entered by the user and thus have default value # of V(0, 0, 0), then enter the endPoint1 as V(0, 0, 0) and compute # endPoint2 using the duplex length. # Do not use '==' equality check on vectors! its a bug. Use same_vals # or Veq instead. if Veq(endPoint1, endPoint2) and Veq(endPoint1, V(0, 0, 0)): endPoint2 = endPoint1 + self.win.glpane.right * getDuplexLength("B-DNA", numberOfBases) if numberOfBases < 1: msg = redmsg("Cannot preview/insert a DNA duplex with 0 bases.") self.propMgr.updateMessage(msg) self.dna = None # Fixes bug 2530. Mark 2007-09-02 return None if dnaForm == "B-DNA": if dnaModel == "PAM3": dna = B_Dna_PAM3_Generator() elif dnaModel == "PAM5": dna = B_Dna_PAM5_Generator() else: print "bug: unknown dnaModel type: ", dnaModel else: raise PluginBug("Unsupported DNA Form: " + dnaForm) self.dna = dna # needed for done msg # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name # Create the model tree group node. # Make sure that the 'topnode' of this part is a Group (under which the # DNa group will be placed), if the topnode is not a group, make it a # a 'Group' (applicable to Clipboard parts).See part.py # --Part.ensure_toplevel_group method. This is an important line # and it fixes bug 2585 self.win.assy.part.ensure_toplevel_group() dnaSegment = DnaSegment(self.name, self.win.assy, self.win.assy.part.topnode, editCommand=self) try: # Make the DNA duplex. <dnaGroup> will contain three chunks: # - Strand1 # - Strand2 # - Axis dna.make(dnaSegment, numberOfBases, basesPerTurn, duplexRise, endPoint1, endPoint2) # set some properties such as duplexRise and number of bases per turn # This information will be stored on the DnaSegment object so that # it can be retrieved while editing this object. # This works with or without dna_updater. Now the question is # should these props be assigned to the DnaSegment in # dnaDuplex.make() itself ? This needs to be answered while modifying # make() method to fit in the dna data model. --Ninad 2008-03-05 # WARNING 2008-03-05: Since self._modifyStructure calls # self._createStructure() # If in the near future, we actually permit modifying a # structure (such as dna) without actually recreating the whole # structre, then the following properties must be set in # self._modifyStructure as well. Needs more thought. props = (duplexRise, basesPerTurn) dnaSegment.setProps(props) return dnaSegment except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 dnaSegment.kill() raise PluginBug("Internal error while trying to create DNA duplex.")
def getCursorText(self): """ This is used as a callback method in DnaLine mode @see: DnaLineMode.setParams, DnaLineMode_GM.Draw """ #@TODO: Refactor this. Similar code exists in #DnaStrand_EditCommand.getCursorText() -- Ninad 2008-04-12 if self.grabbedHandle is None: return currentPosition = self.grabbedHandle.currentPosition fixedEndOfStructure = self.grabbedHandle.fixedEndOfStructure duplexRise = self.struct.getDuplexRise() ############# raw_numberOfBasePairsToAddOrRemove = self._determine_numberOfBasePairs_to_change( ) #Following fixes bugs like 2904 and 2906 #Note that we are using numberOfBasePairsToAddOrRemove in self._modifyStructure() #if self._determine_numberOfBasePairs_to_change() returns the number of basepairs #to add, it returns 1 more than the actual number of basepairs. Because #while creating the dna, it removes the first base pair of the newly created #dna. So, for cursor text and for PM spinbox, we should make adjustments to the #raw_numberOfBasePairsToAddOrRemove so that it reflects the correct value #in the spinbox and in the PM if raw_numberOfBasePairsToAddOrRemove > 1: numberOfBasePairsToAddOrRemove = raw_numberOfBasePairsToAddOrRemove - 1 else: numberOfBasePairsToAddOrRemove = raw_numberOfBasePairsToAddOrRemove ############## current_numberOfBasePairs = self.struct.getNumberOfBasePairs() numberOfBasePairs = current_numberOfBasePairs + numberOfBasePairsToAddOrRemove #@TODO: The following updates the PM as the cursor moves. #Need to rename this method so that you that it also does more things #than just to return a textString -- Ninad 2007-12-20 self.propMgr.numberOfBasePairsSpinBox.setValue(numberOfBasePairs) #Note: for Rattlesnake rc2, the text color is green when bases are added #, red when subtracted black when no change. But this implementation is #changed based on Mark's user experience. The text is now always shown #in black color. -- Ninad 2008-04-17 textColor = black text = "" if not env.prefs[ dnaSegmentEditCommand_showCursorTextCheckBox_prefs_key]: return '', black #@@TODO: refactor. #this duplex length canculation fixes bug 2906 duplexLength = getDuplexLength('B-DNA', numberOfBasePairs, duplexRise=duplexRise) #Cursor text strings -- duplexLengthString = str(round(duplexLength, 3)) numberOfBasePairsString = self._getCursorText_numberOfBasePairs( numberOfBasePairs) duplexLengthString = self._getCursorText_length(duplexLength) changedBasePairsString = self._getCursorText_changedBasePairs( numberOfBasePairs) #Add commas (to be refactored) commaString = ", " text = numberOfBasePairsString if text and changedBasePairsString: text += " " # commaString not needed here. Mark 2008-07-03 text += changedBasePairsString if text and duplexLengthString: text += commaString text += duplexLengthString return (text, textColor)
def _createStructure(self): """ Creates and returns the structure (in this case a L{Group} object that contains the DNA strand and axis chunks. @return : group containing that contains the DNA strand and axis chunks. @rtype: L{Group} @note: This needs to return a DNA object once that model is implemented """ params = self._gatherParameters() # No error checking in build_struct, do all your error # checking in gather_parameters number_of_basePairs_from_struct,\ numberOfBases, \ dnaForm, \ dnaModel, \ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2, \ color_junk = params #Note: color_junk is not used. Ideally it should do struct.setColor(color) #but the color combobox in the PM directly sets the color of the #structure to the specified one when the current index in the combobx #changes #If user enters the number of basepairs and hits preview i.e. endPoint1 #and endPoint2 are not entered by the user and thus have default value #of V(0, 0, 0), then enter the endPoint1 as V(0, 0, 0) and compute #endPoint2 using the duplex length. #Do not use '==' equality check on vectors! its a bug. Use same_vals # or Veq instead. if Veq(endPoint1, endPoint2) and Veq(endPoint1, V(0, 0, 0)): endPoint2 = endPoint1 + \ self.win.glpane.right*getDuplexLength('B-DNA', numberOfBases) if numberOfBases < 1: msg = redmsg("Cannot preview/insert a DNA duplex with 0 bases.") self.propMgr.updateMessage(msg) self.dna = None # Fixes bug 2530. Mark 2007-09-02 return None if dnaForm == 'B-DNA': if dnaModel == 'PAM3': dna = B_Dna_PAM3() elif dnaModel == 'PAM5': dna = B_Dna_PAM5() else: print "bug: unknown dnaModel type: ", dnaModel else: raise PluginBug("Unsupported DNA Form: " + dnaForm) self.dna = dna # needed for done msg # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name # Create the model tree group node. # Make sure that the 'topnode' of this part is a Group (under which the # DNa group will be placed), if the topnode is not a group, make it a # a 'Group' (applicable to Clipboard parts).See part.py # --Part.ensure_toplevel_group method. This is an important line # and it fixes bug 2585 self.win.assy.part.ensure_toplevel_group() dnaSegment = DnaSegment(self.name, self.win.assy, self.win.assy.part.topnode, editCommand=self) try: # Make the DNA duplex. <dnaGroup> will contain three chunks: # - Strand1 # - Strand2 # - Axis dna.make(dnaSegment, numberOfBases, basesPerTurn, duplexRise, endPoint1, endPoint2) #set some properties such as duplexRise and number of bases per turn #This information will be stored on the DnaSegment object so that #it can be retrieved while editing this object. #This works with or without dna_updater. Now the question is #should these props be assigned to the DnaSegment in #dnaDuplex.make() itself ? This needs to be answered while modifying #make() method to fit in the dna data model. --Ninad 2008-03-05 #WARNING 2008-03-05: Since self._modifyStructure calls #self._createStructure() #If in the near future, we actually permit modifying a #structure (such as dna) without actually recreating the whole #structre, then the following properties must be set in #self._modifyStructure as well. Needs more thought. props = (duplexRise, basesPerTurn) dnaSegment.setProps(props) return dnaSegment except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 dnaSegment.kill() raise PluginBug( "Internal error while trying to create DNA duplex.")