Files
EsfRixsApps/graphExample.py
2022-11-08 10:41:05 +01:00

444 lines
15 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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')
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}')
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 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, r1, 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, r2, 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()