451 lines
15 KiB
Python
Executable File
451 lines
15 KiB
Python
Executable File
#!/usr/bin/env python
|
||
# *-----------------------------------------------------------------------*
|
||
# | |
|
||
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
|
||
# | |
|
||
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
|
||
# *-----------------------------------------------------------------------*
|
||
|
||
from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QApplication
|
||
from PyQt5.QtGui import QPainter, QColor, QBrush
|
||
|
||
from pyqtgraph.Qt import QtCore, QtGui
|
||
import numpy as np
|
||
import PyQt5.QtGui as QtGui
|
||
import PyQt5.QtCore as QtCore
|
||
import PyQt5.QtWidgets as QtW
|
||
from PyQt5.uic import loadUiType
|
||
import numpy as np
|
||
import geometry
|
||
|
||
import sys
|
||
|
||
def obj_info(obj,p=''):
|
||
print(f"{p}obj_info:{obj}")
|
||
try:
|
||
pos=obj.pos()
|
||
print(f"{p}pos:({pos.x():.6g},{pos.y():.6g})") # in coordinate value on the scene (no change by zooming)
|
||
except AttributeError:
|
||
pass
|
||
try:
|
||
sz=obj.size()
|
||
print(f"{p}size:({sz.x():.6g},{sz.y():.6g})") # in coordinate value on the scene (no change by zooming)
|
||
except AttributeError:
|
||
pass
|
||
try:
|
||
for k, v in (('Viewport', obj.viewport()), ('Window', obj.window())):
|
||
print(
|
||
f"{p}{k} (x,y)(w,h):({v.x():.6g},{v.y():.6g})({v.width():.6g},{v.height():.6g})") # in coordinate value on the scene (no change by zooming)
|
||
except AttributeError:
|
||
pass
|
||
try:
|
||
scnPos=obj.scenePos()
|
||
print(f"{p}scenePos:({scnPos.x():.6g},{scnPos.y():.6g})") # in pixel on the scene (changes by zooming)
|
||
except AttributeError:
|
||
pass
|
||
try:
|
||
if type(obj)==QtGui.QTransform:
|
||
t=obj
|
||
else:
|
||
t=obj.transform()
|
||
print(f"{p}QTransform:{t.m11():8.5g} {t.m12():8.5g} {t.m13():8.5g}")
|
||
print(f"{p} {t.m21():8.5g} {t.m22():8.5g} {t.m23():8.5g}")
|
||
print(f"{p} {t.m31():8.5g} {t.m32():8.5g} {t.m33():8.5g}")
|
||
except AttributeError:
|
||
pass
|
||
|
||
class RIXSgirder(QWidget):
|
||
|
||
def __init__(self):
|
||
super().__init__()
|
||
self._param={'ctr':(200, 300), # location of big chamber
|
||
'aa':45, # RIXS arm angle
|
||
'cc':45, # UNSUSED
|
||
}
|
||
|
||
self.initUI()
|
||
|
||
def initUI(self):
|
||
self.setGeometry(300, 300, 850, 800)
|
||
self.setWindowTitle('RIXS girder')
|
||
#label = QLabel('Python', self)
|
||
#label.move(50,50)
|
||
#b1 = QPushButton("Button1",self)
|
||
#b1.move(400,150)
|
||
w=QtGui.QGroupBox("Drawing",self)
|
||
w.move(10,10)
|
||
l=QtGui.QVBoxLayout(w)
|
||
|
||
sld={}
|
||
for key,rng,tk,pos in (('aa',(0,180),5,20),('cc',(0,180),5,40),):
|
||
sl=QtGui.QSlider(QtCore.Qt.Horizontal)
|
||
sl.setFixedWidth(200);sl.setMinimum(rng[0]);sl.setMaximum(rng[1])
|
||
sl.setValue(self._param[key])
|
||
sl.setTickPosition(QtGui.QSlider.TicksBelow);sl.setTickInterval(tk)
|
||
l.addWidget(sl)
|
||
sl.valueChanged.connect(lambda val,key=key: self.sldChanged(key,val))
|
||
sld[key]=sl
|
||
self.show()
|
||
|
||
def sldChanged(self,key,val,*args,**kwargs):
|
||
print(key,val)
|
||
self._param[key]=val
|
||
self.update()
|
||
|
||
def paintEvent(self, e):
|
||
p=self._param
|
||
ctr=p['ctr']
|
||
aa=p['aa']
|
||
qp = QPainter()
|
||
qp.begin(self)
|
||
qp.translate(ctr[0],ctr[1])
|
||
qp.setPen(QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine))
|
||
qp.setBrush(QColor(255, 80, 0, 128))
|
||
|
||
rCmb=100 # radius of chamber
|
||
rTrg=10 # radius of target
|
||
|
||
qp.drawEllipse(-rCmb, -rCmb, 2*rCmb, 2*rCmb) # big chamber
|
||
qp.drawEllipse(-rTrg, -rTrg, 2*rTrg, 2*rTrg) # target
|
||
qp.drawLine(0,-rCmb-50,0,-rTrg) #beam
|
||
qp.rotate(-aa)
|
||
qp.drawRect(-50, 100, 100, 300) # girder
|
||
qp.drawEllipse(-50, 100+150, 20, 20) #pusher left
|
||
qp.drawEllipse( 50-20, 100+150, 20, 20) #pusher right
|
||
qp.drawEllipse(-50, 100+250, 20, 20) #air pad left
|
||
qp.drawEllipse( 50-20, 100+250, 20, 20) #air pad right
|
||
|
||
qp.end()
|
||
|
||
|
||
|
||
|
||
#Ui_MainWindow, QMainWindow = loadUiType("graphEx1.ui")
|
||
#class RIXSgrating(QMainWindow, Ui_MainWindow):
|
||
# def __init__(self, ):
|
||
# super(RIXSgrating, self).__init__()
|
||
# self.setupUi(self)
|
||
|
||
class RIXSgrating(QWidget):
|
||
def __init__(self):
|
||
super().__init__()
|
||
|
||
self._param={'ctr':(500,500), # location of vlsg
|
||
'r1':314,#distance probe grating
|
||
'r2':447,#distance grating detector
|
||
'aa':18, #grating angle
|
||
'cc':58, #detector angle
|
||
'szG':(200,5), #size VLS grating
|
||
'szD':(150,5), #size detector
|
||
'energy':300, # input energy in eV
|
||
}
|
||
self.initUI()
|
||
|
||
def initUI(self):
|
||
#p=self.palette()
|
||
#p.setColor(self.backgroundRole(), QtCore.Qt.black)
|
||
#self.setPalette(p)
|
||
self.setGeometry(300, 300, 1050, 800)
|
||
self.setWindowTitle('RIXS grating')
|
||
|
||
#w.move(400,100)
|
||
#w.setFixedSize(200,200)
|
||
|
||
self._wdGrpEnergy=w=QtGui.QGroupBox("Energy",self)
|
||
w.move(10,10)
|
||
#w.setFixedSize(200,42+32*2)
|
||
lv=QtGui.QVBoxLayout(w)
|
||
w=QtGui.QWidget() #QGroupBox("E2",self)
|
||
lv.addWidget(w)
|
||
lg=QtGui.QGridLayout(w)
|
||
|
||
i=0;t='Energy'
|
||
w=QLabel(t); lg.addWidget(w, i,0)
|
||
w=QtGui.QLineEdit(t,objectName=t); lg.addWidget(w, i,1)
|
||
i+=1;t='Grating'
|
||
w=QLabel(t); lg.addWidget(w, i,0)
|
||
w=QtGui.QComboBox(objectName=t); lg.addWidget(w, i,1)
|
||
for i,t in enumerate(('80meV','grating 1','grating 2')):
|
||
w.insertItem(i,t)
|
||
|
||
sld={}
|
||
for key,rng,tk,pos in (('energy',(200,1500),50,60),):
|
||
sl=QtGui.QSlider(QtCore.Qt.Horizontal)
|
||
sl.setFixedWidth(200);sl.setMinimum(rng[0]);sl.setMaximum(rng[1])
|
||
sl.setValue(self._param[key])
|
||
sl.setTickPosition(QtGui.QSlider.TicksBelow);sl.setTickInterval(tk)
|
||
lv.addWidget(sl)
|
||
sl.valueChanged.connect(lambda val,key=key: self.sldChanged(key,val))
|
||
sld[key]=sl
|
||
|
||
|
||
self._wdGrpGeometry=w=QtGui.QGroupBox("Geometry",self)
|
||
w.move(10,160)
|
||
#w.setFixedSize(200,42+32*4)
|
||
l=QtGui.QGridLayout(w)
|
||
lut={'aa':'\u03B1', 'bb':'\u03B2', 'cc':'\u03B3'}
|
||
for i,t in enumerate(('R1','R2','aa','bb','cc',)):
|
||
tl=lut.get(t,t)
|
||
w=QLabel(tl)
|
||
l.addWidget(w, i,0)
|
||
w=QtGui.QLineEdit(tl,objectName=t)
|
||
l.addWidget(w, i,1)
|
||
|
||
self._wdGrpRaw=w=QtGui.QGroupBox("Motors",self)
|
||
w.move(250,10)
|
||
#w.setFixedSize(200,42+32*4)
|
||
l=QtGui.QGridLayout(w)
|
||
|
||
motors=(
|
||
('MT', 'Mask translation'),
|
||
('GTZ', 'Grating translation along Z-axis (along beam)'),
|
||
('GTY1', 'Grating translation along Y-axis (height) Wedge leveller 1'),
|
||
('GTY2', 'Grating translation along Y-axis (height) Wedge leveller 2'),
|
||
('GRX', 'Grating rotation around X-axis'),
|
||
('GTX', 'Grating translation along X-axis'),
|
||
('DTZ', 'Detector Translation along Z-axis'),
|
||
('DTY1', 'Detector Translation along Y-axis'),
|
||
('DTY2', 'Detector Translation along Y-axis'),
|
||
('DRX', 'Detector Rotation around X-axis (ɣ) '),
|
||
)
|
||
|
||
for i,m in enumerate(motors):
|
||
t,inf=m
|
||
w=QLabel(t)
|
||
l.addWidget(w, i,0)
|
||
w=QtGui.QLineEdit(t,objectName=t)
|
||
w.setToolTip(inf)
|
||
l.addWidget(w, i,1)
|
||
w=QtGui.QPushButton('move all motors')
|
||
w.clicked.connect(self.btnMoveAllMotors)
|
||
l.addWidget(w, i+1, 1)
|
||
|
||
|
||
w=QtGui.QGroupBox("Drawing",self)
|
||
w.move(470,10)
|
||
l=QtGui.QVBoxLayout(w)
|
||
|
||
sld={}
|
||
for key,rng,tk,pos in (('r1',(50,800),50,60),('r2',(50,800),50,80),('aa',(0,90),5,20),('cc',(0,180),5,40),):
|
||
sl=QtGui.QSlider(QtCore.Qt.Horizontal)
|
||
sl.setFixedWidth(200);sl.setMinimum(rng[0]);sl.setMaximum(rng[1])
|
||
sl.setValue(self._param[key])
|
||
sl.setTickPosition(QtGui.QSlider.TicksBelow);sl.setTickInterval(tk)
|
||
l.addWidget(sl)
|
||
sl.valueChanged.connect(lambda val,key=key: self.sldChanged(key,val))
|
||
sld[key]=sl
|
||
|
||
self.show()
|
||
|
||
def setEnergy(self,val):
|
||
app=QApplication.instance()
|
||
p=self._param
|
||
wEnergy=self._wdGrpEnergy.findChild(QtGui.QLineEdit, 'Energy')
|
||
wEnergy.setText(f'{val:.4g}')
|
||
vlsg=app._vlsg
|
||
p['geo']=geo=vlsg.energy2geometry(val)
|
||
r1, r2, aa, bb, cc=geo
|
||
p['r1']=r1/8
|
||
p['r2']=r2/8
|
||
p['aa']=(90-aa)*8
|
||
p['bb']=(90-bb)*8
|
||
p['cc']=(90-cc)
|
||
|
||
wGeo=self._wdGrpGeometry
|
||
for i,k in enumerate(('R1','R2','aa','bb','cc',)):
|
||
w=wGeo.findChild(QtGui.QLineEdit, k)
|
||
w.setText(f'{geo[i]:.6g}')
|
||
|
||
p['raw']=raw=vlsg.geometry2raw(geo)
|
||
wRaw=self._wdGrpRaw
|
||
for i,k in enumerate(('MT','GTZ','GTY1','GTY2','GRX','GTX','DTZ','DTY1','DTY2','DRX',)):
|
||
w=wRaw.findChild(QtGui.QLineEdit, k)
|
||
if raw[i] is None:
|
||
w.setText('(null)')
|
||
else:
|
||
w.setText(f'{raw[i]:.6g}')
|
||
|
||
def sldChanged(self,key,val,*args,**kwargs):
|
||
#print(key,val)
|
||
p=self._param
|
||
if key=='energy':
|
||
self.setEnergy(val)
|
||
else:
|
||
p[key]=val
|
||
if 'geo' in p:
|
||
del p['geo']
|
||
self.update()
|
||
|
||
def btnMoveAllMotors(self):
|
||
p=self._param
|
||
print(f'energy:{p["energy"]}')
|
||
print(f'geometry:{p["geo"]}')
|
||
print(f'raw motors:{p["raw"]}')
|
||
|
||
def paintEvent(self, e):
|
||
p=self._param
|
||
r1=p['r1']
|
||
r2=p['r2']
|
||
aa=p['aa']
|
||
bb=aa*1.5
|
||
cc=p['cc']
|
||
szG=p['szG']
|
||
szD=p['szD']
|
||
ctr=p['ctr']
|
||
|
||
#scl=p['scl']
|
||
|
||
qp = QPainter()
|
||
qp.begin(self)
|
||
|
||
#plot black background
|
||
w=int(max(szG[0],szD[0])/2)
|
||
ctr=(max(ctr[0],w+r1),max(w+r2*np.sin((aa+bb)*np.pi/180),ctr[1]))
|
||
qp.translate(ctr[0],ctr[1])
|
||
qp.setBrush(QColor(0, 0, 0))
|
||
qp.drawRect(-r1-w, -w, r1+w, 2*w)
|
||
#qp.drawEllipse(-r1-w, -w, 2*w, 2*w)
|
||
qp.drawEllipse(-w, -w, 2*w, 2*w)
|
||
qp.rotate(180-aa-bb)
|
||
qp.drawRect(-r2-w, -w, r2+w, 2*w)
|
||
#qp.drawEllipse(-r2-w, -w, 2*w, 2*w)
|
||
|
||
#plot beam path
|
||
qp.setTransform(QtGui.QTransform())
|
||
qp.translate(ctr[0],ctr[1])
|
||
qp.setCompositionMode(QtGui.QPainter.CompositionMode_Lighten)
|
||
|
||
|
||
tf0=qp.transform()
|
||
qp.setPen(QtGui.QPen(QtCore.Qt.white, 1, QtCore.Qt.SolidLine))
|
||
qp.setBrush(QColor(255, 80, 0, 128))
|
||
|
||
qp.drawEllipse(-r1-20, -10, 20, 20) # target
|
||
qp.drawLine(-r1,0,0,0) #beam
|
||
qp.rotate(-aa)
|
||
tf1=qp.transform()
|
||
qp.drawRect(int(-szG[0]/2), 0, szG[0], szG[1]) # grating
|
||
qp.rotate(-bb)
|
||
tf2=qp.transform()
|
||
qp.drawLine(0,0,int(r2+szD[0]/2),0) #beam
|
||
qp.translate(r2,0)
|
||
qp.rotate(-cc)
|
||
tf3=qp.transform()
|
||
qp.drawRect(int(-szD[0]/2),0 , szD[0], szD[1]) # detector
|
||
|
||
#beam target to vlsg
|
||
qp.setTransform(QtGui.QTransform())
|
||
p0=QtCore.QPointF(*tf0.map(-r1-10, 10))
|
||
p1=QtCore.QPointF(*tf1.map(-szG[0]/2, 0))
|
||
qp.drawLine(p0,p1)
|
||
p0=QtCore.QPointF(*tf0.map(-r1-10, -10))
|
||
p1=QtCore.QPointF(*tf1.map(szG[0]/2, 0))
|
||
qp.drawLine(p0,p1)
|
||
|
||
# beam vlsg to detector
|
||
#n=4;mode=2;alpha=190
|
||
#n=4;mode=1;alpha=200
|
||
#n=32;mode=1;alpha=120
|
||
#n=8;mode=1;alpha=196
|
||
n=32;mode=0;alpha=120;width=3
|
||
#n=32;mode=2;alpha=255
|
||
scl=256/n
|
||
p0=QtCore.QPointF(*tf1.map(-szG[0]/2, 0))
|
||
p1=QtCore.QPointF(*tf1.map(szG[0]/2, 0))
|
||
|
||
if mode==0:
|
||
pen=QtGui.QPen(QtCore.Qt.black, width, QtCore.Qt.SolidLine)
|
||
col=QtGui.QColor()
|
||
for i in range(n):
|
||
p2=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*i/(n-1),0))
|
||
col.setHsv(int(i*scl),255,255,alpha)
|
||
pen.setColor(col)
|
||
qp.setPen(pen)
|
||
qp.drawLine(p0,p2)
|
||
qp.drawLine(p1,p2)
|
||
if mode==1:
|
||
col=QtGui.QColor()
|
||
qp.setPen(QtGui.QPen(QtCore.Qt.black, 0, QtCore.Qt.SolidLine))
|
||
for i in range(n):
|
||
p2=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*i/(n-1), 0))
|
||
col.setHsv(i*scl, 255, 255, alpha)
|
||
qp.setBrush(col)
|
||
qp.drawPolygon(p0, p1, p2)
|
||
if mode==2:
|
||
col=QtGui.QColor()
|
||
qp.setPen(QtGui.QPen(QtCore.Qt.black, 0, QtCore.Qt.SolidLine))
|
||
for i in range(n):
|
||
p2=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*(i+1)/n, 0))
|
||
p3=QtCore.QPointF(*tf3.map(szD[0]/2-szD[0]*i/n, 0))
|
||
col.setHsv(i*scl, 255, 255, alpha)
|
||
qp.setBrush(col)
|
||
qp.drawPolygon(p0, p1, p2, p3)
|
||
|
||
#draw dimensions
|
||
try:
|
||
(vr1, vr2, vaa, vbb, vcc)=p['geo']
|
||
vaa=90-vaa
|
||
vbb=90-vbb
|
||
vcc=90-vcc
|
||
except KeyError:
|
||
vr1=r1; vr2=r2; vaa=aa; vbb=bb; vcc=cc
|
||
|
||
qp.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
|
||
pen=QtGui.QPen(QtCore.Qt.red, 1, QtCore.Qt.SolidLine)
|
||
penTxt=QtGui.QPen(QtCore.Qt.yellow, 1, QtCore.Qt.SolidLine)
|
||
qp.setPen(pen)
|
||
p0=QtCore.QPointF(*tf0.map(-r1-10, +10))
|
||
p1=QtCore.QPointF(*tf0.map(-r1-10, 0+w))
|
||
qp.drawLine(p0,p1)
|
||
p2=QtCore.QPointF(*tf0.map(0, 0))
|
||
p3=QtCore.QPointF(*tf0.map(0, 0+w))
|
||
qp.drawLine(p2,p3)
|
||
p4=(p1+p3)/2 #text pos
|
||
p5=QtCore.QPointF(*tf2.map(0, 0+w))
|
||
qp.drawLine(p2,p5)
|
||
p6=QtCore.QPointF(*tf2.map(r2, 0))
|
||
p7=QtCore.QPointF(*tf2.map(r2, 0+w))
|
||
qp.drawLine(p6,p7)
|
||
p8=(p5+p7)/2 #text pos
|
||
|
||
p9=QtCore.QPointF(*tf1.map(0, -w))
|
||
qp.drawLine(p2,p9)
|
||
s=50
|
||
qp.drawArc(int(p2.x())-s, int(p2.y())-s, 2*s, 2*s, 180*16, int(aa*16))
|
||
s1=s*np.cos(aa*np.pi/180); s2=s*np.sin(aa*np.pi/180)
|
||
qp.drawArc(int(p2.x())-s, int(p2.y())-s, 2*s, 2*s, int(aa*16), int(bb*16))
|
||
|
||
qp.drawArc(int(p6.x())-s, int(p6.y())-s, 2*s, 2*s, int((aa+bb)*16), int(cc*16))
|
||
p10=QtCore.QPointF(*tf2.map(r2+20, 0)) #text pos
|
||
|
||
qp.setPen(penTxt)
|
||
qp.drawText(p4+QtCore.QPointF(-40,-10),f'R1={vr1:.5g}mm')
|
||
#qp.setTransform(QtGui.QTransform())
|
||
qp.translate(p8); qp.rotate(-aa-bb)
|
||
qp.drawText(-40,-10,f'R2={vr2:.5g}mm')
|
||
qp.setTransform(QtGui.QTransform())
|
||
qp.translate(p2); qp.rotate(-aa)
|
||
qp.drawText(20-int(szG[0]/2),20,f'aa={vaa:.5g}°')
|
||
qp.drawText(20,20,f'bb={vbb:.5g}°')
|
||
qp.setTransform(QtGui.QTransform())
|
||
qp.translate(p10); qp.rotate(-aa-bb)
|
||
qp.drawText(0,20,f'cc={vcc:.5g}°')
|
||
|
||
#for i,p in enumerate((p0,p1,p2,p3,p4,p5,p6,p7,p8,p9)):
|
||
# qp.drawText(p,f'P{i}')
|
||
#p5=QtCore.QPointF(*tf1.map(-r2-10, 50+w))
|
||
qp.end()
|
||
|
||
|
||
|
||
if __name__ == '__main__':
|
||
def main():
|
||
app=QApplication(sys.argv)
|
||
vlsg=geometry.VLSgrating()
|
||
vlsg.setup('80meV')
|
||
app._vlsg=vlsg
|
||
# ex = RIXSgirder()
|
||
ex=RIXSgrating()
|
||
sys.exit(app.exec_())
|
||
|
||
main() |