moving ROI with stage and zoom

This commit is contained in:
2022-08-17 12:04:51 +02:00
parent aa9a2c9948
commit 22fcad62c1
4 changed files with 108 additions and 37 deletions

View File

@@ -141,8 +141,8 @@ class EmblWidget(QWidget):
def __init__(self, parent): def __init__(self, parent):
super(EmblWidget, self).__init__(parent) super(EmblWidget, self).__init__(parent)
parent.pixelsPerMillimeter.connect(self.save_ppm) #parent.pixelsPerMillimeter.connect(self.save_ppm)
parent.beamCameraCoordinatesChanged.connect(self.save_beam_coordinates) #parent.beamCameraCoordinatesChanged.connect(self.save_beam_coordinates)
self.setLayout(QVBoxLayout()) self.setLayout(QVBoxLayout())
w = QWidget() w = QWidget()

View File

@@ -22,13 +22,15 @@ _log = logging.getLogger(__name__)
#logger.setLevel(logging.INFO) #logger.setLevel(logging.INFO)
class SimMotor: class SimMotor:
def __init__(self,motor_base, short_name): def __init__(self,rec_name, short_name):
self._llm = -10 self._llm = -10
self._hlm = 10 self._hlm = 10
self._prec = 5 self._prec = 5
self._twv = 0.1
self._units = 'mm' self._units = 'mm'
self._pos = 3.1415 self._pos = 3.1415
self._short_name=short_name self._short_name=short_name
self._rec_name=rec_name
class SimMotorTweak(QWidget, Ui_MotorTweak): class SimMotorTweak(QWidget, Ui_MotorTweak):
event_val = pyqtSignal(str, dict) event_val = pyqtSignal(str, dict)
@@ -54,12 +56,9 @@ class SimMotorTweak(QWidget, Ui_MotorTweak):
self._templates = {} self._templates = {}
def connect_motor(self, motor_base, short_name=None, *args, **kwargs): def connect_motor(self, rec_name, short_name=None, *args, **kwargs):
self.label.setToolTip('{} => {}'.format(motor_base, motor_base)) self.label.setToolTip('{} => {}'.format(rec_name, short_name))
self.motor=SimMotor(motor_base, short_name) self.motor=SimMotor(rec_name, short_name)
twv=0.1
self.set_motor_validator() self.set_motor_validator()
self._drive_val.setText(str(self.motor._pos)) self._drive_val.setText(str(self.motor._pos))
self._drive_val.returnPressed.connect(self.move_motor_to_position) self._drive_val.returnPressed.connect(self.move_motor_to_position)
@@ -69,7 +68,7 @@ class SimMotorTweak(QWidget, Ui_MotorTweak):
tweak_min = kwargs.get("tweak_min", 0.0001) tweak_min = kwargs.get("tweak_min", 0.0001)
tweak_max = kwargs.get("tweak_max", 20.0) tweak_max = kwargs.get("tweak_max", 20.0)
self._tweak_val.setText(str(twv)) self._tweak_val.setText(str(self.motor._twv))
self._tweak_val.setValidator(QDoubleValidator(tweak_min, tweak_max, 4, self._tweak_val)) self._tweak_val.setValidator(QDoubleValidator(tweak_min, tweak_max, 4, self._tweak_val))
#self._tweak_val.editingFinished.connect(lambda m=self._pv_tweak_val: m.put(self._tweak_val.text())) #self._tweak_val.editingFinished.connect(lambda m=self._pv_tweak_val: m.put(self._tweak_val.text()))
self.tweak_forward.clicked.connect(lambda m: self.move_relative(float(self._tweak_val.text()))) self.tweak_forward.clicked.connect(lambda m: self.move_relative(float(self._tweak_val.text())))
@@ -108,6 +107,7 @@ class SimMotorTweak(QWidget, Ui_MotorTweak):
sleep(delay) sleep(delay)
_log.debug('{} rel move => {}'.format(self.motor._short_name, dist)) _log.debug('{} rel move => {}'.format(self.motor._short_name, dist))
self.update_label() self.update_label()
self.emit_signals(source_field='VAL')
def get_position(self): def get_position(self):
return self.motor._pos return self.motor._pos
@@ -148,23 +148,24 @@ class SimMotorTweak(QWidget, Ui_MotorTweak):
_log.debug('{} abs move => {}'.format(self.motor._short_name, drive)) _log.debug('{} abs move => {}'.format(self.motor._short_name, drive))
self.motor._pos=drive self.motor._pos=drive
self.update_label() self.update_label()
self.emit_signals(source_field='VAL')
def emit_signals(self, **kw): def emit_signals(self, **kw):
field = kw['source_field'] field = kw['source_field']
if field == 'VAL': if field == 'VAL':
self.event_val.emit(self._pvname, kw) self.event_val.emit(self.motor._rec_name, kw)
elif field == 'RBV': elif field == 'RBV':
self.event_readback.emit(self._pvname, kw) self.event_readback.emit(self.motor._rec_name, kw)
elif field == 'LVIO': elif field == 'LVIO':
self.event_soft_limit.emit(self._pvname, kw) self.event_soft_limit.emit(self.motor._rec_name, kw)
elif field == 'HLS': elif field == 'HLS':
self.event_high_hard_limit.emit(self._pvname, kw) self.event_high_hard_limit.emit(self.motor._rec_name, kw)
self.event_axis_fault.emit(self._pvname, kw) self.event_axis_fault.emit(self.motor._rec_name, kw)
elif field == 'LVIO': elif field == 'LVIO':
self.event_low_hard_limit.emit(self._pvname, kw) self.event_low_hard_limit.emit(self.motor._rec_name, kw)
self.event_axis_fault.emit(self._pvname, kw) self.event_axis_fault.emit(self.motor._rec_name, kw)
elif field == 'STAT': elif field == 'STAT':
self.event_axis_fault.emit(self._pvname, kw) self.event_axis_fault.emit(self.motor._rec_name, kw)
def set_val_on_status_change(self, **kw): def set_val_on_status_change(self, **kw):

