From: <luc...@us...> - 2008-11-14 23:56:59
|
Revision: 8199 http://cctbx.svn.sourceforge.net/cctbx/?rev=8199&view=rev Author: luc_j_bourhis Date: 2008-11-14 23:56:53 +0000 (Fri, 14 Nov 2008) Log Message: ----------- - display the bounding volume for the iso-surface instead of the volume between (0,0,0) and (1,1,1) - the example changed to show how wrong the iso-surfacing code can get when using a periodic map Modified Paths: -------------- trunk/crys3d/wx_map_viewer.py trunk/crys3d/wx_map_viewer_example.py Modified: trunk/crys3d/wx_map_viewer.py =================================================================== --- trunk/crys3d/wx_map_viewer.py 2008-11-14 23:28:26 UTC (rev 8198) +++ trunk/crys3d/wx_map_viewer.py 2008-11-14 23:56:53 UTC (rev 8199) @@ -81,10 +81,10 @@ self.max_density = density_stats.max() self.iso_level = iso_level(density_stats) - p = (0,0,0) - q = unit_cell.orthogonalize((1,1,1)) - r = unit_cell.orthogonalize((1,0,0)) - s = unit_cell.orthogonalize((0,1,1)) + p = unit_cell.orthogonalize(from_here) + q = unit_cell.orthogonalize(to_there) + r = unit_cell.orthogonalize((to_there[0], from_here[1], from_here[2])) + s = unit_cell.orthogonalize((from_here[0], to_there[1], to_there[2])) self.minimum_covering_sphere = minimum_covering_sphere( flex.vec3_double([p,q,r,s])) @@ -154,10 +154,15 @@ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (0, 0, 0, 1)) glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0) + (x0, y0, z0), (x1, y1, z1) = self.triangulation.bounds + r,g,b = 0.9, 0.4, 0.3 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (r, g, b, 1.)) e = self.unit_cell_label_shift_from_axes - for pos, label in zip([(1/2,e,e), (e,1/2,e),(e,e,1/2)], ['a','b','c']): + for pos, label in zip([((x0 + x1)/2, y0 + e, z0 + e), + (x0 + e, (y0 + y1)/2, z0 + e), + (x0 + e, y0 + e, (z0 + z1)/2)], + ['a','b','c']): self.unit_cell_label_fonts.render_text(pos, label, use_3d_position=True) lw = [0.] @@ -167,26 +172,26 @@ r,g,b = (0.6,)*3 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (r, g, b, 1.)) glBegin(GL_LINE_LOOP) - glVertex3f(0,0,0) - glVertex3f(1,0,0) - glVertex3f(1,1,0) - glVertex3f(0,1,0) + glVertex3f(x0,y0,z0) + glVertex3f(x1,y0,z0) + glVertex3f(x1,y1,z0) + glVertex3f(x0,y1,z0) glEnd() glBegin(GL_LINE_LOOP) - glVertex3f(0,0,1) - glVertex3f(1,0,1) - glVertex3f(1,1,1) - glVertex3f(0,1,1) + glVertex3f(x0,y0,z1) + glVertex3f(x1,y0,z1) + glVertex3f(x1,y1,z1) + glVertex3f(x0,y1,z1) glEnd() glBegin(GL_LINES) - glVertex3f(0,0,0) - glVertex3f(0,0,1) - glVertex3f(1,0,0) - glVertex3f(1,0,1) - glVertex3f(1,1,0) - glVertex3f(1,1,1) - glVertex3f(0,1,0) - glVertex3f(0,1,1) + glVertex3f(x0,y0,z0) + glVertex3f(x0,y0,z1) + glVertex3f(x1,y0,z0) + glVertex3f(x1,y0,z1) + glVertex3f(x1,y1,z0) + glVertex3f(x1,y1,z1) + glVertex3f(x0,y1,z0) + glVertex3f(x0,y1,z1) glEnd() glLineWidth(lw[0]) Modified: trunk/crys3d/wx_map_viewer_example.py =================================================================== --- trunk/crys3d/wx_map_viewer_example.py 2008-11-14 23:28:26 UTC (rev 8198) +++ trunk/crys3d/wx_map_viewer_example.py 2008-11-14 23:56:53 UTC (rev 8199) @@ -11,14 +11,16 @@ grid_size=(50, 40, 30), lazy_normals=False, descending_normals=True) - wx_map_viewer.display(unit_cell=uc, + a = wx_map_viewer.App(unit_cell=uc, raw_map=elliptic.map, - iso_level=lambda map_stats: 1.3, - from_here=(-0.2, -0.3, -0.4), - to_there=(0.3, 0.4, 0.2), - #periodic=True, + iso_level=lambda map_stats: 1.4, + from_here=(-0.3, 0.2, 0.4), + to_there=(0.7, 0.8, 1.6), + periodic=True, wires=False, title="Ellipsoid") + #a.view_objects.orthographic = True + a.MainLoop() def run(): exercise() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luc...@us...> - 2008-11-17 15:04:45
|
Revision: 8214 http://cctbx.svn.sourceforge.net/cctbx/?rev=8214&view=rev Author: luc_j_bourhis Date: 2008-11-17 15:04:40 +0000 (Mon, 17 Nov 2008) Log Message: ----------- - adjustments to the latest changes in scitbx.iso_surface Modified Paths: -------------- trunk/crys3d/wx_map_viewer.py trunk/crys3d/wx_map_viewer_example.py Modified: trunk/crys3d/wx_map_viewer.py =================================================================== --- trunk/crys3d/wx_map_viewer.py 2008-11-17 14:59:58 UTC (rev 8213) +++ trunk/crys3d/wx_map_viewer.py 2008-11-17 15:04:40 UTC (rev 8214) @@ -81,6 +81,8 @@ self.max_density = density_stats.max() self.iso_level = iso_level(density_stats) + if from_here is None: from_here = (0,0,0) + if to_there is None: to_there = (1,1,1) p = unit_cell.orthogonalize(from_here) q = unit_cell.orthogonalize(to_there) r = unit_cell.orthogonalize((to_there[0], from_here[1], from_here[2])) Modified: trunk/crys3d/wx_map_viewer_example.py =================================================================== --- trunk/crys3d/wx_map_viewer_example.py 2008-11-17 14:59:58 UTC (rev 8213) +++ trunk/crys3d/wx_map_viewer_example.py 2008-11-17 15:04:40 UTC (rev 8214) @@ -6,17 +6,19 @@ def exercise(): uc = uctbx.unit_cell((1,1,1,60,120,90)) #uc = uctbx.unit_cell((1,1,1,90,90,90)) - elliptic = tst_iso_surface.triangulation_test_case( - func=tst_iso_surface.elliptic(), + case = tst_iso_surface.triangulation_test_case( + #func=tst_iso_surface.elliptic(), + func=tst_iso_surface.periodic(), grid_size=(50, 40, 30), + periodic=True, lazy_normals=False, descending_normals=True) a = wx_map_viewer.App(unit_cell=uc, - raw_map=elliptic.map, - iso_level=lambda map_stats: 1.4, - from_here=(-0.3, 0.2, 0.4), - to_there=(0.7, 0.8, 1.6), - periodic=True, + raw_map=case.map, + #iso_level=lambda map_stats: 3, + iso_level=lambda map_stats: 0.3, + #from_here=None, to_there=None, + from_here=(-0.5, -0.5, -0.5), to_there=(1.5, 1.5, 1.5), wires=False, title="Ellipsoid") #a.view_objects.orthographic = True This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-02-02 18:30:42
|
Revision: 8556 http://cctbx.svn.sourceforge.net/cctbx/?rev=8556&view=rev Author: natechols Date: 2009-02-02 18:30:38 +0000 (Mon, 02 Feb 2009) Log Message: ----------- sync'd model viewer with phenix, added selection viewer mixin; map viewer mixin Modified Paths: -------------- trunk/crys3d/wx_map_viewer.py trunk/crys3d/wx_model_viewer.py Modified: trunk/crys3d/wx_map_viewer.py =================================================================== --- trunk/crys3d/wx_map_viewer.py 2009-02-02 18:29:22 UTC (rev 8555) +++ trunk/crys3d/wx_map_viewer.py 2009-02-02 18:30:38 UTC (rev 8556) @@ -24,6 +24,12 @@ import math import unicodedata +# this class isn't very well suited to being a mix-in like the classes in +# wx_model_viewer; however, it's a nicely contained stand-alone program, +# so I added the class map_viewer_mixin further down for use in combination +# with the model/selection viewer mixins. when this file is run directly +# it will still use the map_view class as before. --nat 2009-02-01 + class map_view(wx_viewer.wxGLWindow): def barycentre_of_min_max(cls, x=0.8): @@ -213,7 +219,134 @@ def process_pick_points(self): pass +######################################################################## +# MIXIN FOR MAPS +# +# this is combined with a subclass of wx_model_viewer.selection_viewer_mixin +# to display the refinement status in phenix.refine +# TODO: replace map list and associated lists with dict +class map_viewer_mixin (wx_viewer.wxGLWindow) : + initialize_map_viewer_super = True + def __init__ (self, *args, **kwds) : + if self.initialize_map_viewer_super : + wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + # various data objects + self.unit_cell = None + self.orthogonaliser = None + self.maps = [] + self.iso_levels = [] + self.map_colors = [] + self.materials = [] + self.triangles = [] + self._triangle_tmp = [] + # user settings + self.mesh_line_width = 0.25 # very buggy on OS X + NVidia (and ???) + self.map_radius = 10.0 + # flags + self.flag_show_maps = True + self.flag_use_materials = False + # maps look much better when OpenGL materials are used, but this screws + # up the model rendering so it's off by default + def InitGL (self) : + gltbx.util.rescale_normals(fallback_to_normalize=True).enable() + glEnable(GL_DEPTH_TEST) + if self.flag_use_materials : + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glLightfv(GL_LIGHT0, GL_POSITION, [0, 0, 1, 0]) + glShadeModel(GL_SMOOTH) + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_NORMAL_ARRAY) + + def DrawGL (self) : + if self.unit_cell is not None and self.triangles is not None : + glMatrixMode(GL_MODELVIEW) + glPushMatrix() + glMultTransposeMatrixd(self.orthogonaliser) + self.draw_maps() + glPopMatrix() + + def initialize_unit_cell (self, map) : + self.unit_cell = map.unit_cell() + o = self.unit_cell.orthogonalization_matrix() + self.orthogonaliser = ( o[0:3] + (0,) + + o[3:6] + (0,) + + o[6:9] + (0,) + + (0,0,0,1) ) + + def update_map_objects (self) : + self.compute_triangulation() + # this is done to prevent thread clashes (+ ensuing crashes) + self.triangles = self._triangle_tmp + + def set_iso_levels (self, levels) : + assert len(levels) == len(self.maps) + for i, map_contour_level in enumerate(levels) : + self.iso_levels[i] = map_contour_level + + def set_map_colors (self, colors) : + assert len(colors) == len(self.maps) + for i, map_color in enumerate(colors) : + self.map_colors[i] = map_color + self.materials[i] = gltbx.gl_managed.material_model( + front_colour=map_color, + back_colour=map_color) + + def set_maps (self, maps) : + assert len(maps) != 0 + self.maps = maps + if (len(self.iso_levels) != len(maps) or + len(self.map_colors) != len(maps)) : + self.iso_levels = [ 1.0 for m in maps ] + self.map_colors = [ (1., 1., 1.) for m in maps ] + self.materials = [ None for m in maps ] + if self.unit_cell is None : + self.initialize_unit_cell(self.maps[0]) + + def compute_triangulation (self) : + if len(self.maps) == 0 : + return + self._triangle_tmp = [] + r = self.map_radius + c = self.rotation_center # set in wxGLWindow (default is origin) + min = [ c[x] - float(r) for x in [0, 1, 2] ] + max = [ c[x] + float(r) for x in [0, 1, 2] ] + map_boundaries_cart = flex.vec3_double([min,max]) + bounds = self.unit_cell.fractionalize(sites_cart=map_boundaries_cart) + for i, raw_map in enumerate(self.maps) : + rho = raw_map.real_map() + iso_level = self.iso_levels[i] + triangulation = iso_surface.triangulation(rho, + iso_level, + map_extent=(1,1,1), + from_here=bounds[0], + to_there=bounds[1], + periodic=True, + ascending_normal_direction=False + ) + self._triangle_tmp.append(triangulation) + + def draw_maps (self) : + if not self.flag_show_maps : + return + if self.flag_use_materials : + glLightfv(GL_LIGHT0, GL_AMBIENT, [0., 0., 0., 1.]) + for i, triangulation in enumerate(self.triangles) : + glLineWidth(0.2) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) + if self.flag_use_materials : + self.materials[i].execute(specular=False) + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) + else : + glColor3f(*self.map_colors[i]) + va = gltbx.util.vertex_array(triangulation.vertices, + triangulation.normals) + va.draw_triangles(triangulation.triangles) + +######################################################################## +# CLASSES AND METHODS FOR RUNNING map_view +# class App(wx_viewer.App): def __init__(self, @@ -286,7 +419,7 @@ lbl = lbl_fmt % multiplier self.multiplier = wx.StaticText(iso_level_pane, style=wx.ALIGN_CENTER_HORIZONTAL, - label=lbl) + label="label")#lbl) self.iso_level_slider.Bind(wx.EVT_SCROLL, self.on_iso_level_changed) opengl_inspector = wx_extra.Inspector(self.tools, Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-02-02 18:29:22 UTC (rev 8555) +++ trunk/crys3d/wx_model_viewer.py 2009-02-02 18:30:38 UTC (rev 8556) @@ -1,4 +1,5 @@ +from string import strip from libtbx.utils import Sorry import gltbx.util from gltbx import wx_viewer, viewer_utils @@ -10,118 +11,115 @@ from cctbx import crystal, sgtbx import wx +######################################################################## +# BASE CLASS FOR DISPLAYING STRUCTURES +# class model_viewer_mixin (wx_viewer.wxGLWindow) : + initialize_model_viewer_super = True def __init__ (self, *args, **kwds) : - wx_viewer.wxGLWindow.__init__(self, *args, **kwds) - self.active_widget = None + if self.initialize_model_viewer_super : + wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + self.pdb_hierarchy = None + self.atomic_bonds = None # from geometry restraints manager + self.selection_cache = None # this is used by extract_trace + self.atoms = None + self.atom_count = 0 + self.points = None # basic 3d data - atoms.extract_xyz() + self.b_cache = None # atoms.extract_b() + self.atom_index = [] # stores atoms_with_labels data + self.current_atom_i_seq = None + self.closest_point_i_seq = None # usually set by mouse clicks + self.minimum_covering_sphere = None + # display lists - resetting these to None will force a redraw + self.points_display_list = None + self.lines_display_list = None + self.spheres_display_list = None + # various settings; override these in subclasses and/or provide + # a mechanism for changing their values self.line_width = 1 self.buffer_factor = 2.0 self.nonbonded_line_width = 1 - self.processed_pdb_file = None - self.points = None - self.spheres_visible = None - self.atom_index = [] - self.current_atom_i_seq = None - self.current_widget = None - self.minimum_covering_sphere = None + self._fog_start = 50 + self._fog_end = 200 self.draw_mode = "all_atoms" - self.draw_selection_mode = "bonds_and_atoms" self.color_mode = "rainbow" self.recolor = self.color_rainbow - self.base_atom_color = (0.6, 0.6, 0.6) - self.labels_display_list = None - self.points_display_list = None - self.lines_display_list = None - self.spheres_display_list = None - self.selection_cache = None - self.selection_string = "" - self.selection_i_seqs = None - self.selected_points = [] - self.selection_color = (1.0, 1.0, 1.0) + self.base_atom_color = (0.6, 0.6, 0.6) # grey + self.carbon_atom_color = (1.0, 1.0, 0.0) # yellow + self.orthographic = False + # toggles for viewable objects self.flag_show_fog = True self.flag_show_lines = True self.flag_show_points = True self.flag_show_labels = True self.flag_show_spheres = False - self.flag_show_backbone = False + self.flag_show_trace = False self.flag_show_hydrogens = True - self.flag_show_selection = True self.flag_show_minimum_covering_sphere = False self.flag_show_rotation_center = False - self.flag_scale_b_to_visible = True - self.flag_color_selection_separately = True - self._structure_was_updated = False + + def InitGL(self): + gltbx.util.handle_error() + glClearColor(self.r_back, self.g_back, self.b_back, 0.0) + self.minimum_covering_sphere_display_list = None glEnable(GL_LINE_SMOOTH) glDepthFunc(GL_LESS) glEnable(GL_ALPHA_TEST) glEnable(GL_DEPTH_TEST) glEnable(GL_BLEND) - glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE) + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) + self.initialize_modelview() + gltbx.util.handle_error() - def InitGL(self): - gltbx.util.handle_error() - glClearColor(self.r_back, self.g_back, self.b_back, 0.0) - self.minimum_covering_sphere_display_list = None + def initialize_modelview (self) : if self.minimum_covering_sphere is not None : - self.initialize_modelview() - gltbx.util.handle_error() + wx_viewer.wxGLWindow.initialize_modelview(self) def DrawGL(self): if (self.flag_show_points): self.draw_points() if (self.flag_show_lines): self.draw_lines() + if (self.flag_show_labels): + self.draw_labels() if (self.flag_show_spheres): self.draw_spheres() - if (self.flag_show_selection) : - self.draw_selection() def OnRedrawGL (self, event=None) : if self.minimum_covering_sphere is None : + gltbx.util.handle_error() glClear(GL_COLOR_BUFFER_BIT) glClear(GL_DEPTH_BUFFER_BIT) glFlush() self.SwapBuffers() + gltbx.util.handle_error() else : wx_viewer.wxGLWindow.OnRedrawGL(self, event) - def zoom_selection (self, event=None) : - if self.selection_covering_sphere is not None : - self.minimum_covering_sphere = self.selection_covering_sphere - self.move_rotation_center_to_mcs_center() - self.fit_into_viewport() - def unzoom (self, event=None) : if self.atoms is not None : self.minimum_covering_sphere = minimum_covering_sphere( - points=self.atoms.extract_xyz()) + points=self.atoms.extract_xyz(), + epsilon=0.1) self.move_rotation_center_to_mcs_center() self.fit_into_viewport() - def OnChar (self, event) : - wx_viewer.wxGLWindow.OnChar(self, event) - key = event.GetKeyCode() - if key == ord('z') : - self.zoom_selection() - elif key == ord('u') : + def recenter_on_atom (self, i_seq) : + if self.points is not None and i_seq < self.points.size() : + self.rotation_center = self.points[i_seq] + + def process_key_stroke (self, key) : + if key == ord('u') : self.unzoom() - def OnLeftClick (self, event) : - wx_viewer.wxGLWindow.OnLeftClick(self, event) - if event.ControlDown() and not self.was_dragged : - self.get_pick_points((event.GetX(), event.GetY())) - closest_point_i_seq = self.process_pick_points() - if closest_point_i_seq : - self.set_selected_atom(closest_point_i_seq) - def process_pick_points(self): - closest_point_i_seq = viewer_utils.closest_visible_point( - points = self.points, - atoms_visible = self.atoms_visible, - point0 = self.pick_points[0], - point1 = self.pick_points[1] - ) - return closest_point_i_seq + if self.pick_points is not None : + self.closest_point_i_seq = viewer_utils.closest_visible_point( + points = self.points, + atoms_visible = self.atoms_visible, + point0 = self.pick_points[0], + point1 = self.pick_points[1] + ) def update_view (self, redraw_points=True, redraw_lines=False) : self.get_drawn_atom_count() @@ -130,7 +128,6 @@ self.lines_display_list = None if redraw_points : self.points_display_list = None - self.selection_display_list = None self.OnRedraw() def OnUpdate (self, event=None, recenter=False) : @@ -174,6 +171,23 @@ atom_radii[i_seq] = 0.75 self.atom_radii = atom_radii + # when calculations are being done in the background in another thread, + # calling this directly can cause a crash. it's best to bind this to + # an event instead, either a keystroke/button click or a wx.PostEvent + # from a child thread (this is how phenix.refine does it). + def OnUpdate (self, event=None, recenter=False) : + if self._structure_was_updated : + self.extract_atom_data() + self.extract_trace() + else : + self.update_coords() + self._structure_was_updated = False + self.update_view(True, True) + if (recenter or + (event is not None and getattr(event, "recenter", None) == True)) : + self.move_rotation_center_to_mcs_center() + self.fit_into_viewport() + def update_coords (self) : self.points = self.atoms.extract_xyz() self.b_cache = self.atoms.extract_b() @@ -245,52 +259,6 @@ self.visible_atom_count = self.visibility.visible_atoms_count #--------------------------------------------------------------------- - # atom selections - # - def update_selection (self, selection_string=None) : - self.selection_string = selection_string - if selection_string is None : - self.selection_string = self.convert_selections_to_string() - if self.active_widget is not None : - try : # TODO: make sure the widget isn't a menu item??? - self.active_widget.update_value(self.selection_string) - except Exception, e : - print e - self.apply_selection(self.selection_string) - self.frame.update_selection(self.selection_string) - try : - self.set_selection_sphere() - except Exception, e : - print e - - def set_selection_sphere (self) : - selected_points = [] - points = self.points - for i_seq in self.selection_i_seqs : - selected_points.append(points[i_seq]) - if len(selected_points) == 0 : - self.selection_covering_sphere = minimum_covering_sphere( - points=self.atoms.extract_xyz()) - else : - s_p = flex.vec3_double(selected_points) - self.selection_covering_sphere = minimum_covering_sphere( - points=s_p) - - def apply_selection (self, selection_string) : - sel = self.selection_cache.selection - #sel = self.pdb_hierarchy.atom_selection_cache() - try : - self.atoms_selected = sel(selection_string) - except : - self.atoms_selected = sel("none") - raise Sorry("The string '%s' is not a valid selection."%selection_string) - self.selection_i_seqs = self.atoms_selected.iselection() - self.update_view() - - def get_selected_atom_count (self) : - return self.selection_i_seqs.size() - - #--------------------------------------------------------------------- # coloring def set_bg_color (self) : (r,g,b) = self.bg_color @@ -310,7 +278,6 @@ self.recolor = self.color_mono else : pass - self.set_sel_color(color_tuple=self.selection_color) if redraw : self.update_view(True, True) @@ -334,10 +301,11 @@ ) def color_by_chain (self) : + # TODO: all of this using flex array only c = 0 for chain in self.pdb_hierarchy.chains() : c += 1 - rainbow = utils.rainbow_gradient_as_decimals(c) + rainbow = viewer_utils.make_rainbow_gradient(c) j = 0 chain_shades = {} for chain in self.pdb_hierarchy.chains() : @@ -349,23 +317,26 @@ def color_by_element (self) : py_atom_colors = [] - element_shades = {' C' : (0.8, 0.8, 0.8), - ' H' : (0.95, 0.95, 0.95), - ' N' : (0.0, 0.0, 1.0), - ' O' : (1.0, 0.0, 0.0), - ' S' : (1.0, 0.5, 0.0), - ' P' : (1.0, 1.0, 0.0), - 'Se' : (0.0, 1.0, 0.0), - 'Mg' : (0.7, 0.7, 0.9), - 'Fe' : (0.8, 0.2, 0.0), - 'Cl' : (0.8, 1.0, 0.2), - 'Na' : (0.95, 0.95, 0.95), - 'Ca' : (1.0, 1.0, 1.0), - 'Mn' : (0.8, 0.6, 1.0), - 'Zn' : (0.8, 0.9, 1.0), - 'Ni' : (0.0, 1.0, 0.8), - 'Cu' : (0.0, 1.0, 0.5), - 'Co' : (0.0, 0.5, 0.6) } + # these are approximations based on my (probably faulty) memory. + # feel free to change to something more reasonable. + element_shades = {' C' : self.carbon_atom_color, # usually yellow or grey + ' H' : (0.95, 0.95, 0.95), # very light grey + ' N' : (0.0, 0.0, 1.0), # blue + ' O' : (1.0, 0.0, 0.0), # red + ' S' : (1.0, 0.5, 0.0), # orange + ' P' : (1.0, 1.0, 0.0), # yellow + 'Se' : (0.0, 1.0, 0.0), # green + 'Mg' : (0.7, 0.7, 0.9), # very pale blue + 'Fe' : (0.8, 0.2, 0.0), # rust + 'Cl' : (0.8, 1.0, 0.2), # yellow-green + 'Na' : (0.7, 0.7, 0.7), # light grey + 'Ca' : (1.0, 1.0, 1.0), # white + 'Mn' : (1.0, 0.6, 0.8), # lavender + 'Zn' : (0.8, 0.9, 1.0), # very pale cyan + 'Ni' : (0.0, 0.8, 0.4), # teal + 'Cu' : (0.0, 0.8, 0.7), # blue-green + 'Co' : (0.0, 0.5, 0.6) } # marine + # TODO: all of this using flex array only for i_seq, atom_object in enumerate(self.atom_index) : element = atom_object.element color = element_shades.get(element) @@ -374,13 +345,6 @@ py_atom_colors.append(color) self.atom_colors = flex.vec3_double(py_atom_colors) - def set_sel_color (self, color_string=None, color_tuple=None) : - if color_tuple is None : - color_tuple = utils.color_string_converter(color_string) - self.selection_color = color_tuple - py_sele_color_list = [ color_tuple for i_seq in xrange(0,self.atom_count) ] - self.selection_colors = flex.vec3_double(py_sele_color_list) - #--------------------------------------------------------------------- # drawing functions def draw_lines (self): @@ -409,7 +373,6 @@ self.points_display_list.end() self.points_display_list.call() - def draw_spheres (self) : pass @@ -443,17 +406,123 @@ glDisable(GL_LIGHT0) glDisable(GL_BLEND) +######################################################################## +# ATOM SELECTION VIEWER +# this will handle any valid atom selection recognized by cctbx. +# +class selection_viewer_mixin (model_viewer_mixin) : + initialize_model_viewer_super = True + def __init__ (self, *args, **kwds) : + model_viewer_mixin.__init__(self, *args, **kwds) + # objects used internally + self.selection_covering_sphere = None + self.selection_i_seqs = None + self.selection_cache = None + self.selected_points = [] + self.selection_display_list = None + self.selection_colors = None + self.atoms_selected = None + # various settings + self.selection_string = "None" + self.selection_color = (1.0, 1.0, 1.0) + self.selection_draw_mode = "bonds_and_atoms" + # flags + self.flag_show_selection = True + self.flag_recolor_selection = True + + def DrawGL (self) : + model_viewer_mixin.DrawGL(self) + if self.flag_show_selection : + self.draw_selection() + + def process_key_stroke (self, key) : + model_viewer_mixin.process_key_stroke(self, key) + if key == ord('z') : + self.zoom_selection() + + def update_view (self, redraw_points=True, redraw_lines=False) : + self.selection_display_list = None + model_viewer_mixin.update_view(self, redraw_points, redraw_lines) + + def zoom_selection (self, event=None) : + self.set_selection_sphere() + if self.selection_covering_sphere is not None : + self.minimum_covering_sphere = self.selection_covering_sphere + self.move_rotation_center_to_mcs_center() + self.fit_into_viewport() + else : + self.unzoom() + + def update_selection (self, selection_string=None) : + self.selection_string = str(selection_string) + if self.active_widget is not None : + try : # TODO: make sure the widget isn't a menu item??? + self.active_widget.update_value(self.selection_string) + except Exception, e : + print e + self.apply_selection(self.selection_string) + + def apply_selection (self, selection_string) : + if self.selection_cache is None : + return + sel = self.selection_cache.selection + try : + self.atoms_selected = sel(selection_string) + except : + self.atoms_selected = sel("none") + raise Sorry("The string '%s' is not a valid selection."%selection_string) + self.selection_i_seqs = self.atoms_selected.iselection() + self.update_view() + + def get_selected_atom_count (self) : + return self.selection_i_seqs.size() + + def set_selection_sphere (self) : + if self.selection_i_seqs is None or self.selection_i_seqs.size() == 0 : + self.selection_covering_sphere = None + return + selected_points = [] + points = self.points + for i_seq in self.selection_i_seqs : + selected_points.append(points[i_seq]) + if len(selected_points) == 0 : + self.selection_covering_sphere = minimum_covering_sphere( + points=self.atoms.extract_xyz(), + epsilon=0.1) + else : + s_p = flex.vec3_double(selected_points) + self.selection_covering_sphere = minimum_covering_sphere( + points=s_p, + epsilon=0.1) + + def set_color_mode (self, color_mode, redraw=False) : + self.set_sel_color(color_tuple=self.selection_color) + model_viewer_mixin.set_color_mode(self, color_mode, redraw) + + def set_sel_color (self, color_tuple=(1.0,1.0,1.0)) : + self.selection_color = color_tuple + py_sele_color_list = [ color_tuple for i_seq in xrange(0,self.atom_count) ] + self.selection_colors = flex.vec3_double(py_sele_color_list) + + def set_selected_atom (self, closest_point_i_seq) : + self.current_atom_i_seq = closest_point_i_seq + + #--------------------------------------------------------------------- + # DRAWING def draw_selection (self) : selection_i_seqs = self.selection_i_seqs if selection_i_seqs is None or selection_i_seqs.size() == 0 : return selection_colors = self.atom_colors - if self.flag_color_selection_separately : + if self.flag_recolor_selection and self.selection_colors is not None : selection_colors = self.selection_colors if self.selection_display_list is None : self.selection_display_list = gltbx.gl_managed.display_list() self.selection_display_list.compile() - if self.draw_selection_mode == "bonds_and_atoms" : + draw_mode = self.selection_draw_mode + if draw_mode is None : + draw_mode = "bonds_and_atoms" + if draw_mode == "bonds_and_atoms" : self.visibility.get_selection_visibility( bonds = self.bonds, atoms_selected = self.atoms_selected @@ -472,7 +541,7 @@ atom_colors = selection_colors, bonds_visible = self.visibility.selected_bonds_visible ) - elif self.draw_selection_mode == "points" : + elif draw_mode == "points" : glLineWidth(self.line_width + 2) viewer_utils.draw_points( points = self.points, @@ -480,7 +549,7 @@ points_visible = self.atoms_selected, cross_radius = 0.4 ) - elif self.draw_selection_mode == "spheres" : + elif draw_mode == "spheres" : self._draw_spheres( spheres_visible = self.atoms_selected, atom_colors = selection_colors, @@ -490,10 +559,59 @@ self.selection_display_list.end() self.selection_display_list.call() +######################################################################## +# MIXIN FOR DRAWING ATOM LABELS +# +# This is meant to be combined with other viewer mixins, and is much +# simpler as a result. +class atom_label_mixin (wx_viewer.wxGLWindow) : + initialize_atom_label_super = False + def __init__ (self, *args, **kwds) : + if self.initialize_atom_label_super : + wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + self.label_xyz = [] + self.label_text = [] + self.label_color = (1.0, 1.0, 1.0) + self.labels_display_list = None + self.flag_show_labels = True + + # No InitGL method here. + + def DrawGL (self) : + if self.flag_show_labels : + self.draw_labels() + + def clear_labels (self, event=None) : + self.label_xyz = [] + self.label_text = [] + self.labels_display_list = None + def draw_labels (self) : - pass + if (self.labels_display_list is None) : + font = gltbx.fonts.ucs_bitmap_8x13 + font.setup_call_lists() + self.labels_display_list = gltbx.gl_managed.display_list() + self.labels_display_list.compile() + glColor3f(*self.label_color) + for label,point in zip(self.label_text, self.label_xyz): + glRasterPos3f(*point) + font.render_string(label) + self.labels_display_list.end() + self.labels_display_list.call() + def show_atom_label (self, i_seq) : + if self.points is None or i_seq >= self.points.size() : + return + self.label_xyz.append(self.points[i_seq]) + a = self.atom_index[i_seq] + atom_str = "%s %s%s %s" % (strip(a.name), a.chain_id, strip(a.resseq), + strip(a.resname)) + self.label_text.append(atom_str) + self.OnRedrawGL() +######################################################################## +# UTILITY FUNCTIONS +# def compare_conformers (altloc1, altloc2) : if altloc1 == altloc2 : return True @@ -504,6 +622,9 @@ else : return False +######################################################################## +# CLASSES AND METHODS FOR STANDALONE VIEWER +# class App (wx.App) : def __init__ (self, title="crys3d.wx_model_viewer", default_size=(800,600)) : self.title = title This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-02-20 03:22:21
|
Revision: 8678 http://cctbx.svn.sourceforge.net/cctbx/?rev=8678&view=rev Author: natechols Date: 2009-02-20 01:40:23 +0000 (Fri, 20 Feb 2009) Log Message: ----------- detached model_viewer_base, added sites_viewer_mixin to wx_model_viewer Modified Paths: -------------- trunk/crys3d/wx_map_viewer.py trunk/crys3d/wx_model_viewer.py Modified: trunk/crys3d/wx_map_viewer.py =================================================================== --- trunk/crys3d/wx_map_viewer.py 2009-02-20 00:40:05 UTC (rev 8677) +++ trunk/crys3d/wx_map_viewer.py 2009-02-20 01:40:23 UTC (rev 8678) @@ -300,7 +300,7 @@ front_colour=map_color, back_colour=map_color) - def set_maps (self, maps) : + def set_maps (self, maps, reset_unit_cell=False) : assert len(maps) != 0 self.maps = maps if (len(self.iso_levels) != len(maps) or @@ -308,7 +308,7 @@ self.iso_levels = [ 1.0 for m in maps ] self.map_colors = [ (1., 1., 1.) for m in maps ] self.materials = [ None for m in maps ] - if self.unit_cell is None : + if self.unit_cell is None or reset_unit_cell : self.initialize_unit_cell(self.maps[0]) def compute_triangulation (self) : Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-02-20 00:40:05 UTC (rev 8677) +++ trunk/crys3d/wx_model_viewer.py 2009-02-20 01:40:23 UTC (rev 8678) @@ -8,24 +8,20 @@ from scitbx.array_family import flex, shared from scitbx.math import minimum_covering_sphere from mmtbx.monomer_library import pdb_interpretation +from cctbx import uctbx import wx import sys ######################################################################## # BASE CLASS FOR DISPLAYING STRUCTURES # -class model_viewer_mixin (wx_viewer.wxGLWindow) : +class model_viewer_base (wx_viewer.wxGLWindow) : initialize_model_viewer_super = True def __init__ (self, *args, **kwds) : if self.initialize_model_viewer_super : wx_viewer.wxGLWindow.__init__(self, *args, **kwds) - self.pdb_hierarchy = None self.atomic_bonds = None # from geometry restraints manager - self.selection_cache = None # this is used by extract_trace - self.atoms = None - self.atom_count = 0 self.points = None # basic 3d data - atoms.extract_xyz() - self.b_cache = None # atoms.extract_b() self.atom_index = [] # stores atoms_with_labels data self.current_atom_i_seq = None self.closest_point_i_seq = None # usually set by mouse clicks @@ -37,23 +33,17 @@ # various settings; override these in subclasses and/or provide # a mechanism for changing their values self.line_width = 1 - self.buffer_factor = 2.0 self.nonbonded_line_width = 1 self._fog_start = 50 self._fog_end = 200 - self.draw_mode = "all_atoms" - self.color_mode = "rainbow" - self.recolor = self.color_rainbow self.base_atom_color = (0.6, 0.6, 0.6) # grey - self.carbon_atom_color = (1.0, 1.0, 0.0) # yellow + self.atom_colors = flex.vec3_double() self.orthographic = False # toggles for viewable objects self.flag_show_fog = True self.flag_show_lines = True self.flag_show_points = True self.flag_show_spheres = False - self.flag_show_trace = False - self.flag_show_hydrogens = True self.flag_show_minimum_covering_sphere = False self.flag_show_rotation_center = False @@ -98,9 +88,9 @@ wx_viewer.wxGLWindow.OnRedrawGL(self, event) def unzoom (self, event=None) : - if self.atoms is not None : + if self.points is not None : self.minimum_covering_sphere = minimum_covering_sphere( - points=self.atoms.extract_xyz(), + points=self.points, epsilon=0.1) self.move_rotation_center_to_mcs_center() self.fit_into_viewport() @@ -123,8 +113,6 @@ ) def update_view (self, redraw_points=True, redraw_lines=False) : - self.get_drawn_atom_count() - self.recolor() if redraw_lines : self.lines_display_list = None if redraw_points : @@ -132,16 +120,72 @@ self.OnRedraw() def OnUpdate (self, event=None, recenter=False) : + self.update_view(True, True) + if (event is not None and event.recenter == True) or recenter == True : + self.move_rotation_center_to_mcs_center() + self.fit_into_viewport() + + def draw_lines (self): + if self.lines_display_list is None : + self.lines_display_list = gltbx.gl_managed.display_list() + self.lines_display_list.compile() + glLineWidth(self.line_width) + viewer_utils.draw_bonds( + points = self.points, + bonds = self.bonds, + atom_colors = self.atom_colors, + bonds_visible = self.bonds_visible) + self.lines_display_list.end() + self.lines_display_list.call() + + def draw_points (self) : + if self.points_display_list is None : + self.points_display_list = gltbx.gl_managed.display_list() + self.points_display_list.compile() + glLineWidth(self.nonbonded_line_width) + viewer_utils.draw_points( + points = self.points, + atom_colors = self.atom_colors, + points_visible = self.points_visible + ) + self.points_display_list.end() + self.points_display_list.call() + + def draw_spheres (self) : + pass + +class model_viewer_mixin (model_viewer_base) : + def __init__ (self, *args, **kwds) : + model_viewer_base.__init__(self, *args, **kwds) + self.pdb_hierarchy = None + self.selection_cache = None # this is used by extract_trace + self.atoms = None + self.atom_count = 0 + self.b_cache = None # atoms.extract_b() + # various settings; override these in subclasses and/or provide + # a mechanism for changing their values + self.buffer_factor = 2.0 + self.draw_mode = "all_atoms" + self.color_mode = "rainbow" + self.recolor = self.color_rainbow + self.carbon_atom_color = (1.0, 1.0, 0.0) # yellow + # toggles for viewable objects + self.flag_show_trace = False + self.flag_show_hydrogens = True + + def update_view (self, redraw_points=True, redraw_lines=False) : + self.get_drawn_atom_count() + self.recolor() + model_viewer_base.update_view(self, redraw_points, redraw_lines) + + def OnUpdate (self, event=None, recenter=False) : if self._structure_was_updated : self.extract_atom_data() self.extract_trace() else : self.update_coords() self._structure_was_updated = False - self.update_view(True, True) - if (event is not None and event.recenter == True) or recenter == True : - self.move_rotation_center_to_mcs_center() - self.fit_into_viewport() + model_viewer_base.OnUpdate(self, event, recenter) # Hopefully none of the remaining functions need to be overridden... @@ -339,32 +383,6 @@ #--------------------------------------------------------------------- # drawing functions - def draw_lines (self): - if self.lines_display_list is None : - self.lines_display_list = gltbx.gl_managed.display_list() - self.lines_display_list.compile() - glLineWidth(self.line_width) - viewer_utils.draw_bonds( - points = self.points, - bonds = self.bonds, - atom_colors = self.atom_colors, - bonds_visible = self.bonds_visible) - self.lines_display_list.end() - self.lines_display_list.call() - - def draw_points (self) : - if self.points_display_list is None : - self.points_display_list = gltbx.gl_managed.display_list() - self.points_display_list.compile() - glLineWidth(self.nonbonded_line_width) - viewer_utils.draw_points( - points = self.points, - atom_colors = self.atom_colors, - points_visible = self.points_visible - ) - self.points_display_list.end() - self.points_display_list.call() - def draw_spheres (self) : pass @@ -418,6 +436,7 @@ self.selection_string = "None" self.selection_color = (1.0, 1.0, 1.0) self.selection_draw_mode = "bonds_and_atoms" + self.animation_time = 0.00001 # flags self.flag_show_selection = True self.flag_recolor_selection = True @@ -598,6 +617,27 @@ self.label_text.append(atom_str) self.OnRedrawGL() +class sites_viewer_mixin (model_viewer_base) : + initialize_model_viewer_super = True + def __init__ (self, *args, **kwds) : + model_viewer_base.__init__(self, *args, **kwds) + self.points = flex.vec3_double() + self._new_points = None + self.flag_show_lines = False + self.flag_show_points = True + self.flag_show_spheres = False + self.unit_cell = uctbx.unit_cell((100,100,100,90,90,90)) + + def set_sites (self, new_sites) : + sites_frac = flex.vec3_double(new_sites) + self._new_sites = self.unit_cell.orgothonalization_matrix() * sites_frac + self._new_colors = flex.vec3_double(len(new_sites), self.base_atom_color) + + def OnUpdate (self, event=None, recenter=False) : + self.points = self._new_points + self.atom_colors = self._new_colors + model_viewer_base.OnUpdate(self, event, recenter) + ######################################################################## # UTILITY FUNCTIONS # This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-03-05 20:34:04
|
Revision: 8752 http://cctbx.svn.sourceforge.net/cctbx/?rev=8752&view=rev Author: natechols Date: 2009-03-05 20:33:59 +0000 (Thu, 05 Mar 2009) Log Message: ----------- bug fixes for refine_gui functions Modified Paths: -------------- trunk/crys3d/wx_map_viewer.py trunk/crys3d/wx_model_viewer.py Modified: trunk/crys3d/wx_map_viewer.py =================================================================== --- trunk/crys3d/wx_map_viewer.py 2009-03-05 19:34:07 UTC (rev 8751) +++ trunk/crys3d/wx_map_viewer.py 2009-03-05 20:33:59 UTC (rev 8752) @@ -349,11 +349,12 @@ self.minimum_covering_sphere = minimum_covering_sphere( flex.vec3_double([p,q,r,s])) - def update_map_objects (self) : + def update_map_objects (self, redraw=True) : self.compute_triangulation() # this is done to prevent thread clashes (+ ensuing crashes) self.triangles = self._triangle_tmp - self.OnRedraw() + if redraw : + self.OnRedraw() def set_iso_levels (self, levels) : assert len(levels) == len(self.maps) Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-03-05 19:34:07 UTC (rev 8751) +++ trunk/crys3d/wx_model_viewer.py 2009-03-05 20:33:59 UTC (rev 8752) @@ -21,6 +21,7 @@ if self.initialize_model_viewer_super : wx_viewer.wxGLWindow.__init__(self, *args, **kwds) self.atomic_bonds = None # from geometry restraints manager + self.bonds = shared.stl_set_unsigned() self.points = flex.vec3_double() # basic 3d data self.atom_index = [] # stores atoms_with_labels data self.atoms_visible = flex.bool() @@ -74,7 +75,7 @@ self.setup_lighting() def DrawGL(self): - if self.GL_uninitialised : + if self.GL_uninitialised or self.points.size() == 0 : return if (self.flag_show_points): self.draw_points() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-07-27 16:52:45
|
Revision: 9463 http://cctbx.svn.sourceforge.net/cctbx/?rev=9463&view=rev Author: natechols Date: 2009-07-27 16:52:37 +0000 (Mon, 27 Jul 2009) Log Message: ----------- more improvements to model viewer, plus selection viewing support Modified Paths: -------------- trunk/crys3d/wx_model_viewer_multi_scene.py Added Paths: ----------- trunk/crys3d/wx_model_viewer_example.py trunk/crys3d/wx_selection_editor.py Added: trunk/crys3d/wx_model_viewer_example.py =================================================================== --- trunk/crys3d/wx_model_viewer_example.py (rev 0) +++ trunk/crys3d/wx_model_viewer_example.py 2009-07-27 16:52:37 UTC (rev 9463) @@ -0,0 +1,65 @@ + +import sys, os +import cStringIO +from crys3d.wx_model_viewer_multi_scene import model_viewer_mixin +from crys3d.wx_selection_editor import selection_viewer_mixin +from mmtbx.monomer_library import pdb_interpretation +import iotbx.pdb +import wx + +######################################################################## +# CLASSES AND METHODS FOR STANDALONE VIEWER +# +class App (wx.App) : + def __init__ (self, title="crys3d.wx_model_viewer", default_size=(800,600)) : + self.title = title + self.default_size = default_size + wx.App.__init__(self, 0) + + def OnInit (self) : + self.frame = wx.Frame(None, -1, self.title, pos=wx.DefaultPosition, + size=self.default_size) + self.frame.CreateStatusBar() + box = wx.BoxSizer(wx.VERTICAL) + self.view_objects = selection_viewer_mixin(self.frame, size=(800,600)) + box.Add(self.view_objects, wx.EXPAND, wx.EXPAND) + self.frame.SetSizer(box) + box.SetSizeHints(self.frame) + return True + +def run (args) : + import cStringIO + pdb_files = [] + cif_files = [] + for arg in args : + if os.path.isfile(arg) : + if iotbx.pdb.is_pdb_file(arg) : + pdb_files.append(os.path.abspath(arg)) + elif arg.endswith(".cif") : + cif_files.append(os.path.abspath(arg)) + if len(pdb_files) == 0 : + print "Please specify a PDB file (and optional CIFs) on the command line." + return + a = App() + out = sys.stdout + if not "--debug" in args : + out = cStringIO.StringIO() + for file_name in pdb_files : + print "Reading PDB file %s" % file_name + processed_pdb_file = pdb_interpretation.run(args=[file_name]+cif_files, + log=out) + pdb_hierarchy = processed_pdb_file.all_chain_proxies.pdb_hierarchy + pdb_hierarchy.atoms().reset_i_seq() + grm = processed_pdb_file.geometry_restraints_manager() + if grm is None or grm.shell_sym_tables is None : + raise Sorry("Atomic bonds could not be calculated for this model. "+ + "This is probably due to a missing CRYST1 record in the PDB file.") + atomic_bonds = grm.shell_sym_tables[0].full_simple_connectivity() + a.view_objects.add_model(file_name, pdb_hierarchy, atomic_bonds) + a.frame.Show() + a.view_objects.force_update(recenter=True) + a.MainLoop() + +if __name__ == "__main__" : + import sys + run(sys.argv[1:]) Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-07-27 06:08:56 UTC (rev 9462) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-07-27 16:52:37 UTC (rev 9463) @@ -1,57 +1,89 @@ -from string import strip -from libtbx.utils import Sorry +# XXX: To keep these classes as clean as possible, selections are handled +# entirely in wx_selection_editor.py. + +import iotbx.phil +from cctbx import uctbx import gltbx.util from gltbx import wx_viewer, viewer_utils, quadrics from gltbx.gl import * from gltbx.glu import * from scitbx.array_family import flex, shared from scitbx.math import minimum_covering_sphere -from mmtbx.monomer_library import pdb_interpretation -from cctbx import uctbx from libtbx.introspection import method_debug_log +from libtbx.utils import Sorry from libtbx import adopt_init_args import wx -import sys +import sys, os debug = method_debug_log() +opengl_phil = iotbx.phil.parse(""" +opengl { + line_width = 2 + .type = int + .style = spinner min:1 max:10 + nonbonded_line_width = 2 + .type = int + .style = spinner min:1 max:10 + map_radius = 10 + .type = int + .style = spinner min:1 max:40 + base_atom_color = 1.0 1.0 0.0 + .type = floats + .style = color + background_color = 0.0 0.0 0.0 + .type = floats + .style = color + show_hydrogens = False + .type = bool + label_clicked_atom = True + .type = bool + use_atom_color_for_labels = True + .type = bool + use_fog = True + .type = bool + orthographic = False + .type = bool +} +""") + #----------------------------------------------------------------------- # XXX: None of the data in this class is used directly in OpenGL calls; # instead, the model_scene object contains the subset of information # required for immediate display. class model_data (object) : def __init__ (self, object_id, pdb_hierarchy, atomic_bonds, - initial_color=(0.0,1.0,1.0)) : + base_color=(0.0,1.0,1.0)) : self.object_id = object_id + self.base_color = base_color + self.draw_mode = None + self.color_mode = "rainbow" self.update_structure(pdb_hierarchy, atomic_bonds) self.flag_object_visible = True - self.flag_allow_selection = True self.use_u_aniso = flex.bool(self.atoms.size()) - self.trace_bonds = shared.stl_set_unsigned() self.current_bonds = self.atomic_bonds - self.atom_colors = flex.vec3_double(self.atoms.size(), initial_color) + #self.atom_colors = flex.vec3_double(self.atoms.size(), base_color) self._color_cache = {} - self.recalculate_visibility(False, True) + self.flag_show_hydrogens = True + self.flag_show_points = True + self.flag_show_ellipsoids = False + self.set_draw_mode("all_atoms") + #self.recalculate_visibility() - # XXX: selections - self.selection_string = "None" - self.selection_covering_sphere = None - self.selection_i_seqs = None - self.selection_cache = None - self.selected_points = [] - self.selection_display_list = None - self.selection_colors = flex.vec3_double() - self.atoms_selected = None - def reset (self) : self.is_changed = False @debug def get_scene_data (self) : - return model_scene(self.current_bonds, self.atoms.extract_xyz(), - self.atoms.extract_b(), self.atoms.extract_uij(), self.atom_colors, - self.visibility) + return model_scene(bonds=self.current_bonds, + points=self.atoms.extract_xyz(), + b_iso=self.atoms.extract_b(), + b_aniso=self.atoms.extract_uij(), + atom_colors=self.atom_colors, + atom_labels=self.atom_labels, + atom_radii=self.atom_radii, + visibility=self.visibility) def update_scene_data (self, scene) : scene.update_bonds(self.current_bonds) @@ -104,10 +136,13 @@ self.atom_count = self.atoms.size() self.selection_cache = pdb_hierarchy.atom_selection_cache() atom_index = [] + atom_labels = flex.std_string() for atom in self.pdb_hierarchy.atoms_with_labels() : atom_index.append(atom) + atom_labels.append(format_atom_label(atom)) self.atom_index = atom_index - self.extract_trace() + self.atom_labels = atom_labels + self.trace_bonds = extract_trace(pdb_hierarchy) #, self.selection_cache) assert len(self.atom_index) == self.atom_count atom_radii = flex.double(self.atoms.size(), 1.5) hydrogen_flag = flex.bool(self.atoms.size(), False) @@ -117,66 +152,77 @@ hydrogen_flag[i_seq] = True self.atom_radii = atom_radii self.hydrogen_flag = hydrogen_flag - self.minimum_covering_sphere = minimum_covering_sphere( - points=self.atoms.extract_xyz(), - epsilon=0.1) self._color_cache = {} self.is_changed = True @debug - def extract_trace (self) : - if self.selection_cache is None : return - last_atom = None - isel = self.selection_cache.iselection - selection_i_seqs = list( - isel("(name ' CA ' or name ' P ') and (altloc 'A' or altloc ' ')")) - last_atom = None - bonds = shared.stl_set_unsigned(self.atoms.size()) - for atom in self.atom_index : - if atom.i_seq in selection_i_seqs : - if last_atom is not None : - if atom.chain_id == last_atom.chain_id and \ - atom.model_id == last_atom.model_id and \ - atom.resseq_as_int() == (last_atom.resseq_as_int() + 1) and \ - compare_conformers(atom.altloc, last_atom.altloc) == True : - bonds[last_atom.i_seq].append(atom.i_seq) - bonds[atom.i_seq].append(last_atom.i_seq) - last_atom = atom - self.trace_bonds = bonds - - @debug - def toggle_trace_mode (self, show_trace=True) : - if show_trace : - self.current_bonds = self.atomic_bonds - else : - self.current_bonds = self.trace_bonds - - @debug - def recalculate_visibility (self, show_hydrogens=True, show_points=False) : + def recalculate_visibility (self) : c = 0 atoms = self.atom_index - if show_hydrogens : + if self.flag_show_hydrogens : atoms_drawable = flex.bool(self.atom_count, True) else : atoms_drawable = flex.bool([ (atom.element != ' H') for atom in atoms ]) self.visibility = viewer_utils.atom_visibility( bonds = self.current_bonds, atoms_drawable = atoms_drawable, - flag_show_points = show_points + flag_show_points = self.flag_show_points ) self.visible_atom_count = self.visibility.visible_atoms_count + def toggle_hydrogens (self, show_hydrogens) : + self.flag_show_hydrogens = show_hydrogens + + def toggle_ellipsoids (self, show_ellipsoids) : + self.flag_show_ellipsoids = show_ellipsoids + + def set_draw_mode (self, draw_mode) : + if draw_mode == self.draw_mode and not self.is_changed : + pass + else : + self.draw_mode = draw_mode + show_points = True + if draw_mode in ["trace", "trace_and_nb"] : + self.current_bonds = self.trace_bonds + else : + self.current_bonds = self.atomic_bonds + if draw_mode in ["trace", "bonded_only"] : + self.flag_show_points = False + else : + self.flag_show_points = True + self.recalculate_visibility() + self.set_color_mode(self.color_mode) # force re-coloring + #--------------------------------------------------------------------- # XXX: COLORING # + def set_base_color (self, color) : + self.base_color = color + + def set_color_mode (self, color_mode) : + if color_mode == self.color_mode and not self.is_changed : + pass + else : + self.color_mode = color_mode + if color_mode == "mono" : + self.color_mono() + elif color_mode == "rainbow" : + self.color_rainbow() + elif color_mode == "b" : + self.color_b() + elif color_mode == "chain" : + self.color_by_chain() + elif color_mode == "element" : + self.color_by_element() + @debug - def color_mono (self, base_atom_color=(0.0,1.0,1.0)) : + def color_mono (self) : cached = self._color_cache.get("mono") if cached is not None : self.atom_colors = cached else : self.atom_colors = flex.vec3_double( - [ self.base_atom_color for i in xrange(0, self.points.size()) ] + [ self.base_color for i in xrange(0, self.atoms.size()) ] ) self._color_cache["mono"] = self.atom_colors @@ -193,7 +239,7 @@ self._color_cache["rainbow"] = self.atom_colors @debug - def color_b (self, scale_b_to_visible=True) : + def color_b (self) : cached = self._color_cache.get("b") if cached is not None : self.atom_colors = cached @@ -201,7 +247,7 @@ self.atom_colors = viewer_utils.color_by_property( atom_properties = self.atoms.extract_b(), atoms_visible = self.visibility.atoms_visible, - color_invisible_atoms = not scale_b_to_visible, + color_invisible_atoms = False, use_rb_color_gradient = False ) self._color_cache["b"] = self.atom_colors @@ -227,14 +273,14 @@ self._color_cache["chain"] = atom_colors @debug - def color_by_element (self, carbon_atom_color=(1.0,1.0,0.0)) : + def color_by_element (self) : cached = self._color_cache.get("element") if cached is not None : self.atom_colors = cached else : # these are approximations based on my (probably faulty) memory. # feel free to change to something more reasonable. - element_shades = {' C' : carbon_atom_color, # usually yellow or grey + element_shades = {' C' : self.base_color, # usually yellow or grey ' H' : (0.95, 0.95, 0.95), # very light grey ' N' : (0.0, 0.0, 1.0), # blue ' O' : (1.0, 0.0, 0.0), # red @@ -265,12 +311,13 @@ # XXX: this class contains only the information needed for OpenGL commands, # which are also implemented as methods here. class model_scene (object) : - def __init__ (self, bonds, points, b_iso, b_aniso, atom_colors, visibility) : + def __init__ (self, bonds, points, b_iso, b_aniso, atom_colors, atom_labels, + atom_radii, visibility) : adopt_init_args(self, locals()) self.clear_lists() + self.clear_labels() self.update_visibility(visibility) - self.minimum_covering_sphere = minimum_covering_sphere(points=points, - epsilon=0.1) + @debug def clear_lists (self) : self.points_display_list = None @@ -278,8 +325,19 @@ self.spheres_display_list = None self.ellipsoid_display_list = None self.selection_display_list = None + self.labels_display_list = None @debug + def clear_labels (self) : + self.show_labels = flex.bool(self.points.size(), False) + self.labels_display_list = None + + @debug + def add_label (self, i_seq) : + self.show_labels[i_seq] = True + self.labels_display_list = None + + @debug def update_colors (self, atom_colors) : assert atom_colors.size() == self.points.size() self.atom_colors = atom_colors @@ -328,10 +386,11 @@ self.spheres_display_list.compile() glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) atom_radii = self.atom_radii + atom_colors = self.atom_colors spheres_visible = self.spheres_visible for i_seq, point in enumerate(points) : if self.spheres_visible[i_seq] : - #glColor3f(*atom_colors[i_seq]) + glColor3f(*atom_colors[i_seq]) glPushMatrix() glTranslated(*point) gltbx.util.SolidSphere(radius=atom_radii[i_seq], @@ -357,8 +416,26 @@ self.ellipsoid_display_list.end() self.ellipsoid_display_list.call() + def draw_labels (self, font, use_atom_color=False) : + glDisable(GL_LIGHTING) + if (self.labels_display_list is None) : + self.labels_display_list = gltbx.gl_managed.display_list() + self.labels_display_list.compile() + points = self.points + atoms_visible = self.atoms_visible + atom_colors = self.atom_colors + atom_labels = self.atom_labels + for i_seq, show_label in enumerate(self.show_labels) : + if atoms_visible[i_seq] and show_label : + if use_atom_color : + glColor3f(*atom_colors[i_seq]) + glRasterPos3f(*points[i_seq]) + font.render_string(atom_labels[i_seq]) + self.labels_display_list.end() + self.labels_display_list.call() + ######################################################################## -# BASE CLASS FOR DISPLAYING STRUCTURES +# VIEWER CLASS # class model_viewer_mixin (wx_viewer.wxGLWindow) : initialize_model_viewer_super = True @@ -370,19 +447,11 @@ self.model_objects = [] self.model_ids = [] self.scene_objects = {} + self.model_colors = {} + self.model_reps = {} self.update_scene = False - # various settings; override these in subclasses and/or provide - # a mechanism for changing their values - self.buffer_factor = 2 - self.line_width = 2 - self.nonbonded_line_width = 2 - self.base_atom_color = (0.6, 0.6, 0.6) # grey - self.orthographic = False - self.draw_mode = "all_atoms" - self.color_mode = "b_factors" - self.recolor = self.color_b - self.scale_b_to_visible = True - self.carbon_atom_color = (1.0, 1.0, 0.0) # yellow + self.buffer_factor = 2 # see gltbx.wx_viewer + self.settings = opengl_phil.extract() self.closest_point_i_seq = None self.closest_point_model_id = None # toggles for viewable objects @@ -392,14 +461,12 @@ self.flag_show_spheres = False self.flag_show_ellipsoids = False self.flag_use_lights = True + self.flag_show_labels = True self.flag_show_trace = False self.flag_show_hydrogens = False self.flag_show_ellipsoids = False + self.flag_smooth_lines = True - def iter_models (self) : - for model_id, model_object in zip(self.model_ids, self.model_objects) : - yield (model_id, model_object) - @debug def InitGL(self): gltbx.util.handle_error() @@ -409,12 +476,11 @@ glEnable(GL_ALPHA_TEST) glEnable(GL_DEPTH_TEST) glEnable(GL_BLEND) - vendor = glGetString(GL_VENDOR) - if sys.platform == "darwin" and vendor.startswith("NVIDIA") : - glDisable(GL_LINE_SMOOTH) - else : - glEnable(GL_LINE_SMOOTH) - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) + # XXX: line smoothing is pretty essential for wireframe representation; + # the problem with nvidia cards is really only a problem for the isomesh + # in wx_map_viewer.py. + glEnable(GL_LINE_SMOOTH) + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) self.initialize_modelview() if self.flag_use_lights : glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) @@ -433,18 +499,6 @@ else : self.setup_lighting() - def DrawGL(self): - if self.GL_uninitialised or len(self.scene_objects) == 0 : - return - if (self.flag_show_points): - self.draw_points() - if (self.flag_show_lines): - self.draw_lines() - if (self.flag_show_spheres): - self.draw_spheres() - if self.flag_show_ellipsoids : - self.draw_ellipsoids() - def OnRedrawGL (self, event=None) : if self.update_scene : self.update_scene_objects() @@ -459,26 +513,129 @@ else : wx_viewer.wxGLWindow.OnRedrawGL(self, event) + def DrawGL(self): + if self.GL_uninitialised or len(self.scene_objects) == 0 : + return + if (self.flag_show_points): + self.draw_points() + if (self.flag_show_lines): + self.draw_lines() + if (self.flag_show_spheres): + self.draw_spheres() + if self.flag_show_ellipsoids : + self.draw_ellipsoids() + if self.flag_show_labels : + self.draw_labels() + + def draw_points (self) : + glDisable(GL_LIGHTING) + glLineWidth(self.settings.opengl.nonbonded_line_width) + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + scene.draw_points() + + def draw_spheres (self) : + glMatrixMode(GL_MODELVIEW) + if self.flag_use_lights : + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glEnable(GL_LIGHT1) + glEnable(GL_NORMALIZE) + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [1.0,1.0,1.0,1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.1, 0.1, 0.1, 1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [0.1, 0.1, 0.1, 1.0]) + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + scene.draw_spheres() + + def draw_lines (self) : + glEnable(GL_LINE_SMOOTH) + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) + glDisable(GL_LIGHTING) + glLineWidth(self.settings.opengl.line_width) + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + scene.draw_lines() + if not self.flag_smooth_lines : + glDisable(GL_LINE_SMOOTH) + + def draw_ellipsoids (self) : + glMatrixMode(GL_MODELVIEW) + if self.flag_use_lights : + glShadeModel(GL_SMOOTH) + glEnable(GL_DEPTH_TEST) + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glEnable(GL_LIGHT1) + glEnable(GL_NORMALIZE) + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [0.5, 0.5, 0.5, 1.0]) + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + proto_ellipsoid = self.proto_ellipsoid + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + scene.draw_ellipsoids(proto_ellipsoid) + + def draw_labels (self) : + glDisable(GL_LIGHTING) + use_atom_color = self.settings.opengl.use_atom_color_for_labels + if not use_atom_color : + glColor3f(1.0, 1.0, 1.0) + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + font = gltbx.fonts.ucs_bitmap_8x13 + font.setup_call_lists() + scene.draw_labels(font, use_atom_color) + @debug + def refresh_bg_color (self) : + (r, g, b) = tuple(self.settings.opengl.background_color) + glClearColor(r, g, b, 0.0) + + #--------------------------------------------------------------------- + # Non-OpenGL code below here + # + def update_settings (self, params, redraw=False) : + assert (len(params.opengl.base_atom_color) == + len(params.opengl.background_color) == + len(params.opengl.selection_color) == 3) + self.settings = params + if redraw : + self.update_scene = True + + def iter_models (self) : + for model_id, model_object in zip(self.model_ids, self.model_objects) : + yield (model_id, model_object) + + @debug def add_model (self, model_id, pdb_hierarchy, atomic_bonds=None) : - model = model_data(model_id, pdb_hierarchy, atomic_bonds) + assert isinstance(model_id, str) + model = model_data(model_id, pdb_hierarchy, atomic_bonds, + base_color=self.settings.opengl.base_atom_color) self.model_ids.append(model_id) self.model_objects.append(model) self.show_object[model_id] = True - self.recolor() self.update_scene = True + def update_mcs (self, points, recenter_and_zoom=True) : + self.minimum_covering_sphere = minimum_covering_sphere( + points=points, + epsilon=0.1) + if recenter_and_zoom : + self.move_rotation_center_to_mcs_center() + self.fit_into_viewport() + + def zoom_object (self, object_id) : + assert object_id in self.scene_objects + self.update_mcs(self.scene_objects[object_id].points) + @debug def unzoom (self, event=None) : if len(self.scene_objects) > 0 : points = flex.vec3_double() - for scene in self.scene_objects : + for object_id, scene in self.scene_objects.iteritems() : points.extend(scene.points) - self.minimum_covering_sphere = minimum_covering_sphere( - points=points, - epsilon=0.1) - self.move_rotation_center_to_mcs_center() - self.fit_into_viewport() + self.update_mcs(points) @debug def recenter_on_atom (self, object_id, i_seq) : @@ -489,29 +646,9 @@ self.move_to_center_of_viewport(self.rotation_center) @debug - def process_key_stroke (self, key) : - if key == ord('u') : - self.unzoom() - elif key == ord('h') : - self.flag_show_hydrogens = not self.flag_show_hydrogens - self.update_scene = True - elif key == ord('e') : - self.flag_show_ellipsoids = not self.flag_show_ellipsoids - self.update_scene = True - elif key == ord('p') : - self.flag_show_points = not self.flag_show_points - self.update_scene = True - elif key == ord('b') : - if self.color_mode == "b_factors" : - self.set_color_mode("element") - else : - self.set_color_mode("b_factors") - self.update_scene = True - if self.update_scene : - self.OnRedrawGL() - - @debug def process_pick_points (self) : + self.closest_point_object_id = None + self.closest_point_i_seq = None if self.pick_points is not None and len(self.scene_objects) > 0 : for object_id in self.model_ids : if self.show_object[object_id] : @@ -526,16 +663,11 @@ point1 = self.pick_points[1] ) break + if self.closest_point_i_seq is not None : + clicked_scene = self.scene_objects.get(self.closest_point_object_id) + clicked_scene.add_label(self.closest_point_i_seq) @debug - def OnUpdate (self, event) : - self.update_scene_objects() - if (event is not None and hasattr(event, "recenter") and - event.recenter == True) or recenter == True : - self.move_rotation_center_to_mcs_center() - self.fit_into_viewport() - - @debug def update_scene_objects (self) : points = flex.vec3_double() for object_id, model in self.iter_models() : @@ -549,179 +681,122 @@ points.extend(current_scene.points) if points.size() == 0 : points.append((0,0,0)) - self.minimum_covering_sphere = minimum_covering_sphere(points=points, - epsilon=0.1) + self.update_mcs(points, recenter_and_zoom=False) @debug - def update_model_objects (self) : - for object_id, model in self.iter_models() : - model.recalculate_visibility(self.flag_show_hydrogens, - self.flag_show_points) - self.recolor() - - @debug - def set_draw_mode (self, draw_mode, redraw=False) : - if not self.minimum_covering_sphere : - return - self.draw_mode = draw_mode - if draw_mode == "trace" : - self.flag_show_points = False - for object in self.model_objects : - object.toggle_trace_mode(True) - elif self.draw_mode == "bonded_only" : - self.flag_show_points = False - for object in self.model_objects : - object.toggle_trace_mode(False) + def process_key_stroke (self, key) : + if key == ord('u') : + self.unzoom() + elif key == ord('h') : + self.flag_show_hydrogens = not self.flag_show_hydrogens + self.toggle_hydrogens(self.flag_show_hydrogens) + self.update_scene = True + elif key == ord('e') : + self.flag_show_ellipsoids = not self.flag_show_ellipsoids + self.toggle_ellipsoids(self.flag_show_ellipsoids) + self.update_scene = True + elif key == ord('l') : + self.flag_show_labels = not self.flag_show_labels + self.update_scene = True + elif key == ord('t') : + self.flag_show_trace = not self.flag_show_trace + if self.flag_show_trace : + self.set_draw_mode("trace") + else : + self.set_draw_mode("all_atoms") + self.update_scene = True + elif key == ord('b') : + self.set_color_mode("b") + elif key == ord('r') : + self.set_color_mode("rainbow") + elif key == ord('y') : + self.set_color_mode("element") + elif key == 8 : # delete, at least on Mac + self.clear_all_labels() + self.update_scene = True + elif key == ord('q') : + app = wx.GetApp() + app.Exit() else : - self.flag_show_points = True - for object in self.model_objects : - object.toggle_trace_mode(False) - self.update_model_objects() - self.set_color_mode(self.color_mode, redraw=redraw) + print key + if self.update_scene : + self.OnRedrawGL() - #--------------------------------------------------------------------- - # coloring + def hide_others (self, object_id=None) : + for model_id in self.model_ids : + if model_id != object_id : + self.show_objects[model_id] = False + + def show_all (self) : + for model_id in self.model_ids : + self.show_objects[model_id] = True + @debug - def set_bg_color (self) : - (r,g,b) = self.bg_color - glClearColor(r, g, b, 0.0) + def set_draw_mode (self, draw_mode, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.set_draw_mode(draw_mode) + self.update_scene = True @debug - def set_color_mode (self, color_mode) : - self.color_mode = color_mode - if color_mode == "rainbow" : - self.recolor = self.color_rainbow - elif color_mode == "element" : - self.recolor = self.color_by_element - elif color_mode == "b_factors" : - self.recolor = self.color_b - elif color_mode == "chain" : - self.recolor = self.color_by_chain - elif color_mode == "single_color" : - self.recolor = self.color_mono - else : - pass + def set_color_mode (self, color_mode, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.set_color_mode(color_mode) + self.update_scene = True - def color_mono (self) : - for object in self.model_objects : - object.color_mono(self.base_atom_color) + def toggle_ellipsoids (self, show_ellipsoids, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.toggle_ellipsoids(show_ellipsoids) - def color_rainbow (self) : - for object in self.model_objects : - object.color_rainbow() + def toggle_hydrogens (self, show_hydrogens, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.toggle_hydrogens(show_hydrogens) - def color_b (self) : - for object in self.model_objects : - object.color_b(self.scale_b_to_visible) + def toggle_labels (self, show_labels) : + self.flag_show_labels = show_labels - def color_by_chain (self) : - for object in self.model_objects : - object.color_by_chain() + def clear_all_labels (self) : + for object_id, scene in self.scene_objects.iteritems() : + scene.clear_labels() - def color_by_element (self) : - for object in self.model_objects : - object.color_by_element(self.carbon_atom_color) - #--------------------------------------------------------------------- - # DRAWING ROUTINES - def draw_points (self) : - glDisable(GL_LIGHTING) - glLineWidth(self.nonbonded_line_width) - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_points() + # EVENTS + @debug + def OnUpdate (self, event) : + self.update_scene_objects() + if (event is not None and hasattr(event, "recenter") and + event.recenter == True) or recenter == True : + self.move_rotation_center_to_mcs_center() + self.fit_into_viewport() - def draw_spheres (self) : - glMatrixMode(GL_MODELVIEW) - if self.flag_use_lights : - glEnable(GL_LIGHTING) - glEnable(GL_LIGHT0) - glEnable(GL_LIGHT1) - glEnable(GL_NORMALIZE) - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [1.0,1.0,1.0,1.0]) - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.1, 0.1, 0.1, 1.0]) - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [0.1, 0.1, 0.1, 1.0]) - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_spheres() +#----------------------------------------------------------------------- +# Utility functions +def extract_trace (pdb_hierarchy, selection_cache=None) : + if selection_cache is None : + selection_cache = pdb_hierarchy.atom_selection_cache() + last_atom = None + isel = selection_cache.iselection + selection_i_seqs = list( + isel("(name ' CA ' or name ' P ') and (altloc 'A' or altloc ' ')")) + last_atom = None + bonds = shared.stl_set_unsigned(pdb_hierarchy.atoms().size()) + for atom in pdb_hierarchy.atoms_with_labels() : + if atom.i_seq in selection_i_seqs : + if last_atom is not None : + if (atom.chain_id == last_atom.chain_id and + atom.model_id == last_atom.model_id and + atom.resseq_as_int() == (last_atom.resseq_as_int() + 1) and + ((atom.altloc == last_atom.altloc) or + (atom.altloc == "A" and last_atom.altloc == "") or + (atom.altloc == "" and last_atom.altloc == "A"))) : + bonds[last_atom.i_seq].append(atom.i_seq) + bonds[atom.i_seq].append(last_atom.i_seq) + last_atom = atom + return bonds - def draw_lines (self) : - glDisable(GL_LIGHTING) - glLineWidth(self.line_width) - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_lines() - - def draw_ellipsoids (self) : - glMatrixMode(GL_MODELVIEW) - if self.flag_use_lights : - glShadeModel(GL_SMOOTH) - glEnable(GL_DEPTH_TEST) - glEnable(GL_LIGHTING) - glEnable(GL_LIGHT0) - glEnable(GL_LIGHT1) - glEnable(GL_NORMALIZE) - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [0.5, 0.5, 0.5, 1.0]) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) - proto_ellipsoid = self.proto_ellipsoid - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_ellipsoids(proto_ellipsoid) - -######################################################################## -# UTILITY FUNCTIONS -# -def compare_conformers (altloc1, altloc2) : - if altloc1 == altloc2 : - return True - elif altloc1 == "A" and altloc2 == "" : - return True - elif altloc2 == "A" and altloc1 == "" : - return True - else : - return False - -######################################################################## -# CLASSES AND METHODS FOR STANDALONE VIEWER -# -class App (wx.App) : - def __init__ (self, title="crys3d.wx_model_viewer", default_size=(800,600)) : - self.title = title - self.default_size = default_size - wx.App.__init__(self, 0) - - def OnInit (self) : - self.frame = wx.Frame(None, -1, self.title, pos=wx.DefaultPosition, - size=self.default_size) - self.frame.CreateStatusBar() - box = wx.BoxSizer(wx.VERTICAL) - self.view_objects = model_viewer_mixin(self.frame, size=(800,600)) - box.Add(self.view_objects, wx.EXPAND, wx.EXPAND) - self.frame.SetSizer(box) - box.SetSizeHints(self.frame) - return True - -def run (args) : - if len(args) == 0 : - print "Please specify a PDB file (and optional CIFs) on the command line." - return - a = App() - processed_pdb_file = pdb_interpretation.run(args=args) - pdb_hierarchy = processed_pdb_file.all_chain_proxies.pdb_hierarchy - pdb_hierarchy.atoms().reset_i_seq() - grm = processed_pdb_file.geometry_restraints_manager() - if grm is None or grm.shell_sym_tables is None : - raise Sorry("Atomic bonds could not be calculated for this model. "+ - "This is probably due to a missing CRYST1 record in the PDB file.") - atomic_bonds = grm.shell_sym_tables[0].full_simple_connectivity() - #a.frame.Show() - a.view_objects.add_model("1", pdb_hierarchy, atomic_bonds) - a.frame.Show() - a.view_objects.force_update(recenter=True) - #a.view_objects.OnUpdate() - a.MainLoop() - -if __name__ == "__main__" : - import sys - run(sys.argv[1:]) +def format_atom_label (atom_info) : + return ("%s %s%s %s %s" % (atom_info.name, atom_info.altloc, + atom_info.resname, atom_info.chain_id, atom_info.resid())).strip() Added: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py (rev 0) +++ trunk/crys3d/wx_selection_editor.py 2009-07-27 16:52:37 UTC (rev 9463) @@ -0,0 +1,228 @@ + +from crys3d.wx_model_viewer_multi_scene import model_data, model_scene, \ + model_viewer_mixin +from gltbx.gl import * +from gltbx.glu import * +from gltbx import viewer_utils +from scitbx.array_family import flex +import iotbx.phil +from libtbx.utils import Sorry + +viewer_phil = iotbx.phil.parse(""" +include scope crys3d.wx_model_viewer_multi_scene.opengl_phil +selections { + selection_color = 1.0 1.0 1.0 + .type = floats + .style = color + use_global_selection_color = True + .type = bool + line_padding = 2 + .type = int +} +""", process_includes=True) + +class model_data_with_selection (model_data) : + def __init__ (self, *args, **kwds) : + self.mmtbx_handler = None + self.flag_show_selection = False + self.flag_allow_selection = True + self.selection_string = "none" + self.saved_selection = "none" # for recovery later + self.selection_i_seqs = None + model_data.__init__(self, *args, **kwds) + self.selection_colors = flex.vec3_double(self.atoms.size(), (1,1,1)) + self.atoms_selected = flex.bool(self.atoms.size(), False) + self.selection_i_seqs = self.atoms_selected.iselection() + + def set_mmtbx_selection_handler (self, mmtbx_handler) : + self.mmtbx_handler = mmtbx_handler + + def get_scene_data (self) : + return model_scene_with_selection(bonds=self.current_bonds, + points=self.atoms.extract_xyz(), + b_iso=self.atoms.extract_b(), + b_aniso=self.atoms.extract_uij(), + atom_colors=self.atom_colors, + atom_labels=self.atom_labels, + atom_radii=self.atom_radii, + visibility=self.visibility) + + def update_scene_data (self, scene) : + scene.update_selection(self.atoms_selected) + model_data.update_scene_data(self, scene) + + def update_structure (self, pdb_hierarchy, atomic_bonds, + mmtbx_handler=None) : + model_data.update_structure(self, pdb_hierarchy, atomic_bonds) + self.selection_cache = pdb_hierarchy.atom_selection_cache() + self.mmtbx_handler = mmtbx_handler + self.apply_selection(self.saved_selection) + + def selection_size (self) : + return self.selection_i_seqs.size() + + def apply_selection (self, selection_string) : + try : + if self.mmtbx_handler is not None : + atoms_selected = self.mmtbx_handler.selection( + string=selection_string, + cache=self.selection_cache) + else : + atoms_selected = self.selection_cache.selection(selection_string) + except KeyboardInterrupt : + raise + except Exception : + self.selection_string = "none" + atoms_selected = self.selection_cache.selection("none") + raise Sorry("Invalid selection '%s'."%selection_string) + else : + self.selection_string = selection_string + finally : + self.atoms_selected = atoms_selected + self.selection_i_seqs = atoms_selected.iselection() + + def revert_selection (self) : + self.apply_selection(self.saved_selection) + + def set_initial_selection (self, selection_string) : + self.saved_selection = selection_string + self.apply_selection(selection_string) + +#----------------------------------------------------------------------- +class model_scene_with_selection (model_scene) : + def __init__ (self, *args, **kwds) : + model_scene.__init__(self, *args, **kwds) + self.selection_draw_mode = "bonds_and_atoms" + self.update_selection(flex.bool(self.points.size(), False)) + + def clear_lists (self) : + self.selection_display_list = None + model_scene.clear_lists(self) + + def update_selection (self, atoms_selected) : + self.atoms_selected = atoms_selected + self.selection_i_seqs = atoms_selected.iselection() + self.selection_display_list = None + + def get_selected_xyz (self) : + points = self.points + for i_seq in self.selection_i_seqs : + yield points[i_seq] + + # XXX: this is still gross. + def draw_selection (self, color, use_atom_colors=False) : + selection_i_seqs = self.selection_i_seqs + if selection_i_seqs is None or selection_i_seqs.size() == 0 : + return + if self.selection_display_list is None : + if use_atom_colors : + selection_colors = self.atom_colors + else : + selection_colors = flex.vec3_double(self.points.size(), color) + self.selection_display_list = gltbx.gl_managed.display_list() + self.selection_display_list.compile() + draw_mode = self.selection_draw_mode + if draw_mode is None : + draw_mode = "bonds_and_atoms" + if draw_mode == "bonds_and_atoms" : + self.visibility.get_selection_visibility( + bonds = self.bonds, + atoms_selected = self.atoms_selected) + viewer_utils.draw_points( + points = self.points, + atom_colors = selection_colors, + points_visible = self.visibility.selected_points_visible, + cross_radius = 0.4) + viewer_utils.draw_bonds( + points = self.points, + bonds = self.bonds, + atom_colors = selection_colors, + bonds_visible = self.visibility.selected_bonds_visible) + elif draw_mode == "points" : + viewer_utils.draw_points( + points = self.points, + atom_colors = selection_colors, + points_visible = self.atoms_selected, + cross_radius = 0.4) + elif draw_mode == "spheres" : + atoms_selected = self.atoms_selected + atom_radii = self.atom_radii + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + for i_seq, point in enumerate(self.points) : + if atoms_selected[i_seq] : + glColor3f(*selection_colors[i_seq]) + glPushMatrix() + glTranslated(*point) + gltbx.util.SolidSphere(radius=atom_radii[i_seq], + slices=50, stacks=50) + glPopMatrix() + self.selection_display_list.end() + self.selection_display_list.call() + +######################################################################## +# VIEWER CLASS +# mouse controls are implemented separately in selection_editor_mixin. +class selection_viewer_mixin (model_viewer_mixin) : + def __init__ (self, *args, **kwds) : + model_viewer_mixin.__init__(self, *args,**kwds) + self.selection_sphere = None + self.flag_show_selections = True + self.settings = viewer_phil.extract() + + def DrawGL (self) : + model_viewer_mixin.DrawGL(self) + if self.flag_show_selections : + self.draw_selections() + + def draw_selections (self) : + line_width = (self.settings.opengl.line_width + + self.settings.selections.line_padding) + glLineWidth(line_width) + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + scene.draw_selection(color=self.settings.selections.selection_color, + use_atom_colors=self.settings.selections.use_global_selection_color) + + #--------------------------------------------------------------------- + def zoom_selections (self) : + points = flex.vec3_double() + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + for point in scene.get_selected_xyz() : + points.append(point) + if points.size() != 0 : + self.update_mcs(points) + + def set_selection (self, object_id, selection_string) : + for model_id, model in self.iter_models() : + if model_id == object_id : + model.apply_selection(selection_string) + self.update_scene = True + + def add_model (self, model_id, pdb_hierarchy, atomic_bonds, + mmtbx_handler=None) : + assert isinstance(model_id, str) + model = model_data_with_selection(model_id, pdb_hierarchy, atomic_bonds, + base_color=self.settings.opengl.base_atom_color) + self.model_ids.append(model_id) + self.model_objects.append(model) + self.show_object[model_id] = True + model.set_mmtbx_selection_handler(mmtbx_handler) + self.update_scene = True + + def process_key_stroke (self, key) : + if key == ord('s') : + self.flag_show_selections = not self.flag_show_selections + self.update_scene = True + elif key == ord('z') : + self.zoom_selections() + model_viewer_mixin.process_key_stroke(self,key) + + def set_selected_atom (self, i_seq) : + self.current_atom_i_seq = i_seq + +#----------------------------------------------------------------------- +class selection_editor_mixin (selection_viewer_mixin) : + pass + +#---end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-07-29 00:19:30
|
Revision: 9476 http://cctbx.svn.sourceforge.net/cctbx/?rev=9476&view=rev Author: natechols Date: 2009-07-29 00:19:22 +0000 (Wed, 29 Jul 2009) Log Message: ----------- working mouse selection of individual chains, residues, and atoms Modified Paths: -------------- trunk/crys3d/wx_model_viewer_multi_scene.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-07-28 20:44:06 UTC (rev 9475) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-07-29 00:19:22 UTC (rev 9476) @@ -446,11 +446,25 @@ ######################################################################## # VIEWER CLASS # +UPDATE_MODEL_ID = wx.NewId() +ADD_MODEL_ID = wx.NewId() +class AddModelEvent (wx.PyEvent) : + event_id = ADD_MODEL_ID + recenter = True + def __init__ (self, model_id, pdb_hierarchy, atomic_bonds) : + wx.PyEvent.__init__(self) + self.data = (model_id, pdb_hierarchy, atomic_bonds) + self.SetEventType(self.event_id) + +class UpdateModelEvent (AddModelEvent) : + event_id = UPDATE_MODEL_ID + recenter = False + class model_viewer_mixin (wx_viewer.wxGLWindow) : - initialize_model_viewer_super = True def __init__ (self, *args, **kwds) : - if self.initialize_model_viewer_super : - wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + self.Connect(-1, -1, UPDATE_MODEL_ID, self.OnUpdateModel) + self.Connect(-1, -1, ADD_MODEL_ID, self.OnAddModel) self.minimum_covering_sphere = None self.show_object = {} self.pick_object = {} @@ -638,6 +652,11 @@ self.pick_object[model_id] = True self.update_scene = True + def update_model (self, model_id, pdb_hierarchy, atomic_bonds) : + model = self.get_model(model_id) + model.update_structure(pdb_hierarchy, atomic_bonds) + self.update_scene = True + def update_mcs (self, points, recenter_and_zoom=True) : self.minimum_covering_sphere = minimum_covering_sphere( points=points, @@ -796,6 +815,22 @@ self.move_rotation_center_to_mcs_center() self.fit_into_viewport() + def OnUpdateModel (self, event) : + (model_id, pdb_hierarchy, atomic_bonds) = event.data + self.update_model(model_id, pdb_hierarchy, atomic_bonds) + self.OnRedrawGL() + + def OnAddModel (self, event) : + (model_id, pdb_hierarchy, atomic_bonds) = event.data + self.add_model(model_id, pdb_hierarchy, atomic_bonds) + self.OnRedrawGL() + + def thread_safe_add_model (self, model_id, pdb_hierarchy, atomic_bonds) : + wx.PostEvent(self, AddModelEvent(model_id, pdb_hierarchy, atomic_bonds)) + + def thead_safe_update_model (self, model_id, pdb_hierarchy, atomic_bonds) : + wx.PostEvent(self, UpdateModelEvent(model_id, pdb_hierarchy, atomic_bonds)) + #----------------------------------------------------------------------- # Utility functions def extract_trace (pdb_hierarchy, selection_cache=None) : Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-07-28 20:44:06 UTC (rev 9475) +++ trunk/crys3d/wx_selection_editor.py 2009-07-29 00:19:22 UTC (rev 9476) @@ -1,4 +1,6 @@ +# TODO: move selection logic to separate module + from crys3d.wx_model_viewer_multi_scene import model_data, model_scene, \ model_viewer_mixin import gltbx.gl_managed @@ -8,6 +10,7 @@ from scitbx.array_family import flex import iotbx.phil from libtbx.utils import Sorry +from libtbx import adopt_init_args import wx viewer_phil = iotbx.phil.parse(""" @@ -18,7 +21,7 @@ .style = color use_global_selection_color = True .type = bool - line_padding = 4 + line_padding = 2 .type = int } """, process_includes=True) @@ -26,38 +29,65 @@ class chain_selection_info (object) : def __init__ (self, chain_id) : adopt_init_args(self, locals()) + self.ranges = [] + self.remove_ranges = [] - def contains (self, selection_info) : - if selection_info.chain_id == self.chain_id : - return True - return False + def add_range (self, start, end, altloc=None) : + if len(self.remove_ranges) > 0 : + pass + else : + self.ranges.append((start, end, altloc)) + self.ranges.sort(lambda x, y: cmp(x[0], y[0])) + def remove_range (self, start, end, altloc=None) : + if len(self.ranges) > 0 : + pass + else : + self.remove_ranges.append((start, end, altloc)) + self.ranges.sort(lambda x, y: cmp(x[0], y[0])) + def __str__ (self) : - return "chain '%s'" % self.chain_id + sele_str = "chain '%s'" % self.chain_id + if len(self.ranges) > 0 : + clauses = [] + for (start, end, altloc) in self.ranges : + if altloc is None : + clauses.append("resseq %d:%d" % (start, end)) + else : + clauses.append("resseq %d:%d and altloc '%s'" % (start,end,altloc)) + sele_str += " and ((" + ") or (".join(clauses) + "))" + if len(self.remove_ranges) > 0 : + clauses = [] + for (start, end, altloc) in self.remove_ranges : + if altloc is None : + clauses.append("resseq %d:%d" % (start, end)) + else : + clauses.append("resseq %d:%d and altloc '%s'" % (start, end, altloc)) + sele_str +=" and not ((" + ") or (".join(clauses) + "))" + return sele_str class residue_selection_info (object) : def __init__ (self, chain_id, resid, altloc=None) : adopt_init_args(self, locals()) - def contains (self, selection_info) : - if (selection_info.chain_id == self.chain_id and - selection_info.resid == self.resid) : - return True - return False - def __str__ (self) : if self.altloc is None : - return "(chain '%s' and resid '%s')" % (self.chain_id, self.resid) + return "chain '%s' and resid '%s'" % (self.chain_id, self.resid) else : - return "(chain '%s' and resid '%s' and altloc '%s')" % (self.chain_id, + return "chain '%s' and resid '%s' and altloc '%s'" % (self.chain_id, self.resid, self.altloc) class atom_selection_info (object) : - def __init__ (self, chain_id, resid, atom_name, altloc) : + def __init__ (self, i_seq, atom) : #chain_id, resid, atom_name, altloc) : adopt_init_args(self, locals()) def __str__ (self) : - return "(chain '%s' and resid '%s' and name '%s' and altloc '%s')" + atom = self.atom + altloc = atom.altloc + if altloc == "" : + altloc = " " + return ("chain '%s' and resid '%s' and name '%s' and altloc '%s'" % + (atom.chain_id, atom.resid(), atom.name, altloc)) class model_data_with_selection (model_data) : def __init__ (self, *args, **kwds) : @@ -91,7 +121,7 @@ return scene def update_scene_data (self, scene) : - scene.update_selection(self.atoms_selected) + scene.update_selection(self.atom_selection) model_data.update_scene_data(self, scene) def update_structure (self, pdb_hierarchy, atomic_bonds, @@ -106,7 +136,7 @@ model_data.recalculate_visibility(self) self.visibility.get_selection_visibility( bonds = self.current_bonds, - atoms_selected = self.atoms_selected) + atoms_selected = self.atom_selection) #--------------------------------------------------------------------- # @@ -125,32 +155,33 @@ return self.selection_i_seqs.size() def apply_selection (self, selection_string) : - atoms_selected = self.get_atom_selection(selection_string) - if atoms_selected is None : + atom_selection = self.get_atom_selection(selection_string) + if atom_selection is None : self.selection_string = "none" - atoms_selected = self.selection_cache.selection("none") - raise Sorry("Invalid selection '%s'."%selection_string) + atoms_selection = self.selection_cache.selection("none") else : self.selection_string = selection_string - self.atoms_selected = atoms_selected - self.selection_i_seqs = atoms_selected.iselection() + self.atom_selection = atom_selection + self.selection_i_seqs = atom_selection.iselection() self.recalculate_visibility() if self.selection_callback is not None : - self.selection_callback(self.selection_string, self.atoms_selected) + self.selection_callback(self.selection_string, self.atom_selection) + if atom_selection is None : + raise Sorry("Invalid selection '%s'."%selection_string) def get_atom_selection (self, selection_string) : try : if self.mmtbx_handler is not None : - atoms_selected = self.mmtbx_handler.selection( + atom_selection = self.mmtbx_handler.selection( string=selection_string, cache=self.selection_cache) else : - atoms_selected = self.selection_cache.selection(selection_string) + atom_selection = self.selection_cache.selection(selection_string) except KeyboardInterrupt : raise except Exception, e : - atoms_selected =None - return atoms_selected + atom_selection =None + return atom_selection def revert_selection (self) : self.apply_selection(self.saved_selection) @@ -169,51 +200,99 @@ atom = self.atom_index[i_seq] chain_id = atom.chain_id if chain_id in self.selected_chains : - self.selected_chains.pop(chain_id) + chain_info = self.selected_chains.pop(chain_id) + chain_sel = self.selection_cache.selection(str(chain_info)) + self.remove_redundant_residues(chain_sel, self.deselected_residues) + self.remove_redundant_atoms(chain_sel, self.deselected_atoms) else : - self.selected_chains[chain_id] = True + chain_info = chain_selection_info(chain_id) + self.selected_chains[chain_id] = chain_info + chain_sel = self.selection_cache.selection(str(chain_info)) + self.remove_redundant_residues(chain_sel, self.selected_residues) + self.remove_redundant_atoms(chain_sel, self.selected_atoms) self.construct_selection() - def toggle_residue_selection (self, i_seq) : + def remove_redundant_residues (self, main_selection, residue_list) : + i = 0 + while i < len(residue_list) : + residue_info = residue_list[i] + resi_sel = self.selection_cache.selection(str(residue_info)) + if main_selection.is_super_set(resi_sel) : + residue_list.pop(i) + else : + i += 1 + + def remove_redundant_atoms (self, main_selection, atom_list) : + i = 0 + while i < len(atom_list) : + i_seq = atom_list[i] + if main_selection[i_seq] : + atom_list.pop(i) + else : + i += 1 + + def toggle_residue_selection (self, i_seq, ignore_altloc=True) : atom = self.atom_index[i_seq] - resi_sel_str = "chain '%s' and resid '%s'" % (atom.chain_id, atom.resid()) - resi_sel = self.selection_cache.selection(resi_sel_str) - if self.atoms_selected.is_super_set(resi_sel) : - self.deselected_residues.append(resi_sel_str) + if ignore_altloc : + resi_info = residue_selection_info(atom.chain_id, atom.resid()) else : - self.selected_residues.append(resi_sel_str) + resi_info = residue_selection_info(atom.chain_id, atom.resid(), + atom.altloc) + resi_sel = self.selection_cache.selection(str(resi_info)) + if self.atom_selection.is_super_set(resi_sel) : + self.deselected_residues.append(resi_info) + self.remove_redundant_residues(resi_sel, self.selected_residues) + else : + self.selected_residues.append(resi_info) + self.remove_redundant_residues(resi_sel, self.deselected_residues) + self.remove_redundant_atoms(resi_sel, self.selected_atoms) + self.remove_redundant_atoms(resi_sel, self.deselected_atoms) self.construct_selection() - def toggle_atom_selection (self, i_seq, deselect=False) : - pass + def toggle_atom_selection (self, i_seq) : + atom = self.atom_index[i_seq] + if self.atom_selection[i_seq] : #and not i_seq in self.deselected_atoms : + self.deselected_atoms.append(i_seq) + if i_seq in self.selected_atoms : + self.selected_atoms.remove(i_seq) + elif not i_seq in self.selected_atoms : + self.selected_atoms.append(i_seq) + if i_seq in self.deselected_atoms : + self.deselected_atoms.remove(i_seq) + self.construct_selection() def construct_selection (self) : final_selection = "" # Part 1: stuff we want - positive_selection = "" clauses = [] - for chain in sorted(self.selected_chains.keys()) : - chain_selection = "chain '%s'" % chain - clauses.append(chain_selection) - for residue in self.selected_residues : - clauses.append(residue) - for atom in self.selected_atoms : - clauses.append(atom) - if len(clauses) == 1 : # not necessary, but looks nicer - positive_selection = clauses[0] - elif len(clauses) > 1 : - positive_selection = "(" + ") or (".join(clauses) + ")" + for chain_id, chain_info in self.selected_chains.iteritems() : + clauses.append(str(chain_info)) + chains_selection_str = assemble_selection_clauses(clauses) + selection1 = self.get_atom_selection(chains_selection_str) + deselection1 = selection1.__invert__() + self.remove_redundant_residues(selection1, self.selected_residues) + self.remove_redundant_residues(deselection1, self.deselected_residues) + for residue_info in self.selected_residues : + residue_selection_str = str(residue_info) + clauses.append(residue_selection_str) + chains_and_resi_sel_str = assemble_selection_clauses(clauses) + selection2 = self.get_atom_selection(chains_and_resi_sel_str) + deselection2 = selection2.__invert__() + self.remove_redundant_atoms(selection2, self.selected_atoms) + self.remove_redundant_atoms(deselection2, self.deselected_atoms) + for i_seq in self.selected_atoms : + atom_info = atom_selection_info(i_seq, self.atom_index[i_seq]) + clauses.append(str(atom_info)) + positive_selection = assemble_selection_clauses(clauses) # Part 2: stuff we don't want - negative_selection = "" clauses = [] - for residue in self.deselected_residues : - clauses.append(residue) - for atom in self.deselected_atoms : - clauses.append(atom) - if len(clauses) == 1 : - negative_selection = clauses[0] - elif len(clauses) > 1 : - negative_selection = "(" + ") or (".join(clauses) + ")" + for residue_info in self.deselected_residues : + residue_selection_str = str(residue_info) + clauses.append(residue_selection_str) + for i_seq in self.deselected_atoms : + atom_info = atom_selection_info(i_seq, self.atom_index[i_seq]) + clauses.append(str(atom_info)) + negative_selection = assemble_selection_clauses(clauses) # assemble final selection if positive_selection != "" : if negative_selection != "" : @@ -221,8 +300,6 @@ negative_selection) else : final_selection = positive_selection - #elif negative_selection != "" : - # final_selection = "not (%s)" % negative_selection else : final_selection = "none" self.apply_selection(final_selection) @@ -238,9 +315,9 @@ self.selection_display_list = None model_scene.clear_lists(self) - def update_selection (self, atoms_selected) : - self.atoms_selected = atoms_selected - self.selected_atom_count = atoms_selected.iselection().size() + def update_selection (self, atom_selection) : + self.atom_selection = atom_selection + self.selected_atom_count = atom_selection.iselection().size() self.selection_display_list = None def update_visibility (self, visibility) : @@ -282,14 +359,14 @@ viewer_utils.draw_points( points = self.points, atom_colors = selection_colors, - points_visible = self.atoms_selected, + points_visible = self.atom_selection, cross_radius = 0.4) elif draw_mode == "spheres" : - atoms_selected = self.atoms_selected + atom_selection = self.atom_selection atom_radii = self.atom_radii glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) for i_seq, point in enumerate(self.points) : - if atoms_selected[i_seq] : + if atom_selection[i_seq] : glColor3f(*selection_colors[i_seq]) glPushMatrix() glTranslated(*point) @@ -301,9 +378,8 @@ ######################################################################## # VIEWER CLASS -mouse_modes = ["Rotate view", "Show selection menu", "Toggle chain selection", - "Select residue", "Select atom", "Select range", - "Deselect range"] +mouse_modes = ["Rotate view", "Show selection menu", "Toggle chain", + "Toggle residue", "Toggle atom", "Select range", "Deselect range"] class selection_editor_mixin (model_viewer_mixin) : def __init__ (self, *args, **kwds) : self.left_button_mode = 0 @@ -322,7 +398,7 @@ def draw_selections (self) : line_width = (self.settings.opengl.line_width + - self.settings.selections.line_padding) + (2 * self.settings.selections.line_padding)) glLineWidth(line_width) glEnable(GL_LINE_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) @@ -395,12 +471,22 @@ def toggle_residue_selection (self) : model = self.get_model(self.current_object_id) if model is not None : - model.toggle_residue_selection(self.current_atom_i_seq) + model.toggle_residue_selection(self.current_atom_i_seq, + ignore_altloc=self.flag_select_all_conformers) self.update_scene = True + def toggle_atom_selection (self) : + model = self.get_model(self.current_object_id) + if model is not None : + model.toggle_atom_selection(self.current_atom_i_seq) + self.update_scene = True + def process_range_selection (self) : pass + def process_range_deselection (self) : + pass + def context_selection_menu (self) : menu = wx.Menu() toggle_chain = menu.Append(-1, "Toggle chain selection") @@ -435,11 +521,15 @@ def OnToggleResidue (self, event) : pass -def print_cb (selection_string, atoms_selected) : - print "%s (%s)" % (selection_string, atoms_selected.iselection().size()) +def print_cb (selection_string, atom_selection) : + print "%s (%s)" % (selection_string, atom_selection.iselection().size()) -def is_subset (selection1, selection2) : - union = selection1 & selection2 - return union.count(True) == selection2.count(True) +def assemble_selection_clauses (clauses) : + if len(clauses) == 0 : + return "" + elif len(clauses) == 1 : # not necessary, but looks nicer + return clauses[0] + else : + return "(" + ") or (".join(clauses) + ")" #---end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-07-29 22:52:44
|
Revision: 9489 http://cctbx.svn.sourceforge.net/cctbx/?rev=9489&view=rev Author: natechols Date: 2009-07-29 22:52:35 +0000 (Wed, 29 Jul 2009) Log Message: ----------- moved mouse selection handling to new module with partial tests; started range selections Modified Paths: -------------- trunk/crys3d/wx_model_viewer_example.py trunk/crys3d/wx_selection_editor.py Added Paths: ----------- trunk/crys3d/reverse_selection.py Added: trunk/crys3d/reverse_selection.py =================================================================== --- trunk/crys3d/reverse_selection.py (rev 0) +++ trunk/crys3d/reverse_selection.py 2009-07-29 22:52:35 UTC (rev 9489) @@ -0,0 +1,435 @@ +# XXX: internal data for mouse selections in wx_selection_editor.py + +from scitbx.array_family import flex +from libtbx.utils import Sorry +from libtbx import adopt_init_args + +class chain_selection_info (object) : + def __init__ (self, chain_id, resseq_start, resseq_end) : + adopt_init_args(self, locals()) + self.ranges = set() + self.ranges_by_altloc = {} + self.remove_ranges = set() + self.remove_ranges_by_altloc = {} + + def add_range (self, start, end, altloc=None) : + assert start >= self.resseq_start and start <= self.resseq_end + assert end >= self.resseq_start and end <= self.resseq_end + if altloc is None : + self.ranges |= set([ x for x in range(start, end+1)]) + else : + ranges = self.ranges_by_altloc.get(altloc, set()) + ranges |= set([ x for x in range(start, end+1)]) + remove_ranges = self.remove_ranges_by_altloc.get(altloc, set()) + remove_ranges -= ranges + self.remove_ranges_by_altloc[altloc] = remove_ranges + self.ranges_by_altloc[altloc] = ranges + + def remove_range (self, start, end, altloc=None) : + assert start >= self.resseq_start and start <= self.resseq_end + assert end >= self.resseq_start and end <= self.resseq_end + if altloc is None : + self.remove_ranges |= set([ x for x in range(start, end+1)]) + self.ranges -= self.remove_ranges + else : + remove_ranges = self.remove_ranges_by_altloc.get(altloc, set()) + remove_ranges |= set([ x for x in range(start, end+1)]) + ranges = self.ranges_by_altloc.get(altloc, set()) + ranges -= remove_ranges + self.remove_ranges_by_altloc[altloc] = remove_ranges + if len(ranges) == 0 : + self.ranges_by_altloc.pop(altloc) + else : + self.ranges_by_altloc[altloc] = ranges + if len(self.ranges) == 0 and len(self.ranges_by_altloc) == 0 : + return True + + def __str__ (self) : + sele_str = "chain '%s'" % self.chain_id + #if len(self.ranges) > 0 : + return sele_str + +class residue_selection_info (object) : + def __init__ (self, chain_id, resid, altloc=None) : + adopt_init_args(self, locals()) + + def __str__ (self) : + if self.altloc is None : + return "chain '%s' and resid '%s'" % (self.chain_id, self.resid) + else : + return "chain '%s' and resid '%s' and altloc '%s'" % (self.chain_id, + self.resid, self.altloc) + +class atom_selection_info (object) : + def __init__ (self, i_seq, atom) : #chain_id, resid, atom_name, altloc) : + adopt_init_args(self, locals()) + + def __str__ (self) : + atom = self.atom + altloc = atom.altloc + if altloc == "" : + altloc = " " + return ("chain '%s' and resid '%s' and name '%s' and altloc '%s'" % + (atom.chain_id, atom.resid(), atom.name, altloc)) + +class mouse_selection_manager (object) : + def __init__ (self) : + self.saved_selection = "none" + self.selection_string = "none" + self._selection_callback = None + self.start_i_seq = None + self.end_i_seq = None + + def selection_callback (self, selection_string, atom_selection) : + if self._selection_callback is not None : + self._selection_callback(selection_string, atom_selection) + + def set_selection_callback (self, callback) : + assert hasattr(callback, "__call__") or callback is None + self._selection_callback = callback + + def set_mmtbx_selection_function (self, mmtbx_selection_function) : + self.mmtbx_selection_function = mmtbx_selection_function + + def update_selection_handlers (self, pdb_hierarchy, + mmtbx_selection_function) : + self.mmtbx_selection_function = mmtbx_selection_function + self.selection_cache = pdb_hierarchy.atom_selection_cache() + self.atom_selection = flex.bool() + #--- XXX: for testing only + if not hasattr(self, "atom_index") : + self.atom_index = [] + for atom in pdb_hierarchy.atoms_with_labels() : + self.atom_index.append(atom) + if not hasattr(self, "pdb_hierarchy") : + self.pdb_hierarchy = pdb_hierarchy + #--- + self._chain_ends = {} + for chain in pdb_hierarchy.chains() : + if len(chain.conformers()) == 1 : + residues = chain.residues() + resseq_start = residues[0].resseq_as_int() + resseq_end = residues[-1].resseq_as_int() + else : + resseq_start = 100000 + resseq_end = -100000 + for conf in chain.conformers() : + residues = conf.residues() + if residues[0].resseq_as_int() < resseq_start : + resseq_start = residues[0].resseq_as_int() + if residues[-1].resseq_as_int() > resseq_end : + resseq_end = residues[-1].resseq_as_int() + self._chain_ends[chain.id] = (resseq_start, resseq_end) + self.clear_selection() + + def clear_selection (self) : + self.selected_chains = {} + self.deselected_chains = {} + self.selected_atoms = [] + self.deselected_atoms = [] + self.selected_residues = [] + self.deselected_residues = [] + self.apply_selection(self.saved_selection) + + def selection_size (self) : + return self.selection_i_seqs.size() + + def apply_selection (self, selection_string) : + atom_selection = self.get_atom_selection(selection_string) + if atom_selection is None : + self.selection_string = "none" + atom_selection = self.selection_cache.selection("none") + else : + self.selection_string = selection_string + self.atom_selection = atom_selection + self.selection_i_seqs = atom_selection.iselection() + if self.selection_callback is not None : + self.selection_callback(self.selection_string, self.atom_selection) + if atom_selection is None : + raise Sorry("Invalid selection '%s'."%selection_string) + + def get_atom_selection (self, selection_string) : + try : + if self.mmtbx_selection_function is not None : + atom_selection = self.mmtbx_selection_function( + string=selection_string, + cache=self.selection_cache) + else : + atom_selection = self.selection_cache.selection(selection_string) + except KeyboardInterrupt : + raise + except Exception, e : + print e + atom_selection =None + return atom_selection + + def revert_selection (self) : + self.apply_selection(self.saved_selection) + + def set_initial_selection (self, selection_string) : + self.saved_selection = selection_string + self.apply_selection(selection_string) + + def reset_range_selection (self, i_seq) : + self.start_i_seq = None + + def start_range_selection (self, i_seq) : + self.start_i_seq = i_seq + + def end_range_selection (self, i_seq, deselect, ignore_altloc) : + success = False + print i_seq + if self.start_i_seq is not None : + start_atom = self.atom_index[self.start_i_seq] + end_atom = self.atom_index[i_seq] + if (start_atom.chain_id == end_atom.chain_id and + (ignore_altloc or start_atom.altloc == end_atom.altloc)) : + chain_id = start_atom.chain_id + if chain_id in self.selected_chains : + chain_info = self.selected_chains[chain_id] + else : + (resseq_start, resseq_end) = self._chain_ends[chain_id] + chain_info = chain_selection_info(chain_id, resseq_start, resseq_end) + altloc = None + if not ignore_altloc : + altloc = start_atom.altloc + start_range = start_atom.resseq_as_int() + end_range = end_atom.resseq_as_int() + if start_range > end_range : + start_range = end_atom.resseq_as_int() + end_range = start_atom.resseq_as_int() + if deselect : + remove_chain = chain_info.remove_range(start_range, end_range, + altloc) + if remove_chain : + self.selection_chains.pop(chain_id) + else : + chain_info.add_range(start_range, end_range, altloc) + self.selected_chains[chain_id] = chain_info + success = True + self.construct_selection() + self.reset_range_selection() + return success + + def toggle_chain_selection (self, i_seq) : + atom = self.atom_index[i_seq] + chain_id = atom.chain_id + if chain_id in self.selected_chains : + chain_info = self.selected_chains.pop(chain_id) + chain_sel = self.selection_cache.selection(str(chain_info)) + self.remove_redundant_residues(chain_sel, self.deselected_residues) + self.remove_redundant_atoms(chain_sel, self.deselected_atoms) + else : + (resseq_start, resseq_end) = self._chain_ends[chain_id] + chain_info = chain_selection_info(chain_id, resseq_start, resseq_end) + self.selected_chains[chain_id] = chain_info + chain_sel = self.selection_cache.selection(str(chain_info)) + self.remove_redundant_residues(chain_sel, self.selected_residues) + self.remove_redundant_atoms(chain_sel, self.selected_atoms) + self.construct_selection() + + def remove_redundant_residues (self, main_selection, residue_list) : + i = 0 + while i < len(residue_list) : + residue_info = residue_list[i] + resi_sel = self.selection_cache.selection(str(residue_info)) + if main_selection.is_super_set(resi_sel) : + residue_list.pop(i) + else : + i += 1 + + def remove_redundant_atoms (self, main_selection, atom_list) : + i = 0 + while i < len(atom_list) : + i_seq = atom_list[i] + if main_selection[i_seq] : + atom_list.pop(i) + else : + i += 1 + + def toggle_residue_selection (self, i_seq, ignore_altloc=True) : + atom = self.atom_index[i_seq] + if ignore_altloc : + resi_info = residue_selection_info(atom.chain_id, atom.resid()) + else : + resi_info = residue_selection_info(atom.chain_id, atom.resid(), + atom.altloc) + resi_sel = self.selection_cache.selection(str(resi_info)) + if self.atom_selection.is_super_set(resi_sel) : + self.deselected_residues.append(resi_info) + self.remove_redundant_residues(resi_sel, self.selected_residues) + else : + self.selected_residues.append(resi_info) + self.remove_redundant_residues(resi_sel, self.deselected_residues) + self.remove_redundant_atoms(resi_sel, self.selected_atoms) + self.remove_redundant_atoms(resi_sel, self.deselected_atoms) + self.construct_selection() + + def toggle_atom_selection (self, i_seq) : + atom = self.atom_index[i_seq] + if self.atom_selection[i_seq] : #and not i_seq in self.deselected_atoms : + self.deselected_atoms.append(i_seq) + if i_seq in self.selected_atoms : + self.selected_atoms.remove(i_seq) + elif not i_seq in self.selected_atoms : + self.selected_atoms.append(i_seq) + if i_seq in self.deselected_atoms : + self.deselected_atoms.remove(i_seq) + self.construct_selection() + + def construct_selection (self) : + final_selection = "" + # Part 1: stuff we want + clauses = [] + for chain_id, chain_info in self.selected_chains.iteritems() : + clauses.append(str(chain_info)) + chains_selection_str = assemble_selection_clauses(clauses) + selection1 = self.get_atom_selection(chains_selection_str) + deselection1 = selection1.__invert__() + self.remove_redundant_residues(selection1, self.selected_residues) + self.remove_redundant_residues(deselection1, self.deselected_residues) + for residue_info in self.selected_residues : + residue_selection_str = str(residue_info) + clauses.append(residue_selection_str) + chains_and_resi_sel_str = assemble_selection_clauses(clauses) + selection2 = self.get_atom_selection(chains_and_resi_sel_str) + deselection2 = selection2.__invert__() + self.remove_redundant_atoms(selection2, self.selected_atoms) + self.remove_redundant_atoms(deselection2, self.deselected_atoms) + for i_seq in self.selected_atoms : + atom_info = atom_selection_info(i_seq, self.atom_index[i_seq]) + clauses.append(str(atom_info)) + positive_selection = assemble_selection_clauses(clauses) + # Part 2: stuff we don't want + clauses = [] + for residue_info in self.deselected_residues : + residue_selection_str = str(residue_info) + clauses.append(residue_selection_str) + for i_seq in self.deselected_atoms : + atom_info = atom_selection_info(i_seq, self.atom_index[i_seq]) + clauses.append(str(atom_info)) + negative_selection = assemble_selection_clauses(clauses) + # assemble final selection + if positive_selection != "" : + if negative_selection != "" : + final_selection = "(%s) and not (%s)" % (positive_selection, + negative_selection) + else : + final_selection = positive_selection + else : + final_selection = "none" + self.apply_selection(final_selection) + +def assemble_selection_clauses (clauses) : + if len(clauses) == 0 : + return "" + elif len(clauses) == 1 : # not necessary, but looks nicer + return clauses[0] + else : + return "(" + ") or (".join(clauses) + ")" + +######################################################################## +def exercise () : + from mmtbx.monomer_library import pdb_interpretation + import cStringIO + open("tmp.pdb", "w").write("""\ +CRYST1 50.800 50.800 155.300 90.00 90.00 90.00 P 43 21 2 8 +ATOM 4 N SER A 1 8.753 29.755 61.685 1.00 49.13 +ATOM 5 CA SER A 1 9.242 30.200 62.974 1.00 46.62 +ANISOU 5 CA SER A 1 343 490 2719 -45 -169 617 +ATOM 6 C SER A 1 10.453 29.500 63.579 1.00 41.99 +ATOM 7 O SER A 1 10.593 29.607 64.814 1.00 43.24 +ANISOU 7 O SER A 1 343 490 2719 -45 -169 617 +ATOM 8 CB SER A 1 8.052 30.189 63.974 1.00 53.00 +ATOM 9 OG SER A 1 7.294 31.409 63.930 1.00 57.79 +ATOM 10 N ARG A 2 11.360 28.819 62.827 1.00 36.48 +ATOM 11 CA ARG A 2 12.548 28.316 63.532 1.00 30.20 +ATOM 12 C ARG A 2 13.502 29.501 63.500 1.00 25.54 +ATOM 13 O ARG A 2 13.730 30.037 62.407 1.00 23.86 +ATOM 14 CB ARG A 2 13.241 27.119 62.861 1.00 27.44 +ATOM 15 CG ARG A 2 12.412 25.849 62.964 1.00 23.66 +ATOM 16 CD ARG A 2 13.267 24.651 63.266 1.00 23.98 +ATOM 17 NE ARG A 2 13.948 24.115 62.135 1.00 22.71 +ATOM 18 CZ ARG A 2 15.114 23.487 62.201 1.00 21.38 +ATOM 19 NH1 ARG A 2 15.845 23.331 63.301 1.00 19.34 +ATOM 20 NH2 ARG A 2 15.575 23.030 61.051 1.00 26.66 +ATOM 21 N PRO A 3J 13.947 29.997 64.680 1.00 22.94 +ATOM 22 CA PRO A 3J 14.902 31.100 64.827 1.00 20.19 +ATOM 23 C PRO A 3J 16.195 30.718 64.086 1.00 18.44 +ATOM 24 O PRO A 3J 16.545 29.521 64.086 1.00 19.76 +ATOM 25 CB PRO A 3J 15.133 31.218 66.313 1.00 19.17 +ATOM 26 CG PRO A 3J 14.065 30.364 66.951 1.00 15.12 +ATOM 27 CD PRO A 3J 13.816 29.289 65.966 1.00 19.56 +ATOM 28 N AILE A 4 16.953 31.648 63.512 1.00 15.29 +ATOM 29 CA AILE A 4 18.243 31.372 62.859 1.00 14.32 +ATOM 30 C AILE A 4 19.233 32.112 63.743 1.00 13.54 +ATOM 31 O AILE A 4 19.105 33.315 64.009 1.00 11.84 +ATOM 32 CB AILE A 4 18.298 31.951 61.406 1.00 13.62 +ATOM 33 CG1AILE A 4 17.157 31.300 60.620 1.00 18.39 +ATOM 34 CG2AILE A 4 19.661 31.747 60.743 1.00 13.64 +ATOM 35 CD1AILE A 4 16.879 32.102 59.355 1.00 16.69 +ATOM 28 N BILE A 4 16.953 31.648 63.512 1.00 15.29 +ATOM 29 CA BILE A 4 18.243 31.372 62.859 1.00 14.32 +ATOM 30 C BILE A 4 19.233 32.112 63.743 1.00 13.54 +ATOM 31 O BILE A 4 19.105 33.315 64.009 1.00 11.84 +ATOM 32 CB BILE A 4 18.298 31.951 61.406 1.00 13.62 +ATOM 33 CG1BILE A 4 17.157 31.300 60.620 1.00 18.39 +ATOM 34 CG2BILE A 4 19.661 31.747 60.743 1.00 13.64 +ATOM1200035 CD1BILE A 4 16.879 32.102 59.355 1.00 16.69 +HETATM 1475 S SO4 S 188 31.424 42.923 60.396 1.00 55.69 S4+ +HETATM 1476 O1 SO4 S 188 31.631 41.513 60.336 1.00 59.84 O1- +HETATM 1477 O2 SO4 S 188 32.533 43.699 59.932 1.00 49.98 O1- +HETATM 1478 O3 SO4 S 188 31.128 43.217 61.738 1.00 59.44 O1- +HETATM 1479 O4 SO4 S 188 30.353 43.201 59.539 1.00 60.54 O1- +HETATM 1480 O HOH W 200 29.478 23.354 61.364 1.00 8.67 WATE +END""") + out = cStringIO.StringIO() + processed_pdb_file = pdb_interpretation.run(args=["tmp.pdb"], log=out) + m = mouse_selection_manager() + pdb_hierarchy = processed_pdb_file.all_chain_proxies.pdb_hierarchy + pdb_hierarchy.atoms().reset_i_seq() + m.update_selection_handlers( + pdb_hierarchy=pdb_hierarchy, + mmtbx_selection_function=processed_pdb_file.all_chain_proxies.selection) + assert m.selection_size() == 0 + m.apply_selection("chain A") + assert m.selection_size() == 40 + m.clear_selection() + m.toggle_chain_selection(5) + assert m.selection_size() == 40 + m.toggle_residue_selection(10) + assert m.selection_size() == 29 + m.toggle_atom_selection(10) # XXX: doesn't work! + assert m.selection_size() == 29 + m.toggle_atom_selection(20) + assert m.selection_size() == 28 + + from iotbx import pdb + pdb_hierarchy = pdb.input(source_info=None, lines=flex.split_lines("""\ +HETATM 4049 O HOH W 1 2.954 13.042 11.632 1.00 37.53 O +HETATM 4050 O HOH W 2 5.539 14.595 10.951 1.00 31.25 O +HETATM 4051 O HOH W 3 -2.971 14.661 14.669 1.00 38.68 O +HETATM 4052 O HOH W 4 6.281 34.000 7.684 1.00 39.58 O +HETATM 4053 O HOH W 5 16.004 9.039 10.335 1.00 37.31 O +HETATM 4054 O HOH W 6 2.144 5.718 20.447 1.00 49.77 O +HETATM 4055 O HOH W 7 -1.180 10.517 14.630 1.00 32.95 O +HETATM 4056 O HOH W 8 9.227 8.636 12.535 1.00 32.52 O +HETATM 4057 O HOH W 9 11.070 -0.570 15.047 1.00 30.24 O +HETATM 4058 O HOH W 10 15.630 -6.169 12.853 1.00 31.08 O +HETATM 4059 O HOH W 11 14.854 -8.299 16.887 1.00 32.65 O +HETATM 4060 O HOH W 12 27.586 0.391 24.184 1.00 31.29 O +HETATM 4061 O HOH W 13 3.240 7.801 38.401 1.00 32.09 O +END""")).construct_hierarchy() + m = mouse_selection_manager() + pdb_hierarchy.atoms().reset_i_seq() + m.update_selection_handlers(pdb_hierarchy=pdb_hierarchy, + mmtbx_selection_function=None) + assert m.selection_size() == 0 + m.apply_selection("chain W") + assert m.selection_size() == 13 + print "OK" + +if __name__ == "__main__" : + exercise() + +#---end Modified: trunk/crys3d/wx_model_viewer_example.py =================================================================== --- trunk/crys3d/wx_model_viewer_example.py 2009-07-29 20:56:28 UTC (rev 9488) +++ trunk/crys3d/wx_model_viewer_example.py 2009-07-29 22:52:35 UTC (rev 9489) @@ -51,11 +51,13 @@ pdb_hierarchy = processed_pdb_file.all_chain_proxies.pdb_hierarchy pdb_hierarchy.atoms().reset_i_seq() grm = processed_pdb_file.geometry_restraints_manager() + acp_selection = processed_pdb_file.all_chain_proxies.selection if grm is None or grm.shell_sym_tables is None : raise Sorry("Atomic bonds could not be calculated for this model. "+ "This is probably due to a missing CRYST1 record in the PDB file.") atomic_bonds = grm.shell_sym_tables[0].full_simple_connectivity() - a.view_objects.add_model(file_name, pdb_hierarchy, atomic_bonds) + a.view_objects.add_model(file_name, pdb_hierarchy, atomic_bonds, + mmtbx_selection_function=acp_selection) a.frame.Show() a.view_objects.force_update(recenter=True) a.MainLoop() Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-07-29 20:56:28 UTC (rev 9488) +++ trunk/crys3d/wx_selection_editor.py 2009-07-29 22:52:35 UTC (rev 9489) @@ -3,6 +3,7 @@ from crys3d.wx_model_viewer_multi_scene import model_data, model_scene, \ model_viewer_mixin +from crys3d.reverse_selection import mouse_selection_manager import gltbx.gl_managed from gltbx.gl import * from gltbx.glu import * @@ -26,88 +27,13 @@ } """, process_includes=True) -class chain_selection_info (object) : - def __init__ (self, chain_id) : - adopt_init_args(self, locals()) - self.ranges = [] - self.remove_ranges = [] - - def add_range (self, start, end, altloc=None) : - if len(self.remove_ranges) > 0 : - pass - else : - self.ranges.append((start, end, altloc)) - self.ranges.sort(lambda x, y: cmp(x[0], y[0])) - - def remove_range (self, start, end, altloc=None) : - if len(self.ranges) > 0 : - pass - else : - self.remove_ranges.append((start, end, altloc)) - self.ranges.sort(lambda x, y: cmp(x[0], y[0])) - - def __str__ (self) : - sele_str = "chain '%s'" % self.chain_id - if len(self.ranges) > 0 : - clauses = [] - for (start, end, altloc) in self.ranges : - if altloc is None : - clauses.append("resseq %d:%d" % (start, end)) - else : - clauses.append("resseq %d:%d and altloc '%s'" % (start,end,altloc)) - sele_str += " and ((" + ") or (".join(clauses) + "))" - if len(self.remove_ranges) > 0 : - clauses = [] - for (start, end, altloc) in self.remove_ranges : - if altloc is None : - clauses.append("resseq %d:%d" % (start, end)) - else : - clauses.append("resseq %d:%d and altloc '%s'" % (start, end, altloc)) - sele_str +=" and not ((" + ") or (".join(clauses) + "))" - return sele_str - -class residue_selection_info (object) : - def __init__ (self, chain_id, resid, altloc=None) : - adopt_init_args(self, locals()) - - def __str__ (self) : - if self.altloc is None : - return "chain '%s' and resid '%s'" % (self.chain_id, self.resid) - else : - return "chain '%s' and resid '%s' and altloc '%s'" % (self.chain_id, - self.resid, self.altloc) - -class atom_selection_info (object) : - def __init__ (self, i_seq, atom) : #chain_id, resid, atom_name, altloc) : - adopt_init_args(self, locals()) - - def __str__ (self) : - atom = self.atom - altloc = atom.altloc - if altloc == "" : - altloc = " " - return ("chain '%s' and resid '%s' and name '%s' and altloc '%s'" % - (atom.chain_id, atom.resid(), atom.name, altloc)) - -class model_data_with_selection (model_data) : +class model_data_with_selection (model_data, mouse_selection_manager) : def __init__ (self, *args, **kwds) : - self.mmtbx_handler = None self.flag_show_selection = True self.flag_allow_selection = True - self.selection_string = "none" - self.saved_selection = "none" # for recovery later - self.selection_i_seqs = None - self.selection_callback = None - self.start_i_seq = None - self.end_i_seq = None + mouse_selection_manager.__init__(self) model_data.__init__(self, *args, **kwds) - def set_mmtbx_selection_handler (self, mmtbx_handler) : - self.mmtbx_handler = mmtbx_handler - - def set_selection_callback (self, callback) : - self.selection_callback = callback - def get_scene_data (self) : scene = model_scene_with_selection(bonds=self.current_bonds, points=self.atoms.extract_xyz(), @@ -125,12 +51,10 @@ model_data.update_scene_data(self, scene) def update_structure (self, pdb_hierarchy, atomic_bonds, - mmtbx_handler=None) : + mmtbx_selection_function=None) : model_data.update_structure(self, pdb_hierarchy, atomic_bonds) - self.selection_cache = pdb_hierarchy.atom_selection_cache() - self.mmtbx_handler = mmtbx_handler - self.clear_selection() - #self.apply_selection(self.saved_selection) + mouse_selection_manager.update_selection_handlers(self, pdb_hierarchy, + mmtbx_selection_function) def recalculate_visibility (self) : model_data.recalculate_visibility(self) @@ -138,172 +62,10 @@ bonds = self.current_bonds, atoms_selected = self.atom_selection) - #--------------------------------------------------------------------- - # - def clear_selection (self) : - self.selected_chains = {} - self.deselected_chains = {} - self.selected_atoms = [] - self.deselected_atoms = [] - self.selected_residues = [] - self.deselected_residues = [] - self._cached_selections = {} - self._cached_deselections = {} - self.apply_selection(self.saved_selection) - - def selection_size (self) : - return self.selection_i_seqs.size() - - def apply_selection (self, selection_string) : - atom_selection = self.get_atom_selection(selection_string) - if atom_selection is None : - self.selection_string = "none" - atoms_selection = self.selection_cache.selection("none") - else : - self.selection_string = selection_string - self.atom_selection = atom_selection - self.selection_i_seqs = atom_selection.iselection() + def selection_callback (self, *args, **kwds) : self.recalculate_visibility() - if self.selection_callback is not None : - self.selection_callback(self.selection_string, self.atom_selection) - if atom_selection is None : - raise Sorry("Invalid selection '%s'."%selection_string) + mouse_selection_manager.selection_callback(self, *args, **kwds) - def get_atom_selection (self, selection_string) : - try : - if self.mmtbx_handler is not None : - atom_selection = self.mmtbx_handler.selection( - string=selection_string, - cache=self.selection_cache) - else : - atom_selection = self.selection_cache.selection(selection_string) - except KeyboardInterrupt : - raise - except Exception, e : - atom_selection =None - return atom_selection - - def revert_selection (self) : - self.apply_selection(self.saved_selection) - - def set_initial_selection (self, selection_string) : - self.saved_selection = selection_string - self.apply_selection(selection_string) - - def start_selection (self, i_seq) : - self.start_i_seq = i_seq - - def end_range_selection (self, i_seq, deselect=False) : - pass - - def toggle_chain_selection (self, i_seq) : - atom = self.atom_index[i_seq] - chain_id = atom.chain_id - if chain_id in self.selected_chains : - chain_info = self.selected_chains.pop(chain_id) - chain_sel = self.selection_cache.selection(str(chain_info)) - self.remove_redundant_residues(chain_sel, self.deselected_residues) - self.remove_redundant_atoms(chain_sel, self.deselected_atoms) - else : - chain_info = chain_selection_info(chain_id) - self.selected_chains[chain_id] = chain_info - chain_sel = self.selection_cache.selection(str(chain_info)) - self.remove_redundant_residues(chain_sel, self.selected_residues) - self.remove_redundant_atoms(chain_sel, self.selected_atoms) - self.construct_selection() - - def remove_redundant_residues (self, main_selection, residue_list) : - i = 0 - while i < len(residue_list) : - residue_info = residue_list[i] - resi_sel = self.selection_cache.selection(str(residue_info)) - if main_selection.is_super_set(resi_sel) : - residue_list.pop(i) - else : - i += 1 - - def remove_redundant_atoms (self, main_selection, atom_list) : - i = 0 - while i < len(atom_list) : - i_seq = atom_list[i] - if main_selection[i_seq] : - atom_list.pop(i) - else : - i += 1 - - def toggle_residue_selection (self, i_seq, ignore_altloc=True) : - atom = self.atom_index[i_seq] - if ignore_altloc : - resi_info = residue_selection_info(atom.chain_id, atom.resid()) - else : - resi_info = residue_selection_info(atom.chain_id, atom.resid(), - atom.altloc) - resi_sel = self.selection_cache.selection(str(resi_info)) - if self.atom_selection.is_super_set(resi_sel) : - self.deselected_residues.append(resi_info) - self.remove_redundant_residues(resi_sel, self.selected_residues) - else : - self.selected_residues.append(resi_info) - self.remove_redundant_residues(resi_sel, self.deselected_residues) - self.remove_redundant_atoms(resi_sel, self.selected_atoms) - self.remove_redundant_atoms(resi_sel, self.deselected_atoms) - self.construct_selection() - - def toggle_atom_selection (self, i_seq) : - atom = self.atom_index[i_seq] - if self.atom_selection[i_seq] : #and not i_seq in self.deselected_atoms : - self.deselected_atoms.append(i_seq) - if i_seq in self.selected_atoms : - self.selected_atoms.remove(i_seq) - elif not i_seq in self.selected_atoms : - self.selected_atoms.append(i_seq) - if i_seq in self.deselected_atoms : - self.deselected_atoms.remove(i_seq) - self.construct_selection() - - def construct_selection (self) : - final_selection = "" - # Part 1: stuff we want - clauses = [] - for chain_id, chain_info in self.selected_chains.iteritems() : - clauses.append(str(chain_info)) - chains_selection_str = assemble_selection_clauses(clauses) - selection1 = self.get_atom_selection(chains_selection_str) - deselection1 = selection1.__invert__() - self.remove_redundant_residues(selection1, self.selected_residues) - self.remove_redundant_residues(deselection1, self.deselected_residues) - for residue_info in self.selected_residues : - residue_selection_str = str(residue_info) - clauses.append(residue_selection_str) - chains_and_resi_sel_str = assemble_selection_clauses(clauses) - selection2 = self.get_atom_selection(chains_and_resi_sel_str) - deselection2 = selection2.__invert__() - self.remove_redundant_atoms(selection2, self.selected_atoms) - self.remove_redundant_atoms(deselection2, self.deselected_atoms) - for i_seq in self.selected_atoms : - atom_info = atom_selection_info(i_seq, self.atom_index[i_seq]) - clauses.append(str(atom_info)) - positive_selection = assemble_selection_clauses(clauses) - # Part 2: stuff we don't want - clauses = [] - for residue_info in self.deselected_residues : - residue_selection_str = str(residue_info) - clauses.append(residue_selection_str) - for i_seq in self.deselected_atoms : - atom_info = atom_selection_info(i_seq, self.atom_index[i_seq]) - clauses.append(str(atom_info)) - negative_selection = assemble_selection_clauses(clauses) - # assemble final selection - if positive_selection != "" : - if negative_selection != "" : - final_selection = "(%s) and not (%s)" % (positive_selection, - negative_selection) - else : - final_selection = positive_selection - else : - final_selection = "none" - self.apply_selection(final_selection) - #----------------------------------------------------------------------- class model_scene_with_selection (model_scene) : def __init__ (self, *args, **kwds) : @@ -388,6 +150,7 @@ self.flag_enable_mouse_selection = True self.current_atom_i_seq = None self.current_object_id = None + self._in_range_selection = False model_viewer_mixin.__init__(self, *args,**kwds) self.settings = viewer_phil.extract() @@ -428,11 +191,11 @@ model.clear_selection() def add_model (self, model_id, pdb_hierarchy, atomic_bonds, - mmtbx_handler=None) : + mmtbx_selection_function=None) : assert isinstance(model_id, str) model = model_data_with_selection(model_id, pdb_hierarchy, atomic_bonds, base_color=self.settings.opengl.base_atom_color) - model.set_mmtbx_selection_handler(mmtbx_handler) + model.set_mmtbx_selection_function(mmtbx_selection_function) model.set_selection_callback(print_cb) self._add_model(model_id, model) @@ -443,12 +206,16 @@ elif key == ord('z') : self.zoom_selections() elif key >= 49 and key <= 54 : - self.left_button_mode = key - 49 + self.set_left_button_mode(key - 49) elif key == 27 : # escape self.clear_selections() self.update_scene = True model_viewer_mixin.process_key_stroke(self,key) + def set_left_button_mode (self, mode) : + self.left_button_mode = mode + self._in_range_selection = False + #--------------------------------------------------------------------- def pick_selection_object (self, object_id) : for model_id in self.pick_object : @@ -481,12 +248,21 @@ model.toggle_atom_selection(self.current_atom_i_seq) self.update_scene = True - def process_range_selection (self) : - pass + def process_range_selection (self, deselect=False) : + model = self.get_model(self.current_object_id) + if model is not None : + if self._in_range_selection : + try : + model.end_range_selection(self.current_atom_i_seq, deselect, + ignore_altloc=self.flag_select_all_conformers) + finally : + self._in_range_selection = False + else : + model.start_range_selection(self.current_atom_i_seq, deselect, + ignore_altloc=self.flag_select_all_conformers) + self._in_range_selection = True + self.update_scene = True - def process_range_deselection (self) : - pass - def context_selection_menu (self) : menu = wx.Menu() toggle_chain = menu.Append(-1, "Toggle chain selection") @@ -513,7 +289,7 @@ elif self.left_button_mode == 5 : # select range self.process_range_selection() else : # deselect range - self.process_range_deselection() + self.process_range_selection(deselect=True) def OnToggleChain (self, event) : pass @@ -524,12 +300,4 @@ def print_cb (selection_string, atom_selection) : print "%s (%s)" % (selection_string, atom_selection.iselection().size()) -def assemble_selection_clauses (clauses) : - if len(clauses) == 0 : - return "" - elif len(clauses) == 1 : # not necessary, but looks nicer - return clauses[0] - else : - return "(" + ") or (".join(clauses) + ")" - #---end This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-07-31 00:20:58
|
Revision: 9508 http://cctbx.svn.sourceforge.net/cctbx/?rev=9508&view=rev Author: natechols Date: 2009-07-31 00:20:43 +0000 (Fri, 31 Jul 2009) Log Message: ----------- (de)selection of residue ranges mostly working Modified Paths: -------------- trunk/crys3d/reverse_selection.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/reverse_selection.py =================================================================== --- trunk/crys3d/reverse_selection.py 2009-07-30 23:58:41 UTC (rev 9507) +++ trunk/crys3d/reverse_selection.py 2009-07-31 00:20:43 UTC (rev 9508) @@ -5,48 +5,80 @@ from libtbx import adopt_init_args class chain_selection_info (object) : - def __init__ (self, chain_id, resseq_start, resseq_end) : + def __init__ (self, chain_id) : adopt_init_args(self, locals()) - self.ranges = set() - self.ranges_by_altloc = {} - self.remove_ranges = set() - self.remove_ranges_by_altloc = {} + self.resseqs = set() + self.resseqs_by_altloc = {} + self.remove_resseqs = set() + self.remove_resseqs_by_altloc = {} def add_range (self, start, end, altloc=None) : - assert start >= self.resseq_start and start <= self.resseq_end - assert end >= self.resseq_start and end <= self.resseq_end + resseqs = set([ x for x in range(start, end+1)]) if altloc is None : - self.ranges |= set([ x for x in range(start, end+1)]) + if len(self.remove_resseqs) != 0 : + self.remove_resseqs -= resseqs + else : + self.resseqs |= resseqs else : - ranges = self.ranges_by_altloc.get(altloc, set()) - ranges |= set([ x for x in range(start, end+1)]) - remove_ranges = self.remove_ranges_by_altloc.get(altloc, set()) - remove_ranges -= ranges - self.remove_ranges_by_altloc[altloc] = remove_ranges - self.ranges_by_altloc[altloc] = ranges + remove_resseqs = self.remove_resseqs_by_altloc.get(altloc, set()) + if len(remove_resseqs) != 0 : + remove_resseqs -= resseqs + if len(remove_resseqs) == 0 : + self.remove_resseqs_by_altloc.pop(altloc) + else : + self.remove_resseqs_by_altloc[altloc] = remove_resseqs + else : + old_resseqs = self.resseqs_by_altloc.get(altloc, set()) + old_resseqs |= resseqs + self.resseqs_by_altloc[altloc] = old_resseqs def remove_range (self, start, end, altloc=None) : - assert start >= self.resseq_start and start <= self.resseq_end - assert end >= self.resseq_start and end <= self.resseq_end + resseqs = set([ x for x in range(start, end+1)]) if altloc is None : - self.remove_ranges |= set([ x for x in range(start, end+1)]) - self.ranges -= self.remove_ranges + if len(self.resseqs) != 0 : + self.resseqs -= resseqs + else : + self.remove_resseqs |= resseqs else : - remove_ranges = self.remove_ranges_by_altloc.get(altloc, set()) - remove_ranges |= set([ x for x in range(start, end+1)]) - ranges = self.ranges_by_altloc.get(altloc, set()) - ranges -= remove_ranges - self.remove_ranges_by_altloc[altloc] = remove_ranges - if len(ranges) == 0 : - self.ranges_by_altloc.pop(altloc) + selected_resseqs = self.resseqs_by_altloc.get(altloc, set()) + if len(selected_resseqs) > 0 : + selected_resseqs -= resseqs + if len(selected_resseqs) == 0 : + self.resseqs_by_altloc.pop(altloc) + else : + self.resseqs_by_altloc[altloc] = selected_resseqs else : - self.ranges_by_altloc[altloc] = ranges - if len(self.ranges) == 0 and len(self.ranges_by_altloc) == 0 : + old_resseqs = self.remove_resseqs_by_altloc.get(altloc, set()) + old_resseqs |= resseqs + self.remove_resseqs_by_altloc[altloc] = old_resseqs + if (len(self.resseqs) == 0 and len(self.remove_resseqs) == 0 and + len(self.resseqs_by_altloc) == 0 and + len(self.remove_resseqs_by_altloc) == 0) : return True + return False def __str__ (self) : sele_str = "chain '%s'" % self.chain_id - #if len(self.ranges) > 0 : + clauses = [] + if len(self.resseqs) > 0 : + ranges = get_set_ranges(self.resseqs) + clauses.extend(assemble_resseq_ranges(ranges)) + if len(self.resseqs_by_altloc) > 0 : + for altloc in self.resseqs_by_altloc : + ranges = get_set_ranges(self.resseqs_by_altloc[altloc]) + clauses.extend(assemble_resseq_ranges_with_altloc(ranges, altloc)) + if len(clauses) > 0 : + sele_str += " and ((" + ") or (".join(clauses) + "))" + clauses = [] + if len(self.remove_resseqs) > 0 : + ranges = get_set_ranges(self.remove_resseqs) + clauses.extend(assemble_resseq_ranges(ranges)) + if len(self.remove_resseqs_by_altloc) > 0 : + for altloc in self.remove_resseqs_by_altloc : + ranges = get_set_ranges(self.remove_resseqs_by_altloc[altloc]) + clauses.extend(assemble_resseq_ranges_with_altloc(ranges, altloc)) + if len(clauses) > 0 : + sele_str += " and not ((" + ") or (".join(clauses) + "))" return sele_str class residue_selection_info (object) : @@ -72,6 +104,7 @@ return ("chain '%s' and resid '%s' and name '%s' and altloc '%s'" % (atom.chain_id, atom.resid(), atom.name, altloc)) +#----------------------------------------------------------------------- class mouse_selection_manager (object) : def __init__ (self) : self.saved_selection = "none" @@ -104,22 +137,6 @@ if not hasattr(self, "pdb_hierarchy") : self.pdb_hierarchy = pdb_hierarchy #--- - self._chain_ends = {} - for chain in pdb_hierarchy.chains() : - if len(chain.conformers()) == 1 : - residues = chain.residues() - resseq_start = residues[0].resseq_as_int() - resseq_end = residues[-1].resseq_as_int() - else : - resseq_start = 100000 - resseq_end = -100000 - for conf in chain.conformers() : - residues = conf.residues() - if residues[0].resseq_as_int() < resseq_start : - resseq_start = residues[0].resseq_as_int() - if residues[-1].resseq_as_int() > resseq_end : - resseq_end = residues[-1].resseq_as_int() - self._chain_ends[chain.id] = (resseq_start, resseq_end) self.clear_selection() def clear_selection (self) : @@ -159,7 +176,6 @@ except KeyboardInterrupt : raise except Exception, e : - print e atom_selection =None return atom_selection @@ -170,7 +186,7 @@ self.saved_selection = selection_string self.apply_selection(selection_string) - def reset_range_selection (self, i_seq) : + def reset_range_selection (self) : self.start_i_seq = None def start_range_selection (self, i_seq) : @@ -178,18 +194,12 @@ def end_range_selection (self, i_seq, deselect, ignore_altloc) : success = False - print i_seq if self.start_i_seq is not None : start_atom = self.atom_index[self.start_i_seq] end_atom = self.atom_index[i_seq] if (start_atom.chain_id == end_atom.chain_id and (ignore_altloc or start_atom.altloc == end_atom.altloc)) : chain_id = start_atom.chain_id - if chain_id in self.selected_chains : - chain_info = self.selected_chains[chain_id] - else : - (resseq_start, resseq_end) = self._chain_ends[chain_id] - chain_info = chain_selection_info(chain_id, resseq_start, resseq_end) altloc = None if not ignore_altloc : altloc = start_atom.altloc @@ -198,15 +208,34 @@ if start_range > end_range : start_range = end_atom.resseq_as_int() end_range = start_atom.resseq_as_int() + chain_info = self.selected_chains.get(chain_id) if deselect : - remove_chain = chain_info.remove_range(start_range, end_range, - altloc) - if remove_chain : - self.selection_chains.pop(chain_id) + deselect_str = "chain '%s' and resseq %d:%d" % (chain_id, + start_range, end_range) + if altloc is not None : + deselect_str += " and altloc '%s'" % altloc + if chain_info is not None : + remove_chain = chain_info.remove_range(start_range, end_range, + altloc) + if remove_chain : + self.selected_chains.pop(chain_id) + success = True + deselection = self.get_atom_selection(deselect_str) + self.remove_redundant_residues(deselection, self.selected_residues) + self.remove_redundant_atoms(deselection, self.selected_atoms) + self.remove_redundant_residues(deselection.__invert__(), + self.deselected_residues) + self.remove_redundant_atoms(deselection.__invert__(), + self.deselected_atoms) else : + if chain_info is None : + chain_info = chain_selection_info(chain_id) chain_info.add_range(start_range, end_range, altloc) self.selected_chains[chain_id] = chain_info - success = True + chain_sel = self.selection_cache.selection(str(chain_info)) + self.remove_redundant_residues(chain_sel, self.selected_residues) + self.remove_redundant_atoms(chain_sel, self.selected_atoms) + success = True self.construct_selection() self.reset_range_selection() return success @@ -220,8 +249,7 @@ self.remove_redundant_residues(chain_sel, self.deselected_residues) self.remove_redundant_atoms(chain_sel, self.deselected_atoms) else : - (resseq_start, resseq_end) = self._chain_ends[chain_id] - chain_info = chain_selection_info(chain_id, resseq_start, resseq_end) + chain_info = chain_selection_info(chain_id) self.selected_chains[chain_id] = chain_info chain_sel = self.selection_cache.selection(str(chain_info)) self.remove_redundant_residues(chain_sel, self.selected_residues) @@ -328,6 +356,37 @@ else : return "(" + ") or (".join(clauses) + ")" +def get_set_ranges (residue_set) : + resseqs = sorted(residue_set) + previous_resseq = resseqs[0] + ranges = [] + current_start = resseqs[0] + for resseq in resseqs[1:-1] : + if resseq > (previous_resseq + 1) : + ranges.append((current_start, previous_resseq)) + current_start = resseq + previous_resseq = resseq + ranges.append((current_start, resseqs[-1])) + return ranges + +def assemble_resseq_ranges (ranges) : + clauses = [] + for (start, end) in ranges : + if start == end : + clauses.append("resseq %d" % start) + else : + clauses.append("resseq %d:%d" % (start, end)) + return clauses + +def assemble_resseq_ranges_with_altloc (ranges, altloc) : + clauses = [] + for (start, end) in ranges : + if start == end : + clauses.append("resseq %d and altloc '%s'" % (start, altloc)) + else : + clauses.append("resseq %d:%d and altloc '%s'" % (start,end,altloc)) + return clauses + ######################################################################## def exercise () : from mmtbx.monomer_library import pdb_interpretation @@ -413,9 +472,12 @@ HETATM 4053 O HOH W 5 16.004 9.039 10.335 1.00 37.31 O HETATM 4054 O HOH W 6 2.144 5.718 20.447 1.00 49.77 O HETATM 4055 O HOH W 7 -1.180 10.517 14.630 1.00 32.95 O -HETATM 4056 O HOH W 8 9.227 8.636 12.535 1.00 32.52 O -HETATM 4057 O HOH W 9 11.070 -0.570 15.047 1.00 30.24 O -HETATM 4058 O HOH W 10 15.630 -6.169 12.853 1.00 31.08 O +HETATM 4056 O AHOH W 8 9.227 8.636 12.535 1.00 32.52 O +HETATM 4056 O BHOH W 8 9.227 8.636 12.535 1.00 32.52 O +HETATM 4057 O AHOH W 9 11.070 -0.570 15.047 1.00 30.24 O +HETATM 4057 O BHOH W 9 11.070 -0.570 15.047 1.00 30.24 O +HETATM 4058 O AHOH W 10 15.630 -6.169 12.853 1.00 31.08 O +HETATM 4058 O BHOH W 10 15.630 -6.169 12.853 1.00 31.08 O HETATM 4059 O HOH W 11 14.854 -8.299 16.887 1.00 32.65 O HETATM 4060 O HOH W 12 27.586 0.391 24.184 1.00 31.29 O HETATM 4061 O HOH W 13 3.240 7.801 38.401 1.00 32.09 O @@ -426,7 +488,19 @@ mmtbx_selection_function=None) assert m.selection_size() == 0 m.apply_selection("chain W") - assert m.selection_size() == 13 + assert m.selection_size() == 16 + m.start_range_selection(5) + m.end_range_selection(15, deselect=False, ignore_altloc=True) + assert m.selection_size() == 11 + m.start_range_selection(6) + m.end_range_selection(10, deselect=False, ignore_altloc=True) + assert m.selection_size() == 11 # no change because of deselect=False + m.start_range_selection(6) + m.end_range_selection(9, deselect=True, ignore_altloc=True) + assert m.selection_size() == 6 + m.start_range_selection(10) + m.end_range_selection(12, deselect=True, ignore_altloc=False) + assert m.selection_size() == 5 print "OK" if __name__ == "__main__" : Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-07-30 23:58:41 UTC (rev 9507) +++ trunk/crys3d/wx_selection_editor.py 2009-07-31 00:20:43 UTC (rev 9508) @@ -140,8 +140,8 @@ ######################################################################## # VIEWER CLASS -mouse_modes = ["Rotate view", "Show selection menu", "Toggle chain", - "Toggle residue", "Toggle atom", "Select range", "Deselect range"] +mouse_modes = ["Rotate view", "Toggle chain", "Toggle residue", "Toggle atom", + "Select range", "Deselect range", "Show selection menu"] class selection_editor_mixin (model_viewer_mixin) : def __init__ (self, *args, **kwds) : self.left_button_mode = 0 @@ -205,7 +205,7 @@ self.update_scene = True elif key == ord('z') : self.zoom_selections() - elif key >= 49 and key <= 54 : + elif key >= 49 and key <= 55 : # 1-7 self.set_left_button_mode(key - 49) elif key == 27 : # escape self.clear_selections() @@ -214,6 +214,7 @@ def set_left_button_mode (self, mode) : self.left_button_mode = mode + print "left button mode is %s" % mouse_modes[mode] self._in_range_selection = False #--------------------------------------------------------------------- @@ -258,8 +259,7 @@ finally : self._in_range_selection = False else : - model.start_range_selection(self.current_atom_i_seq, deselect, - ignore_altloc=self.flag_select_all_conformers) + model.start_range_selection(self.current_atom_i_seq) self._in_range_selection = True self.update_scene = True @@ -278,18 +278,18 @@ if (self.closest_point_i_seq is not None and self.flag_enable_mouse_selection) : self.save_selected_atom() - if self.left_button_mode == 1 : # Selection menu - self.context_selection_menu() - elif self.left_button_mode == 2 : # (de)select chain + if self.left_button_mode == 1 : # (de)select chain self.toggle_chain_selection() - elif self.left_button_mode == 3 : # (de)select residue + elif self.left_button_mode == 2 : # (de)select residue self.toggle_residue_selection() - elif self.left_button_mode == 4 : # (de)select atom + elif self.left_button_mode == 3 : # (de)select atom self.toggle_atom_selection() - elif self.left_button_mode == 5 : # select range + elif self.left_button_mode == 4 : # select range self.process_range_selection() - else : # deselect range + elif self.left_button_mode == 5 : # deselect range self.process_range_selection(deselect=True) + else: # Selection menu + self.context_selection_menu() def OnToggleChain (self, event) : pass This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-07-31 21:29:24
|
Revision: 9510 http://cctbx.svn.sourceforge.net/cctbx/?rev=9510&view=rev Author: natechols Date: 2009-07-31 21:28:36 +0000 (Fri, 31 Jul 2009) Log Message: ----------- improved map viewer mixin, partial combined model/map viewer Modified Paths: -------------- trunk/crys3d/wx_model_viewer_multi_scene.py Added Paths: ----------- trunk/crys3d/wx_combined_viewer.py Added: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py (rev 0) +++ trunk/crys3d/wx_combined_viewer.py 2009-07-31 21:28:36 UTC (rev 9510) @@ -0,0 +1,278 @@ + +import sys, os +from crys3d.wx_selection_editor import selection_editor_mixin +from gltbx import wx_viewer +import gltbx.util +from gltbx.gl import * +from gltbx.glu import * +from cctbx import maptbx +from scitbx.math import minimum_covering_sphere +from scitbx.array_family import flex +from scitbx import iso_surface +from libtbx import adopt_init_args +import wx + +class map_data (object) : + def __init__ (self, map) : + adopt_init_args(self, locals()) + self.unit_cell = map.unit_cell() + o = self.unit_cell.orthogonalization_matrix() + self.orthogonaliser = ( o[0:3] + (0,) + + o[3:6] + (0,) + + o[6:9] + (0,) + + (0,0,0,1) ) + p = self.unit_cell.orthogonalize((0,0,0)) + q = self.unit_cell.orthogonalize((1,1,1)) + r = self.unit_cell.orthogonalize((1, 0, 0)) + s = self.unit_cell.orthogonalize((0, 1, 1)) + self.iso_levels = [1] + self.colors = [(1,1,1)] + self.radius = 10.0 + + def set_iso_levels (self, levels) : + self.iso_levels = levels + if len(self.colors) != len(levels) : + self.colors = [ (1.0,1.0,1.0) for x in levels ] + + def set_colors (self, colors) : + assert len(self.iso_levels) == len(colors) + self.colors = colors + + def update_map_data (self, map) : + self.map = map + + def get_scene_data (self, rotation_center) : + triangles = [] + r = self.radius + c = rotation_center + min = [ c[x] - float(r) for x in [0, 1, 2] ] + max = [ c[x] + float(r) for x in [0, 1, 2] ] + map_boundaries_cart = flex.vec3_double([min,max]) + bounds = self.unit_cell.fractionalize(sites_cart=map_boundaries_cart) + rho = self.map.real_map() + for iso_level in self.iso_levels : + triangulation = iso_surface.triangulation(rho, + iso_level, + map_extent=(1,1,1), + from_here=bounds[0], + to_there=bounds[1], + periodic=True, + ascending_normal_direction=False + ) + triangles.append(triangulation) + return map_scene(triangles, self.orthogonaliser, self.colors) + +class map_scene (object) : + def __init__ (self, triangles, orthogonaliser, colors) : + assert len(triangles) == len(colors) + adopt_init_args(self, locals()) + self.flag_use_materials = False + + def draw_mesh (self) : + glMatrixMode(GL_MODELVIEW) + glPushMatrix() + glMultTransposeMatrixd(self.orthogonaliser) + gltbx.util.handle_error() + for i, triangulation in enumerate(self.triangles) : + glLineWidth(0.2) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) + if self.flag_use_materials : + pass + # self.materials[i].execute(specular=False) + # glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) + else : + glColor3f(*self.colors[i]) + va = gltbx.util.vertex_array(triangulation.vertices, + triangulation.normals) + va.draw_triangles(triangulation.triangles) + glPopMatrix() + + +class map_viewer_mixin (wx_viewer.wxGLWindow) : + initialize_map_viewer_super = True + def __init__ (self, *args, **kwds) : + if self.initialize_map_viewer_super : + wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + # various data objects + self.map_ids = [] + self.map_objects = [] + self.map_scenes = {} + # user settings + self.mesh_line_width = 0.25 # very buggy on OS X + NVidia (and ???) + self.buffer_factor = 2 + self.update_maps = False + self.flag_show_maps = True + self.flag_smooth_lines = True + self.flag_use_materials = False + self.flag_show_rotation_center = True + self.minimum_covering_sphere = minimum_covering_sphere( + flex.vec3_double([[0,0,0],[100,100,100],[100,0,0],[0,100,100]])) + + def InitGL (self) : + glClearColor(self.r_back, self.g_back, self.b_back, 0.0) + gltbx.util.rescale_normals(fallback_to_normalize=True).enable() + glEnable(GL_DEPTH_TEST) + glShadeModel(GL_SMOOTH) + vendor = glGetString(GL_VENDOR) + if sys.platform == "darwin" and vendor.startswith("NVIDIA") : + self.flag_smooth_lines = False + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_NORMAL_ARRAY) + self.initialize_modelview() + + def OnRedrawGL (self, event=None) : + self.check_and_update_map_scenes() + wx_viewer.wxGLWindow.OnRedrawGL(self, event) + + def check_and_update_map_scenes (self) : + if self.update_maps : + self.update_map_scenes() + self.update_maps = False + + def DrawGL (self) : + if len(self.map_scenes) == 0 : + return + if self.flag_show_maps : + self.draw_maps() + if self.flag_show_rotation_center : + self.draw_rotation_center() + + def OnTranslate (self, event) : + wx_viewer.wxGLWindow.OnTranslate(self, event) + self.update_map_scenes() + + def draw_rotation_center(self): + font = gltbx.fonts.ucs_bitmap_10x20 + font.setup_call_lists() + glColor3f(0, 1.0, 0) + glRasterPos3f(*self.rotation_center) + font.render_string("+") + return + glMatrixMode(GL_MODELVIEW) + glPushMatrix() + rc = self.rotation_center + (x,y,z) = (rc[0], rc[1], rc[2]) + glTranslatef(x,y,z) + #glScalef(a, b, c) + glBegin(GL_LINES) + f = 0.5 + glColor3f(0, 1.0, 0) + glVertex3f(-f, 0, 0) + glVertex3f(f, 0 ,0) + glVertex3f(0, -f, 0) + glVertex3f(0, f, 0) + glVertex3f(0, 0, -f) + glVertex3f(0, 0, f) + glEnd() + glPopMatrix() + + def setup_fog (self) : + if self.flag_show_fog : + near, far = self.get_clipping_distances() + # TODO: this needs work. + fog_start = 0.25*(far - near) + near + self.fog_start_offset + fog_end = self.far - self.fog_end_offset + glMatrixMode(GL_MODELVIEW) + glEnable(GL_FOG) + glFogi(GL_FOG_MODE, GL_LINEAR) + glFogf(GL_FOG_START, fog_start) + glFogf(GL_FOG_END, fog_end) + glFogfv(GL_FOG_COLOR, [self.r_back, self.g_back, self.b_back, 1.0]) + else : + glDisable(GL_FOG) + + def OnMouseWheel (self, event) : + scale = event.GetWheelRotation() + if event.ShiftDown() : + self.fog_end_offset -= scale + else : + self.clip_far -= scale + + def process_key_stroke (self, key) : + if key == wx.WXK_UP : + self.fog_start_offset += 1 + elif key == wx.WXK_DOWN : + self.fog_start_offset -= 1 + elif key == wx.WXK_LEFT : + self.fog_end_offset -= 1 + elif key == wx.WXK_RIGHT : + self.fog_end_offset += 1 + else : + return + self.OnRedrawGL() + + def add_map (self, map_id, map) : + assert not map_id in self.map_ids + map_object = map_data(map) + self.map_ids.append(map_id) + self.map_objects.append(map_object) + self.update_maps = True + + def update_map (self, map_id, map) : + assert map_id in self.map_ids + map_object = self.get_map(map_id) + map_object.update_map(map) + self.update_maps = True + + def iter_maps (self) : + for (map_id, map_object) in zip(self.map_ids, self.map_objects) : + yield (map_id, map_object) + + def get_map (self, map_id) : + for (object_id, map_object) in self.iter_maps() : + if object_id == map_id : + return map_object + + def set_map_levels_and_colors (self, map_id, levels, colors) : + map = self.get_map(map_id) + map.set_iso_levels(levels) + map.set_colors(colors) + self.update_maps = True + + def update_map_scenes (self) : + for object_id, map in self.iter_maps() : + scene = map.get_scene_data(self.rotation_center) + self.map_scenes[object_id] = scene + + def draw_maps (self) : + gltbx.util.handle_error() + if self.flag_use_materials : + glLightfv(GL_LIGHT0, GL_AMBIENT, [0., 0., 0., 1.]) + if self.flag_use_lights : + glDisable(GL_LIGHTING) + glDisable(GL_LIGHT0) + glDisable(GL_BLEND) + if not self.flag_smooth_lines : + glDisable(GL_LINE_SMOOTH) + for map_id, scene in self.map_scenes.iteritems() : + scene.draw_mesh() + +class model_and_map_viewer (selection_editor_mixin, map_viewer_mixin) : + initialize_map_viewer_super = True + def __init__ (self, *args, **kwds) : + selection_editor_mixin.__init__(self, *args, **kwds) + map_viewer_mixin.__init__(self, *args, **kwds) + + def InitGL (self) : + selection_editor_mixin.InitGL(self) + gltbx.util.rescale_normals(fallback_to_normalize=True).enable() + glShadeModel(GL_SMOOTH) + vendor = glGetString(GL_VENDOR) + if sys.platform == "darwin" and vendor.startswith("NVIDIA") : + self.flag_smooth_lines = False + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_NORMAL_ARRAY) + + def OnRedrawGL (self, event=None) : + self.check_and_update_map_scenes() + selection_editor_mixin.OnRedrawGL(self, event) + + def DrawGL (self) : + selection_editor_mixin.DrawGL(self) + map_viewer_mixin.DrawGL(self) + + def process_key_stroke (self, key) : + selection_editor_mixin.process_key_stroke(self, key) + map_viewer_mixin.process_key_stroke(self, key) + +#---end Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-07-31 05:30:16 UTC (rev 9509) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-07-31 21:28:36 UTC (rev 9510) @@ -490,6 +490,7 @@ self.flag_show_hydrogens = False self.flag_show_ellipsoids = False self.flag_smooth_lines = True + self.flag_recenter_on_click = False @debug def InitGL(self): @@ -524,9 +525,7 @@ self.setup_lighting() def OnRedrawGL (self, event=None) : - if self.update_scene : - self.update_scene_objects() - self.update_scene = False + self.check_and_update_model_scenes() if self.minimum_covering_sphere is None : gltbx.util.handle_error() glClear(GL_COLOR_BUFFER_BIT) @@ -537,6 +536,11 @@ else : wx_viewer.wxGLWindow.OnRedrawGL(self, event) + def check_and_update_model_scenes (self) : + if self.update_scene : + self.update_scene_objects() + self.update_scene = False + def DrawGL(self): if self.GL_uninitialised or len(self.scene_objects) == 0 : return @@ -708,6 +712,9 @@ if self.closest_point_i_seq is not None : clicked_scene = self.scene_objects.get(self.closest_point_object_id) clicked_scene.add_label(self.closest_point_i_seq) + if self.flag_recenter_on_click : + self.recenter_on_atom(self.closest_point_object_id, + self.closest_point_i_seq) @debug def update_scene_objects (self) : This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-08-07 23:31:45
|
Revision: 9559 http://cctbx.svn.sourceforge.net/cctbx/?rev=9559&view=rev Author: natechols Date: 2009-08-07 23:31:38 +0000 (Fri, 07 Aug 2009) Log Message: ----------- various changes to new model/map viewers Modified Paths: -------------- trunk/crys3d/reverse_selection.py trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer_multi_scene.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/reverse_selection.py =================================================================== --- trunk/crys3d/reverse_selection.py 2009-08-07 23:09:29 UTC (rev 9558) +++ trunk/crys3d/reverse_selection.py 2009-08-07 23:31:38 UTC (rev 9559) @@ -152,8 +152,12 @@ return self.selection_i_seqs.size() def apply_selection (self, selection_string) : + if selection_string is None or selection_string == "" : + selection_string = "none" atom_selection = self.get_atom_selection(selection_string) + error = False if atom_selection is None : + error = True self.selection_string = "none" atom_selection = self.selection_cache.selection("none") else : @@ -162,7 +166,7 @@ self.selection_i_seqs = atom_selection.iselection() if self.selection_callback is not None : self.selection_callback(self.selection_string, self.atom_selection) - if atom_selection is None : + if error : # wait until the end to do this raise Sorry("Invalid selection '%s'."%selection_string) def get_atom_selection (self, selection_string) : Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-08-07 23:09:29 UTC (rev 9558) +++ trunk/crys3d/wx_combined_viewer.py 2009-08-07 23:31:38 UTC (rev 9559) @@ -1,6 +1,7 @@ import sys, os from crys3d.wx_selection_editor import selection_editor_mixin +import iotbx.phil from gltbx import wx_viewer import gltbx.util from gltbx.gl import * @@ -12,6 +13,10 @@ from libtbx import adopt_init_args import wx +viewer_phil = iotbx.phil.parse(""" + include scope crys3d.wx_selection_editor.viewer_phil +""", process_includes=True) + class map_data (object) : def __init__ (self, map) : adopt_init_args(self, locals()) @@ -187,6 +192,7 @@ self.fog_end_offset -= scale else : self.clip_far -= scale + self.OnRedrawGL() def process_key_stroke (self, key) : if key == wx.WXK_UP : @@ -248,7 +254,7 @@ scene.draw_mesh() class model_and_map_viewer (selection_editor_mixin, map_viewer_mixin) : - initialize_map_viewer_super = True + initialize_map_viewer_super = False def __init__ (self, *args, **kwds) : selection_editor_mixin.__init__(self, *args, **kwds) map_viewer_mixin.__init__(self, *args, **kwds) Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-07 23:09:29 UTC (rev 9558) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-07 23:31:38 UTC (rev 9559) @@ -1,6 +1,7 @@ # XXX: To keep these classes as clean as possible, selections are handled # entirely in wx_selection_editor.py. +# TODO: hide nonbonded point for any atom that has an ellipsoid drawn import iotbx.phil from cctbx import uctbx @@ -64,7 +65,10 @@ self.flag_object_visible = True self._color_cache = {} self.flag_show_hydrogens = False + self.flag_show_lines = True + self.flag_show_labels = True self.flag_show_points = True + self.flag_show_spheres = False self.flag_show_ellipsoids = False self.update_structure(pdb_hierarchy, atomic_bonds) self.use_u_aniso = flex.bool(self.atoms.size()) @@ -131,9 +135,11 @@ @debug def update_structure (self, pdb_hierarchy, atomic_bonds) : self.pdb_hierarchy = pdb_hierarchy - self.atomic_bonds = atomic_bonds self.atoms = pdb_hierarchy.atoms() self.atom_count = self.atoms.size() + if atomic_bonds is None : + atomic_bonds = flex.stl_set_unsigned(self.atom_count) + self.atomic_bonds = atomic_bonds self.selection_cache = pdb_hierarchy.atom_selection_cache() atom_index = [] atom_labels = flex.std_string() @@ -161,6 +167,10 @@ def recalculate_visibility (self) : c = 0 atoms = self.atom_index + if self.draw_mode == "spheres" : + show_points = True + else : + show_points = self.flag_show_points if self.flag_show_hydrogens : atoms_drawable = flex.bool(self.atom_count, True) else : @@ -168,7 +178,7 @@ self.visibility = viewer_utils.atom_visibility( bonds = self.current_bonds, atoms_drawable = atoms_drawable, - flag_show_points = self.flag_show_points + flag_show_points = show_points ) self.visible_atom_count = self.visibility.visible_atoms_count @@ -191,14 +201,17 @@ else : self.draw_mode = draw_mode show_points = True - if draw_mode in ["trace", "trace_and_nb"] : - self.current_bonds = self.trace_bonds + if draw_mode == "spheres" : + self.flag_show_spheres = True else : - self.current_bonds = self.atomic_bonds - if draw_mode in ["trace", "bonded_only"] : - self.flag_show_points = False - else : - self.flag_show_points = True + if draw_mode in ["trace", "trace_and_nb"] : + self.current_bonds = self.trace_bonds + else : + self.current_bonds = self.atomic_bonds + if draw_mode in ["trace", "bonded_only"] : + self.flag_show_points = False + else : + self.flag_show_points = True self.recalculate_visibility() self.set_color_mode(self.color_mode) # force re-coloring @@ -483,12 +496,11 @@ self.flag_show_lines = True self.flag_show_points = True self.flag_show_spheres = False - self.flag_show_ellipsoids = False self.flag_use_lights = True self.flag_show_labels = True self.flag_show_trace = False self.flag_show_hydrogens = False - self.flag_show_ellipsoids = False + self.flag_show_ellipsoids = True self.flag_smooth_lines = True self.flag_recenter_on_click = False @@ -544,11 +556,11 @@ def DrawGL(self): if self.GL_uninitialised or len(self.scene_objects) == 0 : return - if (self.flag_show_points): + if self.flag_show_points : self.draw_points() - if (self.flag_show_lines): + if self.flag_show_lines : self.draw_lines() - if (self.flag_show_spheres): + if self.flag_show_spheres : self.draw_spheres() if self.flag_show_ellipsoids : self.draw_ellipsoids() @@ -558,9 +570,9 @@ def draw_points (self) : glDisable(GL_LIGHTING) glLineWidth(self.settings.opengl.nonbonded_line_width) - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_points() + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_points : + self.scene_objects[model_id].draw_points() def draw_spheres (self) : glMatrixMode(GL_MODELVIEW) @@ -572,9 +584,9 @@ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [1.0,1.0,1.0,1.0]) glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.1, 0.1, 0.1, 1.0]) glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [0.1, 0.1, 0.1, 1.0]) - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_spheres() + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_spheres : + self.scene_objects[model_id].draw_spheres() def draw_lines (self) : glEnable(GL_LINE_SMOOTH) @@ -582,9 +594,9 @@ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glDisable(GL_LIGHTING) glLineWidth(self.settings.opengl.line_width) - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_lines() + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_lines : + self.scene_objects[model_id].draw_lines() if not self.flag_smooth_lines : glDisable(GL_LINE_SMOOTH) @@ -601,20 +613,21 @@ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [0.5, 0.5, 0.5, 1.0]) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) proto_ellipsoid = self.proto_ellipsoid - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - scene.draw_ellipsoids(proto_ellipsoid) + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_ellipsoids : + self.scene_objects[model_id].draw_ellipsoids(proto_ellipsoid) def draw_labels (self) : glDisable(GL_LIGHTING) use_atom_color = self.settings.opengl.use_atom_color_for_labels if not use_atom_color : + print "using global label color" glColor3f(1.0, 1.0, 1.0) - for object_id, scene in self.scene_objects.iteritems() : - if self.show_object[object_id] : - font = gltbx.fonts.ucs_bitmap_8x13 - font.setup_call_lists() - scene.draw_labels(font, use_atom_color) + font = gltbx.fonts.ucs_bitmap_8x13 + font.setup_call_lists() + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_labels : + self.scene_objects[model_id].draw_labels(font, use_atom_color) @debug def refresh_bg_color (self) : @@ -626,9 +639,9 @@ # def update_settings (self, params, redraw=False) : assert (len(params.opengl.base_atom_color) == - len(params.opengl.background_color) == - len(params.opengl.selection_color) == 3) + len(params.opengl.background_color) == 3) self.settings = params + self.toggle_hydrogens(params.opengl.show_hydrogens) if redraw : self.update_scene = True @@ -642,6 +655,26 @@ return model return None + def get_model_state (self, object_id) : + model = self.get_model(object_id) + model_attr = dir(model) + state = {} + for name in model_attr : + if name.startswith("flag_") : + state_var = name[5:] #re.sub("flag_", "", name) + state[state_var] = getattr(model, name) + state["draw_mode"] = model.draw_mode + state["color_mode"] = model.color_mode + return state + + def set_model_state (self, object_id, model_state) : + model = self.get_model(object_id) + for name in model_state : + setattr(model, name, model_state[name]) + model.set_draw_mode(model_state["draw_mode"]) + #model.recalculate_visibility() + self.update_scene = True + @debug def add_model (self, model_id, pdb_hierarchy, atomic_bonds=None) : assert isinstance(model_id, str) @@ -658,9 +691,18 @@ def update_model (self, model_id, pdb_hierarchy, atomic_bonds) : model = self.get_model(model_id) - model.update_structure(pdb_hierarchy, atomic_bonds) - self.update_scene = True + if model is not None : + model.update_structure(pdb_hierarchy, atomic_bonds) + self.update_scene = True + else : + self.add_model(model_id, pdb_hierarchy, atomic_bonds) + def update_model_from_xray_structure (self, model_id, xray_structure) : + model = self.get_model(model_id) + if model is not None : + model.update_from_xray_structure(xray_structure) + self.update_scene = True + def update_mcs (self, points, recenter_and_zoom=True) : self.minimum_covering_sphere = minimum_covering_sphere( points=points, @@ -711,7 +753,8 @@ break if self.closest_point_i_seq is not None : clicked_scene = self.scene_objects.get(self.closest_point_object_id) - clicked_scene.add_label(self.closest_point_i_seq) + if self.settings.opengl.label_clicked_atom : + clicked_scene.add_label(self.closest_point_i_seq) if self.flag_recenter_on_click : self.recenter_on_atom(self.closest_point_object_id, self.closest_point_i_seq) @@ -817,8 +860,7 @@ @debug def OnUpdate (self, event) : self.update_scene_objects() - if (event is not None and hasattr(event, "recenter") and - event.recenter == True) or recenter == True : + if getattr(event, "recenter", False) : self.move_rotation_center_to_mcs_center() self.fit_into_viewport() Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-08-07 23:09:29 UTC (rev 9558) +++ trunk/crys3d/wx_selection_editor.py 2009-08-07 23:31:38 UTC (rev 9559) @@ -79,7 +79,8 @@ def update_selection (self, atom_selection) : self.atom_selection = atom_selection - self.selected_atom_count = atom_selection.iselection().size() + self.selection_i_seqs = atom_selection.iselection() + self.selected_atom_count = self.selection_i_seqs.size() self.selection_display_list = None def update_visibility (self, visibility) : @@ -140,9 +141,9 @@ ######################################################################## # VIEWER CLASS -mouse_modes = ["Rotate view", "Toggle chain", "Toggle residue", "Toggle atom", - "Select range", "Deselect range", "Show selection menu"] class selection_editor_mixin (model_viewer_mixin) : + mouse_modes = ["Rotate view", "Toggle chain", "Toggle residue", + "Toggle atom", "Select range", "Deselect range"] #, "Show selection menu"] def __init__ (self, *args, **kwds) : self.left_button_mode = 0 self.flag_select_all_conformers = True @@ -150,6 +151,7 @@ self.flag_enable_mouse_selection = True self.current_atom_i_seq = None self.current_object_id = None + self._callback = print_cb self._in_range_selection = False model_viewer_mixin.__init__(self, *args,**kwds) self.settings = viewer_phil.extract() @@ -177,18 +179,23 @@ if self.show_object[object_id] : for point in scene.get_selected_xyz() : points.append(point) + if points.size() == 0 : + for object_id, scene in self.scene_objects.iteritems() : + if self.show_object[object_id] : + points.extend(scene.points) if points.size() != 0 : self.update_mcs(points) def set_selection (self, object_id, selection_string) : for model_id, model in self.iter_models() : - if model_id == object_id : + if object_id is None or model_id == object_id : model.apply_selection(selection_string) self.update_scene = True def clear_selections (self) : for model_id, model in self.iter_models() : model.clear_selection() + self.update_scene = True def add_model (self, model_id, pdb_hierarchy, atomic_bonds, mmtbx_selection_function=None) : @@ -196,7 +203,7 @@ model = model_data_with_selection(model_id, pdb_hierarchy, atomic_bonds, base_color=self.settings.opengl.base_atom_color) model.set_mmtbx_selection_function(mmtbx_selection_function) - model.set_selection_callback(print_cb) + model.set_selection_callback(self._callback) self._add_model(model_id, model) def process_key_stroke (self, key) : @@ -214,10 +221,13 @@ def set_left_button_mode (self, mode) : self.left_button_mode = mode - print "left button mode is %s" % mouse_modes[mode] self._in_range_selection = False #--------------------------------------------------------------------- + def set_selection_callback (self, callback) : + assert hasattr(callback, "__call__") + self._callback = callback + def pick_selection_object (self, object_id) : for model_id in self.pick_object : if model_id == object_id : @@ -263,6 +273,7 @@ self._in_range_selection = True self.update_scene = True + # TODO: finish this? def context_selection_menu (self) : menu = wx.Menu() toggle_chain = menu.Append(-1, "Toggle chain selection") @@ -291,6 +302,7 @@ else: # Selection menu self.context_selection_menu() + # Handlers for selection menu events def OnToggleChain (self, event) : pass This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-08-10 23:38:37
|
Revision: 9563 http://cctbx.svn.sourceforge.net/cctbx/?rev=9563&view=rev Author: natechols Date: 2009-08-10 23:38:31 +0000 (Mon, 10 Aug 2009) Log Message: ----------- minor bug fixes; recentering on double-click; maps update on recenter Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer_multi_scene.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-08-08 18:31:26 UTC (rev 9562) +++ trunk/crys3d/wx_combined_viewer.py 2009-08-10 23:38:31 UTC (rev 9563) @@ -217,7 +217,7 @@ def update_map (self, map_id, map) : assert map_id in self.map_ids map_object = self.get_map(map_id) - map_object.update_map(map) + map_object.update_map_data(map) self.update_maps = True def iter_maps (self) : @@ -281,4 +281,12 @@ selection_editor_mixin.process_key_stroke(self, key) map_viewer_mixin.process_key_stroke(self, key) + def update_mcs (self, *args, **kwds) : + self.update_maps = True + selection_editor_mixin.update_mcs(self, *args, **kwds) + + def recenter_on_atom (self, *args, **kwds) : + self.update_maps = True + selection_editor_mixin.recenter_on_atom(self, *args, **kwds) + #---end Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-08 18:31:26 UTC (rev 9562) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-10 23:38:31 UTC (rev 9563) @@ -37,6 +37,10 @@ background_color = 0.0 0.0 0.0 .type = floats .style = color + default_coloring = *rainbow element b chain + .type = choice + default_representation = *all_atoms trace bonded_only + .type = choice show_hydrogens = False .type = bool label_clicked_atom = True @@ -47,6 +51,9 @@ .type = bool orthographic = False .type = bool + .style = noauto + animate_zoom = False + .type = bool } """) @@ -61,7 +68,7 @@ self.base_color = base_color self.draw_mode = None self.current_bonds = None - self.color_mode = "rainbow" + self.color_mode = None #"rainbow" self.flag_object_visible = True self._color_cache = {} self.flag_show_hydrogens = False @@ -72,7 +79,6 @@ self.flag_show_ellipsoids = False self.update_structure(pdb_hierarchy, atomic_bonds) self.use_u_aniso = flex.bool(self.atoms.size()) - self.set_draw_mode("all_atoms") #self.recalculate_visibility() def reset (self) : @@ -121,7 +127,7 @@ sites_cart = xray_structure.sites_cart() u_iso = xray_structure.extract_u_iso_or_u_equiv() u_aniso = xray_structure.extract_u_cart_plus_u_iso() - occ = xray_structure.scatterrers().extract_occupancies() + occ = xray_structure.scatterers().extract_occupancies() assert sites_cart.size() == self.atoms.size() for i_seq, atom in enumerate(self.atoms) : atom.xyz = sites_cart[i_seq] @@ -141,6 +147,7 @@ atomic_bonds = flex.stl_set_unsigned(self.atom_count) self.atomic_bonds = atomic_bonds self.selection_cache = pdb_hierarchy.atom_selection_cache() + #self.index_atoms() atom_index = [] atom_labels = flex.std_string() for atom in self.pdb_hierarchy.atoms_with_labels() : @@ -151,11 +158,11 @@ self.trace_bonds = extract_trace(pdb_hierarchy) #, self.selection_cache) if self.current_bonds is None : self.current_bonds = self.atomic_bonds - assert len(self.atom_index) == self.atom_count atom_radii = flex.double(self.atoms.size(), 1.5) hydrogen_flag = flex.bool(self.atoms.size(), False) for i_seq, atom in enumerate(self.atom_index) : - if atom.element == ' H' : + name = atom.name.strip() + if name[0] == 'H' : atom_radii[i_seq] = 0.75 hydrogen_flag[i_seq] = True self.atom_radii = atom_radii @@ -166,7 +173,6 @@ @debug def recalculate_visibility (self) : c = 0 - atoms = self.atom_index if self.draw_mode == "spheres" : show_points = True else : @@ -174,7 +180,8 @@ if self.flag_show_hydrogens : atoms_drawable = flex.bool(self.atom_count, True) else : - atoms_drawable = flex.bool([ (atom.element != ' H') for atom in atoms ]) + atoms_drawable = self.hydrogen_flag.__invert__() + #atoms_drawable = flex.bool([ (atom.element != ' H') for atom in atoms ]) self.visibility = viewer_utils.atom_visibility( bonds = self.current_bonds, atoms_drawable = atoms_drawable, @@ -195,7 +202,7 @@ def toggle_ellipsoids (self, show_ellipsoids) : self.flag_show_ellipsoids = show_ellipsoids - def set_draw_mode (self, draw_mode) : + def set_draw_mode (self, draw_mode, color_mode=None) : if draw_mode == self.draw_mode and not self.is_changed : pass else : @@ -213,6 +220,8 @@ else : self.flag_show_points = True self.recalculate_visibility() + if color_mode is not None : + self.color_mode = color_mode self.set_color_mode(self.color_mode) # force re-coloring #--------------------------------------------------------------------- @@ -289,8 +298,8 @@ for chain in self.pdb_hierarchy.chains() : chain_shades[chain.id] = rainbow[j] atom_colors = flex.vec3_double() - for i_seq, atom_object in enumerate(self.atom_index) : - atom_colors.append(chain_shades[atom_object.chain_id]) + for atom in self.pdb_hierarchy.atoms_with_labels() : + atom_colors.append(chain_shades[atom.chain_id]) self.atom_colors = atom_colors self._color_cache["chain"] = atom_colors @@ -320,9 +329,8 @@ 'Cu' : (0.0, 0.8, 0.7), # blue-green 'Co' : (0.0, 0.5, 0.6) } # marine atom_colors = flex.vec3_double() - for i_seq, atom_object in enumerate(self.atom_index) : - element = atom_object.element - color = element_shades.get(element) + for atom in self.pdb_hierarchy.atoms_with_labels() : + color = element_shades.get(atom.element) if color is None : color = (0.0, 1.0, 1.0) atom_colors.append(color) @@ -476,6 +484,7 @@ class model_viewer_mixin (wx_viewer.wxGLWindow) : def __init__ (self, *args, **kwds) : wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) self.Connect(-1, -1, UPDATE_MODEL_ID, self.OnUpdateModel) self.Connect(-1, -1, ADD_MODEL_ID, self.OnAddModel) self.minimum_covering_sphere = None @@ -488,7 +497,7 @@ self.model_reps = {} self.update_scene = False self.buffer_factor = 2 # see gltbx.wx_viewer - self.settings = opengl_phil.extract() + self.update_settings(opengl_phil.extract()) self.closest_point_i_seq = None self.closest_point_model_id = None # toggles for viewable objects @@ -641,6 +650,10 @@ assert (len(params.opengl.base_atom_color) == len(params.opengl.background_color) == 3) self.settings = params + if params.opengl.animate_zoom : + self.animation_time = 1 + else : + self.animation_time = 0 self.toggle_hydrogens(params.opengl.show_hydrogens) if redraw : self.update_scene = True @@ -683,6 +696,8 @@ self._add_model(model_id, model) def _add_model (self, model_id, model) : + model.set_draw_mode(draw_mode=self.settings.opengl.default_representation, + color_mode=self.settings.opengl.default_coloring) self.model_ids.append(model_id) self.model_objects.append(model) self.show_object[model_id] = True @@ -818,11 +833,11 @@ def hide_others (self, object_id=None) : for model_id in self.model_ids : if model_id != object_id : - self.show_objects[model_id] = False + self.show_object[model_id] = False def show_all (self) : for model_id in self.model_ids : - self.show_objects[model_id] = True + self.show_object[model_id] = True @debug def set_draw_mode (self, draw_mode, object_id=None) : @@ -874,6 +889,13 @@ self.add_model(model_id, pdb_hierarchy, atomic_bonds) self.OnRedrawGL() + def OnDoubleClick (self, event) : + self.get_pick_points((event.GetX(), event.GetY())) + self.process_pick_points() + if self.closest_point_i_seq is not None : + self.recenter_on_atom(self.closest_point_object_id, + self.closest_point_i_seq) + def thread_safe_add_model (self, model_id, pdb_hierarchy, atomic_bonds) : wx.PostEvent(self, AddModelEvent(model_id, pdb_hierarchy, atomic_bonds)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-08-12 01:15:34
|
Revision: 9585 http://cctbx.svn.sourceforge.net/cctbx/?rev=9585&view=rev Author: natechols Date: 2009-08-12 01:15:23 +0000 (Wed, 12 Aug 2009) Log Message: ----------- added function to delete model; fixed initial zoom bug Modified Paths: -------------- trunk/crys3d/reverse_selection.py trunk/crys3d/wx_model_viewer_multi_scene.py Modified: trunk/crys3d/reverse_selection.py =================================================================== --- trunk/crys3d/reverse_selection.py 2009-08-12 00:56:30 UTC (rev 9584) +++ trunk/crys3d/reverse_selection.py 2009-08-12 01:15:23 UTC (rev 9585) @@ -146,7 +146,7 @@ self.deselected_atoms = [] self.selected_residues = [] self.deselected_residues = [] - self.apply_selection(self.saved_selection) + #self.apply_selection(self.saved_selection) def selection_size (self) : return self.selection_i_seqs.size() Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-12 00:56:30 UTC (rev 9584) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-12 01:15:23 UTC (rev 9585) @@ -695,6 +695,15 @@ base_color=self.settings.opengl.base_atom_color) self._add_model(model_id, model) + def delete_model (self, model_id) : + if model_id in self.model_ids : + i = self.model_ids.index(model_id) + self.model_ids.pop(i) + self.model_objects.pop(i) + if model_id in self.scene_objects : + self.scene_objects.pop(model_id) + self.update_scene = True + def _add_model (self, model_id, model) : model.set_draw_mode(draw_mode=self.settings.opengl.default_representation, color_mode=self.settings.opengl.default_coloring) @@ -727,11 +736,13 @@ self.fit_into_viewport() def zoom_object (self, object_id) : + self.update_scene_objects() assert object_id in self.scene_objects self.update_mcs(self.scene_objects[object_id].points) @debug def unzoom (self, event=None) : + self.update_scene_objects() if len(self.scene_objects) > 0 : points = flex.vec3_double() for object_id, scene in self.scene_objects.iteritems() : This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2010-02-15 05:44:21
|
Revision: 10290 http://cctbx.svn.sourceforge.net/cctbx/?rev=10290&view=rev Author: natechols Date: 2010-02-15 05:44:14 +0000 (Mon, 15 Feb 2010) Log Message: ----------- added methods for showing hydrogen bonds Modified Paths: -------------- trunk/crys3d/wx_model_viewer.py trunk/crys3d/wx_model_viewer_example.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2010-02-13 23:16:09 UTC (rev 10289) +++ trunk/crys3d/wx_model_viewer.py 2010-02-15 05:44:14 UTC (rev 10290) @@ -80,6 +80,7 @@ self.base_color = base_color self.draw_mode = None self.current_bonds = None + self.noncovalent_bonds = None self.color_mode = None #"rainbow" self.flag_object_visible = True self._color_cache = {} @@ -89,6 +90,7 @@ self.flag_show_points = True self.flag_show_spheres = False self.flag_show_ellipsoids = False + self.flag_show_noncovalent_bonds = False self.update_structure(pdb_hierarchy, atomic_bonds) self.use_u_aniso = flex.bool(self.atoms.size()) #self.recalculate_visibility() @@ -107,8 +109,12 @@ atom_colors=self.atom_colors, atom_labels=self.atom_labels, atom_radii=self.atom_radii, - visibility=self.visibility) + visibility=self.visibility, + noncovalent_bonds=self.noncovalent_bonds) + def set_noncovalent_bonds (self, bonded_atoms) : + self.noncovalent_bonds = bonded_atoms + def update_scene_data (self, scene) : scene.update_bonds(self.current_bonds) scene.update_colors(self.atom_colors) @@ -357,7 +363,7 @@ # which are also implemented as methods here. class model_scene (object) : def __init__ (self, bonds, points, b_iso, b_aniso, atom_colors, atom_labels, - atom_radii, visibility) : + atom_radii, visibility, noncovalent_bonds) : adopt_init_args(self, locals()) self.clear_lists() self.clear_labels() @@ -371,6 +377,7 @@ self.ellipsoid_display_list = None self.selection_display_list = None self.labels_display_list = None + self.nc_display_list = None @debug def clear_labels (self) : @@ -479,6 +486,22 @@ self.labels_display_list.end() self.labels_display_list.call() + def draw_noncovalent_bonds (self) : + if self.noncovalent_bonds is None : + return + if self.nc_display_list is None : + self.nc_display_list = gltbx.gl_managed.display_list() + self.nc_display_list.compile() + points = self.points + bonded_atoms = self.noncovalent_bonds + for i_seq, j_seq in bonded_atoms : + glBegin(GL_LINES) + glVertex3f(*points[i_seq]) + glVertex3f(*points[j_seq]) + glEnd() + self.nc_display_list.end() + self.nc_display_list.call() + ######################################################################## # VIEWER CLASS # @@ -527,6 +550,7 @@ self.flag_use_lights = True self.flag_show_labels = True self.flag_show_trace = False + self.flag_show_noncovalent_bonds = False self.flag_show_hydrogens = False self.flag_show_ellipsoids = True self.flag_smooth_lines = True @@ -605,6 +629,8 @@ self.draw_ellipsoids() if self.flag_show_labels : self.draw_labels() + if self.flag_show_noncovalent_bonds : + self.draw_noncovalent_bonds() def draw_points (self) : glDisable(GL_LIGHTING) @@ -667,6 +693,16 @@ if self.show_object[model_id] and model.flag_show_labels : self.scene_objects[model_id].draw_labels(font, use_atom_color) + def draw_noncovalent_bonds (self) : + glDisable(GL_LIGHTING) + glColor3f(0.0, 1.0, 0.0) + glLineStipple(4, 0xAAAA) + glEnable(GL_LINE_STIPPLE) + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_noncovalent_bonds : + self.scene_objects[model_id].draw_noncovalent_bonds() + glDisable(GL_LINE_STIPPLE) + @debug def refresh_bg_color (self) : (r, g, b) = tuple(self.settings.opengl.background_color) @@ -800,6 +836,12 @@ model.update_from_xray_structure(xray_structure) self.update_scene = True + def set_noncovalent_bonds (self, model_id, bonded_atoms) : + model = self.get_model(model_id) + if model is not None : + model.set_noncovalent_bonds(bonded_atoms) + model.flag_show_noncovalent_bonds = True + def update_mcs (self, points, recenter_and_zoom=True, buffer=0) : mcs = minimum_covering_sphere(points=points, epsilon=0.1) @@ -1008,6 +1050,18 @@ self.recenter_on_atom(self.closest_point_object_id, self.closest_point_i_seq) + def OnMouseWheel (self, event) : + scale = event.GetWheelRotation() + if event.ShiftDown() : + self.fog_end_offset -= scale + else : + self.slab_scale += 0.01 * scale + if self.slab_scale > 1.0 : + self.slab_scale = 1.0 + elif self.slab_scale < 0.01 : + self.slab_scale = 0.01 + self.OnRedrawGL() + def OnModelMenu (self, event) : menu = event.GetEventObject() item = menu.FindItemById(event.GetId()) Modified: trunk/crys3d/wx_model_viewer_example.py =================================================================== --- trunk/crys3d/wx_model_viewer_example.py 2010-02-13 23:16:09 UTC (rev 10289) +++ trunk/crys3d/wx_model_viewer_example.py 2010-02-15 05:44:14 UTC (rev 10290) @@ -2,7 +2,7 @@ import sys, os import cStringIO from crys3d.wx_selection_editor import selection_editor_mixin -from mmtbx.monomer_library import pdb_interpretation +from mmtbx.monomer_library import pdb_interpretation, secondary_structure import iotbx.pdb import wx @@ -30,12 +30,15 @@ import cStringIO pdb_files = [] cif_files = [] + show_ss_restraints = False for arg in args : if os.path.isfile(arg) : if iotbx.pdb.is_pdb_file(arg) : pdb_files.append(os.path.abspath(arg)) elif arg.endswith(".cif") : cif_files.append(os.path.abspath(arg)) + elif arg == "--ss" : + show_ss_restraints = True if len(pdb_files) == 0 : print "Please specify a PDB file (and optional CIFs) on the command line." return @@ -57,6 +60,12 @@ atomic_bonds = grm.shell_sym_tables[0].full_simple_connectivity() a.view_objects.add_model(file_name, pdb_hierarchy, atomic_bonds, mmtbx_selection_function=acp_selection) + if show_ss_restraints : + bonds_table = secondary_structure.get_bonds(file_name) + a.view_objects.set_noncovalent_bonds(file_name, bonds_table.bonds) + a.view_objects.flag_show_noncovalent_bonds = True + a.view_objects.set_model_base_color([1.0,1.0,1.0], file_name) + a.view_objects.set_color_mode("element") a.frame.Show() a.view_objects.force_update(recenter=True) a.MainLoop() Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2010-02-13 23:16:09 UTC (rev 10289) +++ trunk/crys3d/wx_selection_editor.py 2010-02-15 05:44:14 UTC (rev 10290) @@ -45,7 +45,8 @@ atom_colors=self.atom_colors, atom_labels=self.atom_labels, atom_radii=self.atom_radii, - visibility=self.visibility) + visibility=self.visibility, + noncovalent_bonds=self.noncovalent_bonds) self.update_scene_data(scene) return scene This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-08-13 00:03:14
|
Revision: 9592 http://cctbx.svn.sourceforge.net/cctbx/?rev=9592&view=rev Author: natechols Date: 2009-08-13 00:03:06 +0000 (Thu, 13 Aug 2009) Log Message: ----------- minor bug fixes and additions for phenix gui Modified Paths: -------------- trunk/crys3d/reverse_selection.py trunk/crys3d/wx_model_viewer_multi_scene.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/reverse_selection.py =================================================================== --- trunk/crys3d/reverse_selection.py 2009-08-12 23:11:56 UTC (rev 9591) +++ trunk/crys3d/reverse_selection.py 2009-08-13 00:03:06 UTC (rev 9592) @@ -146,7 +146,7 @@ self.deselected_atoms = [] self.selected_residues = [] self.deselected_residues = [] - #self.apply_selection(self.saved_selection) + self.apply_selection("none") #self.saved_selection) def selection_size (self) : return self.selection_i_seqs.size() Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-12 23:11:56 UTC (rev 9591) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-13 00:03:06 UTC (rev 9592) @@ -841,6 +841,12 @@ if self.update_scene : self.OnRedrawGL() + def toggle_visibility (self, show_object, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + self.show_object[model_id] = show_object + self.update_scene = True + def hide_others (self, object_id=None) : for model_id in self.model_ids : if model_id != object_id : @@ -874,6 +880,16 @@ if object_id is None or object_id == model_id : model.toggle_hydrogens(show_hydrogens) + # TODO: something smarter - temporary toggle for draw_mode? + def toggle_trace (self, show_trace, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + if show_trace : + model.set_draw_mode("trace") + else : + model.set_draw_mode("all_atoms") + self.update_scene = True + def toggle_labels (self, show_labels) : self.flag_show_labels = show_labels Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-08-12 23:11:56 UTC (rev 9591) +++ trunk/crys3d/wx_selection_editor.py 2009-08-13 00:03:06 UTC (rev 9592) @@ -302,6 +302,10 @@ else: # Selection menu self.context_selection_menu() + def OnDoubleClick (self, event) : + if self.left_button_mode == 0 : + model_viewer_mixin.OnDoubleClick(self, event) + # Handlers for selection menu events def OnToggleChain (self, event) : pass This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-08-14 00:05:39
|
Revision: 9600 http://cctbx.svn.sourceforge.net/cctbx/?rev=9600&view=rev Author: natechols Date: 2009-08-14 00:05:33 +0000 (Fri, 14 Aug 2009) Log Message: ----------- more bug fixes and phenix gui support; removed obsolete map_viewer_mixin from wx_map_viewer.py Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_map_viewer.py trunk/crys3d/wx_model_viewer.py trunk/crys3d/wx_model_viewer_example.py trunk/crys3d/wx_model_viewer_multi_scene.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-08-13 22:56:35 UTC (rev 9599) +++ trunk/crys3d/wx_combined_viewer.py 2009-08-14 00:05:33 UTC (rev 9600) @@ -102,6 +102,7 @@ self.map_ids = [] self.map_objects = [] self.map_scenes = {} + self.show_object = {} # user settings self.mesh_line_width = 0.25 # very buggy on OS X + NVidia (and ???) self.buffer_factor = 2 @@ -212,14 +213,38 @@ map_object = map_data(map) self.map_ids.append(map_id) self.map_objects.append(map_object) + self.show_object[map_id] = True self.update_maps = True - def update_map (self, map_id, map) : - assert map_id in self.map_ids - map_object = self.get_map(map_id) - map_object.update_map_data(map) + def delete_map (self, map_id) : + if map_id in self.map_ids : + i = self.map_ids.index(map_id) + self.map_ids.pop(i) + self.map_objects.pop(i) + if map_id in self.scene_objects : + self.scene_objects.pop(map_id) self.update_maps = True + def update_map (self, map_id, map) : + if not map_id in self.map_ids : + self.add_map(map_id, map) + else : + map_object = self.get_map(map_id) + map_object.update_map_data(map) + self.update_maps = True + + def update_map_from_miller_array (self, map_id, map_coeffs, + resolution_factor=0.33) : + assert map_coeffs.is_complex_array() + fft_map = map_coeffs.fft_map(resolution_factor=resolution_factor) + fft_map.apply_sigma_scaling(resolution_factor=resolution_factor) + self.update_map(map_id, fft_map) + + def hide_others (self, object_id=None) : + for map_id in self.model_ids : + if map_id != object_id : + self.show_object[map_id] = False + def iter_maps (self) : for (map_id, map_object) in zip(self.map_ids, self.map_objects) : yield (map_id, map_object) @@ -251,7 +276,8 @@ if not self.flag_smooth_lines : glDisable(GL_LINE_SMOOTH) for map_id, scene in self.map_scenes.iteritems() : - scene.draw_mesh() + if self.show_object[map_id] : + scene.draw_mesh() class model_and_map_viewer (selection_editor_mixin, map_viewer_mixin) : initialize_map_viewer_super = False @@ -289,4 +315,8 @@ self.update_maps = True selection_editor_mixin.recenter_on_atom(self, *args, **kwds) + def hide_others (self, *args, **kwds) : + selection_editor_mixin.hide_others(self, *args, **kwds) + map_viewer_mixin.hide_others(self, *args, **kwds) + #---end Modified: trunk/crys3d/wx_map_viewer.py =================================================================== --- trunk/crys3d/wx_map_viewer.py 2009-08-13 22:56:35 UTC (rev 9599) +++ trunk/crys3d/wx_map_viewer.py 2009-08-14 00:05:33 UTC (rev 9600) @@ -25,11 +25,8 @@ import unicodedata import sys -# this class isn't very well suited to being a mix-in like the classes in -# wx_model_viewer; however, it's a nicely contained stand-alone program, -# so I added the class map_viewer_mixin further down for use in combination -# with the model/selection viewer mixins. when this file is run directly -# it will still use the map_view class as before. --nat 2009-02-01 +# standalone class. see wx_combined_viewer for something that incorporates +# models. --nat 13-08-2009 class map_view(wx_viewer.wxGLWindow): @@ -218,219 +215,6 @@ pass ######################################################################## -# MIXIN FOR MAPS -# -# this is combined with a subclass of wx_model_viewer.selection_viewer_mixin -# to display the refinement status in phenix.refine -# TODO: replace map list and associated lists with dict -class map_viewer_mixin (wx_viewer.wxGLWindow) : - initialize_map_viewer_super = True - def __init__ (self, *args, **kwds) : - if self.initialize_map_viewer_super : - wx_viewer.wxGLWindow.__init__(self, *args, **kwds) - # various data objects - self.unit_cell = None - self.orthogonaliser = None - self.maps = [] - self.iso_levels = [] - self.map_colors = [] - self.materials = [] - self.triangles = [] - self._triangle_tmp = [] - # user settings - self.mesh_line_width = 0.25 # very buggy on OS X + NVidia (and ???) - self.map_radius = 10.0 - self.buffer_factor = 2 # what does this even do? - # flags - self.flag_show_maps = True - self.flag_use_materials = False - self.flag_show_rotation_center = True - # maps look much better when OpenGL materials are used, but this screws - # up the model rendering so it's off by default - self.minimum_covering_sphere = minimum_covering_sphere( - flex.vec3_double([[0,0,0],[100,100,100],[100,0,0],[0,100,100]])) - - def InitGL (self) : - glClearColor(self.r_back, self.g_back, self.b_back, 0.0) - gltbx.util.rescale_normals(fallback_to_normalize=True).enable() - glEnable(GL_DEPTH_TEST) - glShadeModel(GL_SMOOTH) - vendor = glGetString(GL_VENDOR) - if sys.platform == "darwin" and vendor.startswith("NVIDIA") : - glDisable(GL_LINE_SMOOTH) - else : - glEnable(GL_LINE_SMOOTH) - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) - glEnableClientState(GL_VERTEX_ARRAY) - glEnableClientState(GL_NORMAL_ARRAY) - self.initialize_modelview() - - def DrawGL (self) : - if self.unit_cell is None or self.orthogonaliser is None : - return - if self.flag_show_maps : - self.draw_maps() - if self.flag_show_rotation_center : - self.draw_rotation_center() - - def OnTranslate (self, event) : - wx_viewer.wxGLWindow.OnTranslate(self, event) - self.update_map_objects() - - def draw_rotation_center(self): - font = gltbx.fonts.ucs_bitmap_10x20 - font.setup_call_lists() - glColor3f(0, 1.0, 0) - glRasterPos3f(*self.rotation_center) - font.render_string("+") - return - glMatrixMode(GL_MODELVIEW) - glPushMatrix() - rc = self.rotation_center - (x,y,z) = (rc[0], rc[1], rc[2]) - glTranslatef(x,y,z) - #glScalef(a, b, c) - glBegin(GL_LINES) - f = 0.5 - glColor3f(0, 1.0, 0) - glVertex3f(-f, 0, 0) - glVertex3f(f, 0 ,0) - glVertex3f(0, -f, 0) - glVertex3f(0, f, 0) - glVertex3f(0, 0, -f) - glVertex3f(0, 0, f) - glEnd() - glPopMatrix() - - def setup_fog (self) : - if self.flag_show_fog : - near, far = self.get_clipping_distances() - # TODO: this needs work. - fog_start = 0.25*(far - near) + near + self.fog_start_offset - fog_end = self.far - self.fog_end_offset - glMatrixMode(GL_MODELVIEW) - glEnable(GL_FOG) - glFogi(GL_FOG_MODE, GL_LINEAR) - glFogf(GL_FOG_START, fog_start) - glFogf(GL_FOG_END, fog_end) - glFogfv(GL_FOG_COLOR, [self.r_back, self.g_back, self.b_back, 1.0]) - else : - glDisable(GL_FOG) - - def OnMouseWheel (self, event) : - scale = event.GetWheelRotation() - if event.ShiftDown() : - self.fog_end_offset -= scale - else : - self.clip_far -= scale - - def process_key_stroke (self, key) : - if key == wx.WXK_UP : - self.fog_start_offset += 1 - self.OnRedrawGL() - elif key == wx.WXK_DOWN : - self.fog_start_offset -= 1 - self.OnRedrawGL() - elif key == wx.WXK_LEFT : - self.fog_end_offset -= 1 - self.OnRedrawGL() - elif key == wx.WXK_RIGHT : - self.fog_end_offset += 1 - self.OnRedrawGL() - - def initialize_unit_cell (self, map) : - self.unit_cell = map.unit_cell() - o = self.unit_cell.orthogonalization_matrix() - self.orthogonaliser = ( o[0:3] + (0,) - + o[3:6] + (0,) - + o[6:9] + (0,) - + (0,0,0,1) ) - p = self.unit_cell.orthogonalize((0,0,0)) - q = self.unit_cell.orthogonalize((1,1,1)) - r = self.unit_cell.orthogonalize((1, 0, 0)) - s = self.unit_cell.orthogonalize((0, 1, 1)) - self.minimum_covering_sphere = minimum_covering_sphere( - flex.vec3_double([p,q,r,s])) - - def update_map_objects (self, redraw=True) : - self.compute_triangulation() - # this is done to prevent thread clashes (+ ensuing crashes) - self.triangles = self._triangle_tmp - if redraw : - self.OnRedraw() - - def set_iso_levels (self, levels) : - assert len(levels) == len(self.maps) - for i, map_contour_level in enumerate(levels) : - self.iso_levels[i] = map_contour_level - - def set_map_colors (self, colors) : - assert len(colors) == len(self.maps) - for i, map_color in enumerate(colors) : - self.map_colors[i] = map_color - self.materials[i] = gltbx.gl_managed.material_model( - front_colour=map_color, - back_colour=map_color) - - def set_maps (self, maps, reset_unit_cell=False) : - assert len(maps) != 0 - self.maps = maps - if (len(self.iso_levels) != len(maps) or - len(self.map_colors) != len(maps)) : - self.iso_levels = [ 1.0 for m in maps ] - self.map_colors = [ (1., 1., 1.) for m in maps ] - self.materials = [ None for m in maps ] - if self.unit_cell is None or reset_unit_cell : - self.initialize_unit_cell(self.maps[0]) - - def compute_triangulation (self) : - if len(self.maps) == 0 : - return - self._triangle_tmp = [] - r = self.map_radius - c = self.rotation_center # set in wxGLWindow (default is origin) - min = [ c[x] - float(r) for x in [0, 1, 2] ] - max = [ c[x] + float(r) for x in [0, 1, 2] ] - map_boundaries_cart = flex.vec3_double([min,max]) - bounds = self.unit_cell.fractionalize(sites_cart=map_boundaries_cart) - for i, raw_map in enumerate(self.maps) : - rho = raw_map.real_map() - iso_level = self.iso_levels[i] - triangulation = iso_surface.triangulation(rho, - iso_level, - map_extent=(1,1,1), - from_here=bounds[0], - to_there=bounds[1], - periodic=True, - ascending_normal_direction=False - ) - self._triangle_tmp.append(triangulation) - - def draw_maps (self) : - glMatrixMode(GL_MODELVIEW) - glPushMatrix() - glMultTransposeMatrixd(self.orthogonaliser) - gltbx.util.handle_error() - if self.flag_use_materials : - glLightfv(GL_LIGHT0, GL_AMBIENT, [0., 0., 0., 1.]) - for i, triangulation in enumerate(self.triangles) : - glLineWidth(0.2) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) - if self.flag_use_materials : - self.materials[i].execute(specular=False) - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) - else : - glColor3f(*self.map_colors[i]) - if self.flag_use_lights : - glDisable(GL_LIGHTING) - glDisable(GL_LIGHT0) - glDisable(GL_BLEND) - va = gltbx.util.vertex_array(triangulation.vertices, - triangulation.normals) - va.draw_triangles(triangulation.triangles) - glPopMatrix() - -######################################################################## # CLASSES AND METHODS FOR RUNNING map_view # class App(wx_viewer.App): Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-08-13 22:56:35 UTC (rev 9599) +++ trunk/crys3d/wx_model_viewer.py 2009-08-14 00:05:33 UTC (rev 9600) @@ -1,4 +1,6 @@ +# XXX: deprecated! + from string import strip from libtbx.utils import Sorry import gltbx.util Modified: trunk/crys3d/wx_model_viewer_example.py =================================================================== --- trunk/crys3d/wx_model_viewer_example.py 2009-08-13 22:56:35 UTC (rev 9599) +++ trunk/crys3d/wx_model_viewer_example.py 2009-08-14 00:05:33 UTC (rev 9600) @@ -1,7 +1,6 @@ import sys, os import cStringIO -from crys3d.wx_model_viewer_multi_scene import model_viewer_mixin from crys3d.wx_selection_editor import selection_editor_mixin from mmtbx.monomer_library import pdb_interpretation import iotbx.pdb Modified: trunk/crys3d/wx_model_viewer_multi_scene.py =================================================================== --- trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-13 22:56:35 UTC (rev 9599) +++ trunk/crys3d/wx_model_viewer_multi_scene.py 2009-08-14 00:05:33 UTC (rev 9600) @@ -870,6 +870,13 @@ model.set_color_mode(color_mode) self.update_scene = True + def set_model_base_color (self, color, object_id=None) : + assert len(color) == 3 + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.set_base_color(color) + self.update_scene = True + def toggle_ellipsoids (self, show_ellipsoids, object_id=None) : for model_id, model in self.iter_models() : if object_id is None or object_id == model_id : This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-08-14 21:51:51
|
Revision: 9603 http://cctbx.svn.sourceforge.net/cctbx/?rev=9603&view=rev Author: natechols Date: 2009-08-14 21:51:37 +0000 (Fri, 14 Aug 2009) Log Message: ----------- more changes for phenix gui; replaced old wx_model_viewer.py with new multi-scene version Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer.py trunk/crys3d/wx_selection_editor.py Removed Paths: ------------- trunk/crys3d/wx_model_viewer_multi_scene.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-08-14 17:46:01 UTC (rev 9602) +++ trunk/crys3d/wx_combined_viewer.py 2009-08-14 21:51:37 UTC (rev 9603) @@ -240,9 +240,9 @@ fft_map.apply_sigma_scaling() self.update_map(map_id, fft_map) - def hide_others (self, object_id=None) : - for map_id in self.model_ids : - if map_id != object_id : + def hide_maps (self, object_id=None) : + for map_id in self.map_ids : + if object_id is None or map_id == object_id : self.show_object[map_id] = False def iter_maps (self) : @@ -315,8 +315,22 @@ self.update_maps = True selection_editor_mixin.recenter_on_atom(self, *args, **kwds) - def hide_others (self, *args, **kwds) : - selection_editor_mixin.hide_others(self, *args, **kwds) - map_viewer_mixin.hide_others(self, *args, **kwds) + def hide_all (self, *args, **kwds) : + self.hide_models(*args, **kwds) + self.hide_maps(*args, **kwds) + def hide_others (self, object_id=None) : + if object_id is None : + self.hide_models() + self.hide_maps() + else : + for current_object_id in self.model_ids+self.map_ids : + if current_object_id != object_id : + self.show_object[current_object_id] = False + + def toggle_visibility (self, show_object, object_id=None) : + for current_object_id in self.model_ids+self.map_ids : + if current_object_id == object_id : + self.show_object[current_object_id] = show_object + #---end Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-08-14 17:46:01 UTC (rev 9602) +++ trunk/crys3d/wx_model_viewer.py 2009-08-14 21:51:37 UTC (rev 9603) @@ -1,226 +1,534 @@ -# XXX: deprecated! +# XXX: To keep these classes as clean as possible, selections are handled +# entirely in wx_selection_editor.py. +# TODO: hide nonbonded point for any atom that has an ellipsoid drawn -from string import strip -from libtbx.utils import Sorry +import iotbx.phil +from cctbx import uctbx import gltbx.util from gltbx import wx_viewer, viewer_utils, quadrics from gltbx.gl import * from gltbx.glu import * +import gltbx from scitbx.array_family import flex, shared from scitbx.math import minimum_covering_sphere -from mmtbx.monomer_library import pdb_interpretation -from cctbx import uctbx +from libtbx.introspection import method_debug_log +from libtbx.utils import Sorry +from libtbx import adopt_init_args import wx -import sys +import sys, os -######################################################################## -# BASE CLASS FOR DISPLAYING STRUCTURES -# -class model_viewer_base (wx_viewer.wxGLWindow) : - initialize_model_viewer_super = True - def __init__ (self, *args, **kwds) : - if self.initialize_model_viewer_super : - wx_viewer.wxGLWindow.__init__(self, *args, **kwds) - self.atomic_bonds = None # from geometry restraints manager - self.bonds = shared.stl_set_unsigned() - self.points = flex.vec3_double() # basic 3d data - self.atom_index = [] # stores atoms_with_labels data - self.atoms_visible = flex.bool() - self.points_visible = flex.bool() - self.bonds_visible = flex.bool() - self.spheres_visible = flex.bool() - self.atom_radii = flex.double() - self.current_atom_i_seq = None - self.closest_point_i_seq = None # usually set by mouse clicks - self.minimum_covering_sphere = None - self.points_display_list = None - self.lines_display_list = None - self.spheres_display_list = None - # various settings; override these in subclasses and/or provide - # a mechanism for changing their values - self.buffer_factor = 2 - self.line_width = 2 - self.nonbonded_line_width = 2 - self.base_atom_color = (0.6, 0.6, 0.6) # grey - self.atom_colors = flex.vec3_double() - self.orthographic = False - # toggles for viewable objects - self.flag_show_fog = True - self.flag_show_lines = True - self.flag_show_points = True - self.flag_show_spheres = False - self.flag_show_ellipsoids = False - self.flag_use_lights = True +debug = method_debug_log() - def InitGL(self): - gltbx.util.handle_error() - glClearColor(self.r_back, self.g_back, self.b_back, 0.0) - self.minimum_covering_sphere_display_list = None - glDepthFunc(GL_LESS) - glEnable(GL_ALPHA_TEST) - glEnable(GL_DEPTH_TEST) - glEnable(GL_BLEND) - vendor = glGetString(GL_VENDOR) - if sys.platform == "darwin" and vendor.startswith("NVIDIA") : - glDisable(GL_LINE_SMOOTH) - else : - glEnable(GL_LINE_SMOOTH) - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) - self.initialize_modelview() - gltbx.util.handle_error() +opengl_phil = iotbx.phil.parse(""" +opengl { + line_width = 2 + .type = int + .style = spinner min:1 max:10 + nonbonded_line_width = 2 + .type = int + .style = spinner min:1 max:10 + map_radius = 10 + .type = int + .style = spinner min:1 max:40 + base_atom_color = 1.0 1.0 0.0 + .type = floats + .style = color + background_color = 0.0 0.0 0.0 + .type = floats + .style = color + default_coloring = *rainbow element b chain + .type = choice + default_representation = *all_atoms trace bonded_only + .type = choice + show_hydrogens = False + .type = bool + label_clicked_atom = True + .type = bool + use_atom_color_for_labels = True + .type = bool + use_fog = True + .type = bool + orthographic = False + .type = bool + .style = noauto + animate_zoom = False + .type = bool +} +""") - def initialize_modelview (self) : - if self.minimum_covering_sphere is not None : - wx_viewer.wxGLWindow.initialize_modelview(self) +#----------------------------------------------------------------------- +# XXX: None of the data in this class is used directly in OpenGL calls; +# instead, the model_scene object contains the subset of information +# required for immediate display. +class model_data (object) : + def __init__ (self, object_id, pdb_hierarchy, atomic_bonds, + base_color=(0.0,1.0,1.0)) : + self.object_id = object_id + self.base_color = base_color + self.draw_mode = None + self.current_bonds = None + self.color_mode = None #"rainbow" + self.flag_object_visible = True + self._color_cache = {} + self.flag_show_hydrogens = False + self.flag_show_lines = True + self.flag_show_labels = True + self.flag_show_points = True + self.flag_show_spheres = False + self.flag_show_ellipsoids = False + self.update_structure(pdb_hierarchy, atomic_bonds) + self.use_u_aniso = flex.bool(self.atoms.size()) + #self.recalculate_visibility() + + def reset (self) : + self.is_changed = False + + @debug + def get_scene_data (self) : + return model_scene(bonds=self.current_bonds, + points=self.atoms.extract_xyz(), + b_iso=self.atoms.extract_b(), + b_aniso=self.atoms.extract_uij(), + atom_colors=self.atom_colors, + atom_labels=self.atom_labels, + atom_radii=self.atom_radii, + visibility=self.visibility) + + def update_scene_data (self, scene) : + scene.update_bonds(self.current_bonds) + scene.update_colors(self.atom_colors) + scene.update_visibility(self.visibility) + scene.clear_lists() + + @debug + def update_xyz (self, xyz) : + assert xyz.size() == self.atoms.size() + for i_seq, atom in enumerate(self.atoms) : + atom.xyz = xyz[i_seq] + self.is_changed = True + + @debug + def update_u_iso (self, u_iso) : + assert u_iso.size() == self.atoms.size() + for i_seq, atom in enumerate(self.atoms) : + atom.b = adptbx.u_as_b(u_iso[i_seq]) + self.is_changed = True + + @debug + def update_u_aniso (self, u_aniso, aniso_flag=None) : + assert u_aniso.size() == self.atoms.size() + for i_seq, atom in enumerate(self.atoms) : + atom.uij = u_aniso[i_seq] + self.is_changed = True + + @debug + def update_from_xray_structure (self, xray_structure) : + sites_cart = xray_structure.sites_cart() + u_iso = xray_structure.extract_u_iso_or_u_equiv() + u_aniso = xray_structure.extract_u_cart_plus_u_iso() + occ = xray_structure.scatterers().extract_occupancies() + assert sites_cart.size() == self.atoms.size() + for i_seq, atom in enumerate(self.atoms) : + atom.xyz = sites_cart[i_seq] + atom.occ = occ[i_seq] + atom.b = adptbx.u_as_b(u_iso[i_seq]) + atom.uij = u_aniso[i_seq] + self.use_u_aniso = xray_structure.use_u_aniso() + self._color_cache["b"] = None + self.is_changed = True + + @debug + def update_structure (self, pdb_hierarchy, atomic_bonds) : + self.pdb_hierarchy = pdb_hierarchy + self.atoms = pdb_hierarchy.atoms() + self.atom_count = self.atoms.size() + if atomic_bonds is None : + atomic_bonds = flex.stl_set_unsigned(self.atom_count) + self.atomic_bonds = atomic_bonds + self.selection_cache = pdb_hierarchy.atom_selection_cache() + #self.index_atoms() + atom_index = [] + atom_labels = flex.std_string() + for atom in self.pdb_hierarchy.atoms_with_labels() : + atom_index.append(atom) + atom_labels.append(format_atom_label(atom)) + self.atom_index = atom_index + self.atom_labels = atom_labels + self.trace_bonds = extract_trace(pdb_hierarchy) #, self.selection_cache) + if self.current_bonds is None : + self.current_bonds = self.atomic_bonds + atom_radii = flex.double(self.atoms.size(), 1.5) + hydrogen_flag = flex.bool(self.atoms.size(), False) + for i_seq, atom in enumerate(self.atom_index) : + name = atom.name.strip() + if name[0] == 'H' : + atom_radii[i_seq] = 0.75 + hydrogen_flag[i_seq] = True + self.atom_radii = atom_radii + self.hydrogen_flag = hydrogen_flag + self._color_cache = {} + self.is_changed = True + + @debug + def recalculate_visibility (self) : + c = 0 + if self.draw_mode == "spheres" : + show_points = True else : - self.setup_lighting() + show_points = self.flag_show_points + if self.flag_show_hydrogens : + atoms_drawable = flex.bool(self.atom_count, True) + else : + atoms_drawable = self.hydrogen_flag.__invert__() + #atoms_drawable = flex.bool([ (atom.element != ' H') for atom in atoms ]) + self.visibility = viewer_utils.atom_visibility( + bonds = self.current_bonds, + atoms_drawable = atoms_drawable, + flag_show_points = show_points + ) + self.visible_atom_count = self.visibility.visible_atoms_count - def DrawGL(self): - if self.GL_uninitialised or self.points.size() == 0 : - return - if (self.flag_show_points): - self.draw_points() - if (self.flag_show_lines): - self.draw_lines() - if (self.flag_show_spheres): - self.draw_spheres() - if self.flag_show_ellipsoids : - self.draw_ellipsoids() + def refresh (self) : + self.is_changed = True + self._color_cache = {} + self.set_draw_mode(self.draw_mode) + self.is_changed = False - def OnRedrawGL (self, event=None) : - if self.minimum_covering_sphere is None : - gltbx.util.handle_error() - glClear(GL_COLOR_BUFFER_BIT) - glClear(GL_DEPTH_BUFFER_BIT) - glFlush() - self.SwapBuffers() - gltbx.util.handle_error() + def toggle_hydrogens (self, show_hydrogens) : + self.flag_show_hydrogens = show_hydrogens + self.refresh() + + def toggle_ellipsoids (self, show_ellipsoids) : + self.flag_show_ellipsoids = show_ellipsoids + + def set_draw_mode (self, draw_mode, color_mode=None) : + if draw_mode == self.draw_mode and not self.is_changed : + pass else : - wx_viewer.wxGLWindow.OnRedrawGL(self, event) + self.draw_mode = draw_mode + show_points = True + if draw_mode == "spheres" : + self.flag_show_spheres = True + else : + if draw_mode in ["trace", "trace_and_nb"] : + self.current_bonds = self.trace_bonds + else : + self.current_bonds = self.atomic_bonds + if draw_mode in ["trace", "bonded_only"] : + self.flag_show_points = False + else : + self.flag_show_points = True + self.recalculate_visibility() + if color_mode is not None : + self.color_mode = color_mode + self.set_color_mode(self.color_mode) # force re-coloring - def unzoom (self, event=None) : - if self.points is not None : - self.minimum_covering_sphere = minimum_covering_sphere( - points=self.points, - epsilon=0.1) - self.move_rotation_center_to_mcs_center() - self.fit_into_viewport() + #--------------------------------------------------------------------- + # XXX: COLORING + # + def set_base_color (self, color) : + self.base_color = color - def recenter_on_atom (self, i_seq) : - if self.points is not None and i_seq < self.points.size() : - self.rotation_center = self.points[i_seq] - self.move_to_center_of_viewport(self.rotation_center) + def set_color_mode (self, color_mode) : + if color_mode == self.color_mode and not self.is_changed : + pass + else : + self.color_mode = color_mode + if color_mode == "mono" : + self.color_mono() + elif color_mode == "rainbow" : + self.color_rainbow() + elif color_mode == "b" : + self.color_b() + elif color_mode == "chain" : + self.color_by_chain() + elif color_mode == "element" : + self.color_by_element() - def set_selected_atom (self, closest_point_i_seq) : - self.current_atom_i_seq = closest_point_i_seq + @debug + def color_mono (self) : + cached = self._color_cache.get("mono") + if cached is not None : + self.atom_colors = cached + else : + self.atom_colors = flex.vec3_double( + [ self.base_color for i in xrange(0, self.atoms.size()) ] + ) + self._color_cache["mono"] = self.atom_colors - def process_key_stroke (self, key) : - if key == ord('u') : - self.unzoom() + @debug + def color_rainbow (self) : + cached = self._color_cache.get("rainbow") + if cached is not None : + self.atom_colors = cached + else : + self.atom_colors = viewer_utils.color_rainbow( + atoms_visible = self.visibility.atoms_visible, + visible_atom_count = self.visible_atom_count + ) + self._color_cache["rainbow"] = self.atom_colors - def process_pick_points(self): - if self.pick_points is not None : - self.closest_point_i_seq = viewer_utils.closest_visible_point( - points = self.points, - atoms_visible = self.atoms_visible, - point0 = self.pick_points[0], - point1 = self.pick_points[1] + @debug + def color_b (self) : + cached = self._color_cache.get("b") + if cached is not None : + self.atom_colors = cached + else : + self.atom_colors = viewer_utils.color_by_property( + atom_properties = self.atoms.extract_b(), + atoms_visible = self.visibility.atoms_visible, + color_invisible_atoms = False, + use_rb_color_gradient = False ) + self._color_cache["b"] = self.atom_colors - def update_view (self, redraw_points=True, redraw_lines=True) : - if redraw_lines : - self.lines_display_list = None - if redraw_points : - self.points_display_list = None + @debug + def color_by_chain (self) : + cached = self._color_cache.get("chain") + if cached is not None : + self.atom_colors = cached + else : + c = 0 + for chain in self.pdb_hierarchy.chains() : + c += 1 + rainbow = viewer_utils.make_rainbow_gradient(c) + j = 0 + chain_shades = {} + for chain in self.pdb_hierarchy.chains() : + chain_shades[chain.id] = rainbow[j] + atom_colors = flex.vec3_double() + for atom in self.pdb_hierarchy.atoms_with_labels() : + atom_colors.append(chain_shades[atom.chain_id]) + self.atom_colors = atom_colors + self._color_cache["chain"] = atom_colors + + @debug + def color_by_element (self) : + cached = self._color_cache.get("element") + if cached is not None : + self.atom_colors = cached + else : + # these are approximations based on my (probably faulty) memory. + # feel free to change to something more reasonable. + element_shades = {' C' : self.base_color, # usually yellow or grey + ' H' : (0.95, 0.95, 0.95), # very light grey + ' N' : (0.0, 0.0, 1.0), # blue + ' O' : (1.0, 0.0, 0.0), # red + ' S' : (1.0, 0.5, 0.0), # orange + ' P' : (1.0, 1.0, 0.0), # yellow + 'Se' : (0.0, 1.0, 0.0), # green + 'Mg' : (0.7, 0.7, 0.9), # very pale blue + 'Fe' : (0.8, 0.2, 0.0), # rust + 'Cl' : (0.8, 1.0, 0.2), # yellow-green + 'Na' : (0.7, 0.7, 0.7), # light grey + 'Ca' : (1.0, 1.0, 1.0), # white + 'Mn' : (1.0, 0.6, 0.8), # lavender + 'Zn' : (0.8, 0.9, 1.0), # very pale cyan + 'Ni' : (0.0, 0.8, 0.4), # teal + 'Cu' : (0.0, 0.8, 0.7), # blue-green + 'Co' : (0.0, 0.5, 0.6) } # marine + atom_colors = flex.vec3_double() + for atom in self.pdb_hierarchy.atoms_with_labels() : + color = element_shades.get(atom.element) + if color is None : + color = (0.0, 1.0, 1.0) + atom_colors.append(color) + self.atom_colors = atom_colors + self._color_cache["element"] = cached + +#----------------------------------------------------------------------- +# XXX: this class contains only the information needed for OpenGL commands, +# which are also implemented as methods here. +class model_scene (object) : + def __init__ (self, bonds, points, b_iso, b_aniso, atom_colors, atom_labels, + atom_radii, visibility) : + adopt_init_args(self, locals()) + self.clear_lists() + self.clear_labels() + self.update_visibility(visibility) + + @debug + def clear_lists (self) : + self.points_display_list = None + self.lines_display_list = None self.spheres_display_list = None - self.OnRedraw() + self.ellipsoid_display_list = None + self.selection_display_list = None + self.labels_display_list = None - def OnUpdate (self, event=None, recenter=False) : - self.update_view(True, True) - if (event is not None and hasattr(event, "recenter") and - event.recenter == True) or recenter == True : - self.move_rotation_center_to_mcs_center() - self.fit_into_viewport() + @debug + def clear_labels (self) : + self.show_labels = flex.bool(self.points.size(), False) + self.labels_display_list = None - def draw_lines (self) : - pass + @debug + def add_label (self, i_seq) : + self.show_labels[i_seq] = True + self.labels_display_list = None + @debug + def update_colors (self, atom_colors) : + assert atom_colors.size() == self.points.size() + self.atom_colors = atom_colors + + @debug + def update_bonds (self, bonds) : + assert bonds.size() == self.points.size() + self.bonds = bonds + + @debug + def update_visibility (self, visibility) : + assert visibility.atoms_visible.size() == self.points.size() + self.atoms_visible = visibility.atoms_visible + self.bonds_visible = visibility.bonds_visible + self.points_visible = visibility.points_visible + self.spheres_visible = self.atoms_visible # XXX: what to do here? + self.visible_atom_count = visibility.visible_atoms_count + self.clear_lists() + def draw_points (self) : - assert self.points_visible.size() == self.points.size() - assert self.atom_colors.size() == self.points.size() - glDisable(GL_LIGHTING) if self.points_display_list is None : self.points_display_list = gltbx.gl_managed.display_list() self.points_display_list.compile() - glLineWidth(self.nonbonded_line_width) viewer_utils.draw_points( points = self.points, atom_colors = self.atom_colors, - points_visible = self.points_visible - ) + points_visible = self.points_visible) self.points_display_list.end() self.points_display_list.call() - def draw_spheres (self) : - pass + def draw_lines (self) : + if self.lines_display_list is None : + self.lines_display_list = gltbx.gl_managed.display_list() + self.lines_display_list.compile() + viewer_utils.draw_bonds( + points = self.points, + bonds = self.bonds, + atom_colors = self.atom_colors, + bonds_visible = self.bonds_visible) + self.lines_display_list.end() + self.lines_display_list.call() - def draw_ellipsoids (self) : - pass - - def _draw_spheres(self, points, spheres_visible, atom_colors, atom_radii) : - glMatrixMode(GL_MODELVIEW) - if self.flag_use_lights : - glEnable(GL_LIGHTING) - glEnable(GL_LIGHT0) - glEnable(GL_LIGHT1) - glEnable(GL_NORMALIZE) - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [1.0,1.0,1.0,1.0]) - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.1, 0.1, 0.1, 1.0]) - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [0.1, 0.1, 0.1, 1.0]) + def draw_spheres (self, scale_factor=1.0) : if self.spheres_display_list is None : self.spheres_display_list = gltbx.gl_managed.display_list() self.spheres_display_list.compile() glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) - for i_seq, point in enumerate(points) : + atom_radii = self.atom_radii + atom_colors = self.atom_colors + spheres_visible = self.spheres_visible + for i_seq, point in enumerate(self.points) : if spheres_visible[i_seq] : - #glColor3f(*atom_colors[i_seq]) + glColor3f(*atom_colors[i_seq]) glPushMatrix() glTranslated(*point) - gltbx.util.SolidSphere(radius=atom_radii[i_seq], slices=50, stacks=50) + gltbx.util.SolidSphere(radius=atom_radii[i_seq] * scale_factor, + slices=50, stacks=50) glPopMatrix() self.spheres_display_list.end() self.spheres_display_list.call() -class model_viewer_mixin (model_viewer_base) : + def draw_ellipsoids (self, proto_ellipsoid) : + if self.ellipsoid_display_list is None : + self.ellipsoid_display_list = gltbx.gl_managed.display_list() + self.ellipsoid_display_list.compile() + points = self.points + atoms_visible = self.atoms_visible + atom_colors = self.atom_colors + for i_seq, uij in enumerate(self.b_aniso) : + if atoms_visible[i_seq] and uij[0] != -1 : + col = list(atom_colors[i_seq]) + [1.0] + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.1, 0.1, 0.1, 1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [0.1, 0.1, 0.1, 1.0]) + proto_ellipsoid.draw(points[i_seq], uij) + self.ellipsoid_display_list.end() + self.ellipsoid_display_list.call() + + def draw_labels (self, font, use_atom_color=False) : + glDisable(GL_LIGHTING) + if (self.labels_display_list is None) : + self.labels_display_list = gltbx.gl_managed.display_list() + self.labels_display_list.compile() + points = self.points + atoms_visible = self.atoms_visible + atom_colors = self.atom_colors + atom_labels = self.atom_labels + for i_seq, show_label in enumerate(self.show_labels) : + if atoms_visible[i_seq] and show_label : + if use_atom_color : + glColor3f(*atom_colors[i_seq]) + glRasterPos3f(*points[i_seq]) + font.render_string(atom_labels[i_seq]) + self.labels_display_list.end() + self.labels_display_list.call() + +######################################################################## +# VIEWER CLASS +# +UPDATE_MODEL_ID = wx.NewId() +ADD_MODEL_ID = wx.NewId() +class AddModelEvent (wx.PyEvent) : + event_id = ADD_MODEL_ID + recenter = True + def __init__ (self, model_id, pdb_hierarchy, atomic_bonds) : + wx.PyEvent.__init__(self) + self.data = (model_id, pdb_hierarchy, atomic_bonds) + self.SetEventType(self.event_id) + +class UpdateModelEvent (AddModelEvent) : + event_id = UPDATE_MODEL_ID + recenter = False + +class model_viewer_mixin (wx_viewer.wxGLWindow) : def __init__ (self, *args, **kwds) : - model_viewer_base.__init__(self, *args, **kwds) - self.pdb_hierarchy = None - self.selection_cache = None # this is used by extract_trace - self.processed_pdb_file = None - self.atoms = None - self.atom_count = 0 - self.b_cache = None # atoms.extract_b() - self.uij_cache = None - # various settings; override these in subclasses and/or provide - # a mechanism for changing their values - self.draw_mode = "all_atoms" - self.color_mode = "b_factors" - self.recolor = self.color_b - self.scale_b_to_visible = True - self.carbon_atom_color = (1.0, 1.0, 0.0) # yellow - self.ellipsoid_display_list = None - #self.proto_ellipsoid = quadrics.proto_ellipsoid(slices=32, stacks=32) + wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.Connect(-1, -1, UPDATE_MODEL_ID, self.OnUpdateModel) + self.Connect(-1, -1, ADD_MODEL_ID, self.OnAddModel) + self.minimum_covering_sphere = None + self.show_object = {} + self.pick_object = {} + self.model_objects = [] + self.model_ids = [] + self.scene_objects = {} + self.model_colors = {} + self.model_reps = {} + self.update_scene = False + self.buffer_factor = 2 # see gltbx.wx_viewer + self.sphere_scale_factor = 1.0 + self.update_settings(opengl_phil.extract()) + self.closest_point_i_seq = None + self.closest_point_model_id = None # toggles for viewable objects + self.flag_show_fog = True + self.flag_show_lines = True + self.flag_show_points = True + self.flag_show_spheres = True + self.flag_use_lights = True + self.flag_show_labels = True self.flag_show_trace = False self.flag_show_hydrogens = False - self.flag_show_ellipsoids = False + self.flag_show_ellipsoids = True + self.flag_smooth_lines = True + self.flag_recenter_on_click = False - def setup_lighting (self) : - model_viewer_base.setup_lighting(self) - - def InitGL (self) : - model_viewer_base.InitGL(self) + @debug + def InitGL(self): + gltbx.util.handle_error() + glClearColor(self.r_back, self.g_back, self.b_back, 0.0) + self.minimum_covering_sphere_display_list = None + glDepthFunc(GL_LESS) + glEnable(GL_ALPHA_TEST) + glEnable(GL_DEPTH_TEST) + glEnable(GL_BLEND) + # XXX: line smoothing is pretty essential for wireframe representation; + # the problem with nvidia cards is really only a problem for the isomesh + # in wx_map_viewer.py. + glEnable(GL_LINE_SMOOTH) + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) + self.initialize_modelview() if self.flag_use_lights : glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [0.5, 0.5, 0.5, 1.0]) @@ -229,255 +537,79 @@ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) self.proto_ellipsoid = quadrics.proto_ellipsoid(slices=32, stacks=32) + gltbx.util.handle_error() - def update_view (self, redraw_points=True, redraw_lines=True) : - self.get_drawn_atom_count() - self.recolor() - self.ellipsoid_display_list = None - model_viewer_base.update_view(self, redraw_points, redraw_lines) - - def OnUpdate (self, event=None, recenter=False) : - if self._structure_was_updated : - self.extract_atom_data() - self.extract_trace() + @debug + def initialize_modelview (self) : + if self.minimum_covering_sphere is not None : + wx_viewer.wxGLWindow.initialize_modelview(self) else : - self.update_coords() - self._structure_was_updated = False - model_viewer_base.OnUpdate(self, event, recenter) + self.setup_lighting() - def process_key_stroke (self, key) : - model_viewer_base.process_key_stroke(self, key) - update = False - if key == ord('h') : - self.flag_show_hydrogens = not self.flag_show_hydrogens - update = True - elif key == ord('e') : - self.flag_show_ellipsoids = not self.flag_show_ellipsoids - update = True - elif key == ord('p') : - self.flag_show_points = not self.flag_show_points - update = True - elif key == ord('b') : - if self.color_mode == "b_factors" : self.set_color_mode("element") - else : self.set_color_mode("b_factors") - update = True - if update : - self.update_view(True, True) - - # Hopefully none of the remaining functions need to be overridden... - - #--------------------------------------------------------------------- - # coordinates, bonds, etc. - def update_structure (self, pdb_hierarchy, atomic_bonds, - processed_pdb_file=None, redraw=False) : - self.pdb_hierarchy = pdb_hierarchy - self.atomic_bonds = atomic_bonds - self.extract_atom_data() - self.selection_cache = pdb_hierarchy.atom_selection_cache() - self.processed_pdb_file = processed_pdb_file - self.set_draw_mode(self.draw_mode, redraw=False) - self._structure_was_updated = True - if redraw : - self.OnUpdate(recenter=True) - - def extract_atom_data (self) : - self.update_atoms(self.pdb_hierarchy.atoms(), redraw=False) - self.atom_count = self.atoms.size() - self.update_coords() - atom_index = [] - for atom in self.pdb_hierarchy.atoms_with_labels() : - atom_index.append(atom) - self.atom_index = atom_index - assert len(self.atom_index) == self.atom_count - atom_radii = flex.double(self.points.size(), 1.5) - for i_seq, atom in enumerate(self.atom_index) : - if atom.element == ' H' : - atom_radii[i_seq] = 0.75 - self.atom_radii = atom_radii - - def OnUpdate (self, event=None, recenter=False) : - if self._structure_was_updated : - self.extract_atom_data() - self.extract_trace() + def OnRedrawGL (self, event=None) : + self.check_and_update_model_scenes() + if self.minimum_covering_sphere is None : + gltbx.util.handle_error() + glClear(GL_COLOR_BUFFER_BIT) + glClear(GL_DEPTH_BUFFER_BIT) + glFlush() + self.SwapBuffers() + gltbx.util.handle_error() else : - self.update_coords() - self._structure_was_updated = False - self.update_view(True, True) - if (recenter or - (event is not None and getattr(event, "recenter", None) == True)) : - self.move_rotation_center_to_mcs_center() - self.fit_into_viewport() + wx_viewer.wxGLWindow.OnRedrawGL(self, event) - def update_coords (self) : - self.points = self.atoms.extract_xyz() - self.b_cache = self.atoms.extract_b() - self.uij_cache = self.atoms.extract_uij() - self.lines_display_list = None - self.points_display_list = None - self.selection_display_list = None + def check_and_update_model_scenes (self) : + if self.update_scene : + self.update_scene_objects() + self.update_scene = False - def update_atoms (self, atoms, redraw=False) : - self.atoms = atoms - self.minimum_covering_sphere = minimum_covering_sphere(atoms.extract_xyz(), - epsilon=1.e-1) - if redraw : - self.OnUpdate() - - def extract_trace (self) : - last_atom = None - isel = self.selection_cache.iselection - selection_i_seqs = list( - isel("(name ' CA ' or name ' P ') and (altloc 'A' or altloc ' ')")) - last_atom = None - bonds = shared.stl_set_unsigned(self.atoms.size()) - atoms = self.pdb_hierarchy.atoms_with_labels() - for atom in atoms : - if atom.i_seq in selection_i_seqs : - if last_atom is not None : - if atom.chain_id == last_atom.chain_id and \ - atom.model_id == last_atom.model_id and \ - atom.resseq_as_int() == (last_atom.resseq_as_int() + 1) and \ - compare_conformers(atom.altloc, last_atom.altloc) == True : - bonds[last_atom.i_seq].append(atom.i_seq) - bonds[atom.i_seq].append(last_atom.i_seq) - last_atom = atom - self.trace_bonds = bonds - - def set_draw_mode (self, draw_mode, redraw=False) : - if not self.minimum_covering_sphere : + def DrawGL(self): + if self.GL_uninitialised or len(self.scene_objects) == 0 : return - self.draw_mode = draw_mode - if draw_mode == "trace" : - self.flag_show_points = False - self.bonds = self.trace_bonds - elif self.draw_mode == "bonded_only" : - self.flag_show_points = False - self.bonds = self.atomic_bonds - else : - self.flag_show_points = True - self.bonds = self.atomic_bonds - self.get_drawn_atom_count() - self.set_color_mode(self.color_mode, redraw=redraw) + if self.flag_show_points : + self.draw_points() + if self.flag_show_lines : + self.draw_lines() + if self.flag_show_spheres : + self.draw_spheres() + if self.flag_show_ellipsoids : + self.draw_ellipsoids() + if self.flag_show_labels : + self.draw_labels() - def get_drawn_atom_count (self) : - c = 0 - atoms = self.pdb_hierarchy.atoms_with_labels() - if self.flag_show_hydrogens : - atoms_drawable = flex.bool(self.atom_count, True) - else : - atoms_drawable = flex.bool([ (atom.element != ' H') for atom in atoms ]) - self.visibility = viewer_utils.atom_visibility( - bonds = self.bonds, - atoms_drawable = atoms_drawable, - flag_show_points = self.flag_show_points - ) - self.atoms_visible = self.visibility.atoms_visible - self.bonds_visible = self.visibility.bonds_visible - self.points_visible = self.visibility.points_visible - self.visible_atom_count = self.visibility.visible_atoms_count + def draw_points (self) : + glDisable(GL_LIGHTING) + glLineWidth(self.settings.opengl.nonbonded_line_width) + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_points : + self.scene_objects[model_id].draw_points() - #--------------------------------------------------------------------- - # coloring - def set_bg_color (self) : - (r,g,b) = self.bg_color - glClearColor(r, g, b, 0.0) + def draw_spheres (self) : + glMatrixMode(GL_MODELVIEW) + if self.flag_use_lights : + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glEnable(GL_LIGHT1) + glEnable(GL_NORMALIZE) + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [1.0,1.0,1.0,1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.1, 0.1, 0.1, 1.0]) + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [0.1, 0.1, 0.1, 1.0]) + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_spheres : + self.scene_objects[model_id].draw_spheres(self.sphere_scale_factor) - def set_color_mode (self, color_mode, redraw=False) : - self.color_mode = color_mode - if color_mode == "rainbow" : - self.recolor = self.color_rainbow - elif color_mode == "element" : - self.recolor = self.color_by_element - elif color_mode == "b_factors" : - self.recolor = self.color_b - elif color_mode == "chain" : - self.recolor = self.color_by_chain - elif color_mode == "single_color" : - self.recolor = self.color_mono - else : - pass - if redraw : - self.update_view(True, True) - - def color_mono (self) : - self.atom_colors = flex.vec3_double( - [ self.base_atom_color for i in xrange(0, self.points.size()) ] - ) - - def color_rainbow (self) : - self.atom_colors = viewer_utils.color_rainbow( - atoms_visible = self.atoms_visible, - visible_atom_count = self.visible_atom_count - ) - - def color_b (self) : - self.atom_colors = viewer_utils.color_by_property( - atom_properties = self.b_cache, - atoms_visible = self.atoms_visible, - color_invisible_atoms = not self.scale_b_to_visible, - use_rb_color_gradient = False - ) - - def color_by_chain (self) : - c = 0 - for chain in self.pdb_hierarchy.chains() : - c += 1 - rainbow = viewer_utils.make_rainbow_gradient(c) - j = 0 - chain_shades = {} - for chain in self.pdb_hierarchy.chains() : - chain_shades[chain.id] = rainbow[j] - atom_colors = flex.vec3_double() - for i_seq, atom_object in enumerate(self.atom_index) : - atom_colors.append(chain_shades[atom_object.chain_id]) - self.atom_colors = atom_colors - - def color_by_element (self) : - # these are approximations based on my (probably faulty) memory. - # feel free to change to something more reasonable. - element_shades = {' C' : self.carbon_atom_color, # usually yellow or grey - ' H' : (0.95, 0.95, 0.95), # very light grey - ' N' : (0.0, 0.0, 1.0), # blue - ' O' : (1.0, 0.0, 0.0), # red - ' S' : (1.0, 0.5, 0.0), # orange - ' P' : (1.0, 1.0, 0.0), # yellow - 'Se' : (0.0, 1.0, 0.0), # green - 'Mg' : (0.7, 0.7, 0.9), # very pale blue - 'Fe' : (0.8, 0.2, 0.0), # rust - 'Cl' : (0.8, 1.0, 0.2), # yellow-green - 'Na' : (0.7, 0.7, 0.7), # light grey - 'Ca' : (1.0, 1.0, 1.0), # white - 'Mn' : (1.0, 0.6, 0.8), # lavender - 'Zn' : (0.8, 0.9, 1.0), # very pale cyan - 'Ni' : (0.0, 0.8, 0.4), # teal - 'Cu' : (0.0, 0.8, 0.7), # blue-green - 'Co' : (0.0, 0.5, 0.6) } # marine - atom_colors = flex.vec3_double() - for i_seq, atom_object in enumerate(self.atom_index) : - element = atom_object.element - color = element_shades.get(element) - if color is None : - color = (0.0, 1.0, 1.0) - atom_colors.append(color) - self.atom_colors = atom_colors - def draw_lines (self) : - assert self.bonds_visible.size() == self.points.size() - assert self.atom_colors.size() == self.points.size() + glEnable(GL_LINE_SMOOTH) + #glDisable(GL_LINE_SMOOTH) + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glDisable(GL_LIGHTING) - if self.lines_display_list is None : - self.lines_display_list = gltbx.gl_managed.display_list() - self.lines_display_list.compile() - glLineWidth(self.line_width) - viewer_utils.draw_bonds( - points = self.points, - bonds = self.bonds, - atom_colors = self.atom_colors, - bonds_visible = self.bonds_visible) - self.lines_display_list.end() - self.lines_display_list.call() + glLineWidth(self.settings.opengl.line_width) + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_lines : + self.scene_objects[model_id].draw_lines() + if not self.flag_smooth_lines : + glDisable(GL_LINE_SMOOTH) - # XXX def draw_ellipsoids (self) : glMatrixMode(GL_MODELVIEW) if self.flag_use_lights : @@ -491,346 +623,345 @@ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [0.5, 0.5, 0.5, 1.0]) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) proto_ellipsoid = self.proto_ellipsoid - if self.ellipsoid_display_list is None : - self.ellipsoid_display_list = gltbx.gl_managed.display_list() - self.ellipsoid_display_list.compile() - points = self.points - atoms_visible = self.atoms_visible - atom_colors = self.atom_colors - for i_seq, uij in enumerate(self.uij_cache) : - if atoms_visible[i_seq] and uij[0] != -1 : - col = list(atom_colors[i_seq]) + [1.0] - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, col) - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [0.1, 0.1, 0.1, 1.0]) - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, [0.1, 0.1, 0.1, 1.0]) - proto_ellipsoid.draw(points[i_seq], uij) - self.ellipsoid_display_list.end() - self.ellipsoid_display_list.call() + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_ellipsoids : + self.scene_objects[model_id].draw_ellipsoids(proto_ellipsoid) -######################################################################## -# ATOM SELECTION VIEWER -# this will handle any valid atom selection recognized by cctbx. -# -class selection_viewer_mixin (model_viewer_mixin) : - initialize_model_viewer_super = True - def __init__ (self, *args, **kwds) : - model_viewer_mixin.__init__(self, *args, **kwds) - # objects used internally - self.selection_covering_sphere = None - self.selection_i_seqs = None - self.selection_cache = None - self.selected_points = [] - self.selection_display_list = None - self.selection_colors = None - self.atoms_selected = None - # various settings - self.selection_string = "None" - self.selection_color = (1.0, 1.0, 1.0) - self.selection_draw_mode = "bonds_and_atoms" - self.animation_time = 0.00001 - # flags - self.flag_show_selection = True - self.flag_recolor_selection = True + def draw_labels (self) : + glDisable(GL_LIGHTING) + use_atom_color = self.settings.opengl.use_atom_color_for_labels + if not use_atom_color : + print "using global label color" + glColor3f(1.0, 1.0, 1.0) + font = gltbx.fonts.ucs_bitmap_8x13 + font.setup_call_lists() + for model_id, model in self.iter_models() : + if self.show_object[model_id] and model.flag_show_labels : + self.scene_objects[model_id].draw_labels(font, use_atom_color) - def DrawGL (self) : - model_viewer_mixin.DrawGL(self) - if self.flag_show_selection : - self.draw_selection() + @debug + def refresh_bg_color (self) : + (r, g, b) = tuple(self.settings.opengl.background_color) + glClearColor(r, g, b, 0.0) - def process_key_stroke (self, key) : - model_viewer_mixin.process_key_stroke(self, key) - if key == ord('z') : - self.zoom_selection() + #--------------------------------------------------------------------- + # Non-OpenGL code below here + # + def update_settings (self, params, redraw=False) : + assert (len(params.opengl.base_atom_color) == + len(params.opengl.background_color) == 3) + self.settings = params + if params.opengl.animate_zoom : + self.animation_time = 1 + else : + self.animation_time = 0 + self.toggle_hydrogens(params.opengl.show_hydrogens) + if redraw : + self.update_scene = True - def update_view (self, redraw_points=True, redraw_lines=True) : - self.selection_display_list = None - model_viewer_mixin.update_view(self, redraw_points, redraw_lines) + def iter_models (self) : + for model_id, model_object in zip(self.model_ids, self.model_objects) : + yield (model_id, model_object) - def zoom_selection (self, event=None) : - self.set_selection_sphere() - if self.selection_covering_sphere is not None : - self.minimum_covering_sphere = self.selection_covering_sphere + def get_model (self, object_id) : + for model in self.model_objects : + if model.object_id == object_id : + return model + return None + + def get_model_state (self, object_id) : + model = self.get_model(object_id) + model_attr = dir(model) + state = {} + for name in model_attr : + if name.startswith("flag_") : + state_var = name[5:] #re.sub("flag_", "", name) + state[state_var] = getattr(model, name) + state["draw_mode"] = model.draw_mode + state["color_mode"] = model.color_mode + return state + + def set_model_state (self, object_id, model_state) : + model = self.get_model(object_id) + for name in model_state : + setattr(model, name, model_state[name]) + model.set_draw_mode(model_state["draw_mode"]) + #model.recalculate_visibility() + self.update_scene = True + + @debug + def add_model (self, model_id, pdb_hierarchy, atomic_bonds=None) : + assert isinstance(model_id, str) + model = model_data(model_id, pdb_hierarchy, atomic_bonds, + base_color=self.settings.opengl.base_atom_color) + self._add_model(model_id, model) + + def delete_model (self, model_id) : + if model_id in self.model_ids : + i = self.model_ids.index(model_id) + self.model_ids.pop(i) + self.model_objects.pop(i) + if model_id in self.scene_objects : + self.scene_objects.pop(model_id) + self.update_scene = True + + def _add_model (self, model_id, model) : + model.set_draw_mode(draw_mode=self.settings.opengl.default_representation, + color_mode=self.settings.opengl.default_coloring) + self.model_ids.append(model_id) + self.model_objects.append(model) + self.show_object[model_id] = True + self.pick_object[model_id] = True + self.update_scene = True + + def update_model (self, model_id, pdb_hierarchy, atomic_bonds) : + model = self.get_model(model_id) + if model is not None : + model.update_structure(pdb_hierarchy, atomic_bonds) + self.update_scene = True + else : + self.add_model(model_id, pdb_hierarchy, atomic_bonds) + + def update_model_from_xray_structure (self, model_id, xray_structure) : + model = self.get_model(model_id) + if model is not None : + model.update_from_xray_structure(xray_structure) + self.update_scene = True + + def update_mcs (self, points, recenter_and_zoom=True) : + self.minimum_covering_sphere = minimum_covering_sphere( + points=points, + epsilon=0.1) + if recenter_and_zoom : self.move_rotation_center_to_mcs_center() self.fit_into_viewport() - else : - self.unzoom() - def update_selection (self, selection_string=None) : - self.selection_string = str(selection_string) - self.apply_selection(self.selection_string) + def zoom_object (self, object_id) : + self.update_scene_objects() + assert object_id in self.scene_objects + self.update_mcs(self.scene_objects[object_id].points) - def apply_selection (self, selection_string) : - if self.selection_cache is None : - return - try : - if self.processed_pdb_file is not None : - self.atoms_selected = self._mmtbx_pdb_selection(selection_string) - else : - self.atoms_selected = self._iotbx_pdb_selection(selection_string) - except : - self.atoms_selected = self.selection_cache.selection("none") - self.selection_i_seqs = self.atoms_selected.iselection() - raise Sorry("The string '%s' is not a valid selection."%selection_string) - else : - self.selection_i_seqs = self.atoms_selected.iselection() - self.update_view() + @debug + def unzoom (self, event=None) : + self.update_scene_objects() + if len(self.scene_objects) > 0 : + points = flex.vec3_double() + for object_id, scene in self.scene_objects.iteritems() : + points.extend(scene.points) + self.update_mcs(points) - # original pdb_hierarchy selection - def _iotbx_pdb_selection (self, selection_string) : - return self.selection_cache.selection(selection_string) + @debug + def recenter_on_atom (self, object_id, i_seq) : + assert object_id is not None and i_seq >= 0 + scene = self.scene_objects.get(object_id) + if scene is not None and i_seq < scene.points.size() : + self.rotation_center = scene.points[i_seq] + self.move_to_center_of_viewport(self.rotation_center) - # monomer_library.pdb_interpretation "smart" selections - def _mmtbx_pdb_selection (self, selection_string) : - return self.processed_pdb_file.all_chain_proxies.selection( - string=selection_string, - cache=self.selection_cache) + @debug + def process_pick_points (self) : + self.closest_point_object_id = None + self.closest_point_i_seq = None + if self.pick_points is not None and len(self.scene_objects) > 0 : + for object_id in self.model_ids : + if self.show_object[object_id] and self.pick_object[object_id] : + scene = self.scene_objects.get(object_id) + if scene is None : + continue + closest_point_i_seq = viewer_utils.closest_visible_point( + points = scene.points, + atoms_visible = scene.atoms_visible, + point0 = self.pick_points[0], + point1 = self.pick_points[1] + ) + if closest_point_i_seq is not None : + self.closest_point_i_seq = closest_point_i_seq + self.closest_point_object_id = object_id + break + if self.closest_point_i_seq is not None : + clicked_scene = self.scene_objects.get(self.closest_point_object_id) + if self.settings.opengl.label_clicked_atom : + clicked_scene.add_label(self.closest_point_i_seq) + if self.flag_recenter_on_click : + self.recenter_on_atom(self.closest_point_object_id, + self.closest_point_i_seq) - def get_selected_atom_count (self) : - return self.selection_i_seqs.size() + @debug + def update_scene_objects (self) : + points = flex.vec3_double() + for object_id, model in self.iter_models() : + current_scene = self.scene_objects.get(object_id) + if current_scene is None or model.is_changed : + current_scene = model.get_scene_data() + self.scene_objects[object_id] = current_scene + model.reset() + else : + model.update_scene_data(current_scene) + points.extend(current_scene.points) + if points.size() == 0 : + points.append((0,0,0)) + self.update_mcs(points, recenter_and_zoom=False) - def set_selection_sphere (self) : - if self.selection_i_seqs is None or self.selection_i_seqs.size() == 0 : - self.selection_covering_sphere = None - return - if self.selection_i_seqs.size() == 0 : - self.selection_covering_sphere = minimum_covering_sphere( - points=self.atoms.extract_xyz(), - epsilon=0.1) + @debug + def process_key_stroke (self, key) : + if key == ord('u') : + self.unzoom() + elif key == ord('h') : + self.flag_show_hydrogens = not self.flag_show_hydrogens + self.toggle_hydrogens(self.flag_show_hydrogens) + self.update_scene = True + elif key == ord('e') : + self.flag_show_ellipsoids = not self.flag_show_ellipsoids + self.toggle_ellipsoids(self.flag_show_ellipsoids) + self.update_scene = True + elif key == ord('l') : + self.flag_show_labels = not self.flag_show_labels + self.update_scene = True + elif key == ord('t') : + self.flag_show_trace = not self.flag_show_trace + if self.flag_show_trace : + self.set_draw_mode("trace") + else : + self.set_draw_mode("all_atoms") + self.update_scene = True + elif key == ord('b') : + self.set_color_mode("b") + elif key == ord('r') : + self.set_color_mode("rainbow") + elif key == ord('y') : + self.set_color_mode("element") + elif key == 8 : # delete, at least on Mac + self.clear_all_labels() + self.update_scene = True + elif key == ord('q') : + app = wx.GetApp() + app.Exit() else : - selected_points = flex.vec3_double() - points = self.points - for i_seq in self.selection_i_seqs : - selected_points.append(points[i_seq]) - self.selection_covering_sphere = minimum_covering_sphere( - points=selected_points, - epsilon=0.1) + pass + #print key + if self.update_scene : + self.OnRedrawGL() - def set_color_mode (self, color_mode, redraw=False) : - self.set_sel_color(color_tuple=self.selection_color) - model_viewer_mixin.set_color_mode(self, color_mode, redraw) + def toggle_visibility (self, show_object, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + self.show_object[model_id] = show_object + self.update_scene = True - def set_sel_color (self, color_tuple=(1.0,1.0,1.0)) : - self.selection_color = color_tuple - sele_color_list = flex.vec3_double() - # does this need to be done in c++? - for i_seq in xrange(0, self.atom_count) : - sele_color_list.append(color_tuple) - self.selection_colors = sele_color_list + def hide_models (self, object_id=None) : + for model_id in self.model_ids : + if object_id is None or model_id == object_id : + self.show_object[model_id] = False - def set_selected_atom (self, closest_point_i_seq) : - self.current_atom_i_seq = closest_point_i_seq + def show_all (self) : + for model_id in self.model_ids : + self.show_object[model_id] = True - #--------------------------------------------------------------------- - # DRAWING - def draw_selection (self) : - selection_i_seqs = self.selection_i_seqs - if selection_i_seqs is None or selection_i_seqs.size() == 0 : - return - selection_colors = self.atom_colors - if self.flag_recolor_selection and self.selection_colors is not None : - selection_colors = self.selection_colors - if self.selection_display_list is None : - self.selection_display_list = gltbx.gl_managed.display_list() - self.selection_display_list.compile() - draw_mode = self.selection_draw_mode - if draw_mode is None : - draw_mode = "bonds_and_atoms" - if draw_mode == "bonds_and_atoms" : - self.visibility.get_selection_visibility( - bonds = self.bonds, - atoms_selected = self.atoms_selected - ) - glLineWidth(self.line_width + 2) - viewer_utils.draw_points( - points = self.points, - atom_colors = selection_colors, - points_visible = self.visibility.selected_points_visible, - cross_radius = 0.4 - ) - glLineWidth(self.line_width + 3) - viewer_utils.draw_bonds( - points = self.points, - bonds = self.bonds, - atom_colors = selection_colors, - bonds_visible = self.visibility.selected_bonds_visible - ) - elif draw_mode == "points" : - glLineWidth(self.line_width + 2) - viewer_utils.draw_points( - points = self.points, - atom_colors = selection_colors, - points_visible = self.atoms_selected, - cross_radius = 0.4 - ) - elif draw_mode == "spheres" : - self._draw_spheres( - spheres_visible = self.atoms_selected, - atom_colors = selection_colors, - atom_radii = self.atom_radii - ) - self.selection_display_list.end() - self.selection_display_list.call() + @debug + def set_draw_mode (self, draw_mode, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.set_draw_mode(draw_mode) + self.update_scene = True -######################################################################## -# MIXIN FOR DRAWING ATOM LABELS -# -# This is meant to be combined with other viewer mixins, and is much -# simpler as a result. -class atom_label_mixin (wx_viewer.wxGLWindow) : - initialize_atom_label_super = False - def __init__ (self, *args, **kwds) : - if self.initialize_atom_label_super : - wx_viewer.wxGLWindow.__init__(self, *args, **kwds) - self.label_xyz = [] - self.label_text = [] - self.label_color = (1.0, 1.0, 1.0) - self.labels_display_list = None - self.flag_show_labels = True + @debug + def set_color_mode (self, color_mode, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.set_color_mode(color_mode) + self.update_scene = True - # No InitGL method here. + def set_model_base_color (self, color, object_id=None) : + assert len(color) == 3 + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.set_base_color(color) + self.update_scene = True - def DrawGL (self) : - if self.flag_show_labels : - self.draw_labels() + def toggle_ellipsoids (self, show_ellipsoids, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.toggle_ellipsoids(show_ellipsoids) - def clear_labels (self, event=None) : - self.label_xyz = flex.vec3_double() - self.label_text = [] - self.labels_display_list = None + def toggle_hydrogens (self, show_hydrogens, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + model.toggle_hydrogens(show_hydrogens) - def draw_labels (self) : - glDisable(GL_LIGHTING) - if (self.labels_display_list is None) : - font = gltbx.fonts.ucs_bitmap_8x13 - font.setup_call_lists() - self.labels_display_list = gltbx.gl_managed.display_list() - self.labels_display_list.compile() - glColor3f(*self.label_color) - for label,point in zip(self.label_text, self.label_xyz): - glRasterPos3f(*point) - font.render_string(label) - self.labels_display_list.end() - self.labels_display_list.call() + # TODO: something smarter - temporary toggle for draw_mode? + def toggle_trace (self, show_trace, object_id=None) : + for model_id, model in self.iter_models() : + if object_id is None or object_id == model_id : + if show_trace : + model.set_draw_mode("trace") + else : + model.set_draw_mode("all_atoms") + self.update_scene = True - def show_atom_label (self, i_seq) : - if self.points is None or i_seq >= self.points.size() : - return - point = self.points[i_seq] - self.label_xyz.append((point[0] + 1, point[1] + 1, point[2])) - a = self.atom_index[i_seq] - if not isinstance(a, str) : - atom_str = "%s %s%s %s" % (strip(a.name), a.chain_id, strip(a.resseq), - strip(a.resname)) - else : - atom_str = a - self.label_text.append(atom_str) - self.OnRedrawGL() + def toggle_labels (self, show_labels) : + self.flag_show_labels = show_labels -class sites_viewer_mixin (model_viewer_base) : - initialize_model_viewer_super = True - use_sites_mcs = True - def __init__ (self, *args, **kwds) : - model_viewer_base.__init__(self, *args, **kwds) - self.points = flex.vec3_double() - self.atoms_visible = flex.bool() - self.atom_radii = flex.double() - self.atom_colors = flex.vec3_double() - self._new_sites = flex.vec3_double() - self.base_atom_color = (0.8, 0.8, 0.8) - self.flag_show_fog = True - self.flag_show_lines = False - self.flag_show_points = False - self.flag_show_spher... [truncated message content] |
From: <nat...@us...> - 2009-08-21 00:21:51
|
Revision: 9630 http://cctbx.svn.sourceforge.net/cctbx/?rev=9630&view=rev Author: natechols Date: 2009-08-21 00:21:30 +0000 (Fri, 21 Aug 2009) Log Message: ----------- fixed bug caused by change of atom count Modified Paths: -------------- trunk/crys3d/wx_model_viewer.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-08-20 23:09:19 UTC (rev 9629) +++ trunk/crys3d/wx_model_viewer.py 2009-08-21 00:21:30 UTC (rev 9630) @@ -2,6 +2,7 @@ # XXX: To keep these classes as clean as possible, selections are handled # entirely in wx_selection_editor.py. # TODO: hide nonbonded point for any atom that has an ellipsoid drawn +# TODO: clean up handling of changes in atom count import iotbx.phil from cctbx import uctbx @@ -86,6 +87,8 @@ @debug def get_scene_data (self) : + if self.atoms.size() != self.visibility.atoms_visible.size() : + self.recalculate_visibility() return model_scene(bonds=self.current_bonds, points=self.atoms.extract_xyz(), b_iso=self.atoms.extract_b(), @@ -156,7 +159,9 @@ self.atom_index = atom_index self.atom_labels = atom_labels self.trace_bonds = extract_trace(pdb_hierarchy) #, self.selection_cache) - if self.current_bonds is None : + if self.draw_mode is None or self.draw_mode.startswith("trace") : + self.current_bonds = self.trace_bonds + else : self.current_bonds = self.atomic_bonds atom_radii = flex.double(self.atoms.size(), 1.5) hydrogen_flag = flex.bool(self.atoms.size(), False) @@ -718,6 +723,9 @@ model = self.get_model(model_id) if model is not None : model.update_structure(pdb_hierarchy, atomic_bonds) + model.set_draw_mode(model.draw_mode) + if model_id in self.scene_objects : + self.scene_objects.pop(model_id) self.update_scene = True else : self.add_model(model_id, pdb_hierarchy, atomic_bonds) Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-08-20 23:09:19 UTC (rev 9629) +++ trunk/crys3d/wx_selection_editor.py 2009-08-21 00:21:30 UTC (rev 9630) @@ -34,6 +34,9 @@ model_data.__init__(self, *args, **kwds) def get_scene_data (self) : + if self.atoms.size() != self.visibility.atoms_visible.size() : + self.recalculate_visibility() + print 123456789 scene = model_scene_with_selection(bonds=self.current_bonds, points=self.atoms.extract_xyz(), b_iso=self.atoms.extract_b(), This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-09-01 19:09:21
|
Revision: 9687 http://cctbx.svn.sourceforge.net/cctbx/?rev=9687&view=rev Author: natechols Date: 2009-09-01 19:09:08 +0000 (Tue, 01 Sep 2009) Log Message: ----------- added modified wx_viewer base class for (future) improved fog/clipping when zooming Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer.py trunk/crys3d/wx_selection_editor.py Added Paths: ----------- trunk/crys3d/wx_viewer_zoom.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-09-01 18:02:15 UTC (rev 9686) +++ trunk/crys3d/wx_combined_viewer.py 2009-09-01 19:09:08 UTC (rev 9687) @@ -1,8 +1,9 @@ +from __future__ import division import sys, os +from crys3d import wx_viewer_zoom from crys3d.wx_selection_editor import selection_editor_mixin import iotbx.phil -from gltbx import wx_viewer import gltbx.util from gltbx.gl import * from gltbx.glu import * @@ -93,11 +94,11 @@ glPopMatrix() -class map_viewer_mixin (wx_viewer.wxGLWindow) : +class map_viewer_mixin (wx_viewer_zoom.viewer_with_automatic_zoom) : initialize_map_viewer_super = True def __init__ (self, *args, **kwds) : if self.initialize_map_viewer_super : - wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + wx_viewer_zoom.viewer_with_automatic_zoom.__init__(self, *args, **kwds) # various data objects self.map_ids = [] self.map_objects = [] @@ -128,7 +129,7 @@ def OnRedrawGL (self, event=None) : self.check_and_update_map_scenes() - wx_viewer.wxGLWindow.OnRedrawGL(self, event) + wx_viewer_zoom.viewer_with_automatic_zoom.OnRedrawGL(self, event) def check_and_update_map_scenes (self) : if self.update_maps : @@ -144,7 +145,7 @@ self.draw_rotation_center() def OnTranslate (self, event) : - wx_viewer.wxGLWindow.OnTranslate(self, event) + wx_viewer_zoom.viewer_with_automatic_zoom.OnTranslate(self, event) self.update_map_scenes() def draw_rotation_center(self): @@ -172,21 +173,6 @@ glEnd() glPopMatrix() - def setup_fog (self) : - if self.flag_show_fog : - near, far = self.get_clipping_distances() - # TODO: this needs work. - fog_start = 0.25*(far - near) + near + self.fog_start_offset - fog_end = self.far - self.fog_end_offset - glMatrixMode(GL_MODELVIEW) - glEnable(GL_FOG) - glFogi(GL_FOG_MODE, GL_LINEAR) - glFogf(GL_FOG_START, fog_start) - glFogf(GL_FOG_END, fog_end) - glFogfv(GL_FOG_COLOR, [self.r_back, self.g_back, self.b_back, 1.0]) - else : - glDisable(GL_FOG) - def OnMouseWheel (self, event) : scale = event.GetWheelRotation() if event.ShiftDown() : @@ -196,17 +182,7 @@ self.OnRedrawGL() def process_key_stroke (self, key) : - if key == wx.WXK_UP : - self.fog_start_offset += 1 - elif key == wx.WXK_DOWN : - self.fog_start_offset -= 1 - elif key == wx.WXK_LEFT : - self.fog_end_offset -= 1 - elif key == wx.WXK_RIGHT : - self.fog_end_offset += 1 - else : - return - self.OnRedrawGL() + pass def add_map (self, map_id, map) : assert not map_id in self.map_ids @@ -306,6 +282,15 @@ def process_key_stroke (self, key) : selection_editor_mixin.process_key_stroke(self, key) map_viewer_mixin.process_key_stroke(self, key) + if key == wx.WXK_UP : + self.fog_start_offset += 1 + elif key == wx.WXK_DOWN : + self.fog_start_offset -= 1 + elif key == wx.WXK_LEFT : + self.clip_near -= 1 + elif key == wx.WXK_RIGHT : + self.clip_near += 1 + self.OnRedrawGL() def update_mcs (self, *args, **kwds) : self.update_maps = True Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-09-01 18:02:15 UTC (rev 9686) +++ trunk/crys3d/wx_model_viewer.py 2009-09-01 19:09:08 UTC (rev 9687) @@ -1,3 +1,4 @@ +from __future__ import division # XXX: To keep these classes as clean as possible, selections are handled # entirely in wx_selection_editor.py. @@ -5,9 +6,10 @@ # TODO: clean up handling of changes in atom count import iotbx.phil +from crys3d import wx_viewer_zoom from cctbx import uctbx import gltbx.util -from gltbx import wx_viewer, viewer_utils, quadrics +from gltbx import viewer_utils, quadrics from gltbx.gl import * from gltbx.glu import * import gltbx @@ -485,9 +487,9 @@ event_id = UPDATE_MODEL_ID recenter = False -class model_viewer_mixin (wx_viewer.wxGLWindow) : +class model_viewer_mixin (wx_viewer_zoom.viewer_with_automatic_zoom) : def __init__ (self, *args, **kwds) : - wx_viewer.wxGLWindow.__init__(self, *args, **kwds) + wx_viewer_zoom.viewer_with_automatic_zoom.__init__(self, *args, **kwds) self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) self.Connect(-1, -1, UPDATE_MODEL_ID, self.OnUpdateModel) self.Connect(-1, -1, ADD_MODEL_ID, self.OnAddModel) @@ -546,7 +548,7 @@ @debug def initialize_modelview (self) : if self.minimum_covering_sphere is not None : - wx_viewer.wxGLWindow.initialize_modelview(self) + wx_viewer_zoom.viewer_with_automatic_zoom.initialize_modelview(self) else : self.setup_lighting() @@ -560,7 +562,7 @@ self.SwapBuffers() gltbx.util.handle_error() else : - wx_viewer.wxGLWindow.OnRedrawGL(self, event) + wx_viewer_zoom.viewer_with_automatic_zoom.OnRedrawGL(self, event) def check_and_update_model_scenes (self) : if self.update_scene : @@ -811,6 +813,7 @@ @debug def process_key_stroke (self, key) : + wx_viewer_zoom.viewer_with_automatic_zoom.process_key_stroke(self, key) if key == ord('u') : self.unzoom() elif key == ord('h') : Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-09-01 18:02:15 UTC (rev 9686) +++ trunk/crys3d/wx_selection_editor.py 2009-09-01 19:09:08 UTC (rev 9687) @@ -1,3 +1,4 @@ +from __future__ import division # TODO: move selection logic to separate module Added: trunk/crys3d/wx_viewer_zoom.py =================================================================== --- trunk/crys3d/wx_viewer_zoom.py (rev 0) +++ trunk/crys3d/wx_viewer_zoom.py 2009-09-01 19:09:08 UTC (rev 9687) @@ -0,0 +1,76 @@ +from __future__ import division +from gltbx import wx_viewer +import gltbx.util +from gltbx.gl import * +from gltbx.glu import * + +class viewer_with_automatic_zoom (wx_viewer.wxGLWindow) : + def process_key_stroke (self, key) : + if key == wx.WXK_UP : + self.fog_start_offset += 1 + elif key == wx.WXK_DOWN : + self.fog_start_offset -= 1 + elif key == wx.WXK_LEFT : + self.clip_near -= 1 + elif key == wx.WXK_RIGHT : + self.clip_near += 1 + self.update_scene = True + + def setup_distances (self) : + s = self.minimum_covering_sphere + r = self.buffer_factor*s.radius() + #z = -gltbx.util.object_as_eye_coordinates(s.center())[2] + z = -gltbx.util.object_as_eye_coordinates(self.rotation_center)[2] + self.near = max(self.min_near, z-r) + self.far = max(self.near*(1.e-6), z+r) + + def setup_viewing_volume(self): + aspect = self.w / max(1,self.h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + near, far = self.get_clipping_distances() + if self.orthographic: + s = self.minimum_covering_sphere + #c = s.center() + c = self.rotation_center + r = s.radius() + rf = self.buffer_factor * r + left = c[0] - rf + right = c[0] + rf + bottom = c[1] - rf + top = c[1] + rf + if (aspect < 1): + bottom /= aspect + top /= aspect + else: + left *= aspect + right *= aspect + glOrtho(left, right, bottom, top, near, far) + else: + gluPerspective(self.field_of_view_y, aspect, near, far) + self.setup_fog() + + def get_clipping_distances (self) : + near = self.near + self.clip_near + far = self.far + self.clip_far + if near > far : + near = far - 1 + if near < self.min_near : + near = self.min_near + return (near, far) + + def setup_fog (self) : + if self.flag_show_fog : + near, far = self.get_clipping_distances() + # TODO: this needs work. + fog_start = 0.25*(far - near) + near + self.fog_start_offset + fog_end = far - self.fog_end_offset + #print "%6.1f - %6.1f (%6.1f - %6.1f)" % (near, far, fog_start, fog_end) + glMatrixMode(GL_MODELVIEW) + glEnable(GL_FOG) + glFogi(GL_FOG_MODE, GL_LINEAR) + glFogf(GL_FOG_START, fog_start) + glFogf(GL_FOG_END, fog_end) + glFogfv(GL_FOG_COLOR, [self.r_back, self.g_back, self.b_back, 1.0]) + else : + glDisable(GL_FOG) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-09-21 18:00:38
|
Revision: 9744 http://cctbx.svn.sourceforge.net/cctbx/?rev=9744&view=rev Author: natechols Date: 2009-09-21 18:00:28 +0000 (Mon, 21 Sep 2009) Log Message: ----------- fixed zombie map bug in wx_combined_viewer Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-09-20 14:10:54 UTC (rev 9743) +++ trunk/crys3d/wx_combined_viewer.py 2009-09-21 18:00:28 UTC (rev 9744) @@ -189,8 +189,9 @@ i = self.map_ids.index(map_id) self.map_ids.pop(i) self.map_objects.pop(i) - if map_id in self.scene_objects : - self.scene_objects.pop(map_id) + self.show_object.pop(map_id) + if map_id in self.map_scenes : + self.map_scenes.pop(map_id) self.update_maps = True def update_map (self, map_id, map) : Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-09-20 14:10:54 UTC (rev 9743) +++ trunk/crys3d/wx_model_viewer.py 2009-09-21 18:00:28 UTC (rev 9744) @@ -50,8 +50,6 @@ .type = bool use_atom_color_for_labels = True .type = bool - use_fog = True - .type = bool orthographic = False .type = bool .style = noauto @@ -637,7 +635,6 @@ glDisable(GL_LIGHTING) use_atom_color = self.settings.opengl.use_atom_color_for_labels if not use_atom_color : - print "using global label color" glColor3f(1.0, 1.0, 1.0) font = gltbx.fonts.ucs_bitmap_8x13 font.setup_call_lists() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-09-24 00:11:24
|
Revision: 9751 http://cctbx.svn.sourceforge.net/cctbx/?rev=9751&view=rev Author: natechols Date: 2009-09-24 00:11:02 +0000 (Thu, 24 Sep 2009) Log Message: ----------- minor improvements in view setup in model viewer Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-09-23 21:24:07 UTC (rev 9750) +++ trunk/crys3d/wx_combined_viewer.py 2009-09-24 00:11:02 UTC (rev 9751) @@ -288,14 +288,6 @@ def process_key_stroke (self, key) : selection_editor_mixin.process_key_stroke(self, key) map_viewer_mixin.process_key_stroke(self, key) - if key == wx.WXK_UP : - self.fog_start_offset += 1 - elif key == wx.WXK_DOWN : - self.fog_start_offset -= 1 - elif key == wx.WXK_LEFT : - self.clip_near -= 1 - elif key == wx.WXK_RIGHT : - self.clip_near += 1 self.OnRedrawGL() def update_mcs (self, *args, **kwds) : Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-09-23 21:24:07 UTC (rev 9750) +++ trunk/crys3d/wx_model_viewer.py 2009-09-24 00:11:02 UTC (rev 9751) @@ -14,7 +14,7 @@ from gltbx.glu import * import gltbx from scitbx.array_family import flex, shared -from scitbx.math import minimum_covering_sphere +from scitbx.math import minimum_covering_sphere, sphere_3d from libtbx.introspection import method_debug_log from libtbx.utils import Sorry from libtbx import adopt_init_args @@ -501,6 +501,7 @@ self.model_reps = {} self.update_scene = False self.buffer_factor = 2 # see gltbx.wx_viewer + self.min_slab = 4 self.sphere_scale_factor = 1.0 self.update_settings(opengl_phil.extract()) self.closest_point_i_seq = None @@ -562,6 +563,17 @@ else : wxGLWindow.OnRedrawGL(self, event) + def get_clipping_distances (self) : + slab = self.far - self.near + clip = (1.0 - self.slab_scale) * (slab / 2.0) + near = self.near + clip + far = self.far - clip + if near < self.min_near : + near = self.min_near + if near > far or far < (near + self.min_slab) : + far = near + self.min_slab + return (near, far) + def check_and_update_model_scenes (self) : if self.update_scene : self.update_scene_objects() @@ -734,10 +746,15 @@ model.update_from_xray_structure(xray_structure) self.update_scene = True - def update_mcs (self, points, recenter_and_zoom=True) : - self.minimum_covering_sphere = minimum_covering_sphere( - points=points, - epsilon=0.1) + def update_mcs (self, points, recenter_and_zoom=True, buffer=0) : + mcs = minimum_covering_sphere(points=points, + epsilon=0.1) + if buffer > 0 : + self.minimum_covering_sphere = sphere_3d( + center=mcs.center(), + radius=mcs.radius() + buffer) + else : + self.minimum_covering_sphere = mcs if recenter_and_zoom : self.move_rotation_center_to_mcs_center() self.fit_into_viewport() Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2009-09-23 21:24:07 UTC (rev 9750) +++ trunk/crys3d/wx_selection_editor.py 2009-09-24 00:11:02 UTC (rev 9751) @@ -156,6 +156,7 @@ self.current_object_id = None self._callback = print_cb self._in_range_selection = False + self.buffer_selection_sphere = 5 model_viewer_mixin.__init__(self, *args,**kwds) self.settings = viewer_phil.extract() @@ -187,7 +188,7 @@ if self.show_object[object_id] : points.extend(scene.points) if points.size() != 0 : - self.update_mcs(points) + self.update_mcs(points, buffer=self.buffer_selection_sphere) def set_selection (self, object_id, selection_string) : for model_id, model in self.iter_models() : This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-09-25 19:52:39
|
Revision: 9754 http://cctbx.svn.sourceforge.net/cctbx/?rev=9754&view=rev Author: natechols Date: 2009-09-25 19:52:26 +0000 (Fri, 25 Sep 2009) Log Message: ----------- controls for changing model/map appearance Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-09-25 01:27:28 UTC (rev 9753) +++ trunk/crys3d/wx_combined_viewer.py 2009-09-25 19:52:26 UTC (rev 9754) @@ -104,6 +104,7 @@ self.map_objects = [] self.map_scenes = {} self.show_object = {} + self.map_ctrls = {} # user settings self.mesh_line_width = 0.25 # very buggy on OS X + NVidia (and ???) self.update_maps = False @@ -202,6 +203,19 @@ map_object.update_map_data(map) self.update_maps = True + def show_map_ctrls (self, map_id) : + map_object = self.get_map(map_id) + if map_object is None : + print "oops" + return + elif self.map_ctrls.get(map_id) is not None : + self.map_ctrls[map_id].Raise() + else : + print 0 + frame = MapEditor(self, map_object, map_id) + frame.Show() + self.map_ctrls[map_id] = frame + def update_map_from_miller_array (self, map_id, map_coeffs, resolution_factor=0.33) : assert map_coeffs.is_complex_array() @@ -316,4 +330,62 @@ if current_object_id == object_id : self.show_object[current_object_id] = show_object +class MapEditor (wx.MiniFrame) : + def __init__ (self, parent, map_object, map_id) : + import wx.lib.colourselect + adopt_init_args(self, locals()) + wx.MiniFrame.__init__(self, parent, -1, map_id, + style=wx.CAPTION|wx.CLOSE_BOX|wx.RAISED_BORDER) + panel = wx.Panel(self, -1) + main_sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(main_sizer) + self.ctrls = [] + for iso_level, color in zip(map_object.iso_levels, map_object.colors) : + level_sizer = wx.BoxSizer(wx.HORIZONTAL) + slider = wx.Slider(panel, + size=(160,-1), + minValue=-100, + maxValue=100, + value=int(iso_level * 10), + style=wx.SL_AUTOTICKS) + level_txt = wx.TextCtrl(panel, + size=(64,-1), + style=wx.TE_READONLY|wx.TE_RIGHT) + level_txt.SetValue("%.2f" % iso_level) + initial_color = [ int(x*255) for x in color ] + color_ctrl = wx.lib.colourselect.ColourSelect(panel, + colour=initial_color) + level_sizer.Add(slider, 0, wx.ALL, 5) + level_sizer.Add(level_txt, 0, wx.ALL, 5) + level_sizer.Add(color_ctrl, 0, wx.ALL, 5) + main_sizer.Add(level_sizer, 1, wx.ALL, 5) + self.ctrls.append((slider, level_txt, color_ctrl)) + main_sizer.Fit(panel) + self.Fit() + self.Bind(wx.EVT_SLIDER, self.OnUpdate) + self.Bind(wx.lib.colourselect.EVT_COLOURSELECT, self.OnUpdate) + self.Bind(wx.EVT_CLOSE, self.OnClose) + self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) + + def OnUpdate (self, event) : + source_ctrl = event.GetEventObject() + for i, (s, t, c) in enumerate(self.ctrls) : + if source_ctrl is s : + new_level = s.GetValue() / 10.0 + self.map_object.iso_levels[i] = new_level + t.SetValue("%.2f" % new_level) + self.parent.update_maps = True + elif source_ctrl is c : + new_color = c.GetValue() + new_color = [ x / 255.0 for x in new_color ] + self.map_object.colors[i] = new_color + self.parent.update_maps = True + self.parent.OnRedrawGL() + + def OnClose (self, event) : + self.Destroy() + + def OnDestroy (self, event) : + self.parent.map_ctrls[self.map_id] = None + #---end Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-09-25 01:27:28 UTC (rev 9753) +++ trunk/crys3d/wx_model_viewer.py 2009-09-25 19:52:26 UTC (rev 9754) @@ -58,6 +58,17 @@ } """) +draw_modes = [ ("trace", "Show trace"), + ("all_atoms", "Show all atoms"), + ("bonded_only", "Show bonded atoms"), ] +draw_flags = [ ("flag_show_hydrogens", "Show hydrogens"), + ("flag_show_ellipsoids", "Show B-factor ellipsoids"), + ("flag_show_labels", "Show labels"), ] +color_modes = [ ("rainbow", "Color rainbow"), + ("b", "Color by B-factor"), + ("element", "Color by element"), + ("chain", "Color by chain"), ] + #----------------------------------------------------------------------- # XXX: None of the data in this class is used directly in OpenGL calls; # instead, the model_scene object contains the subset of information @@ -313,6 +324,7 @@ if cached is not None : self.atom_colors = cached else : + print self.base_color # these are approximations based on my (probably faulty) memory. # feel free to change to something more reasonable. element_shades = {' C' : self.base_color, # usually yellow or grey @@ -684,18 +696,59 @@ return model return None - def get_model_state (self, object_id) : + def show_model_controls_menu (self, object_id, source_widget) : model = self.get_model(object_id) - model_attr = dir(model) - state = {} - for name in model_attr : - if name.startswith("flag_") : - state_var = name[5:] #re.sub("flag_", "", name) - state[state_var] = getattr(model, name) - state["draw_mode"] = model.draw_mode - state["color_mode"] = model.color_mode - return state + if model is None : + return + menu = wx.Menu(title=object_id) + for mode_name, mode_label in draw_modes : + item = menu.AppendCheckItem(-1, mode_label) + if model.draw_mode == mode_name : + item.Check(True) + source_widget.Bind(wx.EVT_MENU, self.OnModelMenu, item) + menu.AppendSeparator() + for flag_name, flag_label in draw_flags : + item = menu.AppendCheckItem(-1, flag_label) + if getattr(model, flag_name, False) : + item.Check(True) + source_widget.Bind(wx.EVT_MENU, self.OnModelMenu, item) + menu.AppendSeparator() + for color_name, color_label in color_modes : + item = menu.AppendCheckItem(-1, color_label) + if model.color_mode == color_name : + item.Check(True) + source_widget.Bind(wx.EVT_MENU, self.OnModelMenu, item) + menu.AppendSeparator() + item = menu.Append(-1, "Change base color. . .") + source_widget.Bind(wx.EVT_MENU, self.OnChangeModelColor, item) + source_widget.PopupMenu(menu) + menu.Destroy() + self.OnRedrawGL() + def process_model_menu_event (self, object_id, menu_item) : + model = self.get_model(object_id) + if model is None : + return + item_label = menu_item.GetText() + is_checked = menu_item.IsChecked() + for mode, label in draw_modes : + if label == item_label and is_checked : + model.set_draw_mode(mode) + self.update_scene = True + return True + for mode, label in color_modes : + if label == item_label and is_checked : + model.set_color_mode(mode) + self.update_scene = True + return True + for flag, label in draw_flags : + if label == item_label : + setattr(model, flag, is_checked) + model.refresh() + self.update_scene = True + return True + return False + def set_model_state (self, object_id, model_state) : model = self.get_model(object_id) for name in model_state : @@ -955,6 +1008,24 @@ self.recenter_on_atom(self.closest_point_object_id, self.closest_point_i_seq) + def OnModelMenu (self, event) : + menu = event.GetEventObject() + item = menu.FindItemById(event.GetId()) + model_id = menu.GetTitle() + self.process_model_menu_event(model_id, item) + + def OnChangeModelColor (self, event) : + menu = event.GetEventObject() + model_id = menu.GetTitle() + model = self.get_model(model_id) + if model is not None : + base_color = [ int(x*255) for x in model.base_color ] + new_color = wx.GetColourFromUser(self, base_color) + new_color = [ x / 255 for x in new_color ] + model.set_base_color(new_color) + model.refresh() + self.update_scene = True + def thread_safe_add_model (self, model_id, pdb_hierarchy, atomic_bonds) : wx.PostEvent(self, AddModelEvent(model_id, pdb_hierarchy, atomic_bonds)) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2009-10-10 00:21:15
|
Revision: 9804 http://cctbx.svn.sourceforge.net/cctbx/?rev=9804&view=rev Author: natechols Date: 2009-10-10 00:21:06 +0000 (Sat, 10 Oct 2009) Log Message: ----------- got rid of print statements Modified Paths: -------------- trunk/crys3d/wx_combined_viewer.py trunk/crys3d/wx_model_viewer.py Modified: trunk/crys3d/wx_combined_viewer.py =================================================================== --- trunk/crys3d/wx_combined_viewer.py 2009-10-10 00:20:35 UTC (rev 9803) +++ trunk/crys3d/wx_combined_viewer.py 2009-10-10 00:21:06 UTC (rev 9804) @@ -211,7 +211,6 @@ elif self.map_ctrls.get(map_id) is not None : self.map_ctrls[map_id].Raise() else : - print 0 frame = MapEditor(self, map_object, map_id) frame.Show() self.map_ctrls[map_id] = frame Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2009-10-10 00:20:35 UTC (rev 9803) +++ trunk/crys3d/wx_model_viewer.py 2009-10-10 00:21:06 UTC (rev 9804) @@ -324,7 +324,6 @@ if cached is not None : self.atom_colors = cached else : - print self.base_color # these are approximations based on my (probably faulty) memory. # feel free to change to something more reasonable. element_shades = {' C' : self.base_color, # usually yellow or grey This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2010-02-22 18:10:27
|
Revision: 10312 http://cctbx.svn.sourceforge.net/cctbx/?rev=10312&view=rev Author: natechols Date: 2010-02-22 18:10:20 +0000 (Mon, 22 Feb 2010) Log Message: ----------- changes to enable editing secondary structure Modified Paths: -------------- trunk/crys3d/reverse_selection.py trunk/crys3d/wx_model_viewer.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/reverse_selection.py =================================================================== --- trunk/crys3d/reverse_selection.py 2010-02-21 23:47:14 UTC (rev 10311) +++ trunk/crys3d/reverse_selection.py 2010-02-22 18:10:20 UTC (rev 10312) @@ -109,10 +109,14 @@ def __init__ (self) : self.saved_selection = "none" self.selection_string = "none" + self.flag_overwrite_mode = False self._selection_callback = None self.start_i_seq = None self.end_i_seq = None + def set_overwrite_mode (self, overwrite=True) : + self.flag_overwrite_mode = overwrite + def selection_callback (self, selection_string, atom_selection) : if self._selection_callback is not None : self._selection_callback(selection_string, atom_selection) @@ -204,6 +208,9 @@ if (start_atom.chain_id == end_atom.chain_id and (ignore_altloc or start_atom.altloc == end_atom.altloc)) : chain_id = start_atom.chain_id + if self.flag_overwrite_mode and not deselect : + if chain_id in self.selected_chains : + del self.selected_chains[chain_id] altloc = None if not ignore_altloc : altloc = start_atom.altloc @@ -287,12 +294,15 @@ resi_info = residue_selection_info(atom.chain_id, atom.resid(), atom.altloc) resi_sel = self.selection_cache.selection(str(resi_info)) - if self.atom_selection.is_super_set(resi_sel) : - self.deselected_residues.append(resi_info) - self.remove_redundant_residues(resi_sel, self.selected_residues) - else : - self.selected_residues.append(resi_info) - self.remove_redundant_residues(resi_sel, self.deselected_residues) + if self.flag_overwrite_mode : + pass + if True : #else : + if self.atom_selection.is_super_set(resi_sel) : + self.deselected_residues.append(resi_info) + self.remove_redundant_residues(resi_sel, self.selected_residues) + else : + self.selected_residues.append(resi_info) + self.remove_redundant_residues(resi_sel, self.deselected_residues) self.remove_redundant_atoms(resi_sel, self.selected_atoms) self.remove_redundant_atoms(resi_sel, self.deselected_atoms) self.construct_selection() @@ -309,6 +319,16 @@ self.deselected_atoms.remove(i_seq) self.construct_selection() + def select_single_residue (self, i_seq) : + atom = self.atom_index[i_seq] + resi_info = residue_selection_info(atom.chain_id, atom.resid()) + resi_sel = self.selection_cache.selection(str(resi_info)) + is_current_selection = ((resi_sel==self.atom_selection).count(False) == 0) + self.clear_selection() + if is_current_selection : + return False + self.toggle_residue_selection(i_seq) + def construct_selection (self) : final_selection = "" # Part 1: stuff we want Modified: trunk/crys3d/wx_model_viewer.py =================================================================== --- trunk/crys3d/wx_model_viewer.py 2010-02-21 23:47:14 UTC (rev 10311) +++ trunk/crys3d/wx_model_viewer.py 2010-02-22 18:10:20 UTC (rev 10312) @@ -111,7 +111,8 @@ atom_labels=self.atom_labels, atom_radii=self.atom_radii, visibility=self.visibility, - noncovalent_bonds=self.noncovalent_bonds) + noncovalent_bonds=self.noncovalent_bonds, + atomic_bonds=self.atomic_bonds) def set_noncovalent_bonds (self, bonded_atoms) : self.noncovalent_bonds = bonded_atoms @@ -368,7 +369,7 @@ # which are also implemented as methods here. class model_scene (object) : def __init__ (self, bonds, points, b_iso, b_aniso, atom_colors, atom_labels, - atom_radii, visibility, noncovalent_bonds) : + atom_radii, visibility, noncovalent_bonds, atomic_bonds) : adopt_init_args(self, locals()) self.clear_lists() self.clear_labels() @@ -555,11 +556,12 @@ self.flag_use_lights = True self.flag_show_labels = True self.flag_show_trace = False - self.flag_show_noncovalent_bonds = False + self.flag_show_noncovalent_bonds = False self.flag_show_hydrogens = False self.flag_show_ellipsoids = True self.flag_smooth_lines = True self.flag_recenter_on_click = False + self.flag_show_context_menu = True #False @debug def InitGL(self): @@ -961,10 +963,7 @@ app = wx.GetApp() app.Exit() else : - pass - #print key - if self.update_scene : - self.OnRedrawGL() + return False def toggle_visibility (self, show_object, object_id=None) : for model_id, model in self.iter_models() : @@ -1048,6 +1047,11 @@ self.add_model(model_id, pdb_hierarchy, atomic_bonds) self.OnRedrawGL() + def OnChar (self, *args, **kwds) : + super(model_viewer_mixin, self).OnChar(*args, **kwds) + if self.update_scene : + self.OnRedrawGL() + def OnDoubleClick (self, event) : self.get_pick_points((event.GetX(), event.GetY())) self.process_pick_points() Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2010-02-21 23:47:14 UTC (rev 10311) +++ trunk/crys3d/wx_selection_editor.py 2010-02-22 18:10:20 UTC (rev 10312) @@ -31,6 +31,7 @@ def __init__ (self, *args, **kwds) : self.flag_show_selection = True self.flag_allow_selection = True + self._cached_colors = None mouse_selection_manager.__init__(self) model_data.__init__(self, *args, **kwds) @@ -38,6 +39,9 @@ if self.atoms.size() != self.visibility.atoms_visible.size() : self.recalculate_visibility() print 123456789 + atomic_bonds = self.atomic_bonds + #if not self.flag_show_hydrogens : + # atomic_bonds = atomic_bonds & ~self.hydrogen_flag scene = model_scene_with_selection(bonds=self.current_bonds, points=self.atoms.extract_xyz(), b_iso=self.atoms.extract_b(), @@ -46,12 +50,16 @@ atom_labels=self.atom_labels, atom_radii=self.atom_radii, visibility=self.visibility, - noncovalent_bonds=self.noncovalent_bonds) + noncovalent_bonds=self.noncovalent_bonds, + atomic_bonds=atomic_bonds) self.update_scene_data(scene) return scene def update_scene_data (self, scene) : - scene.update_selection(self.atom_selection) + if self.flag_show_hydrogens : + scene.update_selection(self.atom_selection) + else : + scene.update_selection(self.atom_selection & ~self.hydrogen_flag) model_data.update_scene_data(self, scene) def update_structure (self, pdb_hierarchy, atomic_bonds, @@ -70,9 +78,28 @@ self.recalculate_visibility() mouse_selection_manager.selection_callback(self, *args, **kwds) + def highlight_atoms (self, selection_string) : + if selection_string is None : + self.is_changed = True + if self._cached_colors is not None : + self.atom_colors = self._cached_colors + else : + self.set_color_mode(self.color_mode) + else : + atom_selection = self.get_atom_selection(selection_string) + if atom_selection is not None and atom_selection.count(True) != 0 : + self._cached_colors = self.atom_colors + #self.set_color_mode(self.color_mode) + self.is_changed = True + self.atom_colors = viewer_utils.scale_selected_colors( + input_colors=self.atom_colors, + selection=~atom_selection, + scale=0.5) + #----------------------------------------------------------------------- class model_scene_with_selection (model_scene) : def __init__ (self, *args, **kwds) : + self.flag_show_all_selected_atoms = False model_scene.__init__(self, *args, **kwds) self.selection_draw_mode = "bonds_and_atoms" self.update_selection(flex.bool(self.points.size(), False)) @@ -89,8 +116,12 @@ def update_visibility (self, visibility) : model_scene.update_visibility(self, visibility) - self.selected_points_visible = visibility.selected_points_visible - self.selected_bonds_visible = visibility.selected_bonds_visible + if self.flag_show_all_selected_atoms : + self.selected_points_visible = visibility.selected_points_visible + self.selected_bonds_visible = self.atom_selection + else : + self.selected_points_visible = visibility.selected_points_visible + self.selected_bonds_visible = visibility.selected_bonds_visible def get_selected_xyz (self) : points = self.points @@ -117,9 +148,13 @@ atom_colors = selection_colors, points_visible = self.selected_points_visible, cross_radius = 0.4) + if self.flag_show_all_selected_atoms : + bonds = self.atomic_bonds + else : + bonds = self.bonds viewer_utils.draw_bonds( points = self.points, - bonds = self.bonds, + bonds = bonds, atom_colors = selection_colors, bonds_visible = self.selected_bonds_visible) elif draw_mode == "points" : @@ -147,7 +182,7 @@ # VIEWER CLASS class selection_editor_mixin (model_viewer_mixin) : mouse_modes = ["Rotate view", "Toggle chain", "Toggle residue", - "Toggle atom", "Select range", "Deselect range"] #, "Show selection menu"] + "Toggle atom", "Select range", "Deselect range", "Select single residue"] #, "Show selection menu"] def __init__ (self, *args, **kwds) : self.left_button_mode = 0 self.flag_select_all_conformers = True @@ -222,17 +257,38 @@ elif key == 27 : # escape self.clear_selections() self.update_scene = True - model_viewer_mixin.process_key_stroke(self,key) + else : + return model_viewer_mixin.process_key_stroke(self,key) + return True def set_left_button_mode (self, mode) : self.left_button_mode = mode self._in_range_selection = False + def show_all_selected_atoms (self, show=True) : + for object_id, scene in self.scene_objects.iteritems() : + scene.flag_show_all_selected_atoms = show + + def highlight_selection (self, object_id, selection_string) : + for model_id, model in self.iter_models() : + if object_id is None or model_id == object_id : + model.highlight_atoms(selection_string) + self.update_scene = True + + def clear_highlights (self) : + for model_id, model in self.iter_models() : + model.highlight_atoms(None) + self.update_scene = True + #--------------------------------------------------------------------- def set_selection_callback (self, callback) : assert hasattr(callback, "__call__") self._callback = callback + def set_overwrite_mode (self, overwrite=True) : + for model_id, model in self.iter_models() : + model.set_overwrite_mode(overwrite) + def pick_selection_object (self, object_id) : for model_id in self.pick_object : if model_id == object_id : @@ -249,20 +305,20 @@ model = self.get_model(self.current_object_id) if model is not None : model.toggle_chain_selection(self.current_atom_i_seq) - self.update_scene = True + return True def toggle_residue_selection (self) : model = self.get_model(self.current_object_id) if model is not None : model.toggle_residue_selection(self.current_atom_i_seq, ignore_altloc=self.flag_select_all_conformers) - self.update_scene = True + return True def toggle_atom_selection (self) : model = self.get_model(self.current_object_id) if model is not None : model.toggle_atom_selection(self.current_atom_i_seq) - self.update_scene = True + return True def process_range_selection (self, deselect=False) : model = self.get_model(self.current_object_id) @@ -276,8 +332,17 @@ else : model.start_range_selection(self.current_atom_i_seq) self._in_range_selection = True - self.update_scene = True + return True + def processes_range_deselection (self) : + self.process_range_selection(deselect=True) + + def select_single_residue (self) : + model = self.get_model(self.current_object_id) + if model is not None : + model.select_single_residue(self.current_atom_i_seq) + return True + # TODO: finish this? def context_selection_menu (self) : menu = wx.Menu() @@ -294,18 +359,19 @@ if (self.closest_point_i_seq is not None and self.flag_enable_mouse_selection) : self.save_selected_atom() - if self.left_button_mode == 1 : # (de)select chain - self.toggle_chain_selection() - elif self.left_button_mode == 2 : # (de)select residue - self.toggle_residue_selection() - elif self.left_button_mode == 3 : # (de)select atom - self.toggle_atom_selection() - elif self.left_button_mode == 4 : # select range - self.process_range_selection() - elif self.left_button_mode == 5 : # deselect range - self.process_range_selection(deselect=True) - else: # Selection menu - self.context_selection_menu() + methods = ["toggle_chain_selection", + "toggle_residue_selection", + "toggle_atom_selection", + "process_range_selection", + "process_range_deselection", + "select_single_residue", + "context_selection_menu",] + for i, method in enumerate(methods) : + if self.left_button_mode == (i + 1) : + print "%s()" % method + self.update_scene = getattr(self, method).__call__() + self.show_all_selected_atoms(method == "select_single_residue") + break def OnDoubleClick (self, event) : if self.left_button_mode == 0 : This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <nat...@us...> - 2010-02-23 01:09:21
|
Revision: 10317 http://cctbx.svn.sourceforge.net/cctbx/?rev=10317&view=rev Author: natechols Date: 2010-02-23 01:09:15 +0000 (Tue, 23 Feb 2010) Log Message: ----------- more changes for sec. str. editor in phenix Modified Paths: -------------- trunk/crys3d/reverse_selection.py trunk/crys3d/wx_selection_editor.py Modified: trunk/crys3d/reverse_selection.py =================================================================== --- trunk/crys3d/reverse_selection.py 2010-02-23 01:09:05 UTC (rev 10316) +++ trunk/crys3d/reverse_selection.py 2010-02-23 01:09:15 UTC (rev 10317) @@ -143,14 +143,15 @@ #--- self.clear_selection() - def clear_selection (self) : + def clear_selection (self, apply_empty=True) : self.selected_chains = {} self.deselected_chains = {} self.selected_atoms = [] self.deselected_atoms = [] self.selected_residues = [] self.deselected_residues = [] - self.apply_selection("none") #self.saved_selection) + if apply_empty : + self.apply_selection("none") #self.saved_selection) def selection_size (self) : return self.selection_i_seqs.size() @@ -198,6 +199,8 @@ self.start_i_seq = None def start_range_selection (self, i_seq) : + if self.flag_overwrite_mode : + self.clear_selection(apply_empty=False) self.start_i_seq = i_seq def end_range_selection (self, i_seq, deselect, ignore_altloc) : @@ -295,8 +298,10 @@ atom.altloc) resi_sel = self.selection_cache.selection(str(resi_info)) if self.flag_overwrite_mode : - pass - if True : #else : + self.clear_selection(apply_empty=False) + if not self.atom_selection.all_eq(resi_sel) : + self.selected_residues.append(resi_info) + else : if self.atom_selection.is_super_set(resi_sel) : self.deselected_residues.append(resi_info) self.remove_redundant_residues(resi_sel, self.selected_residues) Modified: trunk/crys3d/wx_selection_editor.py =================================================================== --- trunk/crys3d/wx_selection_editor.py 2010-02-23 01:09:05 UTC (rev 10316) +++ trunk/crys3d/wx_selection_editor.py 2010-02-23 01:09:15 UTC (rev 10317) @@ -31,6 +31,7 @@ def __init__ (self, *args, **kwds) : self.flag_show_selection = True self.flag_allow_selection = True + self.flag_show_all_selected_atoms = False self._cached_colors = None mouse_selection_manager.__init__(self) model_data.__init__(self, *args, **kwds) @@ -52,6 +53,7 @@ visibility=self.visibility, noncovalent_bonds=self.noncovalent_bonds, atomic_bonds=atomic_bonds) + scene.flag_show_all_selected_atoms = self.flag_show_all_selected_atoms self.update_scene_data(scene) return scene @@ -266,8 +268,12 @@ self._in_range_selection = False def show_all_selected_atoms (self, show=True) : + #self.flag_show_all_selected_atoms = show + for model_id, model in self.iter_models() : + model.flag_show_all_selected_atoms = show for object_id, scene in self.scene_objects.iteritems() : scene.flag_show_all_selected_atoms = show + self.update_scene = True def highlight_selection (self, object_id, selection_string) : for model_id, model in self.iter_models() : @@ -368,9 +374,9 @@ "context_selection_menu",] for i, method in enumerate(methods) : if self.left_button_mode == (i + 1) : - print "%s()" % method self.update_scene = getattr(self, method).__call__() - self.show_all_selected_atoms(method == "select_single_residue") + if method == "select_single_residue" : + self.show_all_selected_atoms() break def OnDoubleClick (self, event) : This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |