#!/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()