add optics sample

This commit is contained in:
2022-10-31 14:24:55 +01:00
parent afe4945975
commit 6eff498fba
4 changed files with 408 additions and 21 deletions

View File

@@ -22,6 +22,15 @@ bitmask for simulation:
import logging
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
logging.getLogger('PyQt5.uic').setLevel(logging.INFO)
#logging.getLogger('requests').setLevel(logging.INFO)
#logging.getLogger('urllib3').setLevel(logging.INFO)
#logging.getLogger('paramiko').setLevel(logging.INFO)
logging.getLogger('matplotlib').setLevel(logging.INFO)
#logging.getLogger('PIL').setLevel(logging.INFO)
#logging.getLogger('illumination').setLevel(logging.INFO)
#logging.getLogger('zoom').setLevel(logging.INFO)
#logging.getLogger('pbtools.misc.pp_comm').setLevel(logging.INFO)
_log = logging.getLogger("furkaRIXS")
import time
@@ -34,7 +43,7 @@ class timestamp():
self.t=t
ts=timestamp()
ts.log('Import part 1/8:')
import sys, os, time
import sys, os, time, signal
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.use('Qt5Agg') # needed to avoid blocking of ui !
@@ -79,11 +88,32 @@ def sigint_handler(*args):
app=QApplication.instance()
app.quit()
class StartupSplash:
def __init__(self):
splash_pix = QPixmap("logo/256x256.png")
self._wnd=splash = QSplashScreen(splash_pix, Qt.WindowStaysOnTopHint)
splash.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
splash.setEnabled(False)
self._prgsBar=prgs=QProgressBar(splash)
prgs.setMaximum(100)
prgs.setGeometry(0, splash_pix.height() - 50, splash_pix.width(), 20)
splash.show()
def set(self,i,msg):
self._prgsBar.setValue(i)
self._wnd.showMessage(f"<font color='red'>{msg}</font></h1>", int(Qt.AlignBottom|Qt.AlignCenter), Qt.black)
app=QApplication.instance()
app.processEvents()
time.sleep(.1)
Ui_MainWindow, QMainWindow = loadUiType("furkaRIXS.ui")
class WndFurkaRIXS(QMainWindow, Ui_MainWindow):
def __init__(self,):
super(WndSwissMx, self).__init__()
super(WndFurkaRIXS, self).__init__()
self.setupUi(self)
app=QApplication.instance()
@@ -93,9 +123,193 @@ class WndFurkaRIXS(QMainWindow, Ui_MainWindow):
#self.init_settings()
#self.setup_sliders()
#self.init_graphics()
#self.init_actions()
self.init_graphics()
self.init_actions()
def init_graphics(self):
app = QApplication.instance()
#cfg = app._cfg
#geo = app._geometry
self.glw = pg.GraphicsLayoutWidget()
self._wdVert1.setLayout(QVBoxLayout())
self._wdVert1.layout().addWidget(self.glw)
self.glw.show()
self.glw.scene().sigMouseMoved.connect(self.cb_mouse_move)
self.glw.scene().sigMouseClicked.connect(self.cb_mouse_click)
#--- viewbox ---
self.vb=vb=self.glw.addViewBox(invertY=False,border='r',enableMenu=True)
#TODO: vb.enableAutoRange(enable=True), vb.autoRange() does not work for ItemGroups
#therefore set the vieweRange manually
pad=10
vb.setRange(QRectF(-1200-pad,-1000-pad,1200+2*pad,1000+2*pad))
vb.setAspectLocked(True)
vb.setBackgroundColor((120, 90, 90))
tr=QtGui.QTransform() # prepare ImageItem transformation:
# opt_ctr=app._geometry._opt_ctr
# #--- image group ---
# # uses image transformation
# # contains image and opticalcenter
# self._goImgGrp=grp=pg.ItemGroup()
# self.vb.addItem(grp)
# trf=cfg.value(AppCfg.GEO_CAM_TRF)
# # be aware: setTransform is transposed!
# # Qt uses: p'=(p.T*A.T).T , but I am used: p'=A*p, with p=[x,y,1].T
# tr.setMatrix(trf[0,0],trf[1,0],trf[2,0], #(-1, 0, 0,
# trf[0,1],trf[1,1],trf[2,1], # 0,-1, 0,
# trf[0,2],trf[1,2],trf[2,2]) # 0, 0, 1)
# grp.setTransform(tr) # assign transform
# #--- image ---
# self._goImg=img=pg.ImageItem() #border=pg.mkPen('r',width=2))
# grp.addItem(img)
# #--- opctical center ----
# oc_sz=np.array((50,50))
# #self._goOptCtr=obj=UsrGO.Marker(-opt_ctr+oc_sz/2, oc_sz,mode=1)
# self._goOptCtr=obj=UsrGO.Marker(opt_ctr-oc_sz/2, oc_sz,mode=1, movable=False)
# obj.sigRegionChangeFinished.connect(self.cb_marker_moved)
# grp.addItem(obj)
#--- grid ---
try:
self._goGrid=grid=pg.GridItem(pen=(0,255,0),textPen=(0,255,0)) #green grid and labels
except NameError:
_log.debug('workaround for typo in pyqtgraph:0.11.0')
from PyQt5.QtGui import QPen,QColor
self._goGrid=grid=pg.GridItem() # green grid and labels
grid.opts['pen']=QPen(QColor(0, 255, 0))
grid.opts['textPen']=QPen(QColor(0, 255, 0))
#tr.reset()
#grid.setTransform(tr) # assign transform
vb.addItem(grid)
# #--- fixed group ---
# # uses pix2pos transformation with a fixed fx,fy value =(0,0)
# # contains beam marker
# self._goFixGrp=grp=pg.ItemGroup()
# geo.interp_zoom(1)
# pix2pos=geo._pix2pos
# A=np.asarray(pix2pos.I)
# tr=grp.transform()
# p1=np.hstack((opt_ctr,1)) #position of optical center on image item
# p2=np.matmul(trf, p1) #position of optical center on viewbox
# tr.setMatrix(A[0,0], A[0,1], 0,
# A[1,0], A[1,1], 0,
# p2[0], p2[1], 1) # translate dx,dy
# grp.setTransform(tr)
# self.vb.addItem(grp)
# #--- beam marker ---
# size_eu=cfg.value(AppCfg.GEO_BEAM_SZ)/1000 # convert from um to mm
# pos_eu=cfg.value(AppCfg.GEO_BEAM_POS)/1000 # convert from um to mm
# self._goBeamMarker=obj=UsrGO.Marker(pos_eu-size_eu/2,size_eu,mode=0,movable=False)
# obj.sigRegionChangeFinished.connect(self.cb_marker_moved)
# #bm.setTransform(tr) # assign transform
# grp.addItem(obj)
def init_actions(self):
app = QApplication.instance()
self._actQuit.triggered.connect(self.cb_really_quit)
self._actPreferences.triggered.connect(self.cb_modify_app_param)
self._actAbout.triggered.connect(self.cb_about)
def cb_really_quit(self):
"""called when user Ctrl-Q the app"""
if QMessageBox.question(self, "", "Are you sure you want to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) == QMessageBox.Yes:
self._do_quit = True
self.close()
def cb_modify_app_param(self):
wnd=WndParameter(self)
wnd.show()
def cb_about(self):
try:
ver,gitcmt=get_version()
v_txt=f'{ver} git:{gitcmt}'
except:
v_txt='git version failed'
txt=f'''About Swissmx:
FurkaRIXS: {v_txt}
qt:{QT_VERSION_STR}
pyqtgraph:{pg.__version__}
numpy:{np.__version__}
matplotlib:{mpl.__version__}
epics:{epics.__version__}
Copyright (c) 2022 by Paul Scherrer Institute
(http://www.psi.ch)
Author Thierry Zamofing (thierry.zamofing@psi.ch)
'''
QMessageBox.about(self, "FurkaRIXS", txt)
pass
def cb_mouse_move(self, pos):
app = QApplication.instance()
return
geo = app._geometry
#pos = pixel position on the widget
task = self.active_task()
z = app._zoom.get_val()
bm=self._goBeamMarker
#pos=event.scenePos()
pImg=pg.Point(self._goImg.mapFromScene(pos))
pTrk=pg.Point(self._goTracked.mapFromScene(pos))
pFix=pg.Point(self._goFixGrp.mapFromScene(pos))
pFix-=bm.pos()+bm.size()/2
fx=self.tweakers["fast_x"].get_val()
fy=self.tweakers["fast_y"].get_val()
pRel=pTrk-(fx,fy)
#s=f'pImg{pImg} pTrk{pTrk} bm._pos_eu{bm._pos_eu}'
try:
pln=geo._fitPlane
except AttributeError:
cz=np.nan
else:
cz=pln[0]*pTrk[0]+pln[1]*pTrk[1]+pln[2] # z=ax+by+c
s=\
f'img pix ({pImg[0]:0.1f} {pImg[1]:0.1f})px \u23A2 ' \
f'stage ({pTrk[0]:0.4f} {pTrk[1]:>0.4f} {cz:>0.4f})mm \u23A2 ' \
f'dist to beam ({pFix[0]:>0.4f} {pFix[1]:>0.4f})mm '
#f'dist to beam ({pRel[0]:>0.6g} {pRel[1]:>0.6g}mm) '
#_log.debug(s)
self._lb_coords.setText(s)
def cb_mouse_click(self, event):
#_log.debug("{}".format(event))
#_log.debug("screen pos {}".format(event.screenPos())) #pixel position on the whole screen
#_log.debug("scene pos {}".format(event.scenePos())) #pixel position on the scene (including black frame)
#_log.debug(" pos {}".format(event.pos())) #pixel position of the ckicked object mapped to its coordinates
#p=event.scenePos()
#_log.debug(f"vb pos {self.vb.mapFromScene(p)}") #pixel position on the scene (including black frame)
#for o in self.vb.childGroup.childItems():
# _log.debug(f"{type(o)} pos {o.mapFromScene(p)}") #pixel position on the scene (including black frame)
#_log.debug(f"currentItem:{event.currentItem}")
app=QApplication.instance()
mod=event.modifiers()
btn=event.button()
#dblclick = event.double()
#if btn==Qt.LeftButton:
# if mod&Qt.ShiftModifier:
# pass
# elif mod&Qt.ControlModifier:
# pos=event.scenePos()
# _log.debug(f'move to position :scene pos {pos}')
if __name__=="__main__":
@@ -118,20 +332,21 @@ if __name__=="__main__":
from PyQt5.QtWidgets import QApplication
# set app icon
#app = QApplication(sys.argv)
#app_icon = QtGui.QIcon()
app = QApplication(sys.argv)
app_icon = QtGui.QIcon()
#app_icon.addFile("artwork/logo/16x16.png", QtCore.QSize(16, 16))
#app_icon.addFile("artwork/logo/24x24.png", QtCore.QSize(24, 24))
#app_icon.addFile("artwork/logo/32x32.png", QtCore.QSize(32, 32))
#app_icon.addFile("artwork/logo/48x48.png", QtCore.QSize(48, 48))
#app_icon.addFile("artwork/logo/256x256.png", QtCore.QSize(256, 256))
#app.setWindowIcon(app_icon)
app_icon.addFile("logo/256x256.png", QtCore.QSize(256, 256))
app.setWindowIcon(app_icon)
#startupWin=StartupSplash()
startupWin=StartupSplash()
app._args=args
#startupWin.set(5, f'load settings')
startupWin.set(5, f'load settings')
startupWin.set(10, f'load settings')
#app._cfg=cfg=AppCfg()
#app._geometry=geometry.geometry()
@@ -165,11 +380,11 @@ if __name__=="__main__":
# app._camera = camera.epics_cam()
##app._camera.run() is called in center_piece_update
#startupWin.set(60, f'start main window')
startupWin.set(60, f'start main window')
app._mainWnd=wnd=WndFurkaRIXS()
wnd.show()
#startupWin._wnd.finish(wnd)
startupWin._wnd.finish(wnd)
# needed so pycharm can restart application
signal.signal(signal.SIGINT, sigint_handler)

View File

@@ -47,15 +47,7 @@
</layout>
</widget>
<widget class="QWidget" name="_wdVert1" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
<layout class="QVBoxLayout" name="verticalLayout_2"/>
</widget>
<widget class="QWidget" name="_wdVert2" native="true">
<layout class="QVBoxLayout" name="verticalLayout_3">

BIN
logo/256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

180
opticsExample.py Executable file
View File

@@ -0,0 +1,180 @@
#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | Based on Zac great first implementation |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
# -*- coding: utf-8 -*-
"""
Optical system design demo
"""
#import initExample ## Add path to library (just for examples; you do not need this)
#sys.path.insert(0, "/home/myname/pythonfiles")
from pyqtgraph.examples.optics import *
import pyqtgraph as pg
import numpy as np
from pyqtgraph import Point
app = pg.QtGui.QApplication([])
w = pg.GraphicsLayoutWidget(show=True, border=0.5)
w.resize(1000, 900)
w.show()
### Curved mirror demo
view = w.addViewBox()
view.setAspectLocked()
#grid = pg.GridItem()
#view.addItem(grid)
view.setRange(pg.QtCore.QRectF(-50, -30, 100, 100))
optics = []
rays = []
m1 = Mirror(r1=-100, pos=(5,0), d=5, angle=-15)
optics.append(m1)
m2 = Mirror(r1=-70, pos=(-40, 30), d=6, angle=180-15)
optics.append(m2)
allRays = []
for y in np.linspace(-10, 10, 21):
r = Ray(start=Point(-100, y))
view.addItem(r)
allRays.append(r)
for o in optics:
view.addItem(o)
t1 = Tracer(allRays, optics)
### Dispersion demo
optics = []
view = w.addViewBox()
view.setAspectLocked()
#grid = pg.GridItem()
#view.addItem(grid)
view.setRange(pg.QtCore.QRectF(-10, -50, 90, 60))
optics = []
rays = []
l1 = Lens(r1=20, r2=20, d=10, angle=8, glass='Corning7980')
optics.append(l1)
allRays = []
for wl in np.linspace(355,1040, 25):
for y in [10]:
r = Ray(start=Point(-100, y), wl=wl)
view.addItem(r)
allRays.append(r)
for o in optics:
view.addItem(o)
t2 = Tracer(allRays, optics)
### Scanning laser microscopy demo
w.nextRow()
view = w.addViewBox(colspan=2)
optics = []
#view.setAspectLocked()
view.setRange(QtCore.QRectF(200, -50, 500, 200))
## Scan mirrors
scanx = 250
scany = 20
m1 = Mirror(dia=4.2, d=0.001, pos=(scanx, 0), angle=315)
m2 = Mirror(dia=8.4, d=0.001, pos=(scanx, scany), angle=135)
## Scan lenses
l3 = Lens(r1=23.0, r2=0, d=5.8, pos=(scanx+50, scany), glass='Corning7980') ## 50mm UVFS (LA4148)
l4 = Lens(r1=0, r2=69.0, d=3.2, pos=(scanx+250, scany), glass='Corning7980') ## 150mm UVFS (LA4874)
## Objective
obj = Lens(r1=15, r2=15, d=10, dia=8, pos=(scanx+400, scany), glass='Corning7980')
IROptics = [m1, m2, l3, l4, obj]
## Scan mirrors
scanx = 250
scany = 30
m1a = Mirror(dia=4.2, d=0.001, pos=(scanx, 2*scany), angle=315)
m2a = Mirror(dia=8.4, d=0.001, pos=(scanx, 3*scany), angle=135)
## Scan lenses
l3a = Lens(r1=46, r2=0, d=3.8, pos=(scanx+50, 3*scany), glass='Corning7980') ## 100mm UVFS (LA4380)
l4a = Lens(r1=0, r2=46, d=3.8, pos=(scanx+250, 3*scany), glass='Corning7980') ## 100mm UVFS (LA4380)
## Objective
obja = Lens(r1=15, r2=15, d=10, dia=8, pos=(scanx+400, 3*scany), glass='Corning7980')
IROptics2 = [m1a, m2a, l3a, l4a, obja]
for o in set(IROptics+IROptics2):
view.addItem(o)
IRRays = []
IRRays2 = []
for dy in [-0.4, -0.15, 0, 0.15, 0.4]:
IRRays.append(Ray(start=Point(-50, dy), dir=(1, 0), wl=780))
IRRays2.append(Ray(start=Point(-50, dy+2*scany), dir=(1, 0), wl=780))
for r in set(IRRays+IRRays2):
view.addItem(r)
IRTracer = Tracer(IRRays, IROptics)
IRTracer2 = Tracer(IRRays2, IROptics2)
phase = 0.0
def update():
global phase
if phase % (8*np.pi) > 4*np.pi:
m1['angle'] = 315 + 1.5*np.sin(phase)
m1a['angle'] = 315 + 1.5*np.sin(phase)
else:
m2['angle'] = 135 + 1.5*np.sin(phase)
m2a['angle'] = 135 + 1.5*np.sin(phase)
phase += 0.2
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(40)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()