Package Pmv :: Module setangleCommands
[hide private]
[frames] | no frames]

Source Code for Module Pmv.setangleCommands

   1  ############################################################################# 
   2  # 
   3  # Author: Ruth HUEY, Michel F. SANNER 
   4  # 
   5  # Copyright: M. Sanner TSRI 2000 
   6  # 
   7  ############################################################################# 
   8   
   9  # 
  10  # $Header: /opt/cvs/python/packages/share1.5/Pmv/setangleCommands.py,v 1.36 2007/05/15 17:39:37 vareille Exp $  
  11  # 
  12  # $Id: setangleCommands.py,v 1.36 2007/05/15 17:39:37 vareille Exp $  
  13  # 
  14  # 
  15   
  16  from ViewerFramework.VFCommand import CommandGUI 
  17  from ViewerFramework.VF import EditAtomsEvent  
  18  from mglutil.gui.InputForm.Tk.gui import InputFormDescr 
  19   
  20  from mglutil.gui.BasicWidgets.Tk.Dial import Dial 
  21  from mglutil.gui.BasicWidgets.Tk.customizedWidgets import ExtendedSliderWidget, ListChooser 
  22   
  23  from DejaVu import viewerConst 
  24  from DejaVu.Geom import Geom 
  25  #from DejaVu.Labels import Labels 
  26  from DejaVu.Spheres import Spheres 
  27  from DejaVu.IndexedPolylines import IndexedPolylines 
  28  from opengltk.OpenGL import GL 
  29  from Pmv.mvCommand import MVCommand, MVAtomICOM 
  30  from Pmv.measureCommands import MeasureDistance, MeasureTorsion, MeasureTorsionGUICommand 
  31  from MolKit.protein import Protein 
  32  from MolKit.molecule import Atom, AtomSet 
  33  import string, types 
  34  import Tkinter, Numeric 
  35  import math 
  36   
  37  from mglutil.math.rotax import rotax 
  38   
  39  from DejaVu.glfLabels import GlfLabels 
  40   
  41   
42 -def vvmult(a,b):
43 """ 44 Compute a vector product for 3D vectors 45 """ 46 import Numeric 47 res = Numeric.zeros(3, 'f') 48 res[0] = a[1]*b[2] - a[2]*b[1] 49 res[1] = a[2]*b[0] - a[0]*b[2] 50 res[2] = a[0]*b[1] - a[1]*b[0] 51 return res
52 53
54 -def torsionAngle(x1, x2, x3, x4):
55 """ 56 Compute the torsion angle between x1,x2,x3,x4. 57 All coordinates are cartesian, result is in degrees. 58 Raises a ValueError if angle is not defined. 59 """ 60 from math import sqrt, acos 61 import Numeric 62 63 tang=0.0 64 assert x1.shape == (3,) 65 assert x2.shape == (3,) 66 assert x3.shape == (3,) 67 assert x4.shape == (3,) 68 69 a = x1-x2 70 b = x3-x2 71 c = vvmult(a,b) 72 73 a = x2-x3 74 b = x4-x3 75 d = vvmult(a,b) 76 77 dd=sqrt(Numeric.add.reduce(c*c)) 78 de=sqrt(Numeric.add.reduce(d*d)) 79 80 if dd<0.001 or de<0.001: 81 raise ValueError ( 'Torsion angle undefined, degenerate points') 82 83 vv = Numeric.dot(c,d) / (dd*de); 84 if vv<1.0: tang=vv 85 else: tang= 1.0 86 if tang<-1.0: tang=-1.0 87 tang = acos(tang) 88 tang = tang*57.296 89 90 b = vvmult(c,d) 91 if Numeric.dot(a,b) > 0.0: tang = -tang 92 return tang
93 94 95
96 -class SetRelativeTorsion(MeasureTorsion):
97 """ 98 Transform the coords of atoms in subTree defined by atom1-atom2 99 Set the coords of these atoms to the new values and return new coords 100 """ 101 102
103 - def __call__(self, atom1, atom2, angle, mov_atoms=None, returnVal=0,**kw):
104 """movedAtomsCoords<-setRelativeTorsion(atom1, atom2, angle, returnVal)""" 105 ats = self.vf.expandNodes(atom1) 106 if not len(ats): return 'ERROR' 107 atom1 = ats[0] 108 ats = self.vf.expandNodes(atom2) 109 if not len(ats): return 'ERROR' 110 atom2 = ats[0] 111 assert atom1.top == atom2.top 112 return apply(self.doitWrapper,(atom1,atom2,angle,mov_atoms,returnVal),kw)
113 114
115 - def doit(self, atom1, atom2, angle, mov_atoms, returnVal=0):
116 mol = atom1.top 117 if mov_atoms is None: 118 mov_atoms = mol.subTree(atom1, atom2, mol.allAtoms) 119 assert len(mov_atoms) 120 mov_coords = Numeric.array(mov_atoms.coords) 121 lenCoords = len(mov_coords) 122 x = Numeric.array(atom1.coords) 123 y = Numeric.array(atom2.coords) 124 rot = (angle * 3.14159/180.)%(2 * Numeric.pi) 125 matrix = rotax(x, y, rot) 126 _ones = Numeric.ones(lenCoords, 'f') 127 _ones.shape = (lenCoords,1) 128 mov_coords = Numeric.concatenate((mov_coords, _ones),1) 129 newcoords = Numeric.matrixmultiply(mov_coords, matrix) 130 nc = newcoords[:,:3].astype('f') 131 for i in range(lenCoords): 132 at = mov_atoms[i] 133 at._coords[at.conformation] = nc[i].tolist() 134 #have to return nc for setTorsionGC 135 if returnVal: 136 return nc
137 138 139
140 -class SetTranslation(MeasureDistance):
141 """ 142 Transform the coords by array 143 Set the coords of these atoms to the new values and return new coords 144 """ 145 146
147 - def __call__(self, ats, trans, **kw):
148 """newCoords<-setTranslation(ats,trans)""" 149 ats = self.vf.expandNodes(ats) 150 if not len(ats): return 'ERROR' 151 allAtoms = ats.findType(Atom) 152 #check that trans is tuple with length 3 153 assert len(trans)==3 154 return apply(self.doitWrapper, (allAtoms, trans), kw)
155 156
157 - def doit(self, ats, trans):
158 for at in ats: 159 at._coords[at.conformation] = (at.coords[0]+trans[0], 160 at.coords[1]+trans[1], at.coords[2]+trans[2])
161 162 163
164 -class SetQuaternion(MeasureDistance):
165 """ 166 Transform the coords by quaternion 167 Set the coords of these atoms to the new values and return new coords 168 """ 169 170
171 - def __call__(self, ats, quat, origin= (0., 0., 0.), trans=(0.,0.,0.), **kw):
172 """newCoords<-setTranslation(ats,quat, trans) 173 quat in form (x,y,z,w) 174 origin is (x,y,z) default is (0., 0., 0.) 175 trans is (x,y,z) default is (0., 0., 0.) 176 doesnot assume quat is already normalized 177 """ 178 179 ats = self.vf.expandNodes(ats) 180 if not len(ats): return 'ERROR' 181 allAtoms = ats.findType(Atom) 182 #check that trans is tuple with length 3 183 assert len(quat)==4 184 return apply(self.doitWrapper, (allAtoms, quat, origin, trans), kw)
185 186
187 - def hypotenuse(self, x,y,z):
188 return math.sqrt(x*x + y*y + z*z)
189 190
191 - def mkUnitQuat(self, quat):
192 #from qmultiply.cc 193 x = quat[0] 194 y = quat[1] 195 z = quat[2] 196 w = quat[3] 197 #print 'x,y,z,w=',x,y,z,w 198 inv_nmag = 1./self.hypotenuse(x,y,z) 199 #print 'inv_nmag=', inv_nmag 200 x = x*inv_nmag 201 y = y*inv_nmag 202 z = z*inv_nmag 203 #WHAT IS THIS??? 204 hqang = 0.5 * w 205 s = math.sin(hqang) 206 w = math.cos(hqang) 207 x = s*x 208 y = s*y 209 z = s*z 210 return x,y,z,w
211 212
213 - def doit(self, ats, quat, origin, trans):
214 x,y,z,w = self.mkUnitQuat(quat) 215 216 tx = x+x 217 ty = y+y 218 tz = z+z 219 220 twx = w*tx 221 omtxx = 1. - x*tx 222 txy = y*tx 223 txz = z*tx 224 225 226 twy = w*ty 227 tyy = y*ty 228 tyz = z*ty 229 230 twz = w*tz 231 tzz = z*tz 232 233 r11 = 1. - tyy - tzz 234 r12 = txy + twz 235 r13 = txz - twy 236 r21 = txy - twz 237 r22 = omtxx - tzz 238 r23 = tyz + twx 239 r31 = txz + twy 240 r32 = tyz - twx 241 r33 = omtxx - tyy 242 243 newcoords = [] 244 transx = trans[0] 245 transy = trans[1] 246 transz = trans[2] 247 originx = origin[0] 248 originy = origin[1] 249 originz = origin[2] 250 for i in range(len(ats)): 251 coords = ats[i].coords 252 coordx = coords[0] - originx 253 coordy = coords[1] - originy 254 coordz = coords[2] - originz 255 #NB: it seems these would also set Translation 'T' 256 tmpx = coordx*r11 + coordy*r21 + coordz*r31 + transx 257 tmpy = coordx*r12 + coordy*r22 + coordz*r32 + transy 258 tmpz = coordx*r13 + coordy*r23 + coordz*r33 + transz 259 newentry = (tmpx, tmpy, tmpz) 260 newcoords.append(newentry) 261 at = ats[i] 262 at._coords[at.conformation] = newentry
263 264 #return newcoords 265 266 267
268 -class SetTorsion(MeasureTorsion):
269 """ 270 Transform the coords of atoms in subTree defined by atom1-atom2 271 by angle less initial torsion defined by atom0, atom1, atom2, atom3 272 Set the coords of these atoms to the new values and return new coords 273 """ 274 275
276 - def __call__(self, atom0, atom1, atom2, atom3, angle, returnVal=0, **kw):
277 """movedAtomsCoords<-setTorsion(atom0, atom1, atom2, atom3, 278 angle,returnVal)""" 279 ats = self.vf.expandNodes(atom0) 280 if not len(ats): return 'ERROR' 281 atom0 = ats[0] 282 ats = self.vf.expandNodes(atom1) 283 if not len(ats): return 'ERROR' 284 atom1 = ats[0] 285 ats = self.vf.expandNodes(atom2) 286 if not len(ats): return 'ERROR' 287 atom2 = ats[0] 288 ats = self.vf.expandNodes(atom3) 289 if not len(ats): return 'ERROR' 290 atom3 = ats[0] 291 assert atom0.top == atom1.top == atom2.top == atom3.top 292 #check that angle is between -360 and +360 293 #why? 294 #assert angle >= -360 and angle <= 360 295 return apply(self.doitWrapper, (atom0, atom1, atom2, atom3, angle,returnVal), kw)
296 297
298 - def doit(self, atom0, atom1, atom2, atom3, angle, returnVal):
299 init_angle=self.vf.measureTorsion.doit(atom0, atom1, atom2, atom3) 300 angle = angle - init_angle 301 return self.vf.setRelativeTorsion.doit(atom1, atom2, angle, None, 302 returnVal=returnVal)
303 304 305
306 -class SetTorsionGUICommand(MeasureTorsionGUICommand):
307 308
309 - def guiCallback(self):
310 self.vf.setICOM(self, topCommand=0) 311 if not hasattr(self, 'form'): 312 self.buildForm() 313 else: 314 self.form.deiconify()
315 316
317 - def onAddCmdToViewer(self):
318 if not hasattr(self.vf, 'GUI'): 319 return 320 self.undoNow = 0 321 from DejaVu.bitPatterns import pat3 322 from DejaVu.IndexedPolygons import IndexedPolygons 323 if not self.vf.commands.has_key('setICOM'): 324 self.vf.loadCommand('interactiveCommands', 'setICOM', 'Pmv', 325 topCommand=0) 326 if not self.vf.commands.has_key('measureTorsion'): 327 self.vf.loadCommand('measureCommands', 'measureTorsion', 'Pmv', 328 topCommand=0) 329 330 self.masterGeom = Geom('setTorsionGeom',shape=(0,0), 331 pickable=0, protected=True) 332 self.masterGeom.isScalable = 0 333 self.vf.GUI.VIEWER.AddObject(self.masterGeom, 334 parent=self.vf.GUI.miscGeom) 335 self.lines = IndexedPolygons('settorsionLine', materials = ((0,1,1),), 336 inheritMaterial=0, 337 stipplePolygons=1, protected=True,) 338 if self.vf.userpref['sharpColorBoundariesForMsms']['value'] == 'blur': 339 self.lines.Set(inheritSharpColorBoundaries=False, sharpColorBoundaries=False,) 340 self.lines.polygonstipple.Set(pattern=pat3, tagModified=False) 341 #self.lines.RenderMode(GL.GL_FILL, face=GL.GL_BACK) 342 self.lines.Set(backPolyMode=GL.GL_FILL) 343 self.labels = GlfLabels(name='settorsionLabel', shape=(0,3), 344 inheritMaterial=0, 345 materials = ((0,1,1),)) 346 self.spheres = Spheres(name='settorsionSpheres', shape=(0,3), 347 radii=0.2, quality=15, 348 inheritMaterial=0, 349 materials = ((0.,1.,1.),), protected=True) 350 for item in [self.lines, self.labels, self.spheres]: 351 self.vf.GUI.VIEWER.AddObject(item, parent=self.masterGeom) 352 self.snakeLength = 1 353 self.oldValue = None 354 self.torsionType = Tkinter.StringVar() 355 self.torsionType.set('1') 356 self.newAngList = Tkinter.StringVar() 357 self.TAHdata = None 358 self.molecule = None 359 #self.bondString = Tkinter.StringVar() 360 self.callbackDict = {} 361 self.callbackDict['measureDistanceGC'] = 'update' 362 self.callbackDict['measureAngleGC'] = 'update' 363 self.callbackDict['measureTorsionGC'] = 'update'
364 365
366 - def onRemoveObjectFromViewer(self, mol):
367 lenAts = len(self.atomList) 368 #if cmd has no atoms on its list, nothing to do 369 if not lenAts: 370 return 371 #remove any atoms which are being deleted from viewer 372 self.atomList = AtomSet(self.atomList) - mol.allAtoms 373 #if some have been removed, do an update 374 if lenAts!=len(self.atomList): 375 self.update() 376 self.extslider.set(0)
377 378 379
380 - def __call__(self, atoms, angle=None,**kw):
381 """torsion/None<-setTorsionGC(atoms, angle=None) 382 the torsion is returned when the number of atoms is a multiple of 4""" 383 ats = self.vf.expandNodes(atoms) 384 if not len(ats): return 'ERROR' 385 return apply(self.doitWrapper, (ats, angle,), kw)
386 387
388 - def doit(self, ats, angle):
389 for at in ats: 390 lenAts = len(self.atomList) 391 if lenAts and lenAts%4!=0 and at==self.atomList[-1]: 392 continue 393 if len(self.atomList)==0: 394 self.molecule = at.top 395 if at.top == self.molecule: 396 self.atomList.append(at) 397 else: 398 #all atoms in torsion must be in same molecule ...(?) 399 s = at.full_name()+ " not in " + self.molecule.full_name() 400 self.warningMsg(s) 401 return 'ERROR' 402 if len(self.atomList)>4*self.snakeLength: 403 self.atomList = self.atomList[4:] 404 self.update() 405 if len(self.atomList)==4: 406 mol = self.atomList[0].top 407 at0,at1,at2,at3 = self.atomList 408 self.mov_atoms = mol.subTree(at1, at2, mol.allAtoms) 409 self.oldValue = self.vf.measureTorsion.doit(at0,at1,at2,at3) 410 self.origValue = self.oldValue 411 self.origCoords = self.mov_atoms.coords 412 if hasattr(self, 'extslider'): 413 self.extslider.set(self.oldValue, update=0) 414 if angle: 415 #angle is what you want to end up with 416 deltaAngle = angle - self.oldValue 417 #print 'deltaAngle=', deltaAngle, 'angle=', angle 418 self.transformCoords(deltaAngle) 419 if hasattr(self, 'extslider'): 420 self.extslider.set(angle, update=0) 421 #s = self.atomList[2].full_name()+'--'+self.atomList[3].full_name() 422 #self.bondString.set(s) 423 self.updateHistory() 424 ##if self.undoNow: raise 'abc' 425 #return float(self.labelStrs[-1]) 426 return
427 428
429 - def update(self, forward=1, event=None):
430 if not len(self.atomList): 431 self.spheres.Set(vertices=[], tagModified=False) 432 self.labels.Set(vertices=[], tagModified=False) 433 self.lines.Set(vertices=[], tagModified=False) 434 self.vf.GUI.VIEWER.Redraw() 435 return 436 limit = self.snakeLength 437 #each time have to recalculate lineVertices 438 self.lineVertices=[] 439 for at in self.atomList: 440 c1 = self.getTransformedCoords(at) 441 self.lineVertices.append(tuple(c1)) 442 #display spheres: 443 self.spheres.Set(vertices=self.lineVertices, tagModified=False) 444 self.vf.GUI.VIEWER.Redraw() 445 #label with torsion 446 #lines between spheres are only drawn when angle completed 447 #that is, len(ats)%4=0 448 if len(self.lineVertices)<4: 449 self.labels.Set(vertices=[], tagModified=False) 450 self.lines.Set(vertices=[], tagModified=False) 451 else: 452 #rebuild labels and polygons each time 453 self.labelCenters=[] 454 self.labelStrs=[] 455 #labelCenters, labelStrs, 456 #this gets done lenATs/4 times 457 numItems = len(self.atomList)/4 458 for i in range(numItems): 459 at0,at1,at2,at3 = self.atomList[i*4:i*4+4] 460 torsion = self.vf.measureTorsion.doit(at0, at1, at2, at3) 461 torsionLabel = '%.3f' %torsion 462 self.labelStrs.append(torsionLabel) 463 c0 = self.getTransformedCoords(at0) 464 c1 = self.getTransformedCoords(at3) 465 newcenter = tuple((c0+c1)/2.0) 466 self.labelCenters.append(newcenter) 467 self.vf.GUI.VIEWER.Redraw() 468 items = self.callbackDict.keys() 469 #items = ['measureDistanceGC','measureAngleGC','measureTorsionGC'] 470 #checkout whether measure update needs to be called 471 icomVals = self.vf.ICmdCaller.commands.value.values() 472 for item in items: 473 if not len(icomVals): break 474 if not hasattr(self.vf, item): 475 continue 476 exec('cmd = self.vf.'+item) 477 if cmd in icomVals: 478 #cmd.update() 479 s = self.callbackDict[item] 480 exec('self.vf.' + item + '.'+ s + '()')
481 482 483
484 - def transformCoords(self, deltaAngle):
485 """ deltaAngle is NOW not final angle wanted but relative""" 486 #mov_coords is the array of the coords of the atoms to be moved, 487 #x2 and x3 are atoms which define the axis of the transformation 488 #by deltaAngle. NB: effect is that mov_atoms.coords 489 #are transformed... 490 if not hasattr(self, 'mov_atoms'): return 491 if not len(self.mov_atoms): return 492 x1, x2, x3, x4 = self.atomList 493 nc = self.vf.setRelativeTorsion.doit(x2, x3, deltaAngle, 494 self.mov_atoms, returnVal=1) 495 mol = x2.top 496 #mov_atoms = mol.subTree(x2, x3, mol.allAtoms) 497 for i in range(len(nc)): 498 at = self.mov_atoms[i] 499 at._coords[at.conformation] = nc[i].tolist() 500 event = EditAtomsEvent('coords', self.mov_atoms) 501 self.vf.dispatchEvent(event) 502 self.update()
503 504 505 #####Callback Functions for the Dial: 506 #####slideCallback
507 - def slideCallback(self, eventval):
508 #print 'in slideCallback' 509 if len(self.atomList)!=4: return 510 if not hasattr(self, 'oldValue'): return 511 if self.oldValue==None: 512 return 513 #self.setupUndoBefore(self.atomList, self.oldValue) 514 try: 515 newAngle = self.extslider.get() 516 tT = self.torsionType.get() 517 at0, at1, at2, at3 = self.atomList 518 #torsion = self.vf.measureTorsion.doit(at0, at1, at2, at3) 519 torsion = self.oldValue 520 if tT == '1': 521 #NEWdeltaAngle = newAngle 522 deltaAngle = newAngle - torsion 523 else: 524 #NEWdeltaAngle = newAngle + torsion 525 deltaAngle = newAngle 526 self.transformCoords(deltaAngle) 527 #print 'deltaAngle=', deltaAngle 528 self.oldValue = newAngle 529 #self.oldValue = newAngle 530 except ValueError: 531 self.vf.GUI.message("error in slideCallback\n")
532 533
534 - def rdSet(self, event=None):
535 #"""radiobutton selection of torsionType: 536 #Absolute: initial angle to be displayed in slider/entry 537 #Relative: 0 is displayed """ 538 if self.torsionType.get()=='1': 539 aL = self.atomList 540 if len(aL)==4: 541 torsion = self.vf.measureTorsion.doit(aL[0],aL[1],aL[2],aL[3]) 542 self.extslider.set(torsion) 543 else: 544 self.extslider.set(0)
545 546 547
548 - def setupUndoBefore(self, ats, angle):
549 pass
550 551 552 #def setupUndoBefore(self, ats, angle): 553 ##no atoms, <4 atoms, 554 #aSet = AtomSet(self.atomList) 555 #self.undoMenuString = self.name 556 #if len(self.atomList)==0: 557 #undoCmd = 'self.setTorsionGC.atomList=[]; self.setTorsionGC.update()' 558 #elif len(self.atomList)<4: 559 ##need to step back here 560 #undoCmd = 'self.setTorsionGC.atomList=self.setTorsionGC.atomList[:-1]; self.setTorsionGC.update()' 561 #else: 562 ##print 'self.oldValue=', self.oldValue 563 #undoCmd = 'self.setTorsionGC(\''+ aSet.full_name()+ '\',' + str(self.oldValue) + ', topCommand=0)' 564 ##self.oldValue = str(self.extslider.get()) 565 #self.vf.undo.addEntry((undoCmd), (self.name)) 566 567
568 - def setupUndoAfter(self, ats, angle,**kw):
569 #no atoms, <4 atoms, 570 aSet = AtomSet(self.atomList) 571 self.undoMenuString = self.name 572 if len(self.atomList)==0: 573 undoCmd = 'self.setTorsionGC.atomList=[]; self.setTorsionGC.update()' 574 elif len(self.atomList)<4: 575 #need to step back here 576 undoCmd = 'self.setTorsionGC.atomList=self.setTorsionGC.atomList[:-1]; self.setTorsionGC.update()' 577 elif self.origValue==self.oldValue: 578 return 579 else: 580 restoreAngle = self.origValue 581 self.undoNow = 1 582 undoCmd = 'self.setTorsionGC(\''+ aSet.full_name()+ '\',' + str(restoreAngle) + ', topCommand=0)' 583 self.vf.undo.addEntry((undoCmd), (self.name))
584 585
586 - def Accept_cb(self):
587 apply(self.setupUndoAfter,(self.atomList, self.oldValue),{}) 588 self.origValue = self.oldValue
589 590
591 - def Done_cb(self):
592 self.stopICOM()
593 594 595
596 - def startICOM(self):
597 self.vf.setIcomLevel( Atom ) 598 if not hasattr(self, 'form'): 599 self.buildForm() 600 else: 601 self.form.deiconify()
602 603
604 - def stopICOM(self):
605 if hasattr(self, 'form'): 606 self.form.withdraw() 607 self.atomList = [] 608 self.atomCenters = [] 609 self.labelStrs = [] 610 self.labelCenters = [] 611 self.lineVertices = [] 612 self.spheres.Set(vertices=[], tagModified=False) 613 self.lines.Set(vertices=[], faces=[], tagModified=False) 614 self.labels.Set(vertices=[], tagModified=False) 615 self.vf.GUI.VIEWER.Redraw() 616 #when cmd stops being icom, remove callback 617 ## ehm = self.vf.GUI.ehm 618 ## for event in ['<B2-Motion>', '<B3-Motion>']: 619 ## if ehm.eventHandlers.has_key(event) and self.update_cb in \ 620 ## ehm.eventHandlers[event]: 621 ## ehm.RemoveCallback(event, self.update_cb) 622 for event in ['<B2-Motion>', '<B3-Motion>']: 623 self.vf.GUI.removeCameraCallback(event, self.update_cb)
624 625
626 - def repeat_transTors(self, event=None):
627 deltaAngle = self.extslider.get() 628 if self.torsionType.get() != '1': 629 self.transformCoords(deltaAngle) 630 #this is here in order to create a log message 631 nc = self.vf.setRelativeTorsion(self.atomList[1], self.atomList[2], deltaAngle, 632 self.mov_atoms, returnVal=1) 633 event = EditAtomsEvent('coords', self.mov_atoms) 634 self.vf.dispatchEvent(event)
635 636
637 - def new_Tors(self, event = 0):
638 self.atomList = [] 639 self.update()
640 641 642 #when called, most recent 4 atoms are in self.atomList
643 - def updateHistory(self):
644 """1: call TorsionHistory.getTorsion: 645 make a new TorsionAngle or add current angle to angleList 646 2: put TA.name_string into ListBox 647 3: best if insert a tuple (string to be displayed, item itself) 648 4: adjust size with self.historyList.configure(height=self.[].size) 649 5: limit overall size to 4""" 650 #print 'in updateHistory' 651 molecule = self.atomList[-1].top 652 if self.TAHdata is None: 653 self.TAHdata = TorsionHistory(molecule) 654 a1,a2,a3,a4 = self.atomList 655 newone=self.TAHdata.getTorsion(a1,a2,a3,a4 ) 656 #first check to see if it is in there already??? 657 #need to get info back from getTorsion....(???) 658 if hasattr(self, 'historyList'): 659 if newone.new: 660 self.historyList.insert('end',newone.name_string) 661 if int(self.historyList.cget('height'))<4: 662 self.historyList.configure(height=self.historyList.size()) 663 if self.historyList.curselection(): 664 self.historyList.select_clear(self.historyList.curselection()) 665 newindex=self.TAHdata.getIndex(newone) 666 self.historyList.select_set(newindex) 667 self.historyList.see(newindex) 668 #set entry to a string ==current TA's angleList 669 newstring= "" 670 for item in newone.angleList: 671 newstring=newstring +" " + "%5.3f" %item 672 self.newAngList.set(newstring)
673 674 675
676 - def HLCommand(self, event=None):
677 """double-clicking selection in listbox causes curselection to be picked... 678 1:self.atomList set to atoms of curselection 679 2:self.mov_atoms set to atoms of curselection 680 3:self.selAtom[1-4].Set(vertices=atoms.coords) 681 4:reset entry +slider and init_bondAngle etc 682 5.add current angle to selection's.angleList""" 683 #get TA: 684 if self.historyList.get(0)=='': return 685 items=self.historyList.curselection() 686 if type(items)==types.TupleType: 687 items = items[0] 688 try: 689 items=map(int, items) 690 except ValueError:pass 691 thisTA=self.TAHdata.torslist[items[0]] 692 #get currentAngle 693 current= thisTA.getCurrentAngle() 694 if not thisTA.inList(current): 695 thisTA.angleList.append(current) 696 newAts = AtomSet([thisTA.atom1,thisTA.atom2, thisTA.atom3,\ 697 thisTA.atom4]) 698 #reset self.molecule 699 self.atomList = [] 700 self.molecule = newAts[0].top 701 self.doit(newAts, current) 702 #self.setTorsionAngle(thisTA.atom1, thisTA.atom2, thisTA.atom3, thisTA.atom4, current, 'A') 703 #self.drawTransformedAngle() 704 #self.updatespheres(items[0]) 705 #self.update() 706 self.extslider.set(current,0) 707 newstring= "" 708 for item in thisTA.angleList: 709 newstring=newstring +" " + "%5.3f" %item 710 self.newAngList.set(newstring)
711 712
713 - def getAngList(self, event=None):
714 items=self.historyList.curselection() 715 try: 716 items=map(int, items) 717 except ValueError:pass 718 thisTA=self.TAHdata.torslist[items[0]] 719 thisTA.angleList=map(float, split(self.newAngList.get())) 720 last=thisTA.angleList[-1] 721 newAts = AtomSet([thisTA.atom1,thisTA.atom2, thisTA.atom3,\ 722 thisTA.atom4]) 723 #reset self.molecule 724 self.atomList = [] 725 self.molecule = newAts[0].top 726 self.doit(newAts, last) 727 #self.doit(thisTA.atom1, thisTA.atom2, thisTA.atom3, thisTA.atom4,last,'A') 728 #self.setTorsionAngle(thisTA.atom1, thisTA.atom2, thisTA.atom3, thisTA.atom4,last,'A') 729 #self.drawTransformedAngle() 730 #self.updatespheres(items[0]) 731 self.extslider.set(last,0)
732 733
734 - def stepBack(self, event=None):
735 items=self.historyList.curselection() 736 if len(items)==0: return 737 try: 738 items=map(int, items) 739 except ValueError: 740 pass 741 thisTA=self.TAHdata.torslist[items[0]] 742 ####last angle is thisTA.angleList[-1] 743 if len(thisTA.angleList)>1: 744 last=thisTA.angleList[-1] 745 lastIndex=thisTA.angleList.index(last) 746 thisTA.angleList=thisTA.angleList[:lastIndex] 747 last=thisTA.angleList[-1] 748 else: 749 last=thisTA.angleList[0] 750 newAts = AtomSet([thisTA.atom1,thisTA.atom2, thisTA.atom3,\ 751 thisTA.atom4]) 752 #reset self.molecule 753 self.atomList = [] 754 self.molecule = newAts[0].top 755 self.doit(newAts, last) 756 #self.doit(thisTA.atom1, thisTA.atom2, thisTA.atom3, thisTA.atom4,last,'A') 757 #self.setTorsionAngle(thisTA.atom1, thisTA.atom2, thisTA.atom3, thisTA.atom4,last,'A') 758 #self.drawTransformedAngle() 759 #self.updatespheres(items[0]) 760 newstring= "" 761 for item in thisTA.angleList: 762 newstring=newstring +" " + "%5.3f" %item 763 self.newAngList.set(newstring) 764 self.extslider.set(last, 0) 765 #IS THIS ENOUGH in order to create correct log? 766 self.mouseUp()
767 768
769 - def startOver(self, event=None):
770 items=self.historyList.curselection() 771 if len(items)==0: return 772 try: 773 items=map(int, items) 774 except ValueError:pass 775 thisTA=self.TAHdata.torslist[items[0]] 776 self.resetAngle(thisTA)
777 778
779 - def resetAngle(self, thisTA, event=None):
780 #first angle is thisTA.angleList[0] 781 ang=thisTA.angleList[0] 782 newAts = AtomSet([thisTA.atom1,thisTA.atom2, thisTA.atom3,\ 783 thisTA.atom4]) 784 #reset self.molecule 785 self.atomList = [] 786 self.molecule = newAts[0].top 787 self.doit(newAts, ang) 788 #self.doit(thisTA.atom1, thisTA.atom2, thisTA.atom3, thisTA.atom4,ang,'A') 789 #self.setTorsionAngle(thisTA.atom1, thisTA.atom2, thisTA.atom3, thisTA.atom4,ang,'A') 790 if len(thisTA.angleList)>1: 791 thisTA.angleList=thisTA.angleList[:1] 792 #self.drawTransformedAngle() 793 self.extslider.set(ang,0) 794 self.mouseUp() 795 self.newAngList.set("%5.3f" %ang)
796 797
798 - def resetAll(self, event=None):
799 if self.TAHdata==None: return 800 for item in self.TAHdata.torslist: 801 self.resetAngle(item) 802 self.spheres.Set(vertices=[], tagModified=False) 803 self.vf.GUI.VIEWER.Redraw()
804 805
806 - def buildForm(self):
807 if hasattr(self, 'ifd'): 808 return 809 self.torsionType = Tkinter.StringVar() 810 self.torsionType.set('1') 811 self.ifd = ifd = InputFormDescr(title = 'Set Torsion Angle') 812 ifd.append({'name':'extLabel', 813 'widgetType': Tkinter.Label, 814 'wcfg':{'text':'Set Angle:\n(180=trans)'}, 815 'gridcfg':{'sticky':Tkinter.W+Tkinter.E, 816 'columnspan':2}}) 817 ifd.append( {'name':'extslider', 818 'widgetType': ExtendedSliderWidget, 819 'wcfg':{'label':'torsion', 820 'minval':-360., 'maxval':360., 821 'width':150, 822 'immediate':1, 823 'command':self.slideCallback, 824 'sliderType':'float', 825 'entrypackcfg':{'side':'bottom'}}, 826 'gridcfg':{'sticky':'we', 'columnspan':2}}) 827 ifd.append({'name':'typeLabel', 828 'widgetType': Tkinter.Label, 829 'wcfg':{'text':'Torsion Type'}, 830 'gridcfg':{'sticky':'we', 'columnspan':2}}) 831 ifd.append({'name':'rdbut1', 832 'widgetType':Tkinter.Radiobutton, 833 'wcfg':{'text':'Absolute', 834 'variable': self.torsionType, 835 'value':1, 836 'command':self.rdSet 837 }, 838 'gridcfg':{'sticky':'we'}}) 839 ifd.append({'name':'rdbut2', 840 'widgetType':Tkinter.Radiobutton, 841 'wcfg':{'text':'Relative ', 842 'variable': self.torsionType, 843 'value':0, 844 'command':self.rdSet 845 }, 846 'gridcfg':{'sticky':'we', 'row':-1, 'column':1}}) 847 ifd.append({'name':'historyList', 848 'widgetType':ListChooser, 849 'wcfg':{ 850 'title':'TorsionAngle\nTranformation History', 851 'mode': 'single', 852 'command': self.HLCommand, 853 'lbwcfg':{'height':5, 854 'selectforeground': 'yellow', 855 'exportselection': 0, 856 'width': 30}, 857 }, 858 'gridcfg':{'sticky':'we', 'columnspan':2}}) 859 ifd.append({'name':'hbut1', 860 'widgetType':Tkinter.Button, 861 'wcfg': { 'text':'Step Back ', 862 'command': self.stepBack}, 863 'gridcfg':{'sticky':'we','columnspan':2}}) 864 ifd.append({'name':'hbut2', 865 'widgetType':Tkinter.Button, 866 'wcfg': { 'text':'Start Over ', 867 'command': self.startOver}, 868 'gridcfg':{'sticky':'we','columnspan':2}}) 869 ifd.append({'name':'hbut3', 870 'widgetType':Tkinter.Button, 871 'wcfg': { 'text':'Reset All ', 872 'command': self.resetAll}, 873 'gridcfg':{'sticky':'we','columnspan':2}}) 874 ifd.append({'name':'angListEnt', 875 'widgetType':Tkinter.Entry, 876 'wcfg':{'width':5, 877 'command':self.getAngList, 878 'textvariable':self.newAngList}, 879 'gridcfg':{'sticky':'we','columnspan':2}}) 880 ifd.append({'name':'hbut4', 881 'widgetType':Tkinter.Button, 882 'wcfg': { 'text':'Move', 883 'command': self.repeat_transTors}, 884 'gridcfg':{'sticky':'we','columnspan':2}}) 885 ifd.append({'name':'hbut5', 886 'widgetType':Tkinter.Button, 887 'wcfg': { 'text':'New Torsion', 888 'command': self.new_Tors}, 889 'gridcfg':{'sticky':'we','columnspan':2}}) 890 #ifd.append({'name':'accept', 891 #'widgetType': Tkinter.Button, 892 #'wcfg':{'text' : 'Accept', 893 #'command': self.Accept_cb}, 894 #'gridcfg':{'sticky':'we'}}) 895 ifd.append({'name':'done', 896 'widgetType': Tkinter.Button, 897 'wcfg':{'text' : 'Done', 898 'command': self.Done_cb}, 899 'gridcfg':{'sticky':'we','columnspan':2}}) 900 #'gridcfg':{'sticky':'we','column':1, 'row':-1}}) 901 self.form = self.vf.getUserInput(ifd, modal=0, blocking=0) 902 self.form.root.protocol('WM_DELETE_WINDOW',self.Done_cb) 903 self.extslider = self.ifd.entryByName['extslider']['widget'] 904 self.extslider.draw.bind('<ButtonRelease-1>', self.mouseUp, add='+') 905 self.extslider.entry.bind('<Return>', self.mouseUp, add='+') 906 self.historyList = self.ifd.entryByName['historyList']['widget'].lb 907 #self.historyList.bind("<Double-Button-1>",self.HLCommand) 908 self.hbut1 = self.ifd.entryByName['hbut1']['widget'] 909 self.hbut2 = self.ifd.entryByName['hbut2']['widget'] 910 self.hbut3 = self.ifd.entryByName['hbut3']['widget'] 911 self.angListEnt = self.ifd.entryByName['angListEnt']['widget']
912 913
914 - def mouseUp(self, event=None):
915 #print "in mouseUp" 916 #fix this: atomList length dependent 917 if len(self.atomList)==4: 918 at0,at1,at2,at3 = self.atomList 919 angle = self.extslider.get() 920 if self.torsionType.get()=='1': 921 self.vf.setTorsion(at0, at1, at2, at3, angle) 922 else: 923 self.vf.setRelativeTorsion(at1, at2, angle)
924 925 926 927 setTorsionGuiDescr = {'widgetType':'Menu', 'menuBarName':'menuRoot', 928 'menuButtonName':'Set Torsion Angle', 929 'menuEntryLabel':'Show Set Torsion Panel', 930 'index':0} 931 932 SetTorsionGUI = CommandGUI() 933 SetTorsionGUI.addMenuCommand('menuRoot', 'Edit', 'Set Torsion', 934 cascadeName='Torsion angles', index = 0) 935 936 937 938
939 -class TorsionAngle:
940 - def __init__(self, atom1, atom2, atom3, atom4):
941 self.molecule=atom1.top 942 self.name_string=atom1.name +"-"+ atom2.name +"-"+ atom3.name +"-"+ atom4.name 943 self.atom1=atom1 944 self.atom2=atom2 945 self.atom3=atom3 946 self.atom4=atom4 947 self.mov_atoms = self.molecule.subTree(atom2, atom3, self.molecule.allAtoms) 948 self.currentAngle = self.measureAngle(self.atom1, self.atom2, self.atom3, self.atom4) 949 self.angleList=[] 950 self.addAngle(self.currentAngle) 951 self.new=1
952
953 - def __cmp__(self,tA2):
954 if self.atom1==tA2.atom1 and self.atom2==tA2.atom2 and self.atom3==tA2.atom3 and self.atom4 == tA2.atom4: 955 return 1 956 else: 957 return 0
958
959 - def addAngle(self, angle):
960 if not self.inList(angle): 961 self.angleList.append(angle)
962 963
964 - def inList(self, angle):
965 for ent in self.angleList: 966 d = angle-ent 967 if d<.05 and d >-.05: 968 return 1 969 return 0
970 971
972 - def measureAngle(self, atom1,atom2,atom3,atom4):
973 w=Numeric.array(atom1.coords) 974 x=Numeric.array(atom2.coords) 975 y=Numeric.array(atom3.coords) 976 z=Numeric.array(atom4.coords) 977 thisAngle = torsionAngle(w,x,y,z) 978 return thisAngle
979
980 - def getCurrentAngle(self):
981 self.currentAngle=self.measureAngle(self.atom1,self.atom2,self.atom3,self.atom4) 982 return self.currentAngle
983 984 985 986
987 -class TorsionHistory:
988 - def __init__(self, mol):
989 self.torslist=[] 990 self.molecule=mol
991
992 - def addTorsion(self, newtangle):
993 previous=filter(newtangle.__cmp__,self.torslist) 994 #if this angle is already on the list, add its current angle 995 #to its angleList 996 if len(previous)>0: 997 previous[0].addAngle(newtangle.currentAngle) 998 newtangle=previous[0] 999 previous[0].new=0 1000 #if newtangle is new, just append it to the torslist 1001 else: 1002 self.torslist.append(newtangle) 1003 return newtangle
1004
1005 - def getTorsion(self, a1, a2, a3, a4):
1006 newone=TorsionAngle(a1,a2,a3,a4) 1007 return self.addTorsion(newone)
1008
1009 - def getIndex(self, newtangle):
1010 result=map(newtangle.__cmp__, self.torslist) 1011 #at this point result is a list such as [1,0,0,0,0] 1012 return result.index(1)
1013 1014 1015 1016 commandList = [ 1017 {'name':'setTorsionGC','cmd': SetTorsionGUICommand(),'gui':SetTorsionGUI}, 1018 {'name':'setRelativeTorsion','cmd': SetRelativeTorsion(),'gui':None}, 1019 {'name':'setTorsion','cmd': SetTorsion(),'gui':None}, 1020 {'name':'setTranslation','cmd': SetTranslation(),'gui':None}, 1021 {'name':'setQuaternion','cmd': SetQuaternion(),'gui':None}, 1022 ] 1023 1024
1025 -def initModule(viewer):
1026 1027 for dict in commandList: 1028 viewer.addCommand(dict['cmd'], dict['name'], dict['gui'])
1029