Changeset 4431


Ignore:
Timestamp:
May 24, 2020 5:19:15 PM (16 months ago)
Author:
toby
Message:

new code for locating RBs; redo GUI for RB extractor

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASIIconstrGUI.py

    r4421 r4431  
    1616'''
    1717from __future__ import division, print_function
     18import platform
    1819import sys
    1920import copy
     
    4647WACV = wx.ALIGN_CENTER_VERTICAL
    4748
     49class G2BoolEditor(wg.GridCellBoolEditor):
     50    '''Substitute for wx.grid.GridCellBoolEditor except toggles
     51    grid items immediately when opened, updates grid & table contents after every
     52    item change
     53    '''
     54    def __init__(self):
     55        self.saveVals = None
     56        wx.grid.GridCellBoolEditor.__init__(self)
     57
     58
     59    def Create(self, parent, id, evtHandler):
     60        '''Create the editing control (wx.CheckBox) when cell is opened
     61        for edit
     62        '''
     63        self._tc = wx.CheckBox(parent, -1, "")
     64        self._tc.Bind(wx.EVT_CHECKBOX, self.onCheckSet)
     65        self.SetControl(self._tc)
     66        if evtHandler:
     67            self._tc.PushEventHandler(evtHandler)
     68
     69    def onCheckSet(self, event):
     70        '''Callback used when checkbox is toggled.
     71        Makes change to table immediately (creating event)
     72        '''
     73        if self.saveVals:
     74            self.ApplyEdit(*self.saveVals)
     75
     76       
     77    def SetSize(self, rect):
     78        '''Set position/size the edit control within the cell's rectangle.
     79        '''
     80#        self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2, # older
     81        self._tc.SetSize(rect.x, rect.y, rect.width+2, rect.height+2,
     82                               wx.SIZE_ALLOW_MINUS_ONE)
     83
     84    def BeginEdit(self, row, col, grid):
     85        '''Prepares the edit control by loading the initial
     86        value from the table (toggles it since you would not
     87        click on it if you were not planning to change it),
     88        buts saves the original, pre-change value.
     89        Makes change to table immediately.
     90        Saves the info needed to make updates in self.saveVals.
     91        Sets the focus.
     92        '''
     93        self.startValue = int(grid.GetTable().GetValue(row, col))
     94        self.saveVals = row, col, grid
     95        # invert state and set in editor
     96        if self.startValue:
     97            grid.GetTable().SetValue(row, col, 0)
     98            self._tc.SetValue(0)
     99        else:
     100            grid.GetTable().SetValue(row, col, 1)
     101            self._tc.SetValue(1)
     102        self._tc.SetFocus()
     103        self.ApplyEdit(*self.saveVals)
     104
     105    def EndEdit(self, row, col, grid, oldVal=None):
     106        '''End editing the cell.  This is supposed to
     107        return None if the value has not changed, but I am not
     108        sure that actually works.
     109        '''
     110        val = int(self._tc.GetValue())
     111        if val != oldVal:   #self.startValue:?
     112            return val
     113        else:
     114            return None
     115
     116    def ApplyEdit(self, row, col, grid):
     117        '''Save the value into the table, and create event.
     118        Called after EndEdit(), BeginEdit and onCheckSet.
     119        '''
     120        val = int(self._tc.GetValue())
     121        grid.GetTable().SetValue(row, col, val) # update the table
     122
     123    def Reset(self):
     124        '''Reset the value in the control back to its starting value.
     125        '''
     126        self._tc.SetValue(self.startValue)
     127
     128    def StartingClick(self):
     129        '''This seems to be needed for BeginEdit to work properly'''
     130        pass
     131
     132    def Destroy(self):
     133        "final cleanup"
     134        super(G2BoolEditor, self).Destroy()
     135
     136    def Clone(self):
     137        'required'
     138        return G2BoolEditor()
     139   
    48140class DragableRBGrid(wg.Grid):
    49141    '''Simple grid implentation for display of rigid body positions.
     
    62154        self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.OnRowMove, self)
    63155        self.SetColSize(0, 60)
    64         self.SetColSize(1, 35)
    65         self.SetColSize(5, 40)
     156        self.SetColSize(1, 40)
     157        self.SetColSize(2, 35)
    66158        for r in range(len(rb['RBlbls'])):
    67159            self.SetReadOnly(r,0,isReadOnly=True)
    68             self.SetCellEditor(r,2, wg.GridCellFloatEditor())
     160            self.SetCellEditor(r, 1, G2BoolEditor())           
     161            self.SetCellRenderer(r, 1, wg.GridCellBoolRenderer())
     162            self.SetReadOnly(r,2,isReadOnly=True)
    69163            self.SetCellEditor(r,3, wg.GridCellFloatEditor())
    70164            self.SetCellEditor(r,4, wg.GridCellFloatEditor())
     165            self.SetCellEditor(r,6, wg.GridCellFloatEditor())
    71166
    72167    def OnRowMove(self,evt):
     
    89184    def __init__(self,rb,onChange):
    90185        wg.GridTableBase.__init__(self)
    91         self.colLabels = ['Label','Type','x','y','z','Select']
     186        self.colLabels = ['Label','Select','Type','x','y','z']
    92187        self.coords = rb['RBcoords']
    93188        self.labels = rb['RBlbls']
     
    109204            return self.labels[row]
    110205        elif col == 1:
     206            return int(self.select[row])
     207        elif col == 2:
    111208            return self.types[row]
    112         elif col < 5:
    113             return '{:.5f}'.format(self.coords[row][col-2])
    114         elif col == 5:
    115             return self.select[row]
     209        else:
     210            return '{:.5f}'.format(self.coords[row][col-3])
    116211    def SetValue(self, row, col, value):
    117212        row = self.index[row]
    118         if col == 0:
    119             self.labels[row] = value
    120         elif col == 1:
    121             self.types[row] = value
    122         elif col < 5:
    123             self.coords[row][col-2] = float(value)
    124         elif col == 5:
    125             self.select[row] = value
     213        try:
     214            if col == 0:
     215                self.labels[row] = value
     216            elif col == 1:
     217                self.select[row] = int(value)
     218            elif col == 2:
     219                self.types[row] = value
     220            else:
     221                self.coords[row][col-3] = float(value)
     222        except:
     223            pass
    126224        if self.onChange:
    127225            self.onChange()
    128     # implement boolean for selection
    129     def GetTypeName(self, row, col):
    130         if col==5:
    131             return wg.GRID_VALUE_BOOL
    132         else:
    133             return wg.GRID_VALUE_STRING
    134     def CanGetValueAs(self, row, col, typeName):
    135         if col==5 and typeName != wg.GRID_VALUE_BOOL:
    136             return False
    137         return True
    138 
    139226    # Display column & row labels
    140227    def GetColLabelValue(self, col):
     
    20272114            def onSetAll(event):
    20282115                'Set all atoms as selected'
     2116                grid.completeEdits()
    20292117                for i in range(len(rd.Phase['RBselection'])):
    2030                     rd.Phase['RBselection'][i] = True
     2118                    rd.Phase['RBselection'][i] = 1 # table needs 0/1 for T/F
    20312119                grid.ForceRefresh()
    20322120                UpdateDraw()
     
    20362124                grid.completeEdits()
    20372125                for i in range(len(rd.Phase['RBselection'])):
    2038                     rd.Phase['RBselection'][i] = not rd.Phase['RBselection'][i]
     2126                    rd.Phase['RBselection'][i] = int(not rd.Phase['RBselection'][i])
    20392127                grid.ForceRefresh()
    20402128                UpdateDraw()
     
    20632151                        center += rd.Phase['RBcoords'][i]
    20642152                if not count:
     2153                    G2G.G2MessageBox(G2frame,'No atoms selected',
     2154                                    'Selection required')
    20652155                    return
    2066                 XP = center/count
    2067                 if np.sqrt(sum(XP**2)) < 0.1:
     2156                XYZP = center/count
     2157                if np.sqrt(sum(XYZP**2)) < 0.1:
    20682158                    G2G.G2MessageBox(G2frame,
    20692159                            'The selected atom(s) are too close to the origin',
    20702160                            'near origin')
    20712161                    return
    2072                 XP /= np.sqrt(np.sum(XP**2))
    2073                 Z = np.array((0,0,1.))
    2074                 YP = np.cross(Z,XP)
    2075                 ZP = np.cross(XP,YP)
     2162                if bntOpts['direction'] == 'y':
     2163                    YP = XYZP / np.sqrt(np.sum(XYZP**2))
     2164                    ZP = np.cross((1,0,0),YP)
     2165                    if sum(ZP*ZP) < .1: # pathological condition: Y' along X
     2166                        ZP = np.cross((0,0,1),YP)
     2167                    XP = np.cross(YP,ZP)
     2168                elif bntOpts['direction'] == 'z':
     2169                    ZP = XYZP / np.sqrt(np.sum(XYZP**2))
     2170                    XP = np.cross((0,1,0),ZP)
     2171                    if sum(XP*XP) < .1: # pathological condition: X' along Y
     2172                        XP = np.cross((0,0,1),ZP)
     2173                    YP = np.cross(ZP,XP)
     2174                else:
     2175                    XP = XYZP / np.sqrt(np.sum(XYZP**2))
     2176                    YP = np.cross((0,0,1),XP)
     2177                    if sum(YP*YP) < .1: # pathological condition: X' along Z
     2178                        YP = np.cross((0,1,0),XP)
     2179                    ZP = np.cross(XP,YP)
    20762180                trans = np.array((XP,YP,ZP))
    20772181                # update atoms in place
     
    20802184                UpdateDraw()
    20812185
    2082             def onSetPlane(event):
     2186            def onSetPlane(event): 
    20832187                '''Compute least-squares plane for selected atoms;
    20842188                move atoms so that LS plane aligned with x-y plane,
     
    20862190                '''
    20872191                grid.completeEdits()
    2088                 #X,Y,Z = rd.Phase['RBcoords'][rd.Phase['RBselection']].T
    2089                 XYZ = rd.Phase['RBcoords'][rd.Phase['RBselection']]
    2090                 Z = copy.copy(XYZ[:,2])
    2091                 if len(Z) < 3:
     2192                selList = [i==1 for i in rd.Phase['RBselection']]
     2193                XYZ = rd.Phase['RBcoords'][selList]
     2194                if len(XYZ) < 3:
    20922195                    G2G.G2MessageBox(G2frame,'A plane requires three or more atoms',
    20932196                                     'Need more atoms')
    20942197                    return
    2095                 XY0 = copy.copy(XYZ)
    2096                 XY0[:,2] = 1
     2198                # fit 3 ways (in case of singularity) and take result with lowest residual
     2199                X,Y,Z = [XYZ[:,i] for i in (0,1,2)]
     2200                XZ = copy.copy(XYZ)
     2201                XZ[:,1] = 1
     2202                (a,d,b), resd, rank, sing = nl.lstsq(XZ, -Y)
     2203                resid_min = resd
     2204                normal = a,1,b
     2205                YZ = copy.copy(XYZ)
     2206                YZ[:,0] = 1
     2207                (d,a,b), resd, rank, sing = nl.lstsq(YZ, -X)
     2208                if resid_min > resd:
     2209                    resid_min = resd
     2210                    normal = 1,a,b
     2211                XY = copy.copy(XYZ)
     2212                XY[:,2] = 1
     2213                (a,b,d), resd, rank, sing = nl.lstsq(XY, -Z)
     2214                if resid_min > resd:
     2215                    resid_min = resd
     2216                    normal = a,b,1
    20972217                # solve for  ax + bx + z + c = 0 or equivalently ax + bx + c = -z
    2098                 try:
    2099                     (a,b,c), resd, rank, sing = nl.lstsq(XY0, -Z)
    2100                 except:
    2101                     G2G.G2MessageBox(G2frame,
    2102                             'Error computing plane; are atoms in a line?',
    2103                             'Computation error')
     2218                # try:
     2219                # except:
     2220                #     G2G.G2MessageBox(G2frame,
     2221                #             'Error computing plane; are atoms in a line?',
     2222                #             'Computation error')
     2223                #     return
     2224                if bntOpts['plane'] == 'xy':
     2225                    # new coordinate system is
     2226                    #   ZP, z' normal to plane
     2227                    #   YP, y' = z' cross x (= [0,1,-b])
     2228                    #   XP, x' = (z' cross x) cross z'
     2229                    # this puts XP as close as possible to X with XP & YP in plane
     2230                    ZP = np.array(normal)
     2231                    ZP /= np.sqrt(np.sum(ZP**2))
     2232                    YP = np.cross(ZP,[1,0,0])
     2233                    if sum(YP*YP) < .1: # pathological condition: z' along x
     2234                        YP = np.cross(ZP,[0,1,0])
     2235                    YP /= np.sqrt(np.sum(YP**2))
     2236                    XP = np.cross(YP,ZP)
     2237                elif bntOpts['plane'] == 'yz':
     2238                    # new coordinate system is
     2239                    #   XP, x' normal to plane
     2240                    #   ZP, z' = x' cross y
     2241                    #   YP, y' = (x' cross y) cross x'
     2242                    # this puts y' as close as possible to y with z' & y' in plane
     2243                    XP = np.array(normal)
     2244                    XP /= np.sqrt(np.sum(XP**2))
     2245                    ZP = np.cross(XP,[0,1,0])
     2246                    if sum(ZP*ZP) < .1: # pathological condition: x' along y
     2247                        ZP = np.cross(XP,(0,0,1))
     2248                    ZP /= np.sqrt(np.sum(ZP**2))
     2249                    YP = np.cross(ZP,XP)
     2250                elif bntOpts['plane'] == 'xz':
     2251                    # new coordinate system is
     2252                    #   YP, y' normal to plane
     2253                    #   ZP, z' = x cross y'
     2254                    #   XP, y' = (x cross y') cross z'
     2255                    # this puts XP as close as possible to X with XP & YP in plane
     2256                    YP = np.array(normal)
     2257                    YP /= np.sqrt(np.sum(YP**2))
     2258                    ZP = np.cross([1,0,0],YP)
     2259                    if sum(ZP*ZP) < .1: # pathological condition: y' along x
     2260                        ZP = np.cross([0,1,0],YP)
     2261                    ZP /= np.sqrt(np.sum(ZP**2))
     2262                    XP = np.cross(YP,ZP)
     2263                else:
     2264                    print('unexpected plane',bntOpts['plane'])
    21042265                    return
    2105                 # new coordinate system is z' (zp, normal to plane = [a,b,1]),
    2106                 # y' = z' cross x (YP, = [0,1,-b])
    2107                 # x' = (z' cross x) cross z'
    2108                 # this puts XP as close as possible to X with XP & YP in plane
    2109                 ZP = np.array([a,b,1])
    2110                 ZP /= np.sqrt(np.sum(ZP**2))
    2111                 YP = np.array([0,1,-b])
    2112                 YP /= np.sqrt(np.sum(YP**2))
    2113                 XP = np.cross(YP,ZP)
    21142266                trans = np.array((XP,YP,ZP))
    21152267                # update atoms in place
     
    21842336
    21852337            rd.Phase['RBindex'] = list(range(len(rd.Phase['RBtypes'])))
    2186             rd.Phase['RBselection'] = len(rd.Phase['RBtypes']) * [True]
     2338            rd.Phase['RBselection'] = len(rd.Phase['RBtypes']) * [1]
    21872339            rbData = MakeVectorBody()
    21882340            DrawCallback = G2plt.PlotRigidBody(G2frame,'Vector',
     
    21902342
    21912343            mainSizer = wx.BoxSizer(wx.HORIZONTAL)
    2192             gridSizer = wx.BoxSizer(wx.VERTICAL)
    2193             grid = DragableRBGrid(RBImpPnl,rd.Phase,UpdateDraw)
    2194             gridSizer.Add(grid)
    2195             gridSizer.Add(
     2344            btnSizer = wx.BoxSizer(wx.VERTICAL)
     2345            btnSizer.Add(
    21962346                wx.StaticText(RBImpPnl,wx.ID_ANY,'Reorder atoms by dragging'),
    21972347                0,wx.ALL)
    2198             mainSizer.Add(gridSizer)
    2199             mainSizer.Add((5,5))
    2200             btnSizer = wx.BoxSizer(wx.VERTICAL)
    2201             btn = wx.Button(RBImpPnl, wx.ID_OK, 'Set All')
     2348            btnSizer.Add((-1,15))
     2349            btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Set All')
    22022350            btn.Bind(wx.EVT_BUTTON,onSetAll)
    22032351            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
    2204             btn = wx.Button(RBImpPnl, wx.ID_OK, 'Toggle')
     2352            btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Toggle')
    22052353            btn.Bind(wx.EVT_BUTTON,onToggle)
    22062354            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     
    22102358                0,wx.ALL)
    22112359            btnSizer.Add((-1,5))
    2212             btn = wx.Button(RBImpPnl, wx.ID_OK, 'Set origin')
     2360            btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Set origin')
    22132361            btn.Bind(wx.EVT_BUTTON,onSetOrigin)
    22142362            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
    2215             btn = wx.Button(RBImpPnl, wx.ID_OK, 'Place in xy plane')
     2363
     2364            bntOpts = {'plane':'xy','direction':'x'}
     2365            inSizer = wx.BoxSizer(wx.HORIZONTAL)
     2366            btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Place in plane')
    22162367            btn.Bind(wx.EVT_BUTTON,onSetPlane)
    2217             btnSizer.Add(btn,0,wx.ALIGN_CENTER)
    2218             btn = wx.Button(RBImpPnl, wx.ID_OK, 'Define selection as X')
     2368            inSizer.Add(btn)
     2369            inSizer.Add(G2G.G2ChoiceButton(RBImpPnl,('xy','yz','xz'),
     2370                                           None,None,bntOpts,'plane'))
     2371            btnSizer.Add(inSizer,0,wx.ALIGN_CENTER)
     2372           
     2373            inSizer = wx.BoxSizer(wx.HORIZONTAL)
     2374            btn = wx.Button(RBImpPnl, wx.ID_ANY, 'Define as')
    22192375            btn.Bind(wx.EVT_BUTTON,onSetX)
    2220             btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     2376            inSizer.Add(btn)
     2377            inSizer.Add(G2G.G2ChoiceButton(RBImpPnl,('x','y','z'),
     2378                                           None,None,bntOpts,'direction'))
     2379            btnSizer.Add(inSizer,0,wx.ALIGN_CENTER)
     2380           
    22212381            btnSizer.Add((-1,15))
    22222382            btnSizer.Add(
     
    22242384                0,wx.ALL)
    22252385            btnSizer.Add((-1,5))
    2226             btn = wx.Button(RBImpPnl, wx.ID_OK, 'a Vector Body')
     2386            btn = wx.Button(RBImpPnl, wx.ID_ANY, 'a Vector Body')
    22272387            btn.Bind(wx.EVT_BUTTON,onAddVector)
    22282388            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
    2229             btn = wx.Button(RBImpPnl, wx.ID_OK, 'a Residue Body')
     2389            btn = wx.Button(RBImpPnl, wx.ID_ANY, 'a Residue Body')
    22302390            btn.Bind(wx.EVT_BUTTON,onAddResidue)
    22312391            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     
    22362396
    22372397            mainSizer.Add(btnSizer)
     2398            mainSizer.Add((5,5))
     2399            grid = DragableRBGrid(RBImpPnl,rd.Phase,UpdateDraw)
     2400            mainSizer.Add(grid)
    22382401            RBImpPnl.SetSizer(mainSizer,True)
    22392402            mainSizer.Layout()   
     
    22992462            return rb
    23002463
     2464        # too lazy to figure out why wx crashes
     2465        if wx.__version__.split('.')[0] != '4':
     2466            wx.MessageBox('Sorry, wxPython 4.x is required to run this command',
     2467                                  caption='Update Python',
     2468                                  style=wx.ICON_EXCLAMATION)
     2469            return
     2470        if platform.python_version()[:1] == '2':
     2471            wx.MessageBox('Sorry, Python >=3.x is required to run this command',
     2472                                  caption='Update Python',
     2473                                  style=wx.ICON_EXCLAMATION)
     2474            return
     2475
    23012476        # get importer type and a phase file of that type
    23022477        G2sc.LoadG2fil()
     
    23042479        dlg = G2G.G2SingleChoiceDialog(G2frame,'Select the format of the file',
    23052480                                     'select format',choices)
     2481        dlg.CenterOnParent()
    23062482        try:
    23072483            if dlg.ShowModal() == wx.ID_OK:
  • trunk/GSASIIctrlGUI.py

    r4421 r4431  
    18751875        if self.OnChange:
    18761876            self.OnChange(self.GetSelections(),*self.OnChangeArgs)
    1877         self.SelectList.clear()
     1877        try:
     1878            self.SelectList.clear()
     1879        except:  # patch: clear not in EPD
     1880            for i in reversed((range(len(self.SelectList)))):
     1881                del self.SelectList[i]
    18781882        for i,val in enumerate(self.Selections):
    18791883            if val: self.SelectList.append(i)
     
    33963400    dlg = wx.FileDialog(parent, message, defaultDir, defaultFile, *args,
    33973401                        style=style, **kwargs)
     3402    dlg.CenterOnParent()
    33983403    pth = GetImportPath(G2frame)
    33993404    if not defaultDir and pth: dlg.SetDirectory(pth)
     
    41154120            if colLblCallback: wx.EVT_MOTION(self.GetGridColLabelWindow(), OnMouseMotion)
    41164121            if rowLblCallback: wx.EVT_MOTION(self.GetGridRowLabelWindow(), OnMouseMotion)
    4117                                                    
     4122
     4123    def completeEdits(self):
     4124        'complete any outstanding edits'
     4125        if self.IsCellEditControlEnabled(): # complete any grid edits in progress
     4126            self.SaveEditControlValue()
     4127            #self.HideCellEditControl()
     4128            #self.DisableCellEditControl()
     4129               
    41184130################################################################################           
    41194131class Table(wg.PyGridTableBase):        #TODO: this works in python 3/phoenix but pygridtablebase doesn't exist
  • trunk/GSASIIdataGUI.py

    r4429 r4431  
    60886088        self.DrawAtomEdit.Append(G2G.wxID_DRAWATOMCOLOR,'Atom color','Select atoms first')
    60896089        self.DrawAtomEdit.Append(G2G.wxID_DRAWATOMRESETCOLOR,'Reset atom colors','Resets all atom colors to defaults')
    6090         self.DrawAtomEdit.Append(G2G.wxID_DRWAEDITRADII,'Edit atom radii','Edit drawing atom radii') # TODO: removed until it can be made to do something
     6090#        self.DrawAtomEdit.Append(G2G.wxID_DRWAEDITRADII,'Edit atom radii','Edit drawing atom radii') # TODO: removed until it can be made to do something
    60916091        self.DrawAtomEdit.Append(G2G.wxID_DRAWVIEWPOINT,'View point','View point is 1st atom selected')
    60926092        self.DrawAtomEdit.Append(G2G.wxID_DRAWADDEQUIV,'Add atoms','Add symmetry & cell equivalents to drawing set from selected atoms')
     
    61816181        self.RigidBodiesEdit = wx.Menu(title='')
    61826182        self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit Body')
    6183         self.RigidBodiesEdit.Append(G2G.wxID_ASSIGNATMS2RB,'Assign atoms to rigid body',
    6184             'Select & position rigid body in structure of existing atoms')
     6183        self.RigidBodiesEdit.Append(G2G.wxID_ASSIGNATMS2RB,'Locate && Insert Rigid Body',
     6184            'Locate rigid body in structure mapping to existing atoms')
    61856185        self.RigidBodiesEdit.Append(G2G.wxID_AUTOFINDRESRB,'Auto find residues',
    61866186            'Auto find of residue RBs in macromolecule')
  • trunk/GSASIImath.py

    r4425 r4431  
    984984
    985985def UpdateRBXYZ(Bmat,RBObj,RBData,RBType):
    986     '''default doc string
    987    
    988     :param type name: description
    989    
    990     :returns: type name: description
    991    
    992     '''
    993     ''' returns crystal coordinates for atoms described by RBObj
     986    '''returns crystal coordinates for atoms described by RBObj
     987   
     988    :param np.array Bmat: see :func:`GSASIIlattice.cell2AB`
     989    :param dict rbObj: rigid body selection/orientation information
     990    :param dict RBData: rigid body tree data structure
     991    :param str RBType: rigid body type, 'Vector' or 'Residue'
     992
     993    :returns: coordinates for rigid body as XYZ,Cart where XYZ is
     994       the location in crystal coordinates and Cart is in cartesian
    994995    '''
    995996    RBRes = RBData[RBType][RBObj['RBId']]
  • trunk/GSASIIphsGUI.py

    r4430 r4431  
    4444import subprocess as subp
    4545import distutils.file_util as disfile
     46import scipy.optimize as so
    4647import GSASIIpath
    4748GSASIIpath.SetVersionNumber("$Revision$")
     
    45894590                    fileSizer.Add((5,5),0)
    45904591            return fileSizer
    4591            
     4592       
    45924593        G2frame.GetStatusBar().SetStatusText('',1)
    45934594        if G2frame.RMCchoice == 'RMCProfile':
     
    69886989                            Waves.Add((5,5),0)               
    69896990                        else:
    6990                             waveDel = wx.CheckBox(waveData,label='Delete?')
     6991                            waveDel = wx.Button(waveData,wx.ID_ANY,'Delete',style=wx.BU_EXACTFIT)
    69916992                            Indx[waveDel.GetId()] = [Stype,iwave]
    6992                             waveDel.Bind(wx.EVT_CHECKBOX, OnDelWave)
     6993                            waveDel.Bind(wx.EVT_BUTTON,OnDelWave)
    69936994                            Waves.Add(waveDel,0,WACV)
    69946995                        waveSizer.Add(Waves)                   
     
    92579258               
    92589259            topSizer = wx.FlexGridSizer(0,6,5,5)
    9259             Orig = RBObj['Orig'][0]
     9260            if type(RBObj['Orig'][0]) is tuple:      # patch because somehow adding RB origin is becoming a tuple
     9261                if GSASIIpath.GetConfigValue('debug'): print('patching origin!')
     9262                RBObj['Orig'][0] = list(RBObj['Orig'][0])
    92609263            Orien,OrienV = G2mth.Q2AVdeg(RBObj['Orient'][0])
    92619264            Orien = [Orien,]
    92629265            Orien.extend(OrienV/nl.norm(OrienV))
    92639266            topSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z:'),0,WACV)
    9264             for ix,x in enumerate(Orig):
    9265                 origX = G2G.ValidatedTxtCtrl(RigidBodies,Orig,ix,nDig=(8,5),OnLeave=OnOrigX)
     9267            for ix in range(3):
     9268                origX = G2G.ValidatedTxtCtrl(RigidBodies,RBObj['Orig'][0],ix,nDig=(8,5),
     9269                                    typeHint=float,OnLeave=OnOrigX)
    92669270                topSizer.Add(origX,0,WACV)
    92679271            topSizer.Add((5,0),)
     
    93189322                'Name: '+RBObj['RBname']+RBObj['numChain']+'   '),0,WACV)
    93199323            rbId = RBObj['RBId']
    9320             delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
    9321             delRB.Bind(wx.EVT_CHECKBOX,OnDelResRB)
     9324            delRB = wx.Button(RigidBodies,wx.ID_ANY,'Delete',style=wx.BU_EXACTFIT)
     9325            delRB.Bind(wx.EVT_BUTTON,OnDelResRB)
    93229326            Indx[delRB.GetId()] = rbId
    93239327            topLine.Add(delRB,0,WACV)
     
    93709374                'Name: '+RBObj['RBname']+'   '),0,WACV)
    93719375            rbId = RBObj['RBId']
    9372             delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
    9373             delRB.Bind(wx.EVT_CHECKBOX,OnDelVecRB)
     9376            delRB = wx.Button(RigidBodies,wx.ID_ANY,'Delete',style=wx.BU_EXACTFIT)
     9377            delRB.Bind(wx.EVT_BUTTON,OnDelVecRB)
    93749378            Indx[delRB.GetId()] = rbId
    93759379            topLine.Add(delRB,0,WACV)
     
    94249428        Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Rigid bodies')
    94259429        if not Id:
     9430            G2frame.CheckNotebook()
     9431            Id = G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Rigid bodies')
     9432        if not Id:
     9433            print('Strange! Why no Rigid Bodies tree entry?')
    94269434            return
    94279435        RBData = G2frame.GPXtree.GetItemPyData(Id)
     
    94979505               
    94989506    def OnRBAssign(event):
    9499        
     9507        '''Assign RB to atoms in a phase with tools to locate the RB in the structure
     9508        '''
     9509       
     9510        def assignAtoms(selDict={}):
     9511            '''Find the closest RB atoms to atoms in the structure
     9512            If selDict is specified, it overrides the assignments to specify
     9513            atoms that should be matched.
     9514            '''
     9515            rbType = data['testRBObj']['rbType']
     9516            rbObj = data['testRBObj']['rbObj']
     9517            rbId = rbObj['RBId']
     9518            rbAtmTypes = RBData[rbType][rbId]['rbTypes']
     9519            if 'atNames' in RBData[rbType][rbId]:
     9520                rbAtmLbs = RBData[rbType][rbId]['atNames']
     9521            else:
     9522                rbAtmLbs = None
     9523               
     9524            newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0]
     9525            atmTypes = [atomData[i][ct] for i in range(len(atomData))]
     9526            # remove assigned atoms from search groups
     9527            for i in selDict:
     9528                atmTypes[selDict[i]] = None
     9529            atmXYZ = G2mth.getAtomXYZ(atomData,cx)
     9530            # separate structure's atoms by type (w/o assigned atoms)
     9531            oXYZbyT = {}
     9532            atmNumByT = {}               
     9533            for t in set(atmTypes):
     9534                if t is None: continue
     9535                oXYZbyT[t] = np.array([atmXYZ[i] for i in range(len(atmXYZ)) if atmTypes[i] == t])
     9536                atmNumByT[t] = [i for i in range(len(atmXYZ)) if atmTypes[i] == t]
     9537            Ids = []
     9538            # create table of fixed and found assignments
     9539            matchTable = []
     9540            for i,xyz in enumerate(newXYZ):
     9541                t = rbAtmTypes[i]
     9542                if rbAtmLbs:
     9543                    lbl = rbAtmLbs[i]
     9544                else:
     9545                    lbl = ''
     9546                if i in selDict:
     9547                    searchXYZ = [atmXYZ[selDict[i]]] #assigned
     9548                    numLookup = [selDict[i]]
     9549                else:
     9550                    searchXYZ = oXYZbyT[t]
     9551                    numLookup = atmNumByT[t]
     9552                dist = G2mth.GetXYZDist(xyz,searchXYZ,Amat)
     9553                repeat = True
     9554                while repeat:
     9555                    repeat = False
     9556                    pidIndx = np.argmin(dist)
     9557                    d = dist[pidIndx]
     9558                    pid = numLookup[pidIndx]
     9559                    if atomData[pid][-1] in Ids:   #duplicate - 2 atoms on same site; invalidate & look again
     9560                        repeat = True
     9561                        dist[pidIndx] = 100.
     9562                        if min(dist) == 100:
     9563                            print('no atom matches, how could this happen?')
     9564                            GSASIIpath.IPyBreak()
     9565                            return
     9566                Ids.append(atomData[pid][-1])
     9567                matchTable.append([t , lbl] + list(xyz) + [pid, atomData[pid][0]]
     9568                                      + atomData[pid][cx:cx+3] + [d, Ids[-1]])
     9569            return matchTable
     9570           
     9571        def Draw():
     9572            '''Create the window for assigning RB to atoms'''
     9573            def OnOk(event):
     9574                'respond to OK button, set info into phase'
     9575                matchTable = UpdateTable()
     9576                dmax = 0.
     9577                Ids = []
     9578                for line in matchTable:
     9579                    xyz = line[2:5]
     9580                    pid = line[5]
     9581                    dmax = max(dmax,line[10])
     9582                    atomData[pid][cx:cx+3] = xyz
     9583                    Ids.append(line[11])
     9584                if dmax > 1.0:
     9585                    msg = "Atoms may not be properly located. Are you sure you want to do this?"
     9586                    dlg = wx.MessageDialog(G2frame,msg,caption='Continue?',style=wx.YES_NO|wx.ICON_EXCLAMATION)
     9587                    if dlg.ShowModal() != wx.ID_YES:
     9588                        #OkBtn.SetLabel('Not Ready')
     9589                        #OkBtn.Enable(False)
     9590                        return
     9591                   
     9592                rbType = data['testRBObj']['rbType']
     9593                rbObj['Ids'] = Ids
     9594                rbId = rbObj['RBId']
     9595                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
     9596                rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount'])
     9597                if type(rbObj['Orig'][0]) is tuple:      # patch because somehow adding RB origin is becoming a tuple               
     9598                    if GSASIIpath.GetConfigValue('debug'): print('patching origin!')
     9599                    rbObj['Orig'][0] = list(rbObj['Orig'][0])    # patch: somehow this was getting set as a tuple
     9600                if not rbType in data['RBModels']:
     9601                    data['RBModels'][rbType] = []
     9602                data['RBModels'][rbType].append(rbObj)
     9603                RBData[rbType][rbId]['useCount'] += 1
     9604                del data['testRBObj']
     9605                G2plt.PlotStructure(G2frame,data,False)
     9606                FillRigidBodyGrid(True)
     9607               
     9608            def OnCancel(event):
     9609                del data['testRBObj']
     9610                FillRigidBodyGrid(True)
     9611               
     9612            def OnTorAngle(invalid,value,tc):
     9613                #OkBtn.SetLabel('OK')
     9614                #OkBtn.Enable(True)
     9615                Obj = tc.event.GetEventObject()
     9616                [tor,torSlide] = Indx[Obj.GetId()]
     9617                torSlide.SetValue(int(value*10))
     9618                UpdateTablePlot()
     9619               
     9620            def OnTorSlide(event):
     9621                #OkBtn.SetLabel('OK')
     9622                #OkBtn.Enable(True)
     9623                Obj = event.GetEventObject()
     9624                tor,ang = Indx[Obj.GetId()]
     9625                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
     9626                val = float(Obj.GetValue())/10.
     9627                Tors[0] = val
     9628                ang.SetValue(val)
     9629                UpdateTablePlot()
     9630
     9631            def UpdateTable(event=None):
     9632                '''get fixed atom assignments, find closest mappings &
     9633                update displayed table
     9634                '''
     9635                selDict = getSelectedAtoms()
     9636                matchTable = assignAtoms(selDict)
     9637                for i,l in enumerate(matchTable):
     9638                    RigidBodies.atomsTable.data[i][1:4] = l[5],l[6],l[10]
     9639                RigidBodies.atomsGrid.ForceRefresh()
     9640                return matchTable
     9641               
     9642            def UpdateTablePlot(*args,**kwargs):
     9643                '''update displayed table and plot
     9644                '''
     9645                G2plt.PlotStructure(G2frame,data,False,UpdateTable)
     9646                UpdateTable()
     9647               
     9648            def getSelectedAtoms():
     9649                'Find the FB atoms that have been assigned to specific atoms in structure'
     9650                RigidBodies.atomsGrid.completeEdits()
     9651                tbl = RigidBodies.atomsGrid.GetTable()
     9652                selDict = {}
     9653                dups = []
     9654                assigned = []
     9655                for r in range(tbl.GetRowsCount()):
     9656                    sel = tbl.GetValue(r,4).strip()
     9657                    if sel not in labelsChoices: continue
     9658                    atmNum = labelsChoices.index(sel)-1
     9659                    if atmNum < 0: continue
     9660                    if atmNum in assigned:
     9661                        if sel not in dups:
     9662                            dups.append(sel)
     9663                    else:
     9664                        assigned.append(atmNum)                           
     9665                    selDict[r] = atmNum
     9666                if dups:
     9667                    msg = 'Error: The following atom(s) are assigned multiple times: '
     9668                    for i in dups:
     9669                        msg += i
     9670                        msg += ', '
     9671                    wx.MessageBox(msg[:-2],caption='Duplicated Fixed Atoms',
     9672                                      style=wx.ICON_EXCLAMATION)
     9673                    return
     9674                return selDict
     9675
     9676            def getDeltaXYZ(selDict,data,rbObj):
     9677                '''Evaluate the RB position & return the difference between the coordinates
     9678                and RB coordinates with origin and orientation from data['testRBObj']
     9679                '''
     9680                Amat,Bmat = G2lat.cell2AB(data['General']['Cell'][1:7])
     9681                rbXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,data['testRBObj']['rbData'],data['testRBObj']['rbType'])[0]
     9682                phaseXYZ = G2mth.getAtomXYZ(atomData,cx)
     9683                deltaList = []
     9684                for i in selDict:
     9685                    deltaList.append(phaseXYZ[selDict[i]]-rbXYZ[i])
     9686                return np.array(deltaList)
     9687
     9688            def objectiveDeltaPos(vals,selDict,data,rbObj_in):
     9689                '''Returns a list of distances between atom positions and
     9690                located rigid body positions
     9691
     9692                :param list vals: a 4 or 7 element array with 4 quaterian values
     9693                   or 4 quaterian values followed by 3 origin (x,y,z) values
     9694
     9695                :returns: the 3*n distances between the n selected atoms
     9696                '''
     9697                rbObj = copy.deepcopy(rbObj_in)
     9698                rbObj['Orient'][0][:] = G2mth.normQ(vals[:4])
     9699                if len(vals) == 7:
     9700                    rbObj['Orig'][0][:] = vals[4:]
     9701                #print(np.sqrt(sum(getDeltaXYZ(selDict,data,rbObj).flatten()**2)))
     9702                return getDeltaXYZ(selDict,data,rbObj).flatten()
     9703
     9704            def onSetOrigin(event):
     9705                'Set Origin to best fit selected atoms'
     9706                if rbObj['fixOrig']:
     9707                    wx.MessageBox('Not possible with origin locked',caption='Οrigin Locked',
     9708                                      style=wx.ICON_EXCLAMATION)
     9709                    return
     9710                selDict = getSelectedAtoms()
     9711                if len(selDict) < 1:
     9712                    wx.MessageBox('No atoms were selected',caption='Select Atom(s)',
     9713                                      style=wx.ICON_EXCLAMATION)
     9714                    return
     9715                deltaList = getDeltaXYZ(selDict,data,rbObj)
     9716                data['testRBObj']['rbObj']['Orig'][0][:] = deltaList.sum(axis=0)/len(deltaList)
     9717                for i,item in enumerate(Xsizers):
     9718                    item.SetValue(data['testRBObj']['rbObj']['Orig'][0][i])
     9719                UpdateTablePlot()
     9720               
     9721            def onFitOrientation(event):
     9722                'Set Orientation to best fit selected atoms'
     9723                selDict = getSelectedAtoms()
     9724                if len(selDict) < 2:
     9725                    wx.MessageBox('At least two atoms must be selected',caption='Select Atoms',
     9726                                      style=wx.ICON_EXCLAMATION)
     9727                    return
     9728                vals = rbObj['Orient'][0][:] #+ rbObj['Orig'][0][:]
     9729                out = so.leastsq(objectiveDeltaPos,vals,(selDict,data,rbObj))
     9730                data['testRBObj']['rbObj']['Orient'][0][:] = G2mth.normQ(out[0])
     9731                for i,item in enumerate(Osizers):
     9732                    item.SetLabel('%10.4f'%(data['testRBObj']['rbObj']['Orient'][0][i]))
     9733                UpdateTablePlot()
     9734                # debug code
     9735                #selDict = getSelectedAtoms()
     9736                #for line in assignAtoms(selDict): print(line)
     9737               
     9738            def onFitBoth(event):
     9739                'Set Orientation and origin to best fit selected atoms'
     9740                if rbObj['fixOrig']:
     9741                    wx.MessageBox('Not possible with origin locked',caption='Οrigin Locked',
     9742                                      style=wx.ICON_EXCLAMATION)
     9743                    return
     9744                selDict = getSelectedAtoms()
     9745                if len(selDict) < 3:
     9746                    wx.MessageBox('At least three atoms must be selected',caption='Select Atoms',
     9747                                      style=wx.ICON_EXCLAMATION)
     9748                    return
     9749                vals = rbObj['Orient'][0][:] + rbObj['Orig'][0][:]
     9750                out = so.leastsq(objectiveDeltaPos,vals,(selDict,data,rbObj))
     9751                data['testRBObj']['rbObj']['Orig'][0][:] = out[0][4:]
     9752                data['testRBObj']['rbObj']['Orient'][0][:] = G2mth.normQ(out[0][:4])
     9753                for i,item in enumerate(Xsizers):
     9754                    item.SetValue(data['testRBObj']['rbObj']['Orig'][0][i])
     9755                for i,item in enumerate(Osizers):
     9756                    item.SetLabel('%10.4f'%(data['testRBObj']['rbObj']['Orient'][0][i]))
     9757                UpdateTablePlot()
     9758
     9759            if not data['testRBObj']: return
     9760#            if len(data['testRBObj']):
     9761#                G2plt.PlotStructure(G2frame,data,True,UpdateTable)
     9762            if RigidBodies.GetSizer(): RigidBodies.GetSizer().Clear(True)
     9763            mainSizer = wx.BoxSizer(wx.VERTICAL)
     9764            mainSizer.Add((5,5),0)
     9765            Osizers = []
     9766            rbObj = data['testRBObj']['rbObj']
     9767            rbName = rbObj['RBname']
     9768            rbId = rbObj['RBId']
     9769            Orien = rbObj['Orient'][0]
     9770            rbRef = data['testRBObj']['rbRef']
     9771            Torsions = rbObj['Torsions']
     9772            refName = []
     9773            for ref in rbRef:
     9774                refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref))
     9775            atNames = data['testRBObj']['atNames']
     9776            mainSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Locate rigid body : '+rbName),
     9777                0,WACV)
     9778            mainSizer.Add((5,5),0)
     9779            OriSizer = wx.BoxSizer(wx.HORIZONTAL)
     9780            OriSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Origin: '),0,WACV)
     9781            Xsizers = []
     9782            lbl = 'xyz'
     9783            for ix in range(3):
     9784                OriSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,lbl[ix]),0,WACV,4)
     9785                origX = G2G.ValidatedTxtCtrl(RigidBodies,rbObj['Orig'][0],ix,nDig=(10,5),
     9786                            min=-1.5,max=1.5,typeHint=float,
     9787                                                 OnLeave=UpdateTablePlot)
     9788                OriSizer.Add(origX,0,WACV)
     9789                Xsizers.append(origX)
     9790            try:
     9791                rbObj['fixOrig']
     9792            except:
     9793                rbObj['fixOrig'] = False
     9794            fixOrig = G2G.G2CheckBox(RigidBodies,'Lock',rbObj,'fixOrig')
     9795            OriSizer.Add(fixOrig,0,WACV,10)
     9796
     9797            mainSizer.Add(OriSizer)
     9798            OriSizer.Add((5,0),)
     9799            OriSizer = wx.FlexGridSizer(0,5,5,5)
     9800            if len(atomData):
     9801                choice = list(atNames[0].keys())
     9802                choice.sort()
     9803                G2frame.testRBObjSizers.update({'Xsizers':Xsizers})
     9804            OriSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Orientation quaternion: '),0,WACV)
     9805            for ix,x in enumerate(Orien):
     9806                orien = wx.StaticText(RigidBodies,wx.ID_ANY,'%10.4f'%(x))
     9807                OriSizer.Add(orien,0,WACV)
     9808                Osizers.append(orien)
     9809            G2frame.testRBObjSizers.update({'Osizers':Osizers})
     9810            mainSizer.Add(OriSizer)
     9811            mainSizer.Add((5,5),0)
     9812            RefSizer = wx.FlexGridSizer(0,7,5,5)
     9813            mainSizer.Add(RefSizer)
     9814            mainSizer.Add((5,5),0)
     9815            if Torsions:                   
     9816                rbSeq = RBData['Residue'][rbId]['rbSeq']
     9817                TorSizer = wx.FlexGridSizer(0,4,5,5)
     9818                TorSizer.AddGrowableCol(1,1)
     9819                for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)):
     9820                    torName = ''
     9821                    for item in [seq[0],seq[1],seq[3][0]]:
     9822                        torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' '
     9823                    TorSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'Side chain torsion for rb seq: '+torName),0,WACV)
     9824                    torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL)
     9825                    torSlide.SetRange(0,3600)
     9826                    torSlide.SetValue(int(torsion[0]*10.))
     9827                    torSlide.Bind(wx.EVT_SLIDER, OnTorSlide)
     9828                    TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT)
     9829                    TorSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,' Angle: '),0,WACV)
     9830                    ang = G2G.ValidatedTxtCtrl(RigidBodies,torsion,0,nDig=(8,3),typeHint=float,OnLeave=OnTorAngle)
     9831                    Indx[torSlide.GetId()] = [t,ang]
     9832                    Indx[ang.GetId()] = [t,torSlide]
     9833                    TorSizer.Add(ang,0,WACV)                           
     9834                mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT)
     9835            else:
     9836                mainSizer.Add(wx.StaticText(RigidBodies,wx.ID_ANY,'No side chain torsions'),0,WACV)
     9837            matchTable = assignAtoms()
     9838            OkBtn = wx.Button(RigidBodies,wx.ID_ANY,"Add")
     9839            OkBtn.Bind(wx.EVT_BUTTON, OnOk)
     9840            CancelBtn = wx.Button(RigidBodies,wx.ID_ANY,'Cancel')
     9841            CancelBtn.Bind(wx.EVT_BUTTON, OnCancel)
     9842            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
     9843            btnSizer.Add((20,20),1)
     9844            btnSizer.Add(OkBtn)
     9845            btnSizer.Add(CancelBtn)
     9846            btnSizer.Add((20,20),1)
     9847            mainSizer.Add(btnSizer,0,wx.BOTTOM|wx.TOP, 20)
     9848               
     9849            SetPhaseWindow(RigidBodies,mainSizer)
     9850           
     9851            G2plt.PlotStructure(G2frame,data,True,UpdateTable)
     9852            colLabels = ['RB\ntype','phase\n#','phase\nlabel','delta, A','Assign as atom']
     9853            rowLabels = [l[1] for l in matchTable]
     9854            displayTable = [[l[0],l[5],l[6],l[10],''] for l in matchTable]
     9855            Types = [wg.GRID_VALUE_STRING, wg.GRID_VALUE_NUMBER,
     9856                    wg.GRID_VALUE_STRING, wg.GRID_VALUE_FLOAT+':8,3', wg.GRID_VALUE_STRING]
     9857            RigidBodies.atomsTable = G2G.Table(displayTable,rowLabels=rowLabels,colLabels=colLabels,types=Types)
     9858            RigidBodies.atomsGrid = G2G.GSGrid(RigidBodies)
     9859
     9860            labelsChoices = ['         '] + [a[0] for a in data['Atoms']]
     9861            choiceeditor = wg.GridCellChoiceEditor(labelsChoices, False)
     9862            RigidBodies.atomsGrid.SetTable(RigidBodies.atomsTable,True)
     9863            # make all grid entries read only
     9864            attr = wg.GridCellAttr()
     9865            attr.SetReadOnly(True)
     9866            for i in range(len(colLabels)-1):
     9867                attr.IncRef()
     9868                RigidBodies.atomsGrid.SetColAttr(i, attr)                   
     9869            attr = wg.GridCellAttr()
     9870            attr.SetAlignment(wx.ALIGN_RIGHT,wx.ALIGN_CENTRE)
     9871            RigidBodies.atomsGrid.SetColAttr(1, attr)                   
     9872            attr = wg.GridCellAttr()
     9873            attr.SetEditor(choiceeditor)
     9874            RigidBodies.atomsGrid.SetColAttr(4, attr)
     9875
     9876            RigidBodies.atomsGrid.AutoSizeColumns(True)
     9877            RigidBodies.atomsGrid.SetMargins(0,0)
     9878
     9879            gridSizer = wx.BoxSizer(wx.HORIZONTAL)
     9880            gridSizer.Add(RigidBodies.atomsGrid)#,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
     9881            gridSizer.Add((5,5))
     9882
     9883            btnSizer = wx.BoxSizer(wx.VERTICAL)
     9884            btnSizer.Add((-1,20))
     9885            btnSizer.Add(
     9886                wx.StaticText(RigidBodies,wx.ID_ANY,'Actions with fixed\natom(s)...'),
     9887                0,wx.ALL)
     9888            btnSizer.Add((-1,10))
     9889            btn = wx.Button(RigidBodies, wx.ID_ANY, 'Process Assignments')
     9890            btn.Bind(wx.EVT_BUTTON,UpdateTable)
     9891            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     9892            btnSizer.Add((-1,10))
     9893
     9894            btn = wx.Button(RigidBodies, wx.ID_ANY, 'Set Origin')
     9895
     9896            btn.Bind(wx.EVT_BUTTON,onSetOrigin)
     9897            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     9898            btnSizer.Add((-1,5))
     9899            btn = wx.Button(RigidBodies, wx.ID_ANY, 'Set Orientation')
     9900
     9901            btn.Bind(wx.EVT_BUTTON,onFitOrientation)
     9902            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     9903            btnSizer.Add((-1,5))
     9904            btn = wx.Button(RigidBodies, wx.ID_ANY, 'Set both')
     9905            btn.Bind(wx.EVT_BUTTON,onFitBoth)
     9906            btnSizer.Add(btn,0,wx.ALIGN_CENTER)
     9907            gridSizer.Add(btnSizer)
     9908            mainSizer.Add(gridSizer)
     9909            mainSizer.Layout()
     9910            RigidBodies.SetScrollRate(10,10)
     9911            RigidBodies.SendSizeEvent()
     9912            RigidBodies.Scroll(0,0)
     9913
    95009914        G2frame.GetStatusBar().SetStatusText('',1)
    95019915        RBData = G2frame.GPXtree.GetItemPyData(   
     
    95109924        if not rbNames:
    95119925            print ('**** ERROR - no rigid bodies defined ****')
     9926            G2G.G2MessageBox(G2frame,
     9927                'You must define bodies in Rigid Bodies tree item before trying to add them to a phase',
     9928                'No Rigid Bodies')
    95129929            return
    95139930        general = data['General']
     
    95189935        atInd = [-1,-1,-1]
    95199936        data['testRBObj'] = {}
    9520            
    9521         def Draw():
    9522            
    9523             def OnOk(event):
    9524                 rbType = data['testRBObj']['rbType']
    9525                 RBObjs = data['RBModels'].get(rbType,[])
    9526                 rbObj = data['testRBObj']['rbObj']
    9527                 rbId = rbObj['RBId']
    9528                 newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0]
    9529                 Ids = []
    9530                 dmax = 0.0
    9531                 oldXYZ = G2mth.getAtomXYZ(atomData,cx)
    9532                 for xyz in newXYZ:
    9533                     dist = G2mth.GetXYZDist(xyz,oldXYZ,Amat)
    9534                     dmax = max(dmax,np.min(dist))
    9535                     pid = np.argmin(dist)
    9536                     Id = atomData[pid][-1]
    9537                     if Id in Ids:   #duplicate - 2 atoms on same site; invalidate & look again
    9538                         dist[pid] = 100.
    9539                         Id = atomData[pid][-1]
    9540                     Ids.append(Id)
    9541                     atomData[pid][cx:cx+3] = xyz
    9542                 if dmax > 1.0:
    9543                     print ('**** WARNING - some atoms not found or misidentified ****')
    9544                     print ('****           check torsion angles & try again      ****')
    9545                     OkBtn.SetLabel('Not Ready')
    9546                     OkBtn.Enable(False)
     9937        if len(rbNames) == 1:
     9938            selection = list(rbNames.keys())[0]
     9939        else:
     9940            choices = sorted(list(rbNames.keys()))
     9941            dlg = G2G.G2SingleChoiceDialog(
     9942                G2frame,'Select rigid body to add to structure',
     9943                'Select rigid body',choices)
     9944            dlg.CenterOnParent()
     9945            try:
     9946                if dlg.ShowModal() == wx.ID_OK:
     9947                    selection = choices[dlg.GetSelection()]
     9948                else:
    95479949                    return
    9548                 rbObj['Ids'] = Ids
    9549                 rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
    9550                 rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount'])
    9551                 RBObjs.append(rbObj)
    9552                 data['RBModels'][rbType] = RBObjs
    9553                 RBData[rbType][rbId]['useCount'] += 1
    9554                 del data['testRBObj']
    9555                 G2plt.PlotStructure(G2frame,data)
    9556                 FillRigidBodyGrid(True)
    9557                
    9558             def OnCancel(event):
    9559                 del data['testRBObj']
    9560                 FillRigidBodyGrid(True)
    9561                
    9562             def OnRBSel(event):
    9563                 selection = rbSel.GetValue()
    9564                 if selection not in rbNames:
    9565                     return
    9566                 rbType,rbId = rbNames[selection]
    9567                 data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes']
    9568                 data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo']
    9569                 data['testRBObj']['rbType'] = rbType
    9570                 data['testRBObj']['rbData'] = RBData
    9571                 data['testRBObj']['Sizers'] = {}
    9572                 rbRef = RBData[rbType][rbId]['rbRef']
    9573                 data['testRBObj']['rbRef'] = rbRef
    9574                 refType = []
    9575                 refName = []
    9576                 for ref in rbRef[:3]:
    9577                     reftype = data['testRBObj']['rbAtTypes'][ref]
    9578                     refType.append(reftype)
    9579                     refName.append(reftype+' '+str(rbRef[0]))
    9580                 atNames,AtNames = fillAtNames(refType,atomData,ct)
    9581                 data['testRBObj']['atNames'] = atNames
    9582                 data['testRBObj']['AtNames'] = AtNames
    9583                 data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False],
    9584                     'Orient':[[0.,0.,0.,0.],' '],'Ids':[],'RBId':rbId,'Torsions':[],
     9950            finally:
     9951                dlg.Destroy()
     9952            if selection not in rbNames:
     9953                print('Invalid RB selection',selection,'How did this happen?')
     9954                return
     9955        rbType,rbId = rbNames[selection]
     9956        data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes']
     9957        data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo']
     9958        data['testRBObj']['rbType'] = rbType
     9959        data['testRBObj']['rbData'] = RBData
     9960        data['testRBObj']['Sizers'] = {}
     9961        rbRef = RBData[rbType][rbId]['rbRef']
     9962        data['testRBObj']['rbRef'] = rbRef
     9963        refType = []
     9964        refName = []
     9965        for ref in rbRef[:3]:
     9966            reftype = data['testRBObj']['rbAtTypes'][ref]
     9967            refType.append(reftype)
     9968            refName.append(reftype+' '+str(rbRef[0]))
     9969        atNames = [{},{},{}]
     9970        AtNames = {}
     9971        for iatm,atom in enumerate(atomData):
     9972            AtNames[atom[ct-1]] = iatm
     9973            for i,reftype in enumerate(refType):
     9974                if atom[ct] == reftype:
     9975                    atNames[i][atom[ct-1]] = iatm
     9976        data['testRBObj']['atNames'] = atNames
     9977        data['testRBObj']['AtNames'] = AtNames
     9978        data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False],
     9979                    'Orient':[[0.,0.,0.,1.],' '],'Ids':[],'RBId':rbId,'Torsions':[],
    95859980                    'numChain':'','RBname':RBData[rbType][rbId]['RBname']}
    9586                 data['testRBObj']['torAtms'] = []               
    9587                 for item in RBData[rbType][rbId].get('rbSeq',[]):
    9588                     data['testRBObj']['rbObj']['Torsions'].append([item[2],False])
    9589                     data['testRBObj']['torAtms'].append([-1,-1,-1])
    9590                 wx.CallAfter(Draw)
    9591                
    9592             def fillAtNames(refType,atomData,ct):
    9593                 atNames = [{},{},{}]
    9594                 AtNames = {}
    9595                 for iatm,atom in enumerate(atomData):
    9596                     AtNames[atom[ct-1]] = iatm
    9597                     for i,reftype in enumerate(refType):
    9598                         if atom[ct] == reftype:
    9599                             atNames[i][atom[ct-1]] = iatm
    9600                 return atNames,AtNames
    9601                
    9602             def OnAtOrigPick(event):
    9603                 Obj = event.GetEventObject()
    9604                 item = Indx[Obj.GetId()]
    9605                 atName = Obj.GetValue()
    9606                 rbType = data['testRBObj']['rbType']
    9607                 atInd[0] = atNames[item][atName]
    9608                 if 'Vector' in rbType:
    9609                     rbObj = data['testRBObj']['rbObj']
    9610                     rbId = rbObj['RBId']
    9611                     rbRef = data['testRBObj']['rbRef']
    9612                     rbXYZ = -RBData[rbType][rbId]['rbXYZ']
    9613                     nref = atNames[item][atName]
    9614                     Oxyz = np.inner(Bmat,np.array(rbXYZ[rbRef[0]]))
    9615                     Nxyz = np.array(atomData[nref][cx:cx+3])
    9616                     Orig = Nxyz-Oxyz
    9617                     data['testRBObj']['rbObj']['Orig'][0] = Orig   
    9618                 else:
    9619                     Orig = atomData[atNames[item][atName]][cx:cx+3]
    9620                     data['testRBObj']['rbObj']['Orig'][0] = Orig
    9621                 for x,item in zip(Orig,Xsizers):
    9622                     item.SetLabel('%10.5f'%(x))
    9623                 G2plt.PlotStructure(G2frame,data)
    9624                
    9625             def OnAtQPick(event):
    9626                 Obj = event.GetEventObject()
    9627                 item = Indx[Obj.GetId()]
    9628                 atName = Obj.GetValue()
    9629                 atInd[item] = atNames[item][atName]
    9630                 if any([x<0 for x in atInd]):
    9631                     return
    9632                 OkBtn.SetLabel('OK')
    9633                 OkBtn.Enable(True)
    9634                 rbType = data['testRBObj']['rbType']
    9635                 rbObj = data['testRBObj']['rbObj']
    9636                 rbId = rbObj['RBId']
    9637                 rbRef = data['testRBObj']['rbRef']
    9638                 rbXYZ = RBData[rbType][rbId]['rbXYZ']
    9639                 rbOrig = rbXYZ[rbRef[0]]
    9640                 VAR = rbXYZ[rbRef[1]]-rbOrig
    9641                 VBR = rbXYZ[rbRef[2]]-rbOrig
    9642                 if rbType == 'Vector':
    9643                     Orig = np.array(atomData[atInd[0]][cx:cx+3])
    9644                 else:
    9645                     Orig = np.array(data['testRBObj']['rbObj']['Orig'][0])               
    9646                 VAC = np.inner(Amat,np.array(atomData[atInd[1]][cx:cx+3]-Orig))
    9647                 VBC = np.inner(Amat,np.array(atomData[atInd[2]][cx:cx+3]-Orig))
    9648                 VCC = np.cross(VAR,VAC)
    9649                 if nl.norm(VCC) > 1e-7:
    9650                     QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
    9651                     VAR = G2mth.prodQVQ(QuatA,VAR)
    9652                     VBR = G2mth.prodQVQ(QuatA,VBR)
    9653                     QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
    9654                     QuatC = G2mth.prodQQ(QuatB,QuatA)
    9655                 else:                               #parallel/antiparallel
    9656                     if np.dot(VAR,VAC)/(nl.norm(VAR)*nl.norm(VAC)) > 1e-7:  #no rotation
    9657                         QuatC = G2mth.AVdeg2Q(0.,[0.,0.,1.])
    9658                     else:
    9659                         QuatC = G2mth.AVdeg2Q(180.,VBR+VBC)
    9660                 data['testRBObj']['rbObj']['Orient'] = [QuatC,' ']
    9661                 for x,item in zip(QuatC,Osizers):
    9662                     item.SetLabel('%10.4f'%(x))               
    9663                 if rbType == 'Vector':
    9664                     Oxyz = np.inner(Bmat,G2mth.prodQVQ(QuatC,rbOrig))
    9665                     Nxyz = np.array(atomData[atInd[0]][cx:cx+3])
    9666                     Orig = Nxyz-Oxyz
    9667                     data['testRBObj']['rbObj']['Orig'][0] = Orig
    9668                     for x,item in zip(Orig,Xsizers):
    9669                         item.SetLabel('%10.5f'%(x))
    9670                 G2plt.PlotStructure(G2frame,data)
    9671                
    9672             def OnTorAngle(invalid,value,tc):
    9673                 OkBtn.SetLabel('OK')
    9674                 OkBtn.Enable(True)
    9675                 Obj = tc.event.GetEventObject()
    9676                 [tor,torSlide] = Indx[Obj.GetId()]
    9677                 torSlide.SetValue(int(value*10))
    9678                 G2plt.PlotStructure(G2frame,data)
    9679                
    9680             def OnTorSlide(event):
    9681                 OkBtn.SetLabel('OK')
    9682                 OkBtn.Enable(True)
    9683                 Obj = event.GetEventObject()
    9684                 tor,ang = Indx[Obj.GetId()]
    9685                 Tors = data['testRBObj']['rbObj']['Torsions'][tor]
    9686                 val = float(Obj.GetValue())/10.
    9687                 Tors[0] = val
    9688                 ang.SetValue(val)
    9689                 G2plt.PlotStructure(G2frame,data)
    9690 
    9691             if len(data['testRBObj']):
    9692                 G2plt.PlotStructure(G2frame,data)
    9693                    
    9694             if RigidBodies.GetSizer(): RigidBodies.GetSizer().Clear(True)
    9695             mainSizer = wx.BoxSizer(wx.VERTICAL)
    9696             mainSizer.Add((5,5),0)
    9697             if data['testRBObj']:
    9698                 Xsizers = []
    9699                 Osizers = []
    9700                 rbObj = data['testRBObj']['rbObj']
    9701                 rbName = rbObj['RBname']
    9702                 rbId = rbObj['RBId']
    9703                 Orig = rbObj['Orig'][0]
    9704                 Orien = rbObj['Orient'][0]
    9705                 rbRef = data['testRBObj']['rbRef']
    9706                 Torsions = rbObj['Torsions']
    9707                 refName = []
    9708                 for ref in rbRef:
    9709                     refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref))
    9710                 atNames = data['testRBObj']['atNames']
    9711                 mainSizer.Add(wx.StaticText(RigidBodies,-1,'Locate rigid body : '+rbName),
    9712                     0,WACV)
    9713                 mainSizer.Add((5,5),0)
    9714                 OriSizer = wx.FlexGridSizer(0,5,5,5)
    9715                 OriSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z: '),0,WACV)
    9716                 for ix,x in enumerate(Orig):
    9717                     origX = wx.StaticText(RigidBodies,-1,'%10.5f'%(x))
    9718                     OriSizer.Add(origX,0,WACV)
    9719                     Xsizers.append(origX)
    9720                 OriSizer.Add((5,0),)
    9721                 if len(atomData):
    9722                     choice = list(atNames[0].keys())
    9723                     choice.sort()
    9724                     G2frame.testRBObjSizers.update({'Xsizers':Xsizers})
    9725                 OriSizer.Add(wx.StaticText(RigidBodies,-1,'Orientation quaternion: '),0,WACV)
    9726                 for ix,x in enumerate(Orien):
    9727                     orien = wx.StaticText(RigidBodies,-1,'%10.4f'%(x))
    9728                     OriSizer.Add(orien,0,WACV)
    9729                     Osizers.append(orien)
    9730                 G2frame.testRBObjSizers.update({'Osizers':Osizers})
    9731                 mainSizer.Add(OriSizer)
    9732                 mainSizer.Add((5,5),0)
    9733                 RefSizer = wx.FlexGridSizer(0,7,5,5)
    9734                 if len(atomData):
    9735                     RefSizer.Add(wx.StaticText(RigidBodies,-1,'Location setting: Select match to'),0,WACV)
    9736                     for i in [0,1,2]:
    9737                         choice = ['',]+list(atNames[i].keys())
    9738                         choice.sort()
    9739                         RefSizer.Add(wx.StaticText(RigidBodies,-1,' '+refName[i]+': '),0,WACV)
    9740                         atPick = wx.ComboBox(RigidBodies,-1,value='',
    9741                             choices=choice[1:],style=wx.CB_READONLY|wx.CB_DROPDOWN)
    9742                         if i:
    9743                             atPick.Bind(wx.EVT_COMBOBOX, OnAtQPick)
    9744                         else:
    9745                             atPick.Bind(wx.EVT_COMBOBOX, OnAtOrigPick)                           
    9746                         Indx[atPick.GetId()] = i
    9747                         RefSizer.Add(atPick,0,WACV)
    9748                 mainSizer.Add(RefSizer)
    9749                 mainSizer.Add((5,5),0)
    9750                 if Torsions:                   
    9751                     rbSeq = RBData['Residue'][rbId]['rbSeq']
    9752                     TorSizer = wx.FlexGridSizer(0,4,5,5)
    9753                     TorSizer.AddGrowableCol(1,1)
    9754                     for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)):
    9755                         torName = ''
    9756                         for item in [seq[0],seq[1],seq[3][0]]:
    9757                             torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' '
    9758                         TorSizer.Add(wx.StaticText(RigidBodies,-1,'Side chain torsion for rb seq: '+torName),0,WACV)
    9759                         torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL)
    9760                         torSlide.SetRange(0,3600)
    9761                         torSlide.SetValue(int(torsion[0]*10.))
    9762                         torSlide.Bind(wx.EVT_SLIDER, OnTorSlide)
    9763                         TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT)
    9764                         TorSizer.Add(wx.StaticText(RigidBodies,-1,' Angle: '),0,WACV)
    9765                         ang = G2G.ValidatedTxtCtrl(RigidBodies,torsion,0,nDig=(8,3),typeHint=float,OnLeave=OnTorAngle)
    9766                         Indx[torSlide.GetId()] = [t,ang]
    9767                         Indx[ang.GetId()] = [t,torSlide]
    9768                         TorSizer.Add(ang,0,WACV)                           
    9769                     mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT)
    9770                 else:
    9771                     mainSizer.Add(wx.StaticText(RigidBodies,-1,'No side chain torsions'),0,WACV)
    9772             else:
    9773                 mainSizer.Add(wx.StaticText(RigidBodies,-1,'Assign rigid body:'),0,WACV)
    9774                 mainSizer.Add((5,5),0)
    9775                 topSizer = wx.BoxSizer(wx.HORIZONTAL)
    9776                 topSizer.Add(wx.StaticText(RigidBodies,-1,'Select rigid body model'),0,WACV)
    9777                 rbSel = wx.ComboBox(RigidBodies,-1,value='',choices=['']+list(rbNames.keys()),
    9778                     style=wx.CB_READONLY|wx.CB_DROPDOWN)
    9779                 rbSel.Bind(wx.EVT_COMBOBOX, OnRBSel)
    9780                 topSizer.Add((5,5),0)
    9781                 topSizer.Add(rbSel,0,WACV)
    9782                 mainSizer.Add(topSizer)               
    9783                
    9784             OkBtn = wx.Button(RigidBodies,-1,"Not ready")
    9785             OkBtn.Bind(wx.EVT_BUTTON, OnOk)
    9786             OkBtn.Enable(False)
    9787             CancelBtn = wx.Button(RigidBodies,-1,'Cancel')
    9788             CancelBtn.Bind(wx.EVT_BUTTON, OnCancel)
    9789             btnSizer = wx.BoxSizer(wx.HORIZONTAL)
    9790             btnSizer.Add((20,20),1)
    9791             btnSizer.Add(OkBtn)
    9792             btnSizer.Add(CancelBtn)
    9793             btnSizer.Add((20,20),1)
    9794             mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
    9795             SetPhaseWindow(RigidBodies,mainSizer)
     9981        data['testRBObj']['torAtms'] = []               
     9982        for item in RBData[rbType][rbId].get('rbSeq',[]):
     9983            data['testRBObj']['rbObj']['Torsions'].append([item[2],False])
     9984            data['testRBObj']['torAtms'].append([-1,-1,-1])       
    97969985        wx.CallAfter(Draw)
    97979986       
     
    1148611675        G2frame.Bind(wx.EVT_MENU, DrawAtomColor, id=G2G.wxID_DRAWATOMCOLOR)
    1148711676        G2frame.Bind(wx.EVT_MENU, ResetAtomColors, id=G2G.wxID_DRAWATOMRESETCOLOR)
    11488         G2frame.Bind(wx.EVT_MENU, OnEditAtomRadii, id=G2G.wxID_DRWAEDITRADII)   
     11677        #G2frame.Bind(wx.EVT_MENU, OnEditAtomRadii, id=G2G.wxID_DRWAEDITRADII)           # TODO: removed until fixed
    1148911678        G2frame.Bind(wx.EVT_MENU, SetViewPoint, id=G2G.wxID_DRAWVIEWPOINT)
    1149011679        G2frame.Bind(wx.EVT_MENU, AddSymEquiv, id=G2G.wxID_DRAWADDEQUIV)
  • trunk/GSASIIplot.py

    r4428 r4431  
    79207920################################################################################
    79217921           
    7922 def PlotStructure(G2frame,data,firstCall=False):
     7922def PlotStructure(G2frame,data,firstCall=False,pageCallback=None):
    79237923    '''Crystal structure plotting package. Can show structures as balls, sticks, lines,
    79247924    thermal motion ellipsoids and polyhedra. Magnetic moments shown as black/red
    79257925    arrows according to spin state
     7926
     7927    :param wx.Frame G2frame: main GSAS-II window
     7928    :param dict data: dict with plotting information
     7929      (see :ref:`Phase Tree object<Phase_table>`)
     7930    :param bool firstCall: If True, this is the initial call and causes
     7931      the plot to be shown twice (needed for Mac and possibly linux)
     7932    :param function pageCallback: a callback function to
     7933      update items on the parent page. Currently implemented for
     7934      RB Models tab only
    79267935    '''
    79277936
     
    83048313            if G2frame.phaseDisplay.GetPageText(page) == 'RB Models':
    83058314                for i,sizer in enumerate(G2frame.testRBObjSizers['Xsizers']):
    8306                     sizer.SetValue('%8.5f'%(testRBObj['rbObj']['Orig'][0][i]))
    8307                    
     8315                    sizer.SetValue(testRBObj['rbObj']['Orig'][0][i])
     8316        if pageCallback:
     8317            try:
     8318                pageCallback()
     8319            except:
     8320                pass
     8321           
    83088322    def SetRBOrienText():
    83098323        page = getSelection()
     
    83128326                for i,sizer in enumerate(G2frame.testRBObjSizers['Osizers']):
    83138327                    sizer.SetLabel('%8.5f'%(testRBObj['rbObj']['Orient'][0][i]))
     8328        if pageCallback:
     8329            try:
     8330                pageCallback()
     8331            except:
     8332                pass
    83148333               
    83158334    def SetViewDirText(VD):
     
    84498468       
    84508469    def SetRBTranslation(newxy):
    8451 #first get translation vector in screen coords.       
     8470#first get translation vector in screen coords.
     8471        if 'fixOrig' in rbObj:
     8472            if rbObj['fixOrig']: return
    84528473        oldxy = drawingData['oldxy']
    84538474        if not len(oldxy): oldxy = list(newxy)
     
    84628483        Ty -= V[1]*0.01
    84638484        Tz -= V[2]*0.01
    8464         rbObj['Orig'][0] =  Tx,Ty,Tz
     8485        rbObj['Orig'][0][:] =  Tx,Ty,Tz
    84658486        SetRBOrigText()
    84668487       
Note: See TracChangeset for help on using the changeset viewer.