""" qtgui/ContourSliceDialog.py: CCP4MG Molecular Graphics Program Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009-2010 University of York This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, modified in accordance with the provisions of the license to address the requirements of UK law. You should have received a copy of the modified GNU Lesser General Public License along with this library. If not, copies may be downloaded from http://www.ccp4.ac.uk/ccp4license.php This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. """ """ Contour slice details dialog. """ import MGSimpleDialog from PyQt4 import QtGui,QtCore import mgWidgets from global_definitions import * import MapPlane class MapSliceSpecifyingSelector(QtGui.QDialog): def __init__(self,parent=None): QtGui.QDialog.__init__(self,parent) self.specifying_layout = QtGui.QGridLayout() plane_defn_label = QtGui.QLabel(self.tr("Plane definition")) self.A_edit = QtGui.QLineEdit("1.0") self.B_edit = QtGui.QLineEdit("0.0") self.C_edit = QtGui.QLineEdit("0.0") self.D_edit = QtGui.QLineEdit("0.0") self.planeA_validator = QtGui.QDoubleValidator(-1000.0,1000.0,3,self.A_edit) self.planeB_validator = QtGui.QDoubleValidator(-1000.0,1000.0,3,self.B_edit) self.planeC_validator = QtGui.QDoubleValidator(-1000.0,1000.0,3,self.C_edit) self.planeD_validator = QtGui.QDoubleValidator(-1000.0,1000.0,3,self.D_edit) self.A_edit.setValidator(self.planeA_validator) self.B_edit.setValidator(self.planeB_validator) self.C_edit.setValidator(self.planeC_validator) self.D_edit.setValidator(self.planeD_validator) self.specifying_layout.addWidget(plane_defn_label,0,0) self.specifying_layout.addWidget(self.A_edit,0,1) self.specifying_layout.addWidget(self.B_edit,0,2) self.specifying_layout.addWidget(self.C_edit,0,3) self.specifying_layout.addWidget(self.D_edit,0,4) self.setLayout(self.specifying_layout) class MapSliceFaceSelector(QtGui.QDialog): def __init__(self,parent=None): QtGui.QDialog.__init__(self,parent) self.crystal_layout = QtGui.QGridLayout() crystal_face_label = QtGui.QLabel(self.tr("Crystal face")) data_label = QtGui.QLabel(self.tr("of crystal")) self.crystal_face_combo = QtGui.QComboBox() self.crystal_face_combo.addItem("ab") self.crystal_face_combo.addItem("ac") self.crystal_face_combo.addItem("bc") self.crystal_data_dataCombo = QtGui.QComboBox() for item in get_dataobj(object_type='MapData'): self.crystal_data_dataCombo.addItem("Map: "+item.name) for item in get_dataobj(object_type='MolData'): if hasattr(item,'originalSymmetry'): self.crystal_data_dataCombo.addItem("Mol: "+item.name) self.crystal_layout.addWidget(crystal_face_label,0,0) self.crystal_layout.addWidget(self.crystal_face_combo,0,1) self.crystal_layout.addWidget(data_label,1,0) self.crystal_layout.addWidget(self.crystal_data_dataCombo,1,1) self.setLayout(self.crystal_layout) class MapSliceAtomSelector(QtGui.QDialog): def __init__(self,parent=None): QtGui.QDialog.__init__(self,parent) self.main_layout = QtGui.QVBoxLayout() self.atoms_layout = QtGui.QGridLayout() atom_label_1 = QtGui.QLabel(self.tr("1st Atom")) atom_label_2 = QtGui.QLabel(self.tr("2nd Atom")) atom_label_3 = QtGui.QLabel(self.tr("3rd Atom")) self.atoms_layout.addWidget(atom_label_1,0,0) self.atoms_layout.addWidget(atom_label_2,1,0) self.atoms_layout.addWidget(atom_label_3,2,0) self.atom_sel_1 = mgWidgets.mgAtomPicker() self.atom_sel_2 = mgWidgets.mgAtomPicker() self.atom_sel_3 = mgWidgets.mgAtomPicker() self.atoms_layout.addWidget(self.atom_sel_1,0,1) self.atoms_layout.addWidget(self.atom_sel_2,1,1) self.atoms_layout.addWidget(self.atom_sel_3,2,1) label = QtGui.QLabel('Draw plane through',self) self.atom_spec_combo = QtGui.QComboBox() for item in MapPlane.MapPlane.selection_mode_menu: self.atom_spec_combo.addItem(self.tr(item)) self.atoms_layout.setContentsMargins(0,0,0,0) self.main_layout.addLayout(self.atoms_layout) self.spec_layout = QtGui.QHBoxLayout() self.spec_layout.setContentsMargins(0,0,0,0) self.spec_layout.addWidget(label) self.spec_layout.addWidget(self.atom_spec_combo) self.spec_layout.addStretch(2) self.main_layout.addLayout(self.spec_layout) self.setLayout(self.main_layout) class ContourSliceDialog(MGSimpleDialog.MultiDialog): def hideWidgets(self,layout): for i in range(layout.count()): item = layout.itemAt(i) if hasattr(item,"widget") and callable(item.widget): widget = item.widget() if hasattr(widget,"hide") and callable(widget.hide): widget.hide() def showWidgets(self,layout): for i in range(layout.count()): item = layout.itemAt(i) if hasattr(item,"widget") and callable(item.widget): widget = item.widget() if hasattr(widget,"show") and callable(widget.show): widget.show() def __init__(self,parent=None): MGSimpleDialog.MultiDialog.__init__(self,parent) self.setWindowTitle(self.tr("Contour Slice Details")) self.CreateMenuEntry() mainLayout = QtGui.QVBoxLayout() space_label = QtGui.QLabel(self.tr("Contour spacing")) spaceLayout = QtGui.QHBoxLayout() spaceLayout.addWidget(space_label) self.contour_spacing_edit = QtGui.QLineEdit() self.contour_validator = QtGui.QDoubleValidator(0.0,1000.0,3,self.contour_spacing_edit) self.contour_spacing_edit.setText("1.0") self.contour_spacing_edit.setValidator(self.contour_validator) spaceLayout.addWidget(self.contour_spacing_edit) units_label = QtGui.QLabel(u"\u212B") spaceLayout.addWidget(units_label) plane_label = QtGui.QLabel(self.tr("Define plane")) self.tabWidget = QtGui.QTabWidget() mainLayout.addWidget(self.tabWidget) self.specifying_layout = MapSliceSpecifyingSelector() specifying_layout_layout = QtGui.QVBoxLayout() #Oh dear, need to rename members... specifying_layout_layout.addWidget(self.specifying_layout) specifying_layout_layout.addStretch(2) self.specifying_widget = QtGui.QWidget() self.specifying_widget.setLayout(specifying_layout_layout) self.atoms_layout = MapSliceAtomSelector() self.crystal_layout = MapSliceFaceSelector() crystal_layout_layout = QtGui.QGridLayout() #Oh dear, need to rename members... crystal_layout_layout.addWidget(self.crystal_layout,0,1) crystal_layout_layout.setColumnStretch(0,2) crystal_layout_layout.setColumnStretch(2,2) crystal_layout_layout.setRowStretch(1,2) self.crystal_widget = QtGui.QWidget() self.crystal_widget.setLayout(crystal_layout_layout) self.tabWidget.addTab(self.specifying_widget,self.tr("specifying plane")) self.tabWidget.addTab(self.atoms_layout,self.tr("through selected atoms")) self.tabWidget.addTab(self.crystal_widget,self.tr("parallel to crystal face")) raise_pretext = QtGui.QLabel(self.tr("Raise plane by ")) raise_posttext = QtGui.QLabel(u"\u212B") self.raise_plane = QtGui.QLineEdit() self.raise_plane_validator = QtGui.QDoubleValidator(-1000.0,1000.0,3,self.raise_plane) self.raise_plane.setText("1.0") self.raise_plane.setValidator(self.raise_plane_validator) raiseLayout = QtGui.QHBoxLayout() raiseLayout.addWidget(raise_pretext) raiseLayout.addWidget(self.raise_plane) raiseLayout.addWidget(raise_posttext) raiseLayout.addStretch(2) spaceLayout.addStretch(2) mainLayout.addLayout(raiseLayout) self.camera_check = QtGui.QCheckBox(self.tr("Set camera perpendicular to this plane")) mainLayout.addWidget(self.camera_check) mainLayout.addLayout(spaceLayout) dialog_buttons = QtGui.QDialogButtonBox() ok_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Ok) apply_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Apply) cancel_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Cancel) self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.Close) self.connect(ok_button,QtCore.SIGNAL('clicked()'),self.ApplyAndClose) self.connect(apply_button,QtCore.SIGNAL('clicked()'),self.Apply) mainLayout.addWidget(dialog_buttons) self.setLayout(mainLayout) self.setSizeGripEnabled(1) self.UnClose() #? def Apply(self): self.emit(QtCore.SIGNAL('apply')) return plane = None raise_plane = float(self.raise_plane.text()) import pygl_coord if self.tabWidget.tabText(self.tabWidget.currentIndex()) == self.tr("specifying plane"): plane = pygl_coord.Plane(float(self.specifying_layout.A_edit.text()),float(self.specifying_layout.B_edit.text()),float(self.specifying_layout.C_edit.text()),float(self.specifying_layout.D_edit.text())) self.emit(QtCore.SIGNAL("PlaneChanged"),(plane)) plane.Normalize() orig_D = plane.get_D() new_D = orig_D + raise_plane plane.set_D(new_D) print plane.get_A(),plane.get_B(),plane.get_C(),plane.get_D() if self.tabWidget.tabText(self.tabWidget.currentIndex()) == self.tr("through selected atoms"): print "Through atoms" at1 = None at2 = None at3 = None dataName,model,chain,residue,atom = str(self.atoms_layout.atom_sel_1.selection()).split('/') print dataName,model,chain,residue,atom data = get_dataobj(name=dataName,object_type='MolData') if len(data)==1 and data[0] and hasattr(data[0],'interpretAtomID'): atomid = "/"+model+"/"+chain+"/"+residue+"/"+atom at1 = data[0].interpretAtomID(data[0],atomid) dataName,model,chain,residue,atom = str(self.atoms_layout.atom_sel_2.selection()).split('/') print dataName,model,chain,residue,atom data = get_dataobj(name=dataName,object_type='MolData') if len(data)==1 and data[0] and hasattr(data[0],'interpretAtomID'): atomid = "/"+model+"/"+chain+"/"+residue+"/"+atom at2 = data[0].interpretAtomID(data[0],atomid) dataName,model,chain,residue,atom = str(self.atoms_layout.atom_sel_3.selection()).split('/') print dataName,model,chain,residue,atom data = get_dataobj(name=dataName,object_type='MolData') if len(data)==1 and data[0] and hasattr(data[0],'interpretAtomID'): atomid = "/"+model+"/"+chain+"/"+residue+"/"+atom at3 = data[0].interpretAtomID(data[0],atomid) if not at1 or not at2 or not at3: return cart1 = pygl_coord.Cartesian(at1.x,at1.y,at1.z) cart2 = pygl_coord.Cartesian(at2.x,at2.y,at2.z) cart3 = pygl_coord.Cartesian(at3.x,at3.y,at3.z) if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through all atoms"): pass if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atoms 1 and 2"): cross = pygl_coord.Cartesian.CrossProduct(cart1-cart3,cart2-cart3) cart3 = cart1 + cross if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atoms 1 and 3"): cross = pygl_coord.Cartesian.CrossProduct(cart1-cart2,cart3-cart2) cart2 = cart1 + cross if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atoms 2 and 3"): cross = pygl_coord.Cartesian.CrossProduct(cart2-cart1,cart3-cart1) cart1 = cart2 + cross if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atom 1, perpendicular to 2, 3"): up = pygl_coord.Cartesian.CrossProduct(cart1-cart2,cart1-cart3) up.normalize() forward = cart1-pygl_coord.Cartesian.MidPoint(cart2,cart3) forward.normalize() right = pygl_coord.Cartesian.CrossProduct(up,forward) cart2 = cart1 + up cart3 = cart1 + forward if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atom 1, parallel to 2, 3"): up = pygl_coord.Cartesian.CrossProduct(cart1-cart2,cart1-cart3) up.normalize() forward = cart1-pygl_coord.Cartesian.MidPoint(cart2,cart3) forward.normalize() right = pygl_coord.Cartesian.CrossProduct(up,forward) cart2 = cart1 + up cart3 = cart1 + right if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atom 2, perpendicular to 1, 3"): up = pygl_coord.Cartesian.CrossProduct(cart2-cart1,cart2-cart3) up.normalize() forward = cart2-pygl_coord.Cartesian.MidPoint(cart1,cart3) forward.normalize() right = pygl_coord.Cartesian.CrossProduct(up,forward) cart1 = cart2 + up cart3 = cart2 + forward if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atom 2, parallel to 1, 3"): up = pygl_coord.Cartesian.CrossProduct(cart2-cart1,cart2-cart3) up.normalize() forward = cart2-pygl_coord.Cartesian.MidPoint(cart1,cart3) forward.normalize() right = pygl_coord.Cartesian.CrossProduct(up,forward) cart1 = cart2 + up cart3 = cart2 + right if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atom 3, perpendicular to 1, 2"): up = pygl_coord.Cartesian.CrossProduct(cart3-cart2,cart3-cart1) up.normalize() forward = cart3-pygl_coord.Cartesian.MidPoint(cart1,cart2) forward.normalize() right = pygl_coord.Cartesian.CrossProduct(up,forward) cart1 = cart3 + up cart2 = cart3 + forward if self.atoms_layout.atom_spec_combo.currentText() == self.tr("Through atom 3, parallel to 1, 2"): up = pygl_coord.Cartesian.CrossProduct(cart3-cart2,cart3-cart1) up.normalize() forward = cart3-pygl_coord.Cartesian.MidPoint(cart1,cart2) forward.normalize() right = pygl_coord.Cartesian.CrossProduct(up,forward) cart1 = cart3 + up cart2 = cart3 + right plane = pygl_coord.Plane(cart1,cart2,cart3) plane.Normalize() orig_D = plane.get_D() new_D = orig_D + raise_plane plane.set_D(new_D) print plane.get_A(),plane.get_B(),plane.get_C(),plane.get_D() self.emit(QtCore.SIGNAL("PlaneChanged"),(plane)) if self.tabWidget.tabText(self.tabWidget.currentIndex()) == self.tr("parallel to crystal face"): if len(self.crystal_layout.crystal_data_dataCombo.currentText())<6: return name = str(self.crystal_layout.crystal_data_dataCombo.currentText())[5:] items = get_dataobj(object_type='MolData') map_items = get_dataobj(object_type='MapData') items.extend(map_items) for item in items: if item.name == name: molobj_list = get_dataobj(name=item.name) for obj in molobj_list[0].objinsts: if obj.graphmod: if str(self.crystal_layout.crystal_face_combo.currentText()) == "ab": q = obj.graphmod.obj.GetUnitCellAlignmentRotation("C") elif str(self.crystal_layout.crystal_face_combo.currentText()) == "ac": q = obj.graphmod.obj.GetUnitCellAlignmentRotation("B") elif str(self.crystal_layout.crystal_face_combo.currentText()) == "bc": q = obj.graphmod.obj.GetUnitCellAlignmentRotation("A") else: q = None if q: quat = pygl_coord.QuatPtr(q) zaxis = pygl_coord.Cartesian(0,0,1) norm = pygl_coord.CartesianPtr(quat.getInvMatrix() * zaxis) # SJM 8/2/2010, this is to fix probable hackery below. plane = pygl_coord.Plane(norm.get_x(),norm.get_y(),norm.get_z(),0) self.emit(QtCore.SIGNAL("PlaneChanged"),(plane)) break if self.camera_check.checkState()>0 and plane: import math plane_norm = pygl_coord.Cartesian(plane.get_A(),plane.get_B(),plane.get_C()) zaxis = pygl_coord.Cartesian(0.0, 0.0, 1.0); cross = zaxis.CrossProduct(plane_norm,zaxis); if abs(cross.get_x()*cross.get_x()+cross.get_y()*cross.get_y()+cross.get_z()*cross.get_z()>1.0e-6) : angle = math.acos(abs(plane.get_C())) if plane.get_C()>0.0: angle = -angle rotquat = pygl_coord.Quat(cross.get_x(),cross.get_y(),cross.get_z(),1,-angle*180.0/math.pi); MAINWINDOW().setQuat(rotquat) else: rotquat = pygl_coord.Quat(0.0,0.0,0.0,0) MAINWINDOW().setQuat(rotquat) def ApplyAndClose(self): self.Apply() self.Close() def getParams(self): params = {} params['plane_mode'] = ['plane','selection','crystal_face'][self.tabWidget.currentIndex()] try: params['selection1'] = self.atoms_layout.atom_sel_1.modelNameAtomName() params['selection2'] = self.atoms_layout.atom_sel_2.modelNameAtomName() params['selection3'] = self.atoms_layout.atom_sel_3.modelNameAtomName() except: params['selection1'] = "None" params['selection2'] = "None" params['selection3'] = "None" sele_mode = str(self.atoms_layout.atom_spec_combo.currentText()) if MapPlane.MapPlane.selection_mode_menu.count(sele_mode): params['selection_mode'] = MapPlane.MapPlane.selection_mode_alias[MapPlane.MapPlane.selection_mode_menu.index(sele_mode)] # Sanity check - three different atoms - could relax this for some of # the selection_mode if params['plane_mode'] == 'selection': err = 0 for s1,s2 in [ ['selection1','selection2'], ['selection1','selection3'], ['selection2','selection3'] ] : if params[s1]==params[s2]: err = err+1 if err: QtGui.QMessageBox.warning(self,'Error in Contour Slice Details','Please select three different atoms.') return {} params['specify_plane_A'] = float(self.specifying_layout.A_edit.text()) params['specify_plane_B'] = float(self.specifying_layout.B_edit.text()) params['specify_plane_C'] = float(self.specifying_layout.C_edit.text()) params['specify_plane_D'] = float(self.specifying_layout.D_edit.text()) params['crystal_face'] = str(self.crystal_layout.crystal_face_combo.currentText()) if len(self.crystal_layout.crystal_data_dataCombo.currentText())>=6: params['crystal'] = str(self.crystal_layout.crystal_data_dataCombo.currentText()[5:]) params['raise_plane'] = float(self.raise_plane.text()) params['set_camera'] = int(self.camera_check.checkState()) params['contour_spacing'] = float(self.contour_spacing_edit.text()) #print "getParams",params return params def setParams(self,params): print "ContourSliceDialog.setParams",params if params.has_key('raise_plane'): self.raise_plane.setText(str(params['raise_plane'])) if params.has_key('contour_spacing'): self.contour_spacing_edit.setText(str(params['contour_spacing'])) if params.has_key('set_camera'): self.camera_check.setChecked(params['set_camera']) if params.has_key('specify_plane_A'): self.specifying_layout.A_edit.setText(str(params.get('specify_plane_A',1.0))) self.specifying_layout.B_edit.setText(str(params.get('specify_plane_B',0.0))) self.specifying_layout.C_edit.setText(str(params.get('specify_plane_C',0.0))) self.specifying_layout.D_edit.setText(str(params.get('specify_plane_D',0.0))) if params.has_key('selection1') and len(params['selection1'])>1: self.atoms_layout.atom_sel_1.setSelection(params['selection1'][0],params['selection1'][1]) if params.has_key('selection2') and len(params['selection2'])>1: self.atoms_layout.atom_sel_2.setSelection(params['selection2'][0],params['selection2'][1]) if params.has_key('selection3') and len(params['selection3'])>1: self.atoms_layout.atom_sel_3.setSelection(params['selection3'][0],params['selection3'][1]) if params.has_key('crystal_face'): for i in range(self.crystal_layout.crystal_face_combo.count()): if str(params["crystal_face"]) == str(self.crystal_layout.crystal_face_combo.itemText(i)): self.crystal_layout.crystal_face_combo.setCurrentIndex(i) break if params.has_key('plane_mode'): if params['plane_mode'] == "plane": self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.specifying_widget)) if params['plane_mode'] == "selection": self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.atoms_layout)) if params['plane_mode'] == "crystal_face": self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.crystal_widget)) if params.has_key('selection_mode'): if params['selection_mode'] in MapPlane.MapPlane.selection_mode_alias: idx = MapPlane.MapPlane.selection_mode_alias.index(params['selection_mode']) self.atoms_layout.atom_spec_combo.setCurrentIndex(idx) if params.has_key('crystal'): for i in range(self.crystal_layout.crystal_data_dataCombo.count()): if "Map: "+str(params["crystal"]) == str(self.crystal_layout.crystal_data_dataCombo.itemText(i)): self.crystal_layout.crystal_data_dataCombo.setCurrentIndex(i) break if "Mol: "+str(params["crystal"]) == str(self.crystal_layout.crystal_data_dataCombo.itemText(i)): self.crystal_layout.crystal_data_dataCombo.setCurrentIndex(i) break