"""
Classes and functions that are shared between the Glide GridGen and Docking
panels.
Copyright Schrodinger, LLC. All rights reserved.
"""
#Contributors: Matvey Adzhigirey
import schrodinger
from schrodinger.structutils import analyze
from schrodinger.ui.qt.appframework2.markers import MarkerMixin
maestro = schrodinger.get_maestro()
try:
from schrodinger.graphics3d import sphere
except ImportError:
sphere = None
[docs]def find_equivalent_atoms(st, anum):
"""
Given a structure atom, return a list of atoms that are identical
to it. If no identical atoms are found, and empty list is returned.
"""
for atoms in analyze.find_equivalent_atoms(st, span_molecules=False):
if anum in atoms:
atoms.remove(anum)
return atoms
return []
[docs]class GlideWorkspaceMarkers(MarkerMixin):
"""
Class for marking constraints and excluded volumes in the Workspace. Along
with the marker, optional labels are also drawn.
"""
[docs] def __init__(self):
super().__init__()
self._shown = True
self._labels_shown = True
self._marker_group = sphere.Group()
# List of (label object, entry ID, atom number by entry). For labels
# not associated with atoms, entry ID and atom number are None.
self._label_info = []
maestro.workspace_changed_function_add(self._workspaceChangedCallback)
def __del__(self):
self.clear()
maestro.workspace_changed_function_remove(
self._workspaceChangedCallback)
[docs] def clear(self):
"""
Remove all added labels.
"""
self._marker_group.clear()
# Clear atom markers:
self.removeAllMarkers()
# Clear labels:
for obj_handle, _, _ in self._label_info:
maestro.remove_object(obj_handle)
self._label_info = []
[docs] def add(self,
center=None,
radius=None,
atom=None,
color=None,
name=None,
opacity=0.8):
"""
Add another marker to draw.
Either center and radius need to be specified (to draw a sphere) or an
atom object (to draw atom markers).
"""
if center is None and not atom:
raise ValueError(
"Must specify a center coordinate or an atom object.")
if center is not None and radius:
x, y, z = center[:3]
sphere_obj = sphere.MaestroSphere(
x=x,
y=y,
z=z,
radius=radius,
opacity=opacity,
color=color,
)
self._marker_group.add(sphere_obj)
elif atom:
self.addMarker([atom], color=color)
# TODO consider using self.addAtomMarker()
if name:
if center is None:
center = atom.xyz
obj_handle = maestro.create_single_line_text(name, *center)
if atom:
self._label_info.append(
(obj_handle, atom.entry_id, atom.number_by_entry))
else:
self._label_info.append((obj_handle, None, None))
if not self._shown or not self._labels_shown:
maestro.hide_object(obj_handle)
if self._shown:
self.show()
[docs] def show(self):
"""
Show the markers in the Workspace.
"""
self._shown = True
self._marker_group.show()
self.showAllMarkers()
if self._labels_shown:
self._showDesiredLabels()
[docs] def hide(self):
"""
Hide the markers from the Workspace.
"""
self._shown = False
self._marker_group.hide()
self.hideAllMarkers()
for obj_handle, _, _ in self._label_info:
maestro.hide_object(obj_handle)
[docs] def setVisible(self, visible):
"""
Show the markers if "visible" is True, hide otherwise.
"""
if visible:
self.show()
else:
self.hide()
[docs] def showLabels(self):
"""
Enable labels.
"""
self._labels_shown = True
if self._shown:
self._showDesiredLabels()
def _showDesiredLabels(self):
"""
Show labels for markers - except those whose atoms are no
longer present in the Workspace.
"""
# Show atoms for atoms that were included, and hide labels for
# atoms that were excluded:
st = maestro.workspace_get()
for label_obj, eid, anum in self._label_info:
if eid is not None:
asl = f'(entry.id {eid} AND atom.entrynum {anum})'
if analyze.evaluate_asl(st, asl):
maestro.show_object(label_obj)
else:
maestro.hide_object(label_obj)
else:
# This label is not associated with an atom; always show it
maestro.show_object(label_obj)
[docs] def hideLabels(self):
"""
Disable labels.
"""
self._labels_shown = False
for obj_handle, _, _ in self._label_info:
maestro.hide_object(obj_handle)
[docs] def setLabelsVisible(self, visible):
"""
Show the labels if "visible" is True, hide otherwise.
"""
if visible:
self.showLabels()
else:
self.hideLabels()
def _workspaceChangedCallback(self, what_changed):
"""
Workspace changed callback for hiding labels when marked atoms are
excluded from the Workspace, and re-showing them when the are
re-included. This is already done for marker objects themselves
by the MarkerMixin.
"""
if what_changed not in (maestro.WORKSPACE_CHANGED_EVERYTHING,
maestro.WORKSPACE_CHANGED_APPEND,
maestro.WORKSPACE_CHANGED_CONNECTIVITY):
return
if self._shown and self._labels_shown:
# Show labels, only for those atoms that are still in Workspace:
self._showDesiredLabels()