Files
EsfRixsApps/ARESvis/ARESvis.py
2024-08-28 13:39:27 +02:00

195 lines
6.5 KiB
Python
Executable File

#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2024 by Paul Scherrer Institute (http://www.psi.ch) |
# | |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
"""
SwissFEL Furka ARES visualization
bitmask for simulation:
0x01: EPICS motors
0x02:
0x04:
0x08:
0x10:
0x20:
0x40:
0x80:
"""
import sys, logging
import epics
_log=logging.getLogger(__name__)
from PyQt5.QtWidgets import QApplication, QWidget, QGroupBox, QVBoxLayout, QSlider
from PyQt5.QtGui import QPainter, QColor, QPen
#import PyQt5.QtGui as QtGui
import PyQt5.QtCore as QtCore
import numpy as np
class WndVisualizeARES(QWidget):
_lutColor={0:(255,0,0),1:(0,255,0),2:(255,255,0)}
def __init__(self):
super().__init__()
self._param={'ctr':(200, 320), # location of big chamber
'rCmb':150, # radius of chamber
'rTrg':10, # radius of target
'r2Th':100, # radius 2Theta platfform
'szSeal': (20,50),
'szArm': (80,250),
'aaSeal':70, # RIXS sliding angle
'aaArm':70, # RIXS arm angle
'airPads':0, # air pads (off=0 on=1 undef=2)
'defComp':0, # deformation compensation (off=0 on=1 undef=2)
}
# 2thetha angle SATES30-ARES:MOT_2TRY
# detector angle SATES30-ARES:MOT_DRY
# sliding seal SATES30-RIXS:MOT_RY
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 850, 800)
self.setWindowTitle('ARES visualize')
#label = QLabel('Python', self)
#label.move(50,50)
#b1 = QPushButton("Button1",self)
#b1.move(400,150)
self._wdGrpDraw=w=QGroupBox("ARES chamber",self)
w.move(10,10)
l=QVBoxLayout(w)
sld={}
for key,rng,tk in (('aaSeal',(0,180),5),('aaArm',(0,180),5),('airPads',(0,2),1),('defComp',(0,2),1),):
sl=QSlider(QtCore.Qt.Horizontal,objectName=key)
sl.setFixedWidth(200);sl.setMinimum(rng[0]);sl.setMaximum(rng[1])
sl.setValue(self._param[key])
sl.setTickPosition(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):
p=self._param
#print(key,val)
if key=='aaArm':
p['aaSeal']=v=p['aaSeal']-p['aaArm']+val
wSl=self._wdGrpDraw.findChild(QSlider, 'aaSeal')
wSl.blockSignals(True)
wSl.setValue(int(v))
wSl.blockSignals(False)
sl=QSlider(QtCore.Qt.Horizontal,objectName=key)
p[key]=val
self.update()
def paintEvent(self, e):
p=self._param
ctr=p['ctr']
aaSeal=p['aaSeal']
aaArm=p['aaArm']
rCmb=p['rCmb']
r2Th=p['r2Th']
rTrg=p['rTrg']
xa,ya=p['szArm']
xs,ys=p['szSeal']
ap=p['airPads']
dc=p['defComp']
qp = QPainter()
qp.begin(self)
qp.translate(ctr[0],ctr[1])
tf0=qp.transform()
qp.setPen(QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine))
qp.setBrush(QColor(155, 155, 155, 128))
br1=qp.brush()
qp.drawEllipse(-rCmb, -rCmb, 2*rCmb, 2*rCmb) # big chamber
qp.drawEllipse(-r2Th, -r2Th, 2*r2Th, 2*r2Th) # big chamber
qp.drawEllipse(-rTrg, -rTrg, 2*rTrg, 2*rTrg) # target
qp.drawLine(0,-rCmb-50,0,-rTrg) #beam
qp.rotate(-aaSeal)
qp.translate(0,rCmb)
tf1=qp.transform()
xs2=xs//2
xa2=xa//2
ya2=ya//2
d=int(abs(aaSeal-aaArm)*20)
r=min(155+d,255)
gb=max(155-d,0)
qp.setBrush(QColor(r, gb, gb, 255))
qp.drawRect(-xs2, 0, xs, ys) # seal bellow
qp.setBrush(br1)
qp.setTransform(tf0)
qp.rotate(-aaArm)
qp.translate(0,rCmb+ys)
tf2=qp.transform()
qp.drawRect(-xa2, 0, xa, ya) # girder
#qp.drawEllipse(-ya2, 100+150, 20, 20) #pusher left
#qp.drawEllipse( ya2-r, 100+150, 20, 20) #pusher right
#air pad
r,g,b=WndVisualizeARES._lutColor[ap]
rd=13
r3=int(rd*np.sqrt(3))
qp.setBrush(QColor(r, g, b, 255))
qp.drawEllipse(-xa2-rd, ya-4*rd, 2*rd, 2*rd) #left
qp.drawEllipse(-xa2-rd+r3,ya-3*rd, 2*rd, 2*rd) #left
qp.drawEllipse(-xa2-rd+r3,ya-5*rd, 2*rd, 2*rd) #left
qp.drawEllipse( xa2-rd, ya-4*rd, 2*rd, 2*rd) #right
qp.drawEllipse( xa2-rd-r3,ya-3*rd, 2*rd, 2*rd) #right
qp.drawEllipse( xa2-rd-r3,ya-5*rd, 2*rd, 2*rd) #right
qp.drawEllipse( -rd, 3*rd, 2*rd, 2*rd) #grating
qp.drawEllipse( 0, 3*rd-r3, 2*rd, 2*rd) #grating
qp.drawEllipse( -2*rd, 3*rd-r3, 2*rd, 2*rd) #grating
qp.setBrush(br1)
#deformation compensation
r,g,b=WndVisualizeARES._lutColor[dc]
rd=14
qp.setBrush(QColor(r, g, b, 255))
qp.drawEllipse(-xa2, ya2, 2*rd, 2*rd) #air pad left
qp.drawEllipse( xa2-2*rd, ya2, 2*rd, 2*rd) #air pad right
#qp.drawEllipse( -rd, rd, 2*rd, 2*rd) #air pad grating
qp.setBrush(br1)
qp.end()
if __name__ == '__main__':
import argparse
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
def main():
epilog=__doc__ # +'\nExamples:'+''.join(map(lambda s:cmd+s, exampleCmd))+'\n'
parser=argparse.ArgumentParser(epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--mode', '-m', type=lambda x:int(x, 0), help='mode (see bitmasks) default=0x%(default)x', default=1)
parser.add_argument("--sim", "-s", type=lambda x: int(x,0), help="simulate devices (see bitmasks) default=0x%(default)x", default=0x01)
args=parser.parse_args()
_log.info('Arguments:{}'.format(args.__dict__))
app=QApplication(sys.argv)
app._args=args
#devUS=RIXSdevice('RIXS us', ofs=(750, 200), g=-100, s=-1500, sy=-20, cy=70)
#devDS=RIXSdevice('RIXS ds', ofs=(930, 630))
if args.mode&0x01:
app._wndVis=WndVisualizeARES()
#if args.mode&0x02:
sys.exit(app.exec_())
main()