397 lines
13 KiB
Python
Executable File
397 lines
13 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':(400,400), # location of vlsg
|
|
'r1':314,#distance probe grating
|
|
'r2':447,#distance grating detector
|
|
'aa':22, #grating angle
|
|
'cc':58, #detector angle
|
|
#'geo':(8,8,5,5,1), # scaling: r1,r2,aa,bb,cc
|
|
'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, 850, 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)
|
|
|
|
for i,t in enumerate(('Energy',)):
|
|
w=QLabel(t)
|
|
lg.addWidget(w, i,0)
|
|
w=QtGui.QLineEdit(t,objectName=t)
|
|
lg.addWidget(w, i,1)
|
|
|
|
w=QtGui.QPushButton('calc geometry')
|
|
i+=1;lg.addWidget(w, i, 1)
|
|
|
|
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(250,10)
|
|
#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)
|
|
w=QtGui.QPushButton('calc raw motors')
|
|
l.addWidget(w, i+1, 1)
|
|
|
|
|
|
|
|
w=QtGui.QGroupBox("Drawing",self)
|
|
w.move(10,160)
|
|
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 sldChanged(self,key,val,*args,**kwargs):
|
|
print(key,val)
|
|
if key=='energy':
|
|
app=QApplication.instance()
|
|
wEnergy=self._wdGrpEnergy.findChild(QtGui.QLineEdit,'Energy')
|
|
wGeo=self._wdGrpGeometry
|
|
wR1=wGeo.findChild(QtGui.QLineEdit,'R1')
|
|
wR2=wGeo.findChild(QtGui.QLineEdit,'R2')
|
|
wAA=wGeo.findChild(QtGui.QLineEdit,'aa')
|
|
wBB=wGeo.findChild(QtGui.QLineEdit,'bb')
|
|
wCC=wGeo.findChild(QtGui.QLineEdit,'cc')
|
|
|
|
wEnergy.setText(f'{val:.4g}')
|
|
vlsg=app._vlsg
|
|
(r1,r2,aa,bb,cc)=vlsg.energy2geometry(val)
|
|
wR1.setText(f'{r1:.4g}')
|
|
wR2.setText(f'{r2:.4g}')
|
|
wAA.setText(f'{aa:.4g}')
|
|
wBB.setText(f'{bb:.4g}')
|
|
wCC.setText(f'{cc:.4g}')
|
|
p=self._param
|
|
|
|
p['r1']=r1
|
|
p['r2']=r2
|
|
p['aa']=(90-aa)
|
|
p['bb']=(90-bb)
|
|
p['cc']=(90-cc)
|
|
else:
|
|
self._param[key]=val
|
|
|
|
#print(v)
|
|
|
|
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,r2,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)
|
|
|
|
qp.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
|
|
pen=QtGui.QPen(QtCore.Qt.red, 3, QtCore.Qt.SolidLine)
|
|
qp.setPen(pen)
|
|
p0=QtCore.QPointF(*tf0.map(-r1-10, +10))
|
|
p1=QtCore.QPointF(*tf0.map(-r1-10, 50+w))
|
|
qp.drawLine(p0,p1)
|
|
p2=QtCore.QPointF(*tf0.map(0, 0))
|
|
p3=QtCore.QPointF(*tf0.map(0, 50+w))
|
|
qp.drawLine(p2,p3)
|
|
p4=(p1+p3)/2
|
|
qp.drawText(p4,f'R1={r1:.5g}mm')
|
|
p5=QtCore.QPointF(*tf2.map(0, 50+w))
|
|
qp.drawLine(p2,p5)
|
|
p6=QtCore.QPointF(*tf2.map(r2, 0))
|
|
p7=QtCore.QPointF(*tf2.map(r2, 50+w))
|
|
qp.drawLine(p6,p7)
|
|
p8=(p5+p7)/2
|
|
qp.drawText(p8,f'R2={r2:.5g}mm')
|
|
|
|
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.drawText(p2+QtCore.QPointF(-s1,s2+20),f'aa={aa:.5g}°')
|
|
qp.drawArc(int(p2.x())-s, int(p2.y())-s, 2*s, 2*s, int(aa*16), int(bb*16))
|
|
qp.drawText(p2+QtCore.QPointF(s1,-s2+20),f'bb={bb:.5g}°')
|
|
|
|
qp.drawArc(int(p6.x())-s, int(p6.y())-s, 2*s, 2*s, int(180+aa+bb*16), int(cc*16))
|
|
p10=QtCore.QPointF(*tf2.map(r2+20, 0))
|
|
qp.drawText(p10,f'cc={cc:.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() |