Package mmLib :: Module Viewer
[hide private]
[frames] | no frames]

Source Code for Module mmLib.Viewer

   1  ## Copyright 2002-2010 by PyMMLib Development Group (see AUTHORS file) 
   2  ## This code is part of the PyMMLib distribution and governed by 
   3  ## its license.  Please see the LICENSE file that should have been 
   4  ## included as part of this package. 
   5  """Visualization system for Structure objects. 
   6  """ 
   7  from __future__  import generators 
   8   
   9  import copy 
  10  import math 
  11   
  12  try: 
  13      import numpy 
  14      try: 
  15          from numpy.oldnumeric import linear_algebra as linalg 
  16      except ImportError: 
  17          from numpy.linalg import old as linalg 
  18  except ImportError: 
  19      import NumericCompat as numpy 
  20      from NumericCompat import linalg 
  21   
  22  import Library 
  23  import GeometryDict 
  24  import AtomMath 
  25  import Structure 
  26  import Gaussian 
  27  import Colors 
  28   
  29   
  30  ## MISC Constents 
  31  PROP_OPACITY_RANGE    = "0.0-1.0,0.1" 
  32  PROP_LINE_RANGE       = "1.0-10.0,1.0" 
  33  PROP_PROBABILTY_RANGE = "1-99,1" 
  34  PROP_FRAC_RANGE       = "0-100,1" 
  35   
  36   