View File

@@ -168,7 +168,7 @@ class geometry:
pix2pos[0, 1]=np.interp(zoom, K, AA[:, 0, 1]) pix2pos[0, 1]=np.interp(zoom, K, AA[:, 0, 1])
pix2pos[1, 0]=np.interp(zoom, K, AA[:, 1, 0]) pix2pos[1, 0]=np.interp(zoom, K, AA[:, 1, 0])
pix2pos[1, 1]=np.interp(zoom, K, AA[:, 1, 1]) pix2pos[1, 1]=np.interp(zoom, K, AA[:, 1, 1])
_log.debug('interpolation array:{}'.format(tuple(pix2pos.ravel()))) _log.debug(f'{zoom} -> {pix2pos.ravel()}')
def update_pix2pos(self, meas): def update_pix2pos(self, meas):
# calculates _lut_pix2pos out of measurements # calculates _lut_pix2pos out of measurements

View File

@@ -180,19 +180,19 @@ class Sequencer(QObject):
Ui_MainWindow, QMainWindow = loadUiType("swissmx.ui") Ui_MainWindow, QMainWindow = loadUiType("swissmx.ui")
class Main(QMainWindow, Ui_MainWindow): class Main(QMainWindow, Ui_MainWindow):
pixelsPerMillimeter = pyqtSignal(float) #pixelsPerMillimeter = pyqtSignal(float)
beamCameraCoordinatesChanged = pyqtSignal(float, float) #beamCameraCoordinatesChanged = pyqtSignal(float, float)
addGridRequest = pyqtSignal(float, float) addGridRequest = pyqtSignal(float, float)
zoomChanged = pyqtSignal(float) #zoomChanged = pyqtSignal(float)
folderChanged = pyqtSignal(str) folderChanged = pyqtSignal(str)
prefixChanged = pyqtSignal(str) prefixChanged = pyqtSignal(str)
projectChanged = pyqtSignal(str) projectChanged = pyqtSignal(str)
gridUpdated = pyqtSignal(int) # index in self._grids gridUpdated = pyqtSignal(int) # index in self._grids
gonioMoveRequest = pyqtSignal(float, float, float, float, float) gonioMoveRequest = pyqtSignal(float, float, float, float, float)
fast_x_position = pyqtSignal(float) #fast_x_position = pyqtSignal(float)
fast_y_position = pyqtSignal(float) #fast_y_position = pyqtSignal(float)
fast_dx_position = pyqtSignal(float) #fast_dx_position = pyqtSignal(float)
fast_dy_position = pyqtSignal(float) #fast_dy_position = pyqtSignal(float)
fiducialPositionSelected = pyqtSignal(float, float, float, float) # camx, camy, gonx, gony fiducialPositionSelected = pyqtSignal(float, float, float, float) # camx, camy, gonx, gony
appendPrelocatedPosition = pyqtSignal(float, float, float, float) appendPrelocatedPosition = pyqtSignal(float, float, float, float)
appendPrelocatedFiducial = pyqtSignal(bool, float, float, float, float) appendPrelocatedFiducial = pyqtSignal(bool, float, float, float, float)
@@ -346,18 +346,21 @@ class Main(QMainWindow, Ui_MainWindow):
#--- beam marker --- #--- beam marker ---
bm_sz=np.array((50, 40)) # it is immidiatly repositioned in zoom_changed_cb bm_sz=np.array((50, 40)) # it is immidiatly repositioned in zoom_changed_cb
self._goBeamMarker=bm=UsrGO.Marker(-opt_ctr-bm_sz/2,bm_sz,mode=0) self._goBeamMarker=bm=UsrGO.Marker(-opt_ctr-bm_sz/2,bm_sz,mode=0)
self.vb.addItem(bm) vb.addItem(bm)
#--- opctical center ---- #--- opctical center ----
oc_sz=np.array((50,50)) 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)
bm.setTransform(tr) # assign transform bm.setTransform(tr) # assign transform
self.vb.addItem(obj) vb.addItem(obj)
#--- testing scan grid --- #--- testing scan grid ---
vi=UsrGO.Grid((120, -100), (200, 150), (30, 22), 2) self.track_objects() # first call is needed to initialize the structure self._goTracked
vi.setTransform(tr) # assign transform go=UsrGO.Grid((120, -100), (200, 150), (30, 22), 2)
self.vb.addItem(vi) go.setTransform(tr) # assign transform
vb.addItem(go)
self._goTracked['objLst'].append(go)
self.track_objects() #tracking now the objects
#UsrGO.obj_tree(vb) #UsrGO.obj_tree(vb)
@@ -1037,7 +1040,7 @@ class Main(QMainWindow, Ui_MainWindow):
return return
def zoom_changed_cb(self, value): def zoom_changed_cb(self, value):
self.zoomChanged.emit(value) #self.zoomChanged.emit(value)
app=QApplication.instance() app=QApplication.instance()
cfg=app._cfg cfg=app._cfg
geo=app._geometry geo=app._geometry
@@ -1055,8 +1058,73 @@ class Main(QMainWindow, Ui_MainWindow):
bm.setPos(bm_pos,finish=False) bm.setPos(bm_pos,finish=False)
bm.setSize(bm_sz) bm.setSize(bm_sz)
_log.debug(f"zoom->{value} beam marker pos:{bm_pos} sz:{bm_sz})") _log.debug(f"zoom->{value} beam marker pos:{bm_pos} sz:{bm_sz})")
self.track_objects()
#self.update_beam_marker(value) #self.update_beam_marker(value)
def track_objects(self):
#self._goTracked= dictionary with infos about tracked objects
# objLst = list of objects to track
# state = (zoom, fx, fy) (created at first call of self.track_objects() )
app=QApplication.instance()
geo=app._geometry
zoom = app._zoom.get()
fast_x=self.tweakers["fast_x"];fast_y=self.tweakers["fast_y"]
fx=fast_x.get_position()
fy=fast_y.get_position()
try:
tracked=self._goTracked
zoom_old,fx_old,fy_old=tracked['state']
except AttributeError: # at initialization
self._goTracked={'objLst':list(), 'state':(zoom,fx,fy)}
return
_log.debug(f"zoom:{zoom_old}->{zoom} fx:{fx_old}->{fx} fy:{fy_old}->{fy}")
opt_ctr=geo._opt_ctr
if zoom_old!=zoom:
geo.interp_zoom(zoom_old)
pix2pos_old=geo._pix2pos
geo.interp_zoom(zoom)
pix2pos_new=geo._pix2pos
for o in tracked['objLst']:
# names consists of abrevations
# part 0: po=position sz=size dt=delta
# part 1: px=pixel eu=engineering units (e.g. mm)
po_px=o.pos()
sz_px=o.size()
tr=o.transform()
geo._pix2pos=pix2pos_old
dt_px=-opt_ctr-po_px
dt_eu=geo.pix2pos(dt_px)
sz_eu=geo.pix2pos(sz_px)
geo._pix2pos=pix2pos_new
dt_px2=geo.pos2pix(dt_eu)
sz_px2=geo.pos2pix(sz_eu)
po_px2=-opt_ctr-dt_px2
o.setPos(po_px2)
o.setSize(sz_px2)
#np.asarray(self._pix2pos*np.mat(p).T).ravel()
geo.interp_zoom(zoom)
if fx_old!=fx or fy_old!=fy:
p1=geo.pos2pix((fx_old,fy_old))
p2=geo.pos2pix((fx,fy))
d=p2-p1
for o in tracked['objLst']:
pos=o.pos()
sz=o.size()
tr=o.transform()
o.setPos(pos+d)
tracked['state']=(zoom, fx, fy)
#imgPos=self._goImg.mapFromScene(event.scenePos())
#x=imgPos.x();y=imgPos.y()
def append_to_beam_markers(self, x, y, zoom): def append_to_beam_markers(self, x, y, zoom):
self._beam_markers[zoom] = (x, y) self._beam_markers[zoom] = (x, y)
_log.info("beam markers {}".format(self._beam_markers)) _log.info("beam markers {}".format(self._beam_markers))
@@ -1195,7 +1263,7 @@ class Main(QMainWindow, Ui_MainWindow):
pos=event.scenePos() pos=event.scenePos()
_log.debug(f'move to position :scene pos {pos}') _log.debug(f'move to position :scene pos {pos}')
geo=app._geometry geo=app._geometry
geo.interp_zoom(1) #geo.interp_zoom(1)
bm=self._goBeamMarker bm=self._goBeamMarker
p1=self._goImg.mapFromScene(pos) p1=self._goImg.mapFromScene(pos)
p2=bm.pos()+bm.size()/2 p2=bm.pos()+bm.size()/2
@@ -1657,9 +1725,11 @@ class Main(QMainWindow, Ui_MainWindow):
for key, tweaker in self.tweakers.items(): for key, tweaker in self.tweakers.items():
tweaker.event_axis_fault.connect(self.axis_fault) tweaker.event_axis_fault.connect(self.axis_fault)
self.tweakers["fast_x"].event_readback.connect(lambda alias, value, kw: self.fast_x_position.emit(value)) #self.tweakers["fast_x"].event_readback.connect(lambda alias, value, kw: self.fast_x_position.emit(value))
self.tweakers["fast_y"].event_readback.connect(lambda alias, value, kw: self.fast_y_position.emit(value)) #self.tweakers["fast_y"].event_readback.connect(lambda alias, value, kw: self.fast_y_position.emit(value))
self.tweakers["fast_x"].event_val.connect(lambda rec_name, kw: self.track_objects())
self.tweakers["fast_y"].event_val.connect(lambda rec_name, kw: self.track_objects())
# layout.addStretch() # layout.addStretch()
def axis_fault(self, pvname, kw): def axis_fault(self, pvname, kw):
@@ -1968,7 +2038,7 @@ class Main(QMainWindow, Ui_MainWindow):
usy.move_relative(-tandem_twv) usy.move_relative(-tandem_twv)
dsy.move_relative(-tandem_twv) dsy.move_relative(-tandem_twv)
def get_tweaker(self, pv, alias=None, label=None, mtype="epics_motor", layout=None, **kwargs): def get_tweaker(self, rec, alias=None, label=None, mtype="epics_motor", layout=None, **kwargs):
app = QApplication.instance() app = QApplication.instance()
sim=app._args.sim sim=app._args.sim
if mtype == "epics_motor": if mtype == "epics_motor":
@@ -1981,7 +2051,7 @@ class Main(QMainWindow, Ui_MainWindow):
m=SimMotorTweak() m=SimMotorTweak()
else: else:
m = SmaractMotorTweak() m = SmaractMotorTweak()
m.connect_motor(pv, label, **kwargs) m.connect_motor(rec, label, **kwargs)
self.tweakers[alias] = m self.tweakers[alias] = m
return m return m