add optics sample
This commit is contained in:
239
furkaRIXS.py
239
furkaRIXS.py
@@ -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)
|
||||
|
||||
10
furkaRIXS.ui
10
furkaRIXS.ui
@@ -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
BIN
logo/256x256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
180
opticsExample.py
Executable file
180
opticsExample.py
Executable 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_()
|
||||
Reference in New Issue
Block a user