37 -class GLPropertyDict(dict):
38 """Property cache/routing dictionary 39 """
40 - def __init__(self, gl_object):
41 self.gl_object = gl_object
42
43 - def update(self, **args):
44 self.gl_object.glo_update_properties(**args)
45 46
47 -class GLPropertyDefault(object):
48 """This value means a property should use its default value. 49 """ 50 pass
51 52
53 -class GLObject(object):
54 """Base class for all OpenGL rendering objects. It combines a 55 composite-style tree structure with a system for setting properties. 56 The properties are used for the specific OpenGL drawing objects 57 to control color, position, line width, etc... Implementing properties 58 requres the GLProperties object which is the access object for the 59 properties. 60 """ 61 62 PropertyDefault = GLPropertyDefault() 63
64 - def __init__(self, **args):
65 object.__init__(self) 66 67 self.__globject_parent = None 68 self.__globject_children = [] 69 70 self.properties = GLPropertyDict(self) 71 self.__globject_properties_id = str(id(self)) 72 self.__globject_properties_name = None 73 self.__globject_properties = [] 74 self.__globject_properties_callbacks = [] 75 76 self.glo_install_properties()
77
78 - def glo_name(self):
79 """Returns the GLObject name. 80 """ 81 if self.__globject_properties_name is not None: 82 return self.__globject_properties_name 83 elif self.__globject_properties_id is not None: 84 return "%s(%s)" % (self.__class__.__name__, self.__globject_properties_id) 85 else: 86 return self.__class__.__name__
87
88 - def glo_set_name(self, name):
89 """Sets the GLObject name. 90 """ 91 self.__globject_properties_name = name
92
93 - def glo_add_child(self, child):
94 assert isinstance(child, GLObject) 95 assert child!=self 96 assert self.glo_is_descendant_of(child) is False 97 assert child.__globject_parent is None 98 child.__globject_parent = self 99 self.__globject_children.append(child)
100
101 - def glo_prepend_child(self, child):
102 """Adds a child GLObject to the beginning of the GLObject's 103 child list. 104 """ 105 assert isinstance(child, GLObject) 106 assert child!=self 107 assert self.glo_is_descendant_of(child) is False 108 assert child.__globject_parent is None 109 child.__globject_parent = self 110 self.__globject_children.insert(0, child)
111
112 - def glo_append_child(self, child):
113 """Adds a child GLObject to the end of the GLObject's child list. 114 """ 115 assert isinstance(child, GLObject) 116 assert child!=self 117 assert self.glo_is_descendant_of(child) is False 118 assert child.__globject_parent is None 119 child.__globject_parent = self 120 self.__globject_children.append(child)
121
122 - def glo_remove_child(self, child):
123 """Removes the child GLObject. 124 """ 125 assert isinstance(child, GLObject) 126 assert child.__globject_parent==self 127 child.__globject_parent = None 128 self.__globject_children.remove(child)
129
130 - def glo_remove(self):
131 """The GLObject removes itself from its parent. 132 """ 133 parent = self.__globject_parent 134 if parent is None: 135 return 136 parent.glo_remove_child(self)
137
138 - def glo_iter_children(self):
139 """Iterate immediate children. 140 """ 141 return iter(self.__globject_children)
142
144 """Preorder Traversal for GLObject composite. 145 """ 146 for child1 in self.__globject_children: 147 yield child1 148 for child2 in child1.glo_iter_preorder_traversal(): 149 yield child2
150
151 - def glo_get_depth(self):
152 """Returns the depth, the root composite is depth 0. 153 """ 154 depth = 0 155 ancestor = self.__globject_parent 156 while ancestor: 157 depth += 1 158 ancestor = ancestor.parent 159 return depth
160
161 - def glo_get_degree(self):
162 """Returns the number of children (degree). 163 """ 164 return len(self.__globject_children)
165
166 - def glo_count_descendants(self):
167 """Counts all decendant GLObjects. 168 """ 169 n = self.glo_get_degree() 170 for child in self.__globject_children: 171 n += child.glo_count_descendants() 172 return n
173
174 - def glo_get_root(self):
175 """Returns the root GLObject. 176 """ 177 gl_object = self 178 while gl_object.__globject_parent: 179 gl_object = gl_object.__globject_parent 180 return gl_object
181
182 - def glo_get_parent(self):
183 """Returns the parent GLObject. 184 """ 185 return self.__globject_parent
186
187 - def glo_get_path(self):
188 """Returns the tree-path to the composite as a list of its 189 parent composites. 190 """ 191 path_list = [self] 192 parent = self.__globject_parent 193 while parent: 194 path_list.insert(0, parent) 195 parent = parent.__globject_parent 196 return path_list
197
198 - def glo_get_index_path(self):
199 """Returns the tree-path to the GLObject as a list of its 200 integer indexes. 201 """ 202 ipath_list = [] 203 child = self 204 parent = child.__globject_parent 205 while parent: 206 ipath_list.insert(0, parent.__globject_children.index(child)) 207 child = parent 208 parent = parent.__globject_parent 209 return ipath_list
210
211 - def glo_get_parent_list(self):
212 """Returns a list of the parent GLObjects back to the root. 213 """ 214 parent_list = [] 215 composite = self 216 while composite.__globject_parent: 217 composite = composite.__globject_parent 218 parent_list.append(composite) 219 return parent_list
220
221 - def glo_get_lowest_common_ancestor(self, gl_object):
222 """Returns the lowest common ancesotry of self and argument 223 composite. 224 """ 225 assert isinstance(gl_object, GLObject) 226 227 pl1 = self.glo_get_parent_list() 228 pl2 = gl_object.getParentList() 229 pl1.reverse() 230 pl2.reverse() 231 232 ancestor = None 233 for i in xrange(min(len(pl1), len(pl2))): 234 if pl1[i] == pl2[i]: 235 ancestor = pl1[i] 236 else: 237 break 238 239 return ancestor
240
241 - def glo_is_descendant_of(self, gl_object):
242 """Returns true if self composite is a decent of argument GLObject. 243 """ 244 assert isinstance(gl_object, GLObject) 245 246 ancestor = self.__globject_parent 247 while ancestor: 248 if ancestor==gl_object: 249 return True 250 ancestor = ancestor.__globject_parent 251 return False
252
253 - def glo_set_properties_id(self, gl_object_id):
254 """Set the property name for this GLObject. 255 """ 256 self.__globject_properties_id = gl_object_id
257
258 - def glo_get_properties_id(self):
259 """Returns the properties ID of this object. 260 """ 261 return self.__globject_properties_id
262
263 - def glo_install_properties(self):
264 """Called by GLObject.__init__ to install properties. 265 """ 266 pass
267
268 - def glo_add_property(self, prop_desc):
269 """Adds a new property to the GLObject. The prop_desc is a dictionary 270 with attributes describing the property. See comments in source code 271 for a description of the key values for property descriptions. 272 """ 273 assert prop_desc["name"] not in self.properties 274 275 ## is the proprty marked read-only, this is only a hint to 276 ## the user interface, not a actual read-only property 277 prop_desc["read_only"] = prop_desc.get("read_only", False) 278 279 ## the property triggers update callbacks when the 280 ## value is changed 281 prop_desc["update_on_changed"] = prop_desc.get("update_on_changed", True) 282 283 ## the property triggers update callbacks when the 284 ## property is set with comparison to the old value 285 prop_desc["update_on_set"] = prop_desc.get("update_on_set", False) 286 287 ## the property triggers update callbacks on initalization 288 prop_desc["update_on_init"] = prop_desc.get("update_on_init", True) 289 290 self.__globject_properties.append(prop_desc)
291
292 - def glo_iter_property_desc(self):
293 """Iterates over all property descriptions. 294 """ 295 return iter(self.__globject_properties)
296
297 - def glo_get_property_desc(self, name):
298 """Return the property description dictionary for the given 299 property name. 300 """ 301 for prop_desc in self.__globject_properties: 302 if prop_desc["name"]==name: 303 return prop_desc 304 return None
305 321
322 - def glo_get_child(self, gl_object_id):
323 """Returns the child GLObject matching the given gl_object_id. 324 """ 325 for gl_object in self.glo_iter_children(): 326 if gl_object.__globject_properties_id==gl_object_id: 327 return gl_object 328 return None
329
330 - def glo_get_child_path(self, glo_id_path):
331 """Returns the object at the given path, or None if the object does 332 not exist. 333 """ 334 child = self 335 336 for glo_id in glo_id_path.split("/"): 337 parent = child 338 child = parent.glo_get_child(glo_id) 339 if child is None: 340 return False 341 342 return child
343
344 - def glo_init_properties(self, **args):
345 """This is a special form of update which propagates all linked 346 values, not just the changed ones. 347 """ 348 updates = {} 349 actions = [] 350 351 for prop_desc in self.__globject_properties: 352 name = prop_desc["name"] 353 354 ## set the property value 355 if args.has_key(name): 356 if isinstance(args[name], GLPropertyDefault): 357 self.properties[name] = prop_desc["default"] 358 else: 359 self.properties[name] = args[name] 360 else: 361 self.properties[name] = prop_desc["default"] 362 363 ## if the update callbacks are to be triggered on initialization 364 if prop_desc["update_on_init"] is True: 365 updates[name] = self.properties[name] 366 367 ## add changes to actions list 368 ## case 1: action is a string 369 if isinstance(prop_desc["action"], str): 370 if prop_desc["action"] not in actions: 371 actions.append(prop_desc["action"]) 372 ## case 2: action is a list of strings 373 elif isinstance(prop_desc["action"], list): 374 for prop_action in prop_desc["action"]: 375 if prop_action not in actions: 376 actions.append(prop_action) 377 378 ## propagate linked values 379 try: 380 linked_props = prop_desc["link"] 381 except KeyError: 382 pass 383 else: 384 for linked_prop in linked_props: 385 child = self.glo_get_child(linked_prop["gl_object"]) 386 child_name = linked_prop["name"] 387 child.glo_update_properties(**{ child_name: self.properties[name] }) 388 389 if len(updates)>0: 390 for func in self.__globject_properties_callbacks: 391 func(updates, actions)
392
393 - def glo_update_properties(self, **args):
394 """Update property values and trigger update callbacks. 395 """ 396 updates = {} 397 actions = [] 398 399 ## update properties 400 for prop_desc in self.__globject_properties: 401 name = prop_desc["name"] 402 403 ## continue if this property is not being updated 404 if args.has_key(name) is False: 405 continue 406 407 ## update_on_set: 408 ## If True, always trigger update callbacks when 409 ## the value is set. 410 ## update_on_changed: 411 ## If true, trigger update callbacks when a value 412 ## is changed. 413 do_update = False 414 415 if prop_desc["update_on_set"] is True: 416 do_update = True 417 418 elif prop_desc["update_on_changed"] is True: 419 420 ## special handling for Numeric/Numarray types 421 if isinstance(self.properties[name], numpy.ndarray): 422 if not numpy.allclose(self.properties[name], args[name]): 423 do_update = True 424 425 elif self.properties[name]!=args[name]: 426 do_update = True 427 428 if do_update is True: 429 430 if isinstance(args[name], GLPropertyDefault): 431 self.properties[name] = prop_desc["default"] 432 else: 433 self.properties[name] = args[name] 434 435 updates[name] = self.properties[name] 436 437 ## now update the actions taken when a property changes 438 ## case 1: action is a string 439 if isinstance(prop_desc["action"], str): 440 if prop_desc["action"] not in actions: 441 actions.append(prop_desc["action"]) 442 ## case 2: action is a list of strings 443 elif isinstance(prop_desc["action"], list): 444 for prop_action in prop_desc["action"]: 445 if prop_action not in actions: 446 actions.append(prop_action) 447 448 if do_update is True: 449 ## propagate updates for linked properties 450 try: 451 linked_props = prop_desc["link"] 452 except KeyError: 453 pass 454 else: 455 for linked_prop in linked_props: 456 child = self.glo_get_child(linked_prop["gl_object"]) 457 child_name = linked_prop["name"] 458 child.glo_update_properties(**{ child_name: self.properties[name] }) 459 460 if len(updates)>0: 461 for func in self.__globject_properties_callbacks: 462 func(updates, actions)
463
464 - def glo_update_properties_path(self, glo_id_path, value):
465 """ 466 """ 467 path = glo_id_path.split("/") 468 prop_name = path[-1] 469 path = path[:-1] 470 471 ## get the child to update 472 child = self 473 for glo_id in path: 474 parent = child 475 child = parent.glo_get_child(glo_id) 476 if child is None: 477 break 478 if child is None: 479 return False 480 481 child.glo_update_properties(**{prop_name: value})
482
483 - def glo_add_update_callback(self, func):
484 """Adds a function which is called whenever property values change. 485 The function is called with two arguments: a updates dictionary 486 containing all updated properties and the values they were changed 487 to, and a actions list which contains a unique list of action 488 key words forme self.prop_list = [] 489 self.callback_list = [] from the action fields of the updated 490 properties. 491 """ 492 self.__globject_properties_callbacks.append(func)
493
494 - def glo_remove_update_callback(self, func):
495 """Removes the update callback. 496 """ 497 self.__globject_properties_callbacks.remove(func)
498
499 - def glo_get_glstructure(self):
500 """Returns the parent GLStructure object, or None if the GLObject 501 is not a child of a GLStructure. 502 """ 503 gl_object = self 504 while gl_object is not None and not isinstance(gl_object, GLStructure): 505 gl_object = gl_object.__globject_parent 506 return gl_object
507 508
509 -class GLDrawList(GLObject):
510 """Fundamental OpenGL rigid entity. 511 """ 512 513 gldl_color_list = Colors.COLOR_NAMES_CAPITALIZED[:] 514
515 - def __init__(self, **args):
516 self.driver = None 517 self.gldl_draw_method_list = [] 518 519 GLObject.__init__(self, **args) 520 self.glo_add_update_callback(self.gldl_update_cb) 521 self.glo_init_properties(**args) 522 523 self.gldl_install_draw_methods()
524
525 - def glo_remove_child(self, child):
526 """Override GLObject's remove to also delete the compiled OpenGL 527 draw lists. 528 """ 529 for chd in child.glo_iter_preorder_traversal(): 530 if isinstance(chd, GLDrawList): 531 chd.gldl_draw_method_delete_compiled_all_drivers() 532 GLObject.glo_remove_child(self, child)
533
534 - def glo_remove(self):
535 """Override GLObject's remove to also delete the compiled OpenGL 536 draw lists. 537 """ 538 for child in self.glo_iter_preorder_traversal(): 539 if isinstance(child, GLDrawList): 540 child.gldl_draw_method_delete_compiled_all_drivers() 541 GLObject.glo_remove(self)
542
543 - def glo_install_properties(self):
544 self.glo_add_property( 545 { "name" : "visible", 546 "desc": "Visible", 547 "catagory": "Show/Hide", 548 "type": "boolean", 549 "default": True, 550 "action": "redraw" }) 551 self.glo_add_property( 552 { "name" : "origin", 553 "desc": "Origin", 554 "type": "array(3)", 555 "hidden": True, 556 "default": numpy.zeros(3, float), 557 "action": "redraw" }) 558 self.glo_add_property( 559 { "name" : "axes", 560 "desc": "Rotation Axes", 561 "type": "array(3,3)", 562 "hidden": True, 563 "default": numpy.identity(3, float), 564 "action": "redraw" }) 565 self.glo_add_property( 566 { "name" : "rot_x", 567 "desc": "Degrees Rotation About X Axis", 568 "type": "float", 569 "hidden": True, 570 "default": 0.0, 571 "action": "redraw" }) 572 self.glo_add_property( 573 { "name" : "rot_y", 574 "desc": "Degrees Rotation About Y Axis", 575 "type": "float", 576 "hidden": True, 577 "default": 0.0, 578 "action": "redraw" }) 579 self.glo_add_property( 580 { "name" : "rot_z", 581 "desc": "Degrees Rotation About Z Axis", 582 "type": "float", 583 "hidden": True, 584 "default": 0.0, 585 "action": "redraw" }) 586 self.glo_add_property( 587 { "name" : "visible_distance", 588 "desc": "", 589 "type": "float", 590 "hidden": True, 591 "default": 0.0, 592 "action": "redraw" })
593
594 - def gldl_update_cb(self, updates, actions):
595 """Properties update callback. 596 """ 597 ## recompile action recompiles all OpenGL draw lists 598 if "recompile" in actions: 599 self.gldl_draw_method_delete_compiled_all_drivers() 600 self.gldl_redraw() 601 602 ## redraw action redraws all OpenGL draw lists 603 elif "redraw" in actions: 604 self.gldl_redraw() 605 606 ## go through the draw method definitions and trigger 607 ## fine-grained redraw/recompile actions for specific 608 ## draw methods 609 for draw_method in self.gldl_draw_method_list: 610 if draw_method["recompile_action"] in actions: 611 self.gldl_redraw() 612 613 draw_method["expiration_id"] += 1 614 615 ## check if the opacity flag of the draw list changed 616 op = draw_method["opacity_property"] 617 if op is not None: 618 draw_method["transparent"] = self.properties[op]<1.0
619
620 - def gldl_redraw(self):
621 """Triggers a redraw of the GLViewer 622 """ 623 gl_viewer = self.glo_get_root() 624 if isinstance(gl_viewer, GLViewer): 625 gl_viewer.glv_redraw()
626
627 - def gldl_get_glviewer(self):
628 """Returns the root GLViewer object. 629 """ 630 return self.glo_get_root()
631
632 - def gldl_property_color_rgbf(self, prop_name):
633 """Returns the property value as a RGBF triplet. 634 """ 635 try: 636 colorx = self.properties[prop_name] 637 except KeyError: 638 raise KeyError, "gldl_property_color_rgbf: bad prop_name %s" % (prop_name) 639 640 try: 641 return Colors.COLOR_RGBF[colorx.lower()] 642 except KeyError: 643 pass 644 645 try: 646 r, g, b = colorx.split(",") 647 except ValueError: 648 pass 649 else: 650 try: 651 return (float(r), float(g), float(b)) 652 except ValueError: 653 return (1.0, 0.0, 0.0) 654 655 raise TypeError, "gldl_property_color_rgbf: bad colorx %s" % (str(colorx))
656
657 - def gldl_install_draw_methods(self):
658 """Override in children to install draw methods for a GLDrawList. 659 """ 660 pass
661
662 - def gldl_draw_method_install(self, draw_method):
663 """Installs a draw method to compile and render a OpenGL draw listlist. 664 keys: 665 name: text description of the method 666 func: the method to invoke to render the draw list 667 tranparent: True if the draw list is drawing transparent 668 669 private values: 670 gl_draw_list_id: OpenGL Drawlist ID 671 """ 672 assert draw_method.has_key("name") 673 assert draw_method.has_key("func") 674 675 draw_method["transparent"] = draw_method.get("transparent", False) 676 draw_method["no_gl_compile"] = draw_method.get("no_gl_compile", False) 677 draw_method["visible_property"] = draw_method.get("visible_property", None) 678 draw_method["recompile_action"] = draw_method.get("recompile_action", None) 679 draw_method["opacity_property"] = draw_method.get("opacity_property", None) 680 draw_method["multidraw_iter"] = draw_method.get("multipdraw_iter", None) 681 draw_method["multidraw_all_iter"] = draw_method.get("multipdraw_all_iter", None) 682 683 ## the state_id gets incrimented whever compiled draw methods 684 ## need to be recompiled 685 draw_method["expiration_id"] = 1 686 687 ## list of drivers with compiled rendering of this draw method 688 draw_method["driver_list"] = [] 689 690 self.gldl_draw_method_list.append(draw_method)
691
692 - def gldl_draw_method_get(self, draw_method_name):
693 """Returns the draw metod of the given name or None if not found. 694 """ 695 for draw_method in self.gldl_draw_method_list: 696 if draw_method["name"]==draw_method_name: 697 return draw_method 698 return None
699
700 - def gldl_draw_method_compile(self, draw_method):
701 """Compiles a draw method. 702 """ 703 assert self.driver is not None 704 705 mid = self.driver.glr_compile_start(draw_method) 706 draw_method["func"]() 707 self.driver.glr_compile_end() 708 draw_method["driver_list"].append(self.driver)
709
710 - def gldl_draw_method_delete_compiled(self, draw_method):
711 """Deletes the compiled draw list in the current driver. 712 """ 713 assert self.driver is not None 714 715 if self.driver.glr_compile_exists(draw_method): 716 self.driver.glr_compile_delete(draw_method) 717 draw_method["driver_list"].remove(self.driver)
718
720 """ 721 """ 722 for draw_method in self.gldl_draw_method_list: 723 for driver in draw_method["driver_list"]: 724 if driver.glr_compile_exists(draw_method): 725 driver.glr_compile_delete(draw_method)
726
727 - def gldl_push_matrix(self):
728 """Rotate and translate to the correct position for drawing. 729 """ 730 assert self.driver is not None 731 732 self.driver.glr_push_matrix() 733 734 if not numpy.allclose(self.properties["origin"], numpy.zeros(3, float)): 735 self.driver.glr_translate(self.properties["origin"]) 736 737 axes = self.properties["axes"] 738 if not numpy.allclose(axes, numpy.identity(3, float)): 739 self.driver.glr_rotate_axis(self.properties["rot_x"], axes[0]) 740 self.driver.glr_rotate_axis(self.properties["rot_y"], axes[1]) 741 self.driver.glr_rotate_axis(self.properties["rot_z"], axes[2])
742
743 - def gldl_pop_matrix(self):
744 """Pop the roatated/translated position. 745 """ 746 assert self.driver is not None 747 748 self.driver.glr_pop_matrix()
749
750 - def gldl_render(self, driver, transparent=False):
751 """Compile or force a recompile of this object's gl_draw list, and 752 render the scene. Rendering the scene can be bypassed if 753 this method is called with render = False. 754 """ 755 if self.properties["visible"] is False: 756 return 757 758 self.driver = driver 759 self.gldl_push_matrix() 760 761 ## support multiple rendering images by implementing class 762 ## iterators gldl_iter_multidraw_all() for multiple 763 ## rendering iterations of the GLDrawList and all its children, 764 ## or gldl_iter_multidraw_self() for multiple images of just 765 ## this GLDrawList, rendering the children just once 766 for draw_flag_multi in self.gldl_iter_multidraw_all(): 767 768 for draw_flag_self in self.gldl_iter_multidraw_self(): 769 self.gldl_render_draw_methods(transparent) 770 771 ## render first-level children of this GLDrawList 772 ## which, in turn, will render their children 773 for draw_list in self.glo_iter_children(): 774 if isinstance(draw_list, GLDrawList): 775 draw_list.gldl_render(driver, transparent) 776 777 self.gldl_pop_matrix() 778 self.driver = None
779
780 - def gldl_render_draw_methods(self, transparent):
781 """Render all draw methods. 782 """ 783 for draw_method in self.gldl_draw_method_list: 784 785 ## check if the draw method is currently visible 786 ## skip it if it is not visible 787 visable_property_name = draw_method["visible_property"] 788 if visable_property_name is not None: 789 if self.properties[visable_property_name] is False: 790 continue 791 792 ## transparent methods are only drawn when during the second 793 ## rednering pass 794 if draw_method["transparent"]!=transparent: 795 continue 796 797 ## some draw lists may be not be compiled into a OpenGL draw 798 ## list, these have to be redrawn every time 799 if draw_method["no_gl_compile"] is True or not self.driver.glr_compile_supported(): 800 draw_method["func"]() 801 802 else: 803 if not self.driver.glr_compile_exists(draw_method): 804 self.gldl_draw_method_compile(draw_method) 805 806 elif not self.driver.glr_compile_current(draw_method): 807 self.gldl_draw_method_delete_compiled(draw_method) 808 self.gldl_draw_method_compile(draw_method) 809 810 self.driver.glr_compile_render(draw_method)
811
812 - def gldl_iter_multidraw_all(self):
813 """When implemented as a iterator in a subclass, each time yield 814 is invoked the GLDrawList and all its decendants will be rendered 815 from whatever OpenGL coordinate system is set in the iterator. 816 """ 817 yield True
818
819 - def gldl_iter_multidraw_self(self):
820 """Similar to gldl_iter_multidraw_all, but only this GLDrawList is 821 rendered. The decendant GLDrawLists are rendered normally. 822 """ 823 yield True
824
825 - def gldl_draw(self):
826 """Implement in subclass to draw somthing. 827 """ 828 pass
829
830 - def gldl_draw_transparent(self):
831 """Implement in subclass to draw transparent objects. 832 """ 833 pass
834 835
836 -class GLAxes(GLDrawList):
837 """Draw orthogonal axes in red = x, green = y, blue = z. 838 """
839 - def __init__(self, **args):
840 GLDrawList.__init__(self, **args) 841 self.glo_set_name("Cartesian Axes") 842 self.glo_init_properties(**args)
843
844 - def glo_install_properties(self):
845 GLDrawList.glo_install_properties(self) 846 847 self.glo_add_property( 848 { "name": "line_length", 849 "desc": "Axis Length", 850 "catagory": "Show/Hide", 851 "type": "float", 852 "spin": "1.0-500.0,10.0", 853 "default": 20.0, 854 "action": "recompile" }) 855 self.glo_add_property( 856 { "name": "line_width", 857 "desc": "Axis Radius", 858 "catagory": "Show/Hide", 859 "type": "float", 860 "spin": "0.0-5.0,0.1", 861 "default": 0.1, 862 "action": "recompile" }) 863 self.glo_add_property( 864 { "name": "color_x", 865 "desc": "X Axis Color", 866 "catagory": "Show/Hide", 867 "type": "enum_string", 868 "default": "Red", 869 "enum_list": self.gldl_color_list, 870 "action": "recompile" }) 871 self.glo_add_property( 872 { "name": "color_y", 873 "desc": "Y Axis Color", 874 "catagory": "Show/Hide", 875 "type": "enum_string", 876 "default": "Green", 877 "enum_list": self.gldl_color_list, 878 "action": "recompile" }) 879 self.glo_add_property( 880 { "name": "color_z", 881 "desc": "Z Axis Color", 882 "catagory": "Show/Hide", 883 "type": "enum_string", 884 "default": "Blue", 885 "enum_list": self.gldl_color_list, 886 "action": "recompile" })
887
888 - def gldl_install_draw_methods(self):
889 self.gldl_draw_method_install( 890 { "name": "axes", 891 "func": self.draw_axes, 892 "transparent": False })
893
894 - def draw_axes(self):
895 line_length = self.properties["line_length"] 896 line_width = self.properties["line_width"] 897 898 r, g, b = self.gldl_property_color_rgbf("color_x") 899 self.driver.glr_set_material_rgb(r, g, b) 900 self.driver.glr_axis( 901 numpy.zeros(3, float), 902 numpy.array([line_length, 0.0, 0.0]), 903 line_width) 904 905 r, g, b = self.gldl_property_color_rgbf("color_y") 906 self.driver.glr_set_material_rgb(r, g, b) 907 self.driver.glr_axis( 908 numpy.zeros(3, float), 909 numpy.array([0.0, line_length, 0.0]), 910 line_width) 911 912 r, g, b = self.gldl_property_color_rgbf("color_z") 913 self.driver.glr_set_material_rgb(r, g, b) 914 self.driver.glr_axis( 915 numpy.zeros(3, float), 916 numpy.array([0.0, 0.0, line_length]), 917 line_width)
918 919
920 -class GLUnitCell(GLDrawList):
921 """Draw unit cell. 922 """
923 - def __init__(self, **args):
924 self.unit_cell = args["unit_cell"] 925 926 GLDrawList.__init__(self, **args) 927 self.glo_set_name("Unit Cell") 928 929 self.glo_init_properties( 930 crystal_system = self.unit_cell.space_group.crystal_system, 931 space_group = self.unit_cell.space_group.pdb_name, 932 933 a = self.unit_cell.a, 934 b = self.unit_cell.b, 935 c = self.unit_cell.c, 936 937 alpha = self.unit_cell.calc_alpha_deg(), 938 beta = self.unit_cell.calc_beta_deg(), 939 gamma = self.unit_cell.calc_gamma_deg(), 940 941 **args)
942
943 - def glo_install_properties(self):
944 GLDrawList.glo_install_properties(self) 945 946 self.glo_add_property( 947 { "name": "radius", 948 "desc": "Radius", 949 "catagory": "Show/Hide", 950 "type": "float", 951 "default": 0.25, 952 "action": "recompile" }) 953 954 self.glo_add_property( 955 { "name": "a_color", 956 "desc": "a Cell Divider Color", 957 "catagory": "Show/Hide", 958 "type": "enum_string", 959 "default": "Red", 960 "enum_list": self.gldl_color_list, 961 "action": "recompile" }) 962 self.glo_add_property( 963 { "name": "b_color", 964 "desc": "b Cell Divider Color", 965 "catagory": "Show/Hide", 966 "type": "enum_string", 967 "default": "Green", 968 "enum_list": self.gldl_color_list, 969 "action": "recompile" }) 970 self.glo_add_property( 971 { "name": "c_color", 972 "desc": "c Cell Divider Color", 973 "catagory": "Show/Hide", 974 "type": "enum_string", 975 "default": "Blue", 976 "enum_list": self.gldl_color_list, 977 "action": "recompile" }) 978 979 self.glo_add_property( 980 { "name": "crystal_system", 981 "desc": "Crystal System", 982 "catagory": "Show/Hide", 983 "read_only": True, 984 "type": "string", 985 "default": "", 986 "action": "" }) 987 self.glo_add_property( 988 { "name": "space_group", 989 "desc": "Spacegroup", 990 "catagory": "Show/Hide", 991 "read_only": True, 992 "type": "string", 993 "default": "", 994 "action": "" }) 995 996 self.glo_add_property( 997 { "name": "a", 998 "desc": "a", 999 "catagory": "Show/Hide", 1000 "read_only": True, 1001 "type": "float", 1002 "default": 0.0, 1003 "action": "" }) 1004 self.glo_add_property( 1005 { "name": "b", 1006 "desc": "b", 1007 "catagory": "Show/Hide", 1008 "read_only": True, 1009 "type": "float", 1010 "default": 0.0, 1011 "action": "" }) 1012 self.glo_add_property( 1013 { "name": "c", 1014 "desc": "c", 1015 "catagory": "Show/Hide", 1016 "read_only": True, 1017 "type": "float", 1018 "default": 0.0, 1019 "action": "" }) 1020 1021 self.glo_add_property( 1022 { "name": "alpha", 1023 "desc": "alpha", 1024 "catagory": "Show/Hide", 1025 "read_only": True, 1026 "type": "float", 1027 "default": 0.0, 1028 "action": "" }) 1029 self.glo_add_property( 1030 { "name": "beta", 1031 "desc": "beta", 1032 "catagory": "Show/Hide", 1033 "read_only": True, 1034 "type": "float", 1035 "default": 0.0, 1036 "action": "" }) 1037 self.glo_add_property( 1038 { "name": "gamma", 1039 "desc": "gamma", 1040 "catagory": "Show/Hide", 1041 "read_only": True, 1042 "type": "float", 1043 "default": 0.0, 1044 "action": "" })
1045
1046 - def gldl_install_draw_methods(self):
1047 self.gldl_draw_method_install( 1048 { "name": "unit_cell", 1049 "func": self.draw_unit_cell, 1050 "transparent": False })
1051
1052 - def draw_unit_cell(self):
1053 self.draw_cell(-1, -1, -1, 0, 0, 0)
1054
1055 - def draw_cell(self, x1, y1, z1, x2, y2, z2):
1056 """Draw the unit cell lines in a rectangle starting at fractional 1057 integer coordinates x1, y1, z1, ending at x2, y2, z2. The first set of 1058 coordinates must be <= the second set. 1059 """ 1060 assert x1<=x2 and y1<=y2 and z1<=z2 1061 1062 a = self.unit_cell.calc_frac_to_orth(numpy.array([1.0, 0.0, 0.0])) 1063 b = self.unit_cell.calc_frac_to_orth(numpy.array([0.0, 1.0, 0.0])) 1064 c = self.unit_cell.calc_frac_to_orth(numpy.array([0.0, 0.0, 1.0])) 1065 1066 rad = self.properties["radius"] 1067 1068 rf, gf, bf = self.gldl_property_color_rgbf("a_color") 1069 self.driver.glr_set_material_rgb(rf, gf, bf) 1070 for k in xrange(z1, z2+2): 1071 for j in xrange(y1, y2+2): 1072 p1 = x1*a + j*b + k*c 1073 p2 = (x2+1)*a + j*b + k*c 1074 self.driver.glr_tube(p1, p2, rad) 1075 1076 rf, gf, bf = self.gldl_property_color_rgbf("b_color") 1077 self.driver.glr_set_material_rgb(rf, gf, bf) 1078 for k in xrange(z1, z2+2): 1079 for i in xrange(x1, x2+2): 1080 p1 = i*a + y1*b + k*c 1081 p2 = i*a + (y2+1)*b + k*c 1082 self.driver.glr_tube(p1, p2, rad) 1083 1084 rf, gf, bf = self.gldl_property_color_rgbf("c_color") 1085 self.driver.glr_set_material_rgb(rf, gf, bf) 1086 for j in xrange(y1, y2+2): 1087 for i in xrange(x1, x2+2): 1088 p1 = i*a + j*b + z1*c 1089 p2 = i*a + j*b + (z2+1)*c 1090 self.driver.glr_tube(p1, p2, rad)
1091 1092
1093 -class GLAtomList(GLDrawList):
1094 """OpenGL renderer for a list of atoms. Optional arguments iare: 1095 color, U, U_color. 1096 """ 1097 glal_res_type_color_dict = { 1098 "aliphatic": (0.50, 0.50, 0.50), 1099 "aromatic": (0.75, 0.75, 0.75), 1100 "sulfer-containing": (0.20, 1.00, 0.20), 1101 "alchols": (1.00, 0.60, 0.60), 1102 "acids": (1.00, 0.25, 0.25), 1103 "bases": (0.25, 0.25, 1.00), 1104 "amides": (0.60, 0.60, 1.00)} 1105
1106 - def __init__(self, **args):
1107 1108 self.glal_atom_color_opts = [ 1109 "Color By Element", 1110 "Color By Residue Type", 1111 "Color By Temp Factor", 1112 "Color By Anisotropy" ] 1113 self.glal_atom_color_opts += self.gldl_color_list 1114 1115 self.glal_hidden_atoms_dict = None 1116 self.glal_visible_atoms_dict = None 1117 self.glal_xyzdict = None 1118 1119 GLDrawList.__init__(self, **args) 1120 self.glo_add_update_callback(self.glal_update_properties) 1121 self.glo_init_properties(**args)
1122
1123 - def glo_install_properties(self):
1124 GLDrawList.glo_install_properties(self) 1125 1126 ## Show/Hide 1127 self.glo_add_property( 1128 { "name": "atom_origin", 1129 "desc": "Atom Calculation Origin", 1130 "type": "array(3)", 1131 "hidden": True, 1132 "default": None, 1133 "action": ["recompile", "recalc_positions"] }) 1134 self.glo_add_property( 1135 { "name": "color", 1136 "desc": "Atom Color", 1137 "catagory": "Colors", 1138 "type": "enum_string", 1139 "default": "Color By Element", 1140 "enum_list": self.glal_atom_color_opts, 1141 "action": "" }) 1142 1143 self.glo_add_property( 1144 { "name": "color_setting", 1145 "desc": "Atom Color", 1146 "catagory": "Colors", 1147 "type": "string", 1148 "hidden": True, 1149 "default": "Color By Element", 1150 "action": "recompile" }) 1151 self.glo_add_property( 1152 { "name": "color_blue", 1153 "desc": "Color Range Blue", 1154 "catagory": "Colors", 1155 "type": "float", 1156 "default": 0.0, 1157 "action": "recompile" }) 1158 self.glo_add_property( 1159 { "name": "color_red", 1160 "desc": "Color Range Red", 1161 "catagory": "Colors", 1162 "type": "float", 1163 "default": 1.0, 1164 "action": "recompile" }) 1165 1166 self.glo_add_property( 1167 { "name": "symmetry", 1168 "desc": "Show Symmetry Equivelants", 1169 "catagory": "Show/Hide", 1170 "type": "boolean", 1171 "default": False, 1172 "action": "redraw" }) 1173 self.glo_add_property( 1174 { "name": "main_chain_visible", 1175 "desc": "Show Main Chain Atoms", 1176 "catagory": "Show/Hide", 1177 "type": "boolean", 1178 "default": True, 1179 "action": ["recompile", "recalc_positions"] }) 1180 self.glo_add_property( 1181 { "name": "oatm_visible", 1182 "desc": "Show Main Chain Carbonyl Atoms", 1183 "catagory": "Show/Hide", 1184 "type": "boolean", 1185 "default": True, 1186 "action": ["recompile", "recalc_positions"] }) 1187 self.glo_add_property( 1188 { "name": "side_chain_visible", 1189 "desc": "Show Side Chain Atoms", 1190 "catagory": "Show/Hide", 1191 "type": "boolean", 1192 "default": True, 1193 "action": ["recompile", "recalc_positions"] }) 1194 self.glo_add_property( 1195 { "name": "hetatm_visible", 1196 "desc": "Show Hetrogen Atoms", 1197 "catagory": "Show/Hide", 1198 "type": "boolean", 1199 "default": True, 1200 "action": ["recompile", "recalc_positions"] }) 1201 self.glo_add_property( 1202 { "name": "water_visible", 1203 "desc": "Show Waters", 1204 "catagory": "Show/Hide", 1205 "type": "boolean", 1206 "default": False, 1207 "action": ["recompile", "recalc_positions"] }) 1208 self.glo_add_property( 1209 { "name": "hydrogen_visible", 1210 "desc": "Show Hydrogens", 1211 "catagory": "Show/Hide", 1212 "type": "boolean", 1213 "default": False, 1214 "action": ["recompile", "recalc_positions"] }) 1215 1216 ## labels 1217 self.glo_add_property( 1218 { "name": "labels", 1219 "desc": "Show Atom Lables", 1220 "catagory": "Show/Hide", 1221 "type": "boolean", 1222 "default": False, 1223 "action": "recompile_labels" }) 1224 self.glo_add_property( 1225 { "name": "label_size", 1226 "desc": "Label Size", 1227 "catagory": "Labels", 1228 "type": "float", 1229 "default": 5.0, 1230 "action": "recompile_labels" }) 1231 self.glo_add_property( 1232 { "name": "label_color", 1233 "desc": "Label Color", 1234 "catagory": "Labels", 1235 "type": "enum_string", 1236 "default": "White", 1237 "enum_list": self.gldl_color_list, 1238 "action": "recompile_labels" }) 1239 self.glo_add_property( 1240 { "name": "label_style", 1241 "desc": "Label Style", 1242 "catagory": "Labels", 1243 "type": "enum_string", 1244 "default": "Residue", 1245 "enum_list": ["Residue", "All Atoms", "CA Atoms"], 1246 "action": "recompile_labels" }) 1247 1248 ## lines 1249 self.glo_add_property( 1250 { "name": "lines", 1251 "desc": "Draw Atom Bond Lines", 1252 "catagory": "Show/Hide", 1253 "type": "boolean", 1254 "default": True, 1255 "action": "recompile_lines" }) 1256 self.glo_add_property( 1257 { "name": "line_width", 1258 "desc": "Bond Line Size", 1259 "catagory": "Bond Lines", 1260 "type": "float", 1261 "spin": PROP_LINE_RANGE, 1262 "default": 1.0, 1263 "action": "recompile_lines" }) 1264 1265 ## Ball/Stick 1266 self.glo_add_property( 1267 { "name": "ball_stick", 1268 "desc": "Draw Ball/Sticks", 1269 "catagory": "Show/Hide", 1270 "type": "boolean", 1271 "default": False, 1272 "action": "recompile_ball_stick" }) 1273 self.glo_add_property( 1274 { "name": "ball_radius", 1275 "desc": "Atom (Ball) Radius", 1276 "catagory": "Ball/Stick", 1277 "type": "float", 1278 "default": 0.1, 1279 "action": "recompile_ball_stick" }) 1280 self.glo_add_property( 1281 { "name": "stick_radius", 1282 "desc": "Bond (Stick) Radius", 1283 "catagory": "Ball/Stick", 1284 "type": "float", 1285 "default": 0.1, 1286 "action": "recompile_ball_stick" }) 1287 1288 ## cpk 1289 self.glo_add_property( 1290 { "name": "cpk", 1291 "desc": "Draw CPK Spheres", 1292 "catagory": "Show/Hide", 1293 "type": "boolean", 1294 "default": False, 1295 "action": "recompile_cpk" }) 1296 self.glo_add_property( 1297 { "name": "cpk_opacity_occupancy", 1298 "desc": "Set Opacity by Atom Occupancy", 1299 "catagory": "CPK", 1300 "type": "boolean", 1301 "default": False, 1302 "action": "recompile_cpk" }) 1303 self.glo_add_property( 1304 { "name": "cpk_scale_radius", 1305 "desc": "Scale CPK Radius", 1306 "catagory": "CPK", 1307 "type": "float", 1308 "range": "0.0-5.0,0.1", 1309 "default": 1.0, 1310 "action": "recompile_cpk" }) 1311 self.glo_add_property( 1312 { "name": "cpk_opacity", 1313 "desc": "CPK Sphere Opacity", 1314 "catagory": "CPK", 1315 "type": "float", 1316 "range": PROP_OPACITY_RANGE, 1317 "default": 1.00, 1318 "action": "recompile_cpk" }) 1319 self.glo_add_property( 1320 { "name": "sphere_quality", 1321 "desc": "CPK Sphere Quality", 1322 "catagory": "CPK", 1323 "type": "integer", 1324 "range": "5-36,5", 1325 "default": 10, 1326 "action": "recompile_cpk" }) 1327 1328 ## trace 1329 self.glo_add_property( 1330 { "name": "trace", 1331 "desc": "Draw Backbone Trace", 1332 "catagory": "Show/Hide", 1333 "type": "boolean", 1334 "default": False, 1335 "action": "recompile_trace" }) 1336 self.glo_add_property( 1337 { "name": "trace_radius", 1338 "desc": "Trace Radius", 1339 "catagory": "Trace", 1340 "type": "float", 1341 "default": 0.2, 1342 "action": "recompile_trace" }) 1343 self.glo_add_property( 1344 { "name": "trace_color", 1345 "desc": "Trace Color", 1346 "catagory": "Trace", 1347 "type": "enum_string", 1348 "default": "White", 1349 "enum_list": self.gldl_color_list, 1350 "action": "recompile_trace" }) 1351 1352 ## ADPs 1353 self.glo_add_property( 1354 { "name": "adp_prob", 1355 "desc": "Isoprobability Magnitude", 1356 "catagory": "ADP", 1357 "type": "integer", 1358 "range": PROP_PROBABILTY_RANGE, 1359 "default": 50, 1360 "action": ["recompile_Uaxes", "recompile_Uellipse"] }) 1361 self.glo_add_property( 1362 { "name": "U", 1363 "desc": "Show Thermal Axes", 1364 "catagory": "Show/Hide", 1365 "type": "boolean", 1366 "default": False, 1367 "action": "recompile_Uaxes" }) 1368 self.glo_add_property( 1369 { "name": "U_color", 1370 "desc": "Thermal Axes Color", 1371 "catagory": "ADP", 1372 "type": "enum_string", 1373 "default": "White", 1374 "enum_list": self.gldl_color_list, 1375 "action": "recompile_Uaxes" }) 1376 self.glo_add_property( 1377 { "name": "ellipse", 1378 "desc": "Show Thermal Ellipsoids", 1379 "catagory": "Show/Hide", 1380 "type": "boolean", 1381 "default": False, 1382 "action": "recompile_Uellipse" }) 1383 self.glo_add_property( 1384 { "name": "ellipse_opacity", 1385 "desc": "Thermal Ellipsoid Opacity", 1386 "catagory": "ADP", 1387 "type": "float", 1388 "range": PROP_OPACITY_RANGE, 1389 "default": 1.0, 1390 "action": "recompile_Uellipse" }) 1391 self.glo_add_property( 1392 { "name": "rms", 1393 "desc": "Show Thermal Peanuts", 1394 "catagory": "Show/Hide", 1395 "type": "boolean", 1396 "default": False, 1397 "action": "recompile_Urms" }) 1398 self.glo_add_property( 1399 { "name": "rms_opacity", 1400 "desc": "Peanut Surface Opacity", 1401 "catagory": "ADP", 1402 "type": "float", 1403 "range": PROP_OPACITY_RANGE, 1404 "default": 1.0, 1405 "action": "recompile_Urms" }) 1406 self.glo_add_property( 1407 { "name": "show_sig_u", 1408 "desc": "Show +/- SIGUIJ Ellipsoids", 1409 "catagory": "ADP", 1410 "type": "boolean", 1411 "default": False, 1412 "action": "recompile_Uellipse" }) 1413 self.glo_add_property( 1414 { "name": "sig_u_opacity", 1415 "desc": "SIGUIJ Ellipsoid Opacity", 1416 "catagory": "ADP", 1417 "type": "float", 1418 "range": PROP_OPACITY_RANGE, 1419 "default": 0.5, 1420 "action": "recompile_Uellipse" })
1421
1422 - def gldl_install_draw_methods(self):
1423 self.gldl_draw_method_install( 1424 { "name": "labels", 1425 "func": self.glal_draw_labels, 1426 "no_gl_compile": True, 1427 "transparent": False, 1428 "visible_property": "labels", 1429 "recompile_action": "recompile_labels" }) 1430 self.gldl_draw_method_install( 1431 { "name": "lines", 1432 "func": self.glal_draw_lines, 1433 "transparent": False, 1434 "visible_property": "lines", 1435 "recompile_action": "recompile_lines" }) 1436 self.gldl_draw_method_install( 1437 { "name": "trace", 1438 "func": self.glal_draw_trace, 1439 "transparent": False, 1440 "visible_property": "trace", 1441 "recompile_action": "recompile_trace" }) 1442 self.gldl_draw_method_install( 1443 { "name": "ball_stick", 1444 "func": self.glal_draw_ball_stick, 1445 "transparent": False, 1446 "visible_property": "ball_stick", 1447 "recompile_action": "recompile_ball_stick" }) 1448 self.gldl_draw_method_install( 1449 { "name": "cpk", 1450 "func": self.glal_draw_cpk, 1451 "visible_property": "cpk", 1452 "opacity_property": "cpk_opacity", 1453 "recompile_action": "recompile_cpk" }) 1454 self.gldl_draw_method_install( 1455 { "name": "Uaxes", 1456 "func": self.glal_draw_Uaxes, 1457 "transparent": False, 1458 "visible_property": "U", 1459 "recompile_action": "recompile_Uaxes" }) 1460 self.gldl_draw_method_install( 1461 { "name": "Uellipse", 1462 "func": self.glal_draw_Uellipse, 1463 "visible_property": "ellipse", 1464 "opacity_property": "ellipse_opacity", 1465 "recompile_action": "recompile_Uellipse" }) 1466 self.gldl_draw_method_install( 1467 { "name": "Urms", 1468 "func": self.glal_draw_Urms, 1469 "visible_property": "rms", 1470 "opacity_property": "rms_opacity", 1471 "recompile_action": "recompile_Urms" })
1472
1473 - def glal_update_color_value(self, value):
1474 """Configure the color_value property from the value argument. 1475 """ 1476 ## selects one of the named color functions 1477 if value in self.glal_atom_color_opts: 1478 1479 if value=="Color By Temp Factor": 1480 ## calculate the min/max temp factor of the atoms 1481 ## and auto-set the low/high color range 1482 min_tf = None 1483 max_tf = None 1484 for atm in self.glal_iter_atoms(): 1485 if min_tf is None: 1486 min_tf = atm.temp_factor 1487 max_tf = atm.temp_factor 1488 continue 1489 min_tf = min(atm.temp_factor, min_tf) 1490 max_tf = max(atm.temp_factor, max_tf) 1491 1492 self.properties.update( 1493 color_blue = min_tf, 1494 color_red = max_tf, 1495 color_setting = value) 1496 return 1497 1498 elif value=="Color By Anisotropy": 1499 self.properties.update( 1500 color_blue = 1.0, 1501 color_red = 0.0, 1502 color_setting = value) 1503 return 1504 1505 try: 1506 self.properties.update(color_setting = Colors.COLOR_RGBF[value.lower()]) 1507 except KeyError: 1508 pass 1509 else: 1510 return 1511 1512 self.properties.update(color_setting=value) 1513 1514 ## maybe the color is in R,G,B format 1515 try: 1516 r, g, b = value.split(",") 1517 except ValueError: 1518 pass 1519 else: 1520 color_setting = (float(r), float(g), float(b)) 1521 self.properties.update(color_setting=color_setting) 1522 return
1523
1524 - def glal_update_properties(self, updates, actions):
1525 ## rebuild visible/hidden dictionaries 1526 if "recalc_positions" in actions: 1527 self.glal_hidden_atoms_dict = None 1528 self.glal_visible_atoms_dict = None 1529 self.glal_xyzdict = None 1530 1531 ## update color 1532 if "color" in updates: 1533 self.glal_update_color_value(updates["color"])
1534
1535 - def gldl_iter_multidraw_self(self):
1536 """Specialized draw list invokation to recycle the draw list for 1537 symmetry related copies. Cartesian versions of the symmetry rotation 1538 and translation operators are generated by GLStructure/UnitCell 1539 classes. 1540 """ 1541 if self.properties["symmetry"] is False: 1542 yield True 1543 1544 else: 1545 1546 gl_struct = self.glo_get_glstructure() 1547 if gl_struct is None: 1548 yield True 1549 1550 else: 1551 for symop in gl_struct.iter_orth_symops(): 1552 self.driver.glr_push_matrix() 1553 1554 if self.properties["atom_origin"] != None: 1555 self.driver.glr_translate(-self.properties["atom_origin"]) 1556 1557 self.driver.glr_mult_matrix_Rt(symop.R, symop.t) 1558 1559 if self.properties["atom_origin"] != None: 1560 self.driver.glr_translate(self.properties["atom_origin"]) 1561 1562 yield True 1563 self.driver.glr_pop_matrix()
1564
1565 - def glal_iter_atoms(self):
1566 """Implement in a subclass to iterate over all atoms which 1567 need to be drawn. 1568 """ 1569 pass
1570
1571 - def glal_iter_fragments(self):
1572 """Implement in a subclass to iterate one Fragment object 1573 at a time, in order. This implementation works with any 1574 implementation of glal_iter_atoms, but is very inefficent. 1575 """ 1576 struct = Structure.Structure() 1577 memo = {} 1578 1579 for atm in self.glal_iter_atoms(): 1580 struct.add_atom(copy.deepcopy(atm, memo)) 1581 1582 for frag in struct.iter_fragments(): 1583 yield frag
1584
1585 - def glal_iter_chains(self):
1586 """Implement in a subclass to iterate one Chain object 1587 at a time, in order. This implementation works with any 1588 implementation of glal_iter_atoms, but is very inefficent. 1589 """ 1590 struct = Structure.Structure() 1591 memo = {} 1592 1593 for atm in self.glal_iter_atoms(): 1594 struct.add_atom(copy.deepcopy(atm, memo)) 1595 1596 for chain in struct.iter_chains(): 1597 yield chain
1598
1599 - def glal_iter_models(self):
1600 """Implement in a subclass to iterate one Model object 1601 at a time, in order. This implementation works with any 1602 implementation of glal_iter_atoms, but is very inefficent. 1603 """ 1604 struct = Structure.Structure() 1605 memo = {} 1606 1607 for atm in self.glal_iter_atoms(): 1608 struct.add_atom(copy.deepcopy(atm, memo)) 1609 1610 for model in struct.iter_models(): 1611 yield model
1612
1613 - def glal_iter_atoms_filtered(self):
1614 """Iterate all atoms and yield the tuble (atom, visible_flag). 1615 """ 1616 aa_bb_atoms = ("N", "CA", "C", "O") 1617 na_bb_atoms = ("P", "O5*", "C5*", "C4*", "C3*", "O3*") 1618 1619 main_chain_visible = self.properties["main_chain_visible"] 1620 oatm_visible = self.properties["oatm_visible"] 1621 side_chain_visible = self.properties["side_chain_visible"] 1622 hetatm_visible = self.properties["hetatm_visible"] 1623 water_visible = self.properties["water_visible"] 1624 hydrogen_visible = self.properties["hydrogen_visible"] 1625 1626 for atm in self.glal_iter_atoms(): 1627 if hydrogen_visible is False: 1628 if atm.element=="H": 1629 yield atm, False 1630 continue 1631 1632 frag = atm.get_fragment() 1633 1634 if frag.is_amino_acid(): 1635 if oatm_visible is False and atm.name == "O": 1636 yield atm, False 1637 continue 1638 1639 elif main_chain_visible and side_chain_visible: 1640 yield atm, True 1641 continue 1642 1643 elif main_chain_visible and not side_chain_visible: 1644 if atm.name in aa_bb_atoms: 1645 yield atm, True 1646 continue 1647 1648 elif not main_chain_visible and side_chain_visible: 1649 if atm.name not in aa_bb_atoms: 1650 yield atm, True 1651 continue 1652 1653 yield atm, False 1654 continue 1655 1656 elif frag.is_nucleic_acid(): 1657 if main_chain_visible and side_chain_visible: 1658 yield atm, True 1659 continue 1660 1661 elif main_chain_visible and not side_chain_visible: 1662 if atm.name in na_bb_atoms: 1663 yield atm, True 1664 continue 1665 1666 elif not main_chain_visible and side_chain_visible: 1667 if atm.name not in na_bb_atoms: 1668 yield atm, True 1669 continue 1670 1671 yield atm, False 1672 continue 1673 1674 elif frag.is_water() is True: 1675 if water_visible is True: 1676 yield atm, True 1677 continue 1678 1679 yield atm, False 1680 continue 1681 1682 elif hetatm_visible is True: 1683 yield atm, True 1684 continue 1685 1686 else: 1687 yield atm, False 1688 continue
1689
1690 - def glal_rebuild_atom_dicts(self):
1691 """When a atom selection setting or origin changes, the atom 1692 dictionaries need to be rebuilt. 1693 """ 1694 self.glal_hidden_atoms_dict = {} 1695 self.glal_visible_atoms_dict = {} 1696 self.glal_xyzdict = GeometryDict.XYZDict(5.0) 1697 1698 for atm, visible in self.glal_iter_atoms_filtered(): 1699 pos = self.glal_calc_position(atm.position) 1700 1701 if visible is True: 1702 self.glal_visible_atoms_dict[atm] = pos 1703 self.glal_xyzdict.add(pos, atm) 1704 else: 1705 self.glal_hidden_atoms_dict[atm] = pos
1706
1707 - def glal_iter_visible_atoms(self):
1708 """Iterate over all visible atoms yielding the 2-tuple (atm, position). 1709 """ 1710 if self.glal_visible_atoms_dict is None: 1711 self.glal_rebuild_atom_dicts() 1712 1713 for atm, pos in self.glal_visible_atoms_dict.iteritems(): 1714 yield atm, pos
1715
1716 - def glal_calc_position(self, position):
1717 """Calculate a position vector with respect to the 1718 proeprty: atom_origin. 1719 """ 1720 if self.properties["atom_origin"] is not None: 1721 return position - self.properties["atom_origin"] 1722 return position
1723
1724 - def glal_calc_color_range(self, value):
1725 """Return a RGBF 3-tuple color of a color gradient for value. 1726 """ 1727 blue = self.properties["color_blue"] 1728 red = self.properties["color_red"] 1729 width = abs(red - blue) 1730 1731 if red>blue: 1732 if value>=red: 1733 return (1.0, 0.0, 0.0) 1734 elif value<=blue: 1735 return (0.0, 0.0, 1.0) 1736 1737 b = 1.0 - ((value - blue) / width) 1738 return (1.0-b, 0.0, b) 1739 1740 else: 1741 if value<=red: 1742 return (1.0, 0.0, 0.0) 1743 elif value>=blue: 1744 return (0.0, 0.0, 1.0) 1745 1746 b = 1.0 - ((value - red) / width) 1747 return (b, 0.0, 1.0-b)
1748
1749 - def glal_calc_color(self, atom):
1750 """Sets the open-gl color for the atom. 1751 """ 1752 ## individual atom colors 1753 if hasattr(atom, "glal_color"): 1754 return atom.glal_color 1755 1756 setting = self.properties["color_setting"] 1757 if isinstance(setting, tuple): 1758 return setting 1759 1760 if setting=="Color By Element": 1761 element = Library.library_get_element_desc(atom.element) 1762 try: 1763 return element.color_rgbf 1764 except AttributeError: 1765 return Colors.COLOR_RGBF["white"] 1766 1767 elif setting=="Color By Residue Type": 1768 monomer = Library.library_get_monomer_desc(atom.res_name) 1769 try: 1770 return self.glal_res_type_color_dict[monomer.chem_type] 1771 except KeyError: 1772 return Colors.COLOR_RGBF["white"] 1773 1774 elif setting=="Color By Temp Factor": 1775 return self.glal_calc_color_range(atom.temp_factor) 1776 1777 elif setting=="Color By Anisotropy": 1778 return self.glal_calc_color_range(atom.calc_anisotropy()) 1779 1780 raise ValueError, "glal_calc_color: bad color setting %s" % (str(setting))
1781
1782 - def glal_calc_color_label(self):
1783 """Returns the label color. 1784 """ 1785 return self.gldl_property_color_rgbf("label_color")
1786
1787 - def glal_calc_color_trace(self):
1788 """Returns the trace color. 1789 """ 1790 return self.gldl_property_color_rgbf("trace_color")
1791
1792 - def glal_calc_color_Uaxes(self, atom):
1793 """Return the color to be used for thermal axes. 1794 """ 1795 return self.gldl_property_color_rgbf("U_color")
1796
1797 - def glal_calc_color_Uellipse(self, atom):
1798 """Return the color to be used for thermal ellipse. 1799 """ 1800 return self.glal_calc_color(atom)
1801
1802 - def glal_calc_color_Urms(self, atom):
1803 """Return the color to be used for thermal peanuts. 1804 """ 1805 return self.glal_calc_color(atom)
1806
1807 - def glal_calc_U(self, atom):
1808 """Return the ADP U tensor for the atom 1809 """ 1810 return atom.get_U()
1811
1812 - def glal_draw_labels(self):
1813 """Draws atom lables. 1814 """ 1815 ## driver optimization 1816 glr_push_matrix = self.driver.glr_push_matrix 1817 glr_pop_matrix = self.driver.glr_pop_matrix 1818 glr_mult_matrix_R = self.driver.glr_mult_matrix_R 1819 glr_translate = self.driver.glr_translate 1820 glr_text = self.driver.glr_text 1821 ## 1822 1823 style = self.properties["label_style"].lower() 1824 scale = self.properties["label_size"] 1825 self.driver.glr_set_material_rgb(*self.glal_calc_color_label()) 1826 1827 viewer = self.gldl_get_glviewer() 1828 R = viewer.properties["R"] 1829 Ri = numpy.transpose(R) 1830 1831 ## this vecor is needed to adjust for origin/atom_origin 1832 ## changes, but it does not account for object rotation yet 1833 cv = self.properties["origin"] 1834 1835 ## shift back to the view window coordinate system so the 1836 ## labels can be drawn in the plane perpendicular to the viewer's 1837 ## z axis 1838 glr_push_matrix() 1839 glr_mult_matrix_R(Ri) 1840 1841 for atm, pos in self.glal_iter_visible_atoms(): 1842 1843 ## amino acid residues 1844 if atm.get_fragment().is_amino_acid(): 1845 1846 ## just label chain/residue 1847 if style=="residue": 1848 if atm.name!="CA": 1849 continue 1850 text = "%s%s" % (atm.chain_id, atm.fragment_id) 1851 1852 ## full lables for CA atoms only 1853 elif style=="ca atoms": 1854 if atm.name!="CA": 1855 continue 1856 1857 if atm.alt_loc=="": 1858 text = "%s %s %s %s" % ( 1859 atm.name, 1860 atm.res_name, 1861 atm.fragment_id, 1862 atm.chain_id) 1863 else: 1864 text = "%s(%s) %s %s %s" % ( 1865 atm.name, 1866 atm.alt_loc, 1867 atm.res_name, 1868 atm.fragment_id, 1869 atm.chain_id) 1870 1871 ## labels for all atoms 1872 elif atm.name=="CA": 1873 if atm.alt_loc=="": 1874 text = "%s %s %s %s" % ( 1875 atm.name, 1876 atm.res_name, 1877 atm.fragment_id, 1878 atm.chain_id) 1879 else: 1880 text = "%s(%s) %s %s %s" % ( 1881 atm.name, 1882 atm.alt_loc, 1883 atm.res_name, 1884 atm.fragment_id, 1885 atm.chain_id) 1886 else: 1887 if atm.alt_loc=="": 1888 text = atm.name 1889 else: 1890 text = "%s(%s)" % (atm.name, atm.alt_loc) 1891 1892 ## all other residues 1893 else: 1894 if atm.alt_loc=="": 1895 text = "%s %s %s %s" % ( 1896 atm.name, 1897 atm.res_name, 1898 atm.fragment_id, 1899 atm.chain_id) 1900 else: 1901 text = "%s(%s) %s %s %s" % ( 1902 atm.name, 1903 atm.alt_loc, 1904 atm.res_name, 1905 atm.fragment_id, 1906 atm.chain_id) 1907 1908 relative_pos = numpy.dot(R, pos + cv) 1909 glr_push_matrix() 1910 glr_translate(relative_pos + numpy.array([0.0, 0.0, 2.0])) 1911 glr_text(text, scale) 1912 glr_pop_matrix() 1913 1914 glr_pop_matrix()
1915
1916 - def glal_draw_cpk(self):
1917 """Draw a atom as a CPK sphere. 1918 """ 1919 ## driver optimization 1920 glr_set_material_rgba = self.driver.glr_set_material_rgba 1921 glr_sphere = self.driver.glr_sphere 1922 ## 1923 1924 for atm, pos in self.glal_iter_visible_atoms(): 1925 edesc = Library.library_get_element_desc(atm.element) 1926 if edesc is not None: 1927 radius = edesc.vdw_radius 1928 else: 1929 radius = 2.0 1930 1931 r, g, b = self.glal_calc_color(atm) 1932 glr_set_material_rgba(r, g, b, self.properties["cpk_opacity"]) 1933 1934 glr_sphere( 1935 pos, 1936 self.properties["cpk_scale_radius"] * radius, 1937 self.properties["sphere_quality"])
1938
1939 - def glal_draw_Uaxes(self):
1940 """Draw thermal axes at the given ADP probability level. 1941 """ 1942 ## driver optimization 1943 glr_Uaxes = self.driver.glr_Uaxes 1944 ## 1945 1946 prob = self.properties["adp_prob"] 1947 1948 for atm, pos in self.glal_iter_visible_atoms(): 1949 rgb = self.glal_calc_color_Uaxes(atm) 1950 U = self.glal_calc_U(atm) 1951 if U is None: 1952 continue 1953 glr_Uaxes(pos, U, prob, rgb, 1.0)
1954
1955 - def glal_draw_Uellipse(self):
1956 """Draw the ADP determined probability ellipsoid. 1957 """ 1958 ## driver optimization 1959 glr_set_material_rgba = self.driver.glr_set_material_rgba 1960 glr_Uellipse = self.driver.glr_Uellipse 1961 ## 1962 1963 opacity = self.properties["ellipse_opacity"] 1964 prob = self.properties["adp_prob"] 1965 1966 show_sig_u = self.properties["show_sig_u"] 1967 sig_u_opacity = self.properties["sig_u_opacity"] 1968 1969 for atm, pos in self.glal_iter_visible_atoms(): 1970 U = self.glal_calc_U(atm) 1971 if U is None: 1972 continue 1973 1974 r, g, b = self.glal_calc_color_Uellipse(atm) 1975 1976 if show_sig_u is True and atm.sig_U is not None: 1977 glr_set_material_rgba(r, g, b,sig_u_opacity) 1978 glr_Uellipse(pos, U - atm.sig_U, prob) 1979 1980 glr_set_material_rgba(r, g, b, opacity) 1981 glr_Uellipse(pos, U, prob) 1982 1983 if show_sig_u is True and atm.sig_U is not None: 1984 glr_set_material_rgba(r, g, b,sig_u_opacity) 1985 glr_Uellipse(pos, U + atm.sig_U, prob)
1986
1987 - def glal_draw_Urms(self):
1988 """Draw the ADP determined RMS displacement surface. 1989 """ 1990 ## driver optimization 1991 glr_set_material_rgba = self.driver.glr_set_material_rgba 1992 glr_Urms = self.driver.glr_Urms 1993 ## 1994 1995 opacity = self.properties["rms_opacity"] 1996 1997 for atm, pos in self.glal_iter_visible_atoms(): 1998 U = self.glal_calc_U(atm) 1999 if U is None: 2000 continue 2001 2002 r, g, b = self.glal_calc_color_Urms(atm) 2003 glr_set_material_rgba(r, g, b, opacity) 2004 glr_Urms(pos, U)
2005
2006 - def glal_draw_lines(self):
2007 """Draw a atom using bond lines only. 2008 """ 2009 ## driver optimization 2010 glr_set_material_rgb = self.driver.glr_set_material_rgb 2011 glr_line = self.driver.glr_line 2012 glr_cross = self.driver.glr_cross 2013 ## 2014 2015 self.driver.glr_lighting_disable() 2016 self.driver.glr_set_line_width(self.properties["line_width"]) 2017 2018 for atm1, pos1 in self.glal_iter_visible_atoms(): 2019 glr_set_material_rgb(*self.glal_calc_color(atm1)) 2020 2021 if len(atm1.bond_list)>0: 2022 ## if there are bonds, then draw the lines 1/2 way to the 2023 ## bonded atoms 2024 for bond in atm1.iter_bonds(): 2025 atm2 = bond.get_partner(atm1) 2026 2027 try: 2028 pos2 = self.glal_visible_atoms_dict[atm2] 2029 except KeyError: 2030 if self.glal_hidden_atoms_dict.has_key(atm2): 2031 continue 2032 else: 2033 pos2 = self.glal_calc_position(atm2.position) 2034 2035 end = pos1 + ((pos2 - pos1) / 2) 2036 glr_line(pos1, end) 2037 2038 ## draw a cross for non-bonded atoms 2039 else: 2040 glr_cross( 2041 pos1, 2042 self.glal_calc_color(atm1), 2043 self.properties["line_width"])
2044
2045 - def glal_draw_ball_stick(self):
2046 """Draw atom with ball/stick model. 2047 """ 2048 ## driver optimization 2049 glr_set_material_rgb = self.driver.glr_set_material_rgb 2050 glr_tube = self.driver.glr_tube 2051 glr_sphere = self.driver.glr_sphere 2052 ## 2053 2054 ball_radius = self.properties["ball_radius"] 2055 stick_radius = self.properties["stick_radius"] 2056 2057 for atm1, pos1 in self.glal_iter_visible_atoms(): 2058 glr_set_material_rgb(*self.glal_calc_color(atm1)) 2059 2060 ## if there are bonds, then draw the lines 1/2 way to the 2061 ## bonded atoms 2062 for bond in atm1.iter_bonds(): 2063 atm2 = bond.get_partner(atm1) 2064 2065 try: 2066 pos2 = self.glal_visible_atoms_dict[atm2] 2067 except KeyError: 2068 if self.glal_hidden_atoms_dict.has_key(atm2): 2069 continue 2070 else: 2071 pos2 = self.glal_calc_position(atm2.position) 2072 2073 end = pos1 + ((pos2 - pos1) / 2) 2074 glr_tube(pos1, end, stick_radius) 2075 2076 ## draw ball 2077 glr_sphere(pos1, ball_radius, 10)
2078
2079 - def glal_draw_cross(self, atm, pos):
2080 """Draws atom with a cross of lines. 2081 """ 2082 self.driver.glr_cross(pos, self.glal_calc_color(atm), self.properties["line_width"])
2083
2084 - def glal_draw_trace(self):
2085 """Draws trace over all polymer backbone atoms. 2086 """ 2087 ## driver optimization 2088 glr_set_material_rgb = self.driver.glr_set_material_rgb 2089 glr_tube = self.driver.glr_tube 2090 glr_sphere = self.driver.glr_sphere 2091 ## 2092 2093 trace_radius = self.properties["trace_radius"] 2094 r, g, b = self.glal_calc_color_trace() 2095 2096 glr_set_material_rgb(r, g, b) 2097 2098 for chain in self.glal_iter_chains(): 2099 2100 last_atm = None 2101 2102 for frag in chain.iter_fragments(): 2103 2104 if frag.is_amino_acid() is True: 2105 backbone_atoms = ["CA"] 2106 prev_atom_path = ["N", "C", "CA"] 2107 elif frag.is_nucleic_acid() is True: 2108 backbone_atoms = ["P", "O5*", "C5*", "C4*", "C3*", "O3*"] 2109 prev_atom_path = None 2110 else: 2111 last_atm = None 2112 prev_atom_path = None 2113 continue 2114 2115 for name in backbone_atoms: 2116 atm = frag.get_atom(name) 2117 if atm is None: 2118 last_atm = None 2119 continue 2120 2121 if prev_atom_path is not None: 2122 prev_atm = atm.get_bonded_atom(prev_atom_path) 2123 if prev_atm != last_atm: 2124 last_atm = atm 2125 continue 2126 2127 if last_atm is None: 2128 last_atm = atm 2129 continue 2130 2131 ## if there are alternate conformations, make sure to 2132 ## trace them all in the backbone trace 2133 2134 if last_atm.alt_loc=="" and atm.alt_loc=="": 2135 lpos = self.glal_calc_position(last_atm.position) 2136 pos = self.glal_calc_position(atm.position) 2137 glr_sphere(lpos, trace_radius, 12) 2138 glr_tube(lpos, pos, trace_radius) 2139 2140 elif last_atm.alt_loc=="" and atm.alt_loc!="": 2141 lpos = self.glal_calc_position(last_atm.position) 2142 2143 for aa in atm.iter_alt_loc(): 2144 pos = self.glal_calc_position(aa.position) 2145 glr_sphere(lpos, trace_radius, 12) 2146 glr_tube(lpos, pos, trace_radius) 2147 2148 elif last_atm.alt_loc!="" and atm.alt_loc=="": 2149 pos = self.glal_calc_position(atm.position) 2150 2151 for laa in last_atm.iter_alt_loc(): 2152 lpos = self.glal_calc_position(laa.position) 2153 glr_sphere(lpos, trace_radius, 12) 2154 glr_tube(lpos, pos, trace_radius) 2155 2156 elif last_atm.alt_loc!="" and atm.alt_loc!="": 2157 for aa in atm.iter_alt_loc(): 2158 for laa in last_atm.iter_alt_loc(): 2159 if aa.alt_loc!=laa.alt_loc: 2160 continue 2161 lpos = self.glal_calc_position(laa.position) 2162 pos = self.glal_calc_position(aa.position) 2163 glr_sphere(lpos, trace_radius, 12) 2164 glr_tube(lpos, pos, trace_radius) 2165 2166 last_atm = atm 2167 2168 if last_atm is not None: 2169 for laa in last_atm.iter_alt_loc(): 2170 lpos = self.glal_calc_position(laa.position) 2171 glr_sphere(lpos, trace_radius, 10)
2172 2173
2174 -class GLChain(GLAtomList):
2175 """Visualization object for mmLib.Structure.Chain. 2176 """
2177 - def __init__(self, **args):
2178 GLAtomList.__init__(self, **args) 2179 self.chain = args["chain"] 2180 self.glo_init_properties(**args)
2181
2182 - def glo_install_properties(self):
2184
2185 - def glo_name(self):
2186 return "Chain %s" % (self.chain.chain_id)
2187
2188 - def glal_iter_atoms(self):
2189 return self.chain.iter_all_atoms()
2190
2191 - def glal_iter_fragments(self):
2192 """The GLAtomList implementation of this is slow. 2193 """ 2194 return self.chain.iter_fragments()
2195
2196 - def glal_iter_chains(self):
2197 """The GLAtomList implementation of this is slow. 2198 """ 2199 yield self.chain
2200 2201
2202 -class GLStructure(GLDrawList):
2203 """Visualization object for a mmLib.Structure.Structure. 2204 """
2205 - def __init__(self, **args):
2206 GLDrawList.__init__(self, **args) 2207 self.struct = args["struct"] 2208 2209 ## add GLObject children 2210 self.glo_set_properties_id("GLStructure_%s" % (self.struct.structure_id)) 2211 2212 ## structure axes 2213 self.gl_axes = GLAxes() 2214 self.gl_axes.glo_set_properties_id("GLAxes") 2215 self.glo_add_child(self.gl_axes) 2216 self.glo_link_child_property("axes_visible", "GLAxes", "visible") 2217 2218 ## unit cell 2219 self.gl_unit_cell = GLUnitCell(unit_cell=self.struct.unit_cell) 2220 self.gl_unit_cell.glo_set_properties_id("GLUnitCell") 2221 self.glo_add_child(self.gl_unit_cell) 2222 self.glo_link_child_property("unit_cell_visible", "GLUnitCell", "visible") 2223 2224 ## GLChains 2225 for chain in self.struct.iter_chains(): 2226 self.gls_add_chain(chain) 2227 2228 ## init properties 2229 self.glo_init_properties(**args)
2230
2231 - def glo_install_properties(self):
2232 GLDrawList.glo_install_properties(self) 2233 2234 self.glo_add_property( 2235 { "name": "axes_visible", 2236 "desc": "Show Cartesian Axes", 2237 "catagory": "Show/Hide", 2238 "type": "boolean", 2239 "default": False, 2240 "action": "redraw" }) 2241 self.glo_add_property( 2242 { "name": "unit_cell_visible", 2243 "desc": "Show Unit Cell", 2244 "catagory": "Show/Hide", 2245 "type": "boolean", 2246 "default": False, 2247 "action": "redraw" }) 2248 self.glo_add_property( 2249 { "name": "symmetry", 2250 "desc": "Show Symmetry Equivelant", 2251 "catagory": "Show/Hide", 2252 "type": "boolean", 2253 "default": False, 2254 "action": "redraw" }) 2255 self.glo_add_property( 2256 { "name": "main_chain_visible", 2257 "desc": "Show Main Chain Atoms", 2258 "catagory": "Show/Hide", 2259 "type": "boolean", 2260 "default": True, 2261 "action": ["recompile", "recalc_positions"] }) 2262 self.glo_add_property( 2263 { "name": "oatm_visible", 2264 "desc": "Show Main Chain Carbonyl Atoms", 2265 "catagory": "Show/Hide", 2266 "type": "boolean", 2267 "default": True, 2268 "action": ["recompile", "recalc_positions"] }) 2269 self.glo_add_property( 2270 { "name": "side_chain_visible", 2271 "desc": "Show Side Chain Atoms", 2272 "catagory": "Show/Hide", 2273 "type": "boolean", 2274 "default": True, 2275 "action": ["recompile", "recalc_positions"] }) 2276 self.glo_add_property( 2277 { "name": "hetatm_visible", 2278 "desc": "Show Hetrogen Atoms", 2279 "catagory": "Show/Hide", 2280 "type": "boolean", 2281 "default": True, 2282 "action": ["recompile", "recalc_positions"] }) 2283 self.glo_add_property( 2284 { "name": "water_visible", 2285 "desc": "Show Waters", 2286 "catagory": "Show/Hide", 2287 "type": "boolean", 2288 "default": False, 2289 "action": ["recompile", "recalc_positions"] }) 2290 self.glo_add_property( 2291 { "name": "hydrogen_visible", 2292 "desc": "Show Hydrogens", 2293 "catagory": "Show/Hide", 2294 "type": "boolean", 2295 "default": False, 2296 "action": ["recompile", "recalc_positions"] })
2297
2298 - def glo_name(self):
2299 return self.struct.structure_id
2300
2301 - def gls_add_chain(self, chain):
2302 """Adds a Chain object to the GLStructure. 2303 """ 2304 gl_chain = GLChain(chain=chain) 2305 gl_chain.glo_set_properties_id("GLChain_%s" % (chain.chain_id)) 2306 self.glo_add_child(gl_chain) 2307 2308 chain_pid = gl_chain.glo_get_properties_id() 2309 2310 self.glo_link_child_property( 2311 "symmetry", chain_pid, "symmetry") 2312 2313 self.glo_link_child_property( 2314 "main_chain_visible", chain_pid, "main_chain_visible") 2315 self.glo_link_child_property( 2316 "oatm_visible", chain_pid, "oatm_visible") 2317 self.glo_link_child_property( 2318 "side_chain_visible", chain_pid, "side_chain_visible") 2319 self.glo_link_child_property( 2320 "hetatm_visible", chain_pid, "hetatm_visible") 2321 self.glo_link_child_property( 2322 "water_visible", chain_pid, "water_visible") 2323 self.glo_link_child_property( 2324 "hydrogen_visible", chain_pid, "hydrogen_visible")
2325
2326 - def iter_orth_symops(self):
2327 """Iterate orthogonal-space symmetry operations useful for 2328 displaying symmetry-equivelant molecules without having to 2329 calculate new draw lists. 2330 """ 2331 if hasattr(self, "orth_symop_cache"): 2332 for symop in self.orth_symop_cache: 2333 yield symop 2334 else: 2335 self.orth_symop_cache = [] 2336 uc = self.struct.unit_cell 2337 2338 for symop in uc.iter_struct_orth_symops(self.struct): 2339 self.orth_symop_cache.append(symop) 2340 yield symop
2341 2342
2343 -class GLViewer(GLObject):
2344 """This class renders a list of GLDrawList (or subclasses of) onto 2345 the given glcontext and gldrawable objects. The glcontext and gldrawable 2346 must be created by the underling GUI toolkit, or perhaps the GLUT 2347 libraries. This class is completely platform and tookit independent 2348 once it is passed the glcontext and gldrawable. The design of this 2349 class and the associated GLDrawList classes incorporates some basic 2350 OpenGL drawing optimizations. The GLDrawList objects are drawn and 2351 compiled into OpenGL draw lists, and have their own 2352 transformation/rotation operators WRT the GLViewer origin, allowing 2353 each GLDrawList to be redrawn very quickly as long as it moves as a 2354 rigid body. 2355 """
2356 - def __init__(self):
2357 GLObject.__init__(self) 2358 2359 self.glo_set_properties_id("GLViewer") 2360 self.glo_set_name("GLViewer") 2361 self.glo_add_update_callback(self.glv_update_cb) 2362 self.glo_init_properties() 2363 2364 self.glv_driver_list = []
2365
2366 - def glo_install_properties(self):
2367 GLObject.glo_install_properties(self) 2368 2369 ## Background 2370 self.glo_add_property( 2371 { "name": "bg_color", 2372 "desc": "Background Color", 2373 "catagory": "Background", 2374 "type": "enum_string", 2375 "default": "Black", 2376 "enum_list": Colors.COLOR_NAMES_CAPITALIZED[:], 2377 "action": "redraw" }) 2378 2379 ## View 2380 self.glo_add_property( 2381 { "name": "R", 2382 "desc": "View Window Rotation Matrix", 2383 "catagory": "View", 2384 "read_only": True, 2385 "type": "array(3,3)", 2386 "default": numpy.identity(3, float), 2387 "action": "redraw" }) 2388 self.glo_add_property( 2389 { "name": "cor", 2390 "desc": "Center of Rotation", 2391 "catagory": "View", 2392 "read_only": True, 2393 "type": "array(3)", 2394 "default": numpy.zeros(3, float), 2395 "action": "redraw" }) 2396 self.glo_add_property( 2397 { "name": "width", 2398 "desc": "Window Width", 2399 "catagory": "View", 2400 "read_only": True, 2401 "type": "integer", 2402 "default": 1, 2403 "action": "redraw" }) 2404 self.glo_add_property( 2405 { "name": "height", 2406 "desc": "Window Height", 2407 "catagory": "View", 2408 "read_only": True, 2409 "type": "integer", 2410 "default": 1, 2411 "action": "redraw" }) 2412 self.glo_add_property( 2413 { "name": "near", 2414 "desc": "Near Clipping Plane", 2415 "catagory": "View", 2416 "type": "float", 2417 "default": -20.0, 2418 "action": "redraw" }) 2419 self.glo_add_property( 2420 { "name": "far", 2421 "desc": "Far Clipping Plane", 2422 "catagory": "View", 2423 "type": "float", 2424 "default": 1000.0, 2425 "action": "redraw" }) 2426 self.glo_add_property( 2427 { "name": "zoom", 2428 "desc": "Zoom", 2429 "catagory": "View", 2430 "type": "float", 2431 "default": 20.0, 2432 "action": "redraw" }) 2433 2434 ## OpenGL Lighting 2435 self.glo_add_property( 2436 { "name": "GL_AMBIENT", 2437 "desc": "Ambient Light", 2438 "catagory": "Lighting", 2439 "type": "float", 2440 "range": "0.0-1.0,0.1", 2441 "default": 0.2, 2442 "action": "redraw" }) 2443 self.glo_add_property( 2444 { "name": "GL_SPECULAR", 2445 "desc": "Specular Light", 2446 "catagory": "Lighting", 2447 "type": "float", 2448 "range": "0.0-1.0,0.1", 2449 "default": 1.0, 2450 "action": "redraw" }) 2451 self.glo_add_property( 2452 { "name": "GL_DIFFUSE", 2453 "desc": "Diffuse Light", 2454 "catagory": "Lighting", 2455 "type": "float", 2456 "range": "0.0-1.0,0.1", 2457 "default": 1.0, 2458 "action": "redraw" }) 2459 2460 ## High-Performance OpenGL Features 2461 self.glo_add_property( 2462 { "name": "GL_LINE_SMOOTH", 2463 "desc": "Smooth Lines", 2464 "catagory": "OpenGL Performance", 2465 "type": "boolean", 2466 "default": False, 2467 "action": "redraw" }) 2468 self.glo_add_property( 2469 { "name": "GL_POINT_SMOOTH", 2470 "desc": "Smooth Points", 2471 "catagory": "OpenGL Performance", 2472 "type": "boolean", 2473 "default": False, 2474 "action": "redraw" }) 2475 self.glo_add_property( 2476 { "name": "GL_POLYGON_SMOOTH", 2477 "desc": "Smooth Polygons", 2478 "catagory": "OpenGL Performance", 2479 "type": "boolean", 2480 "default": False, 2481 "action": "redraw" }) 2482 self.glo_add_property( 2483 { "name": "GL_BLEND", 2484 "desc": "Alpha-Blending (required for Fog)", 2485 "catagory": "OpenGL Performance", 2486 "type": "boolean", 2487 "default": True, 2488 "action": "redraw" }) 2489 self.glo_add_property( 2490 { "name": "GL_FOG", 2491 "desc": "Enable Fog", 2492 "catagory": "OpenGL Performance", 2493 "type": "boolean", 2494 "default": True, 2495 "action": "redraw" })
2496
2497 - def glv_update_cb(self, updates, actions):
2498 ## prevent the near clipping plane from passing behind the far 2499 ## clipping plane 2500 slice = self.properties["near"] - self.properties["far"] 2501 if slice<1.0: 2502 if updates.has_key("near") and updates.has_key("far"): 2503 self.properties.update(far = self.properties["near"] - 1.0) 2504 elif updates.has_key("near") and not updates.has_key("far"): 2505 self.properties.update(near = self.properties["far"] + 1.0) 2506 elif updates.has_key("far") and not updates.has_key("near"): 2507 self.properties.update(far = self.properties["near"] - 1.0) 2508 2509 ## redraw request 2510 if "redraw" in actions: 2511 self.glv_redraw()
2512
2513 - def glv_add_draw_list(self, draw_list):
2514 """Append a GLDrawList. 2515 """ 2516 assert isinstance(draw_list, GLDrawList) 2517 self.glo_add_child(draw_list) 2518 self.glv_redraw()
2519
2520 - def glv_remove_draw_list(self, draw_list):
2521 """Remove a GLDrawList. 2522 """ 2523 assert isinstance(draw_list, GLDrawList) 2524 draw_list.glo_remove() 2525 self.glv_redraw()
2526
2527 - def glv_calc_struct_orientation(self, struct):
2528 """Orient the structure based on a moment-of-intertia like tensor 2529 centered at the centroid of the structure. 2530 """ 2531 slop = 2.0 2532 2533 def aa_atom_iter(structx): 2534 if structx.count_standard_residues()>0: 2535 for frag in structx.iter_standard_residues(): 2536 for atm in frag.iter_atoms(): 2537 yield atm 2538 else: 2539 for atm in structx.iter_atoms(): 2540 yield atm
2541 2542 try: 2543 centroid = AtomMath.calc_atom_centroid(aa_atom_iter(struct)) 2544 except OverflowError: 2545 return None 2546 2547 R = AtomMath.calc_inertia_tensor(aa_atom_iter(struct), centroid) 2548 2549 ori = {} 2550 2551 ## now calculate a rectangular box 2552 first_atm = True 2553 2554 min_x = 0.0 2555 max_x = 0.0 2556 min_y = 0.0 2557 max_y = 0.0 2558 min_z = 0.0 2559 max_z = 0.0 2560 2561 for atm in aa_atom_iter(struct): 2562 x = numpy.dot(R, atm.position - centroid) 2563 2564 if first_atm is True: 2565 first_atm = False 2566 2567 min_x = max_x = x[0] 2568 min_y = max_y = x[1] 2569 min_z = max_z = x[2] 2570 else: 2571 min_x = min(min_x, x[0]) 2572 max_x = max(max_x, x[0]) 2573 min_y = min(min_y, x[1]) 2574 max_y = max(max_y, x[1]) 2575 min_z = min(min_z, x[2]) 2576 max_z = max(max_z, x[2]) 2577 2578 ## add slop 2579 min_x -= slop 2580 max_x += slop 2581 min_y -= slop 2582 max_y += slop 2583 min_z -= slop 2584 max_z += slop 2585 2586 ## calculate the zoom based on a target width 2587 target_pwidth = 640 2588 2589 hwidth = max(abs(min_x),abs(max_x)) 2590 hheight = max(abs(min_y),abs(max_y)) 2591 pheight = target_pwidth * (hheight / hwidth) 2592 hzoom = 2.0 * hwidth 2593 2594 ori["R"] = R 2595 ori["centroid"] = centroid 2596 ori["pwidth"] = target_pwidth 2597 ori["pheight"] = pheight 2598 ori["hzoom"] = hzoom 2599 2600 ## calculate near, far clipping blane 2601 ori["near"] = max_z 2602 ori["far"] = min_z 2603 2604 return ori
2605
2606 - def glv_add_struct(self, struct):
2607 """Adds the visualization for a mmLib.Structure.Structure object 2608 to the GLViewer. It returns the GLStructure object created to 2609 visualize the Structure object. 2610 """ 2611 assert isinstance(struct, Structure.Structure) 2612 2613 ## add the structure 2614 gl_struct = GLStructure(struct=struct) 2615 self.glv_add_draw_list(gl_struct) 2616 2617 ori = self.glv_calc_struct_orientation(struct) 2618 if ori is not None: 2619 self.properties.update( 2620 R = ori["R"], 2621 cor = ori["centroid"], 2622 zoom = ori["hzoom"], 2623 near = ori["near"], 2624 far = ori["far"]) 2625 2626 return gl_struct
2627
2628 - def glv_redraw(self):
2629 """This method is called by GLViewer children to trigger a redraw 2630 in the toolkit embedding the GLViewer object. It needs to be 2631 re-implemented when subclassed to call the tookit's widget redraw 2632 method. 2633 """ 2634 pass
2635
2636 - def glv_init(self):
2637 """Called once to initalize the GL scene before drawing. 2638 """ 2639 pass
2640
2641 - def glv_resize(self, width, height):
2642 """Called to set the size of the OpenGL window this class is 2643 drawing on. 2644 """ 2645 self.properties.update(width=width, height=height)
2646
2647 - def glv_clip(self, near, far):
2648 """Adjust near/far clipping planes. 2649 """ 2650 width = self.properties["width"] 2651 zoom = self.properties["zoom"] 2652 2653 angstrom_per_pixel = zoom / float(width) 2654 2655 nearA = angstrom_per_pixel * float(near) 2656 farA = angstrom_per_pixel * float(far) 2657 2658 n = self.properties["near"] + nearA 2659 f = self.properties["far"] + farA 2660 self.properties.update(near=n, far=f)
2661
2662 - def glv_zoom(self, z):
2663 """Adjust zoom levels. 2664 """ 2665 width = self.properties["width"] 2666 zoom = self.properties["zoom"] 2667 2668 angstrom_per_pixel = zoom / float(width) 2669 2670 zoom = self.properties["zoom"] 2671 zoom += angstrom_per_pixel * float(z) 2672 2673 if zoom<1.0: 2674 zoom = 1.0 2675 2676 self.properties.update(zoom=zoom)
2677
2678 - def glv_straif(self, x, y):
2679 """Translate in the XY plane. 2680 """ 2681 ## figure out A/pixel, multipy straif by pixes to get the 2682 ## the translation 2683 2684 width = self.properties["width"] 2685 zoom = self.properties["zoom"] 2686 2687 angstrom_per_pixel = zoom / float(width) 2688 2689 xA = angstrom_per_pixel * float(x) 2690 yA = angstrom_per_pixel * float(y) 2691 2692 ## XY translational shift 2693 dt = numpy.array((xA, yA, 0.0), float) 2694 2695 ## change the center of rotation 2696 R = self.properties["R"] 2697 2698 ## shift in the XY plane by chainging the position of the 2699 ## center of rotation 2700 cor = self.properties["cor"] - numpy.dot(numpy.transpose(R), dt) 2701 2702 self.properties.update(cor=cor)
2703
2704 - def glv_trackball(self, x1, y1, x2, y2):
2705 """Implements a virtual trackball. 2706 """ 2707 2708 def project_to_sphere(r, x, y): 2709 d = math.sqrt(x*x + y*y) 2710 if d<(r*0.707): 2711 return math.sqrt(r*r - d*d) 2712 else: 2713 return (r/1.414)**2 / d
2714 2715 width = self.properties["width"] 2716 height = self.properties["height"] 2717 2718 ## determine the circle where the trackball is vs. the edges 2719 ## which are z-rotation 2720 square = min(width, height) 2721 radius = int(square * 0.7) 2722 2723 x1c = x1 - width/2 2724 y1c = y1 - width/2 2725 d = math.sqrt(x1c*x1c + y1c*y1c) 2726 2727 ## Z rotation 2728 if d>=radius: 2729 x2c = x2 - width/2 2730 y2c = y2 - width/2 2731 2732 p1 = AtomMath.normalize(numpy.array((x1c, y1c, 0.0), float)) 2733 p2 = AtomMath.normalize(numpy.array((x2c, y2c, 0.0), float)) 2734 2735 c = numpy.cross(p2, p1) 2736 2737 try: 2738 a = AtomMath.normalize(c) 2739 except OverflowError: 2740 return 2741 2742 theta = AtomMath.length(c) * math.pi/2.0 2743 2744 ## XY trackball rotation 2745 else: 2746 2747 x1 = (2.0*x1 - width) / width 2748 y1 = (height - 2.0*y1) / height 2749 x2 = (2.0*x2 - width) / width 2750 y2 = (height - 2.0*y2) / height 2751 2752 tb_size = 1.0 2753 2754 ## check for zero rotation 2755 if x1==x2 and y1==y2: 2756 return 2757 2758 p1 = numpy.array((x1, y1, project_to_sphere(tb_size, x1, y1)), float) 2759 p2 = numpy.array((x2, y2, project_to_sphere(tb_size, x2, y2)), float) 2760 2761 a = numpy.cross(p1, p2) 2762 d = p1 - p2 2763 t = AtomMath.length(d) / (2.0 * tb_size) 2764 2765 if t>1.0: 2766 t - 1.0 2767 if t<-1.0: 2768 t = -1.0 2769 2770 theta = 2.0 * math.asin(t) 2771 2772 ## convert rotation axis a and rotation theta to a quaternion 2773 Rcur = self.properties["R"] 2774 2775 ## calculate a in the original coordinate frame 2776 a = numpy.dot(numpy.transpose(Rcur), a) 2777 qup = AtomMath.rquaternionu(a, theta) 2778 2779 ## convert the current rotation matrix to a quaternion so the 2780 ## new rotation quaternion can be added to it 2781 qcur = AtomMath.quaternionrmatrix(Rcur) 2782 qnew = AtomMath.addquaternion(qcur, qup) 2783 Rnew = AtomMath.rmatrixquaternion(qnew) 2784 2785 self.properties.update(R=Rnew) 2786
2787 - def glv_background_color_rgbf(self):
2788 """Return the R,G,B triplit of the background color. 2789 """ 2790 colorx = self.properties["bg_color"].lower() 2791 if Colors.COLOR_RGBF.has_key(colorx): 2792 return Colors.COLOR_RGBF[colorx] 2793 2794 try: 2795 r, g, b = colorx.split(",") 2796 except ValueError: 2797 pass 2798 else: 2799 try: 2800 return (float(r), float(g), float(b)) 2801 except ValueError: 2802 pass 2803 2804 return (0.0, 0.0, 0.0)
2805
2806 - def glv_render(self):
2807 """Render scene using all drivers. 2808 """ 2809 for driver in self.glv_driver_list: 2810 self.glv_render_one(driver)
2811
2812 - def glv_render_one(self, driver):
2813 """Render the scent once with the argument driver. 2814 """ 2815 ## setup the scene for rendering 2816 driver.glr_render_begin( 2817 width = self.properties["width"], 2818 height = self.properties["height"], 2819 zoom = self.properties["zoom"], 2820 near = self.properties["near"], 2821 far = self.properties["far"], 2822 bg_color_rgbf = self.glv_background_color_rgbf(), 2823 ambient_light = self.properties["GL_AMBIENT"], 2824 diffuse_light = self.properties["GL_DIFFUSE"], 2825 specular_light = self.properties["GL_SPECULAR"], 2826 gl_line_smooth = self.properties["GL_LINE_SMOOTH"], 2827 gl_point_smooth = self.properties["GL_LINE_SMOOTH"], 2828 gl_polygon_smooth = self.properties["GL_POLYGON_SMOOTH"], 2829 gl_blend = self.properties["GL_BLEND"], 2830 gl_fog = self.properties["GL_FOG"]) 2831 2832 R = self.properties["R"] 2833 assert numpy.allclose(linalg.determinant(R), 1.0) 2834 2835 driver.glr_mult_matrix_R(R) 2836 driver.glr_translate(-self.properties["cor"]) 2837 2838 ## render solid objects 2839 for draw_list in self.glo_iter_children(): 2840 draw_list.gldl_render(driver) 2841 2842 ## render transparent objects 2843 for draw_list in self.glo_iter_children(): 2844 draw_list.gldl_render(driver, True) 2845 2846 driver.glr_render_end()
2847