add ModuleFixTarget tab
This commit is contained in:
784
ModuleFixTarget.py
Normal file
784
ModuleFixTarget.py
Normal file
@@ -0,0 +1,784 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# *-----------------------------------------------------------------------*
|
||||||
|
# | |
|
||||||
|
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
|
||||||
|
# | |
|
||||||
|
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
|
||||||
|
# *-----------------------------------------------------------------------*
|
||||||
|
'''
|
||||||
|
Module to handle FixTarget acquisition
|
||||||
|
|
||||||
|
This contains a Widget to handle FixTargetFrames and fiducials, calculate final target positions etc.
|
||||||
|
'''
|
||||||
|
|
||||||
|
#https://stackoverflow.com/questions/27909658/json-encoder-and-decoder-for-complex-numpy-arrays
|
||||||
|
|
||||||
|
# import yaml
|
||||||
|
# class Dice(tuple):
|
||||||
|
# def __new__(cls, a, b):
|
||||||
|
# return tuple.__new__(cls, [a, b])
|
||||||
|
# def __repr__(self):
|
||||||
|
# return "Dice(%s,%s)" % self
|
||||||
|
# d=Dice(3,6)
|
||||||
|
# print(d)
|
||||||
|
# print(yaml.dump(d))
|
||||||
|
# def dice_representer(dumper, data):
|
||||||
|
# return dumper.represent_scalar(u'!dice', u'%sd%s' % data)
|
||||||
|
# yaml.add_representer(Dice, dice_representer)
|
||||||
|
# def dice_constructor(loader, node):
|
||||||
|
# value = loader.construct_scalar(node)
|
||||||
|
# a, b = map(int, value.split('d'))
|
||||||
|
# return Dice(a, b)
|
||||||
|
# yaml.add_constructor(u'!dice', dice_constructor)
|
||||||
|
# print(yaml.load("initial hit points: !dice 8d4"))
|
||||||
|
|
||||||
|
import logging
|
||||||
|
_log=logging.getLogger(__name__)
|
||||||
|
|
||||||
|
import os, pickle, json, yaml,base64
|
||||||
|
import numpy as np
|
||||||
|
import pyqtgraph as pg
|
||||||
|
from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal, pyqtSlot
|
||||||
|
from PyQt5.QtWidgets import (
|
||||||
|
QTableWidgetItem,
|
||||||
|
QFileDialog,
|
||||||
|
QGroupBox,
|
||||||
|
QWidget,
|
||||||
|
QGridLayout,
|
||||||
|
QTableWidget,
|
||||||
|
QAbstractItemView,
|
||||||
|
QItemDelegate,
|
||||||
|
QVBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QPushButton,
|
||||||
|
QApplication,
|
||||||
|
QMainWindow,
|
||||||
|
QHeaderView,
|
||||||
|
QLineEdit,
|
||||||
|
QSpinBox,
|
||||||
|
QMessageBox,
|
||||||
|
QAction,
|
||||||
|
QComboBox,
|
||||||
|
QCheckBox)
|
||||||
|
|
||||||
|
|
||||||
|
class MyJsonEncoder(json.JSONEncoder):
|
||||||
|
""" Special json encoder for numpy types """
|
||||||
|
def default(self, obj):
|
||||||
|
if isinstance(obj, np.integer):
|
||||||
|
return int(obj)
|
||||||
|
elif isinstance(obj, np.floating):
|
||||||
|
return float(obj)
|
||||||
|
elif isinstance(obj, np.ndarray):
|
||||||
|
data_b64=base64.b64encode(obj.data)
|
||||||
|
return dict(__ndarray__=data_b64,dtype=str(obj.dtype),shape=obj.shape)
|
||||||
|
#return obj.tolist()
|
||||||
|
elif isinstance(obj, set):
|
||||||
|
return list(obj)
|
||||||
|
if type(obj) not in (dict,list,str,int):
|
||||||
|
_log.error('dont know how to json')
|
||||||
|
return repr(obj)
|
||||||
|
return json.JSONEncoder.default(self, obj)
|
||||||
|
|
||||||
|
def MyJsonDecoder(dct):
|
||||||
|
if isinstance(dct, dict) and '__ndarray__' in dct:
|
||||||
|
data = base64.b64decode(dct['__ndarray__'])
|
||||||
|
return np.frombuffer(data[:-1], dct['dtype']).reshape(dct['shape'])
|
||||||
|
return dct
|
||||||
|
|
||||||
|
def yaml_repr_numpy(dumper, data):
|
||||||
|
return dumper.represent_scalar(u'!np_array', u'%s' % repr(data))
|
||||||
|
yaml.add_representer(np.ndarray, yaml_repr_numpy)
|
||||||
|
|
||||||
|
def yaml_cnstr_numpy(loader, node):
|
||||||
|
value = loader.construct_scalar(node)
|
||||||
|
a=eval(value[6:-1])
|
||||||
|
return np.array(a)
|
||||||
|
yaml.add_constructor(u'!np_array', yaml_cnstr_numpy)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MarkerDelegate(QItemDelegate):
|
||||||
|
def createEditor(self, parent, option, index):
|
||||||
|
comboBox=QLineEdit(parent)
|
||||||
|
comboBox.editingFinished.connect(self.emitCommitData)
|
||||||
|
return comboBox
|
||||||
|
|
||||||
|
def setEditorData(self, editor, index):
|
||||||
|
# pos = comboBox.findText(index.model().data(index), Qt.MatchExactly)
|
||||||
|
# comboBox.setCurrentIndex(pos)
|
||||||
|
editor.setText("{}".format(index.model().data(index)))
|
||||||
|
|
||||||
|
def setModelData(self, editor, model, index):
|
||||||
|
print("model {}".format(model))
|
||||||
|
print(
|
||||||
|
"delegate setData: {}x{} => {}".format(
|
||||||
|
index.row(), index.column(), editor.text()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
model.setData(index, editor.text())
|
||||||
|
model.setData(index, float(editor.text()), Qt.UserRole)
|
||||||
|
|
||||||
|
def emitCommitData(self):
|
||||||
|
print("imagedelegate emitting")
|
||||||
|
self.commitData.emit(self.sender())
|
||||||
|
|
||||||
|
|
||||||
|
class WndFixTarget(QWidget):
|
||||||
|
prefixSelected = pyqtSignal(str)
|
||||||
|
dataFileLoaded = pyqtSignal(str)
|
||||||
|
prelocatedDataUpdated = pyqtSignal()
|
||||||
|
markersDeleted = pyqtSignal()
|
||||||
|
markerAdded = pyqtSignal(bool, list) # emits is_fiducial(boolean), [x, y, cx, cy]
|
||||||
|
selectedRowChanged = pyqtSignal(int)
|
||||||
|
moveFastStageRequest = pyqtSignal(float, float)
|
||||||
|
|
||||||
|
def __init__(self, parent=None,data=None):
|
||||||
|
super(WndFixTarget, self).__init__(parent)
|
||||||
|
self._xtals_transformed = True
|
||||||
|
|
||||||
|
self._current_row = None
|
||||||
|
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
frame = QWidget()
|
||||||
|
bl = QGridLayout()
|
||||||
|
frame.setLayout(bl)
|
||||||
|
|
||||||
|
btnLd = QPushButton("Load Datafile")
|
||||||
|
btnLd.clicked.connect(lambda: self.load_file(None))
|
||||||
|
bl.addWidget(btnLd, 0, 0)
|
||||||
|
|
||||||
|
btnSv = QPushButton("Save Datafile")
|
||||||
|
btnSv.clicked.connect(lambda: self.save_file())
|
||||||
|
bl.addWidget(btnSv, 0, 1)
|
||||||
|
|
||||||
|
# but = QPushButton("Random Data")
|
||||||
|
# but.clicked.connect(self.generate_random_data)
|
||||||
|
# bl.addWidget(but, 4, 0)
|
||||||
|
# self._num_random_points = QSpinBox()
|
||||||
|
# self._num_random_points.setMinimum(2)
|
||||||
|
# self._num_random_points.setMaximum(10000)
|
||||||
|
# self._num_random_points.setValue(10)
|
||||||
|
# self._num_random_points.setSuffix(" points")
|
||||||
|
# bl.addWidget(self._num_random_points, 4, 1)
|
||||||
|
|
||||||
|
btnDump = QPushButton("dump")
|
||||||
|
btnDump.clicked.connect(self.dump_data)
|
||||||
|
bl.addWidget(btnDump, 0, 2)
|
||||||
|
|
||||||
|
self._cbType=cb=QComboBox()
|
||||||
|
#cb.addItem("C")
|
||||||
|
#cb.addItem("C++")
|
||||||
|
cb.addItems(["Fiducial", "FixTarget(12.5x12.5)", "FixTarget(23.0x23.0)", "FixTarget(<param>)", "Grid(<param>)"])
|
||||||
|
|
||||||
|
|
||||||
|
#cb.currentIndexChanged.connect(self.selectionchange)
|
||||||
|
|
||||||
|
bl.addWidget(cb, 1,0,1,1)
|
||||||
|
self._txtParam=param=QLineEdit()
|
||||||
|
bl.addWidget(param, 1, 1,1,1)
|
||||||
|
|
||||||
|
self._btnAdd=btnAdd = QPushButton("add obj")
|
||||||
|
btnAdd.clicked.connect(self.add_obj)
|
||||||
|
bl.addWidget(btnAdd, 1, 2,1,1)
|
||||||
|
|
||||||
|
|
||||||
|
# but = QPushButton("Dump to console")
|
||||||
|
# but.clicked.connect(self.dump_data)
|
||||||
|
# bl.addWidget(but, 10, 0, 1, 1)
|
||||||
|
|
||||||
|
but = QCheckBox("collect fiducials")
|
||||||
|
but.setChecked(False)
|
||||||
|
but.setToolTip("Collect or not the fiducial positions.")
|
||||||
|
self._collect_fiducials = False
|
||||||
|
but.stateChanged.connect(self.set_collect_fiducials)
|
||||||
|
bl.addWidget(but, 10, 0, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
but = QCheckBox("draw crystal marks")
|
||||||
|
but.setChecked(False)
|
||||||
|
self._draw_crystal_marks = False
|
||||||
|
but.stateChanged.connect(self.set_draw_crystal_marks)
|
||||||
|
bl.addWidget(but, 10, 1, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
but = QPushButton("Transform")
|
||||||
|
but.clicked.connect(self.transform_non_fiducials_in_model)
|
||||||
|
bl.addWidget(but, 20, 0, 2, 2)
|
||||||
|
|
||||||
|
layout.addWidget(frame)
|
||||||
|
self.markersTable = QTableWidget()
|
||||||
|
self.markersTable.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||||
|
self.markersTable.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
self.markersTable.setItemDelegate(MarkerDelegate(self))
|
||||||
|
|
||||||
|
# self.markersTable.horizontalHeader().setDefaultSectionSize(80)
|
||||||
|
self.markersTable.setColumnCount(5)
|
||||||
|
self.markersTable.setHorizontalHeaderLabels(("Fiducial?", "orig X", "orig Y", "X", "Y"))
|
||||||
|
hh=self.markersTable.horizontalHeader()
|
||||||
|
hh.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
||||||
|
hh.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
||||||
|
hh.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
||||||
|
hh.setSectionResizeMode(3, QHeaderView.ResizeToContents)
|
||||||
|
hh.setSectionResizeMode(4, QHeaderView.ResizeToContents)
|
||||||
|
hh.setSectionResizeMode(QHeaderView.Stretch)
|
||||||
|
|
||||||
|
self.markersTable.itemSelectionChanged.connect(self.selection_changed)
|
||||||
|
|
||||||
|
self.markersTable.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||||
|
|
||||||
|
deleteRowAction = QAction("Delete this row", self)
|
||||||
|
deleteRowAction.triggered.connect(self.delete_selected)
|
||||||
|
self.markersTable.addAction(deleteRowAction)
|
||||||
|
|
||||||
|
moveRequestAction = QAction("Move Here", self)
|
||||||
|
moveRequestAction.triggered.connect(self.request_stage_movement)
|
||||||
|
self.markersTable.addAction(moveRequestAction)
|
||||||
|
|
||||||
|
layout.addWidget(self.markersTable, stretch=2)
|
||||||
|
self.connect_all_signals()
|
||||||
|
|
||||||
|
#self._yamlFn=fn=os.path.expanduser('~/.config/PSI/SwissMX.yaml')
|
||||||
|
|
||||||
|
#self._tree=tree=pg.DataTreeWidget(data=self._data)
|
||||||
|
self._data=data
|
||||||
|
self._tree=tree=pg.DataTreeWidget(data=data)
|
||||||
|
layout.addWidget(tree, stretch=2)
|
||||||
|
|
||||||
|
def load_file(self, filename=None):
|
||||||
|
app = QApplication.instance()
|
||||||
|
#cfg = app._cfg
|
||||||
|
#logger = logging.getLogger("preloc.loadMarkers")
|
||||||
|
#def_folder = join(folders.pgroup_folder, "preloc_sheets") #ZAC: orig. code
|
||||||
|
#def_folder =''
|
||||||
|
#data_folder = cfg.value("folders/last_prelocation_folder", def_folder)
|
||||||
|
data_folder=''
|
||||||
|
if filename is None:
|
||||||
|
filename, _ = QFileDialog.getOpenFileName(self,"Load yaml data file",None,
|
||||||
|
"yaml files (*.yaml);;json files (*.json);;pickle files (*.pkl);;text files (*.txt);;all files (*)",)
|
||||||
|
if not filename: # cancelled dialog
|
||||||
|
return
|
||||||
|
|
||||||
|
ext=filename.rsplit('.',1)[1].lower()
|
||||||
|
if ext=='pkl':
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
data=pickle.load(f)
|
||||||
|
if ext=='yaml':
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
data = yaml.load(f)
|
||||||
|
elif ext=='json':
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
data=json.load(f,object_hook=MyJsonDecoder)
|
||||||
|
print(data)
|
||||||
|
self._data=data
|
||||||
|
self._tree.setData(data)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
cfg.setValue("folders/last_prelocation_folder", QFileInfo(filename).canonicalPath())
|
||||||
|
cfg.setValue("folders/last_prelocation_sheet", QFileInfo(filename).absolutePath())
|
||||||
|
except TypeError as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.clearMarkers()
|
||||||
|
|
||||||
|
_log.info(f"loading prelocated coords from {filename}")
|
||||||
|
df = pd.read_csv(filename, comment="#", header=None, delim_whitespace=False, delimiter="[\t,;]")
|
||||||
|
|
||||||
|
try:
|
||||||
|
prefix = QFileInfo(filename).baseName()
|
||||||
|
except:
|
||||||
|
prefix = filename.name
|
||||||
|
filename = prefix
|
||||||
|
|
||||||
|
logger.info(f"prefix => {prefix}")
|
||||||
|
|
||||||
|
gonio_coords_available = True
|
||||||
|
for data in df.as_matrix(): # FIXME FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead.
|
||||||
|
row = self.markersTable.rowCount()
|
||||||
|
self.markersTable.setRowCount(row + 1)
|
||||||
|
original = np.copy(data)
|
||||||
|
data = list(data)
|
||||||
|
|
||||||
|
if len(data) in [2, 3]:
|
||||||
|
gonio_coords_available = False
|
||||||
|
data.extend([0, 0])
|
||||||
|
|
||||||
|
if len(data) == 4:
|
||||||
|
data.insert(0, False) # fiducial flag
|
||||||
|
elif len(data) == 5: # fiducial already there, convert to bool
|
||||||
|
data[0] = bool(data[0])
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"Wrong number of points in data file",
|
||||||
|
"I was expecting either 2, 3, 4 or 5 data points per line."
|
||||||
|
"\n\nFailed around a line with: {}".format(list(original)),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.addSingleMarker(row, data)
|
||||||
|
|
||||||
|
self._xtals_transformed = False
|
||||||
|
self.prefixSelected.emit(prefix)
|
||||||
|
|
||||||
|
# only emit this signal if goniometer coordinates already read from file
|
||||||
|
if gonio_coords_available:
|
||||||
|
logger.debug(f"dataFileLoaded.emit => {filename}")
|
||||||
|
self.dataFileLoaded.emit(filename)
|
||||||
|
|
||||||
|
def save_file(self, filename=None):
|
||||||
|
# filename = folders.get_file("prelocated-save.dat")
|
||||||
|
#data_folder = settings.value("folders/last_prelocation_folder")
|
||||||
|
data_folder=''
|
||||||
|
if filename is None:
|
||||||
|
filename, _ = QFileDialog.getSaveFileName(self,"Soad yaml data file",data_folder,
|
||||||
|
"yaml files (*.yaml);;json files (*.json);;pickle files (*.pkl);;text files (*.txt);;all files (*)",)
|
||||||
|
if not filename:
|
||||||
|
return
|
||||||
|
|
||||||
|
#settings.setValue("folders/last_prelocation_folder", QFileInfo(filename).canonicalPath())
|
||||||
|
#_log.info("Saving data in {}".format(filename))
|
||||||
|
#data = self.get_data(as_numpy=True)
|
||||||
|
#df = pd.DataFrame(data)
|
||||||
|
#df.to_csv(filename, float_format="%.6f")
|
||||||
|
#import numpy as np
|
||||||
|
ext=filename.rsplit('.',1)[1].lower()
|
||||||
|
if ext=='pkl':
|
||||||
|
with open(filename, 'wb') as f:
|
||||||
|
pickle.dump(self._data, f)
|
||||||
|
elif ext=='yaml':
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
yaml.dump(self._data, f)
|
||||||
|
elif ext=='json':
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
json.dump(self._data, f,cls=MyJsonEncoder)
|
||||||
|
print(self._data)
|
||||||
|
|
||||||
|
def add_obj(self):
|
||||||
|
_log.warning("TODO: IMPLEMENT")
|
||||||
|
|
||||||
|
def delete_selected(self):
|
||||||
|
row = self._current_row
|
||||||
|
try:
|
||||||
|
row += 0
|
||||||
|
except:
|
||||||
|
_log.warning("select a row first")
|
||||||
|
QMessageBox.warning(self,"Select a marker first","You must select a marker first before updating its goniometer position",)
|
||||||
|
return
|
||||||
|
self.markersTable.removeRow(row)
|
||||||
|
self.prelocatedDataUpdated.emit()
|
||||||
|
|
||||||
|
def selection_changed(self):
|
||||||
|
row = self.markersTable.currentRow()
|
||||||
|
if row < 0:
|
||||||
|
return
|
||||||
|
self._current_row = row
|
||||||
|
self.selectedRowChanged.emit(row)
|
||||||
|
_log.debug("selection changed: current row {}".format(row))
|
||||||
|
|
||||||
|
def connect_all_signals(self):
|
||||||
|
self.prefixSelected.connect(lambda t: self._label_prefix.setText(t))
|
||||||
|
self.dataFileLoaded.connect(lambda t: self._label_datafile.setText(t))
|
||||||
|
|
||||||
|
def markerItemChanged(self, item):
|
||||||
|
print(item.row(), item.column())
|
||||||
|
|
||||||
|
def set_fiducial_coords(self, camx, camy, gx, gy):
|
||||||
|
tbl = self.markersTable
|
||||||
|
row = self._current_row
|
||||||
|
try:
|
||||||
|
row += 0
|
||||||
|
except:
|
||||||
|
_log.warning("select a row first")
|
||||||
|
QMessageBox.warning(self,"Select a marker first","You must select a marker first before updating its goniometer position",)
|
||||||
|
return
|
||||||
|
|
||||||
|
origx = tbl.item(row, ORIGINAL_X).data(RoleOriginalCoord_X)
|
||||||
|
origy = tbl.item(row, ORIGINAL_Y).data(RoleOriginalCoord_Y)
|
||||||
|
|
||||||
|
item = tbl.item(row, DATA_ITEM)
|
||||||
|
item.setData(RoleCameraCoord_X, camx)
|
||||||
|
item.setData(RoleCameraCoord_Y, camy)
|
||||||
|
item.setData(RoleGoniometerCoord_X, gx)
|
||||||
|
item.setData(RoleGoniometerCoord_Y, gy)
|
||||||
|
# item.setData(RoleOriginalCoord_X, origx)
|
||||||
|
# item.setData(RoleOriginalCoord_Y, origy)
|
||||||
|
# logger.debug(': [{}] = Original: {}, {} | Camera: {}, {} | Gonio: {}, {}'.format(1+row, origx, origy, camx, camy, gx, gy))
|
||||||
|
logger.debug(f": [{1+row}] = Original: {origx}, {origy} | Camera: {camx}, {camy} | Gonio: {gx}, {gy}")
|
||||||
|
|
||||||
|
tbl.item(row, GONIO_X).setData(Qt.DisplayRole, f"{gx:8.5f} mm\n{camx:8.1f} px")
|
||||||
|
tbl.item(row, GONIO_Y).setData(Qt.DisplayRole, f"{gy:8.5f} mm\n{camy:8.1f} px")
|
||||||
|
|
||||||
|
# mark row as a fiducial
|
||||||
|
tbl.item(row, 0).setCheckState(Qt.Checked)
|
||||||
|
tbl.item(row, 0).setData(Qt.UserRole, True)
|
||||||
|
tbl.selectRow(row + 1)
|
||||||
|
self.prelocatedDataUpdated.emit()
|
||||||
|
|
||||||
|
def set_selected_gonio_coords(self, xy):
|
||||||
|
tbl = self.markersTable
|
||||||
|
row = self._current_row
|
||||||
|
try:
|
||||||
|
row += 0
|
||||||
|
except:
|
||||||
|
_log.warning("select a row first")
|
||||||
|
QMessageBox.warning(self,"Select a marker first","You must select a marker first before updating its goniometer position",)
|
||||||
|
return
|
||||||
|
|
||||||
|
for n, v in enumerate(xy):
|
||||||
|
idx = 3 + n
|
||||||
|
tbl.setCurrentCell(row, idx) # gonio X
|
||||||
|
_log.debug("item: [{},{}] = {}".format(row, idx, v))
|
||||||
|
item = tbl.currentItem()
|
||||||
|
item.setData(Qt.EditRole, "{:.3f}".format(v))
|
||||||
|
item.setData(Qt.UserRole, v)
|
||||||
|
|
||||||
|
# mark row as a fiducial
|
||||||
|
tbl.setCurrentCell(row, 0)
|
||||||
|
tbl.currentItem().setCheckState(Qt.Checked)
|
||||||
|
tbl.currentItem().setData(Qt.UserRole, True)
|
||||||
|
|
||||||
|
def set_data_goniometer(self, row: int, xy):
|
||||||
|
tbl = self.markersTable
|
||||||
|
|
||||||
|
row = self._current_row
|
||||||
|
try:
|
||||||
|
row += 0
|
||||||
|
except:
|
||||||
|
_log.warning("select a row first")
|
||||||
|
QMessageBox.warning(self,"Select a marker first","You must select a marker first before updating its goniometer position",)
|
||||||
|
return
|
||||||
|
|
||||||
|
for n, v in enumerate(xy):
|
||||||
|
idx = 3 + n
|
||||||
|
tbl.setCurrentCell(row, idx) # gonio X
|
||||||
|
item = tbl.currentItem()
|
||||||
|
item.setData(Qt.EditRole, "{:.3f}".format(v))
|
||||||
|
item.setData(Qt.UserRole, v)
|
||||||
|
|
||||||
|
@pyqtSlot(int)
|
||||||
|
def set_draw_crystal_marks(self, val):
|
||||||
|
logger.info(f"{'' if val else 'not '}drawing crystal markers")
|
||||||
|
self._draw_crystal_marks = val
|
||||||
|
|
||||||
|
@pyqtSlot(int)
|
||||||
|
def set_collect_fiducials(self, val):
|
||||||
|
logger.info(f"{'' if val else 'not '}collecting fiducials")
|
||||||
|
self._collect_fiducials = val
|
||||||
|
|
||||||
|
def get_collection_targets(self):
|
||||||
|
return self.get_data(fiducials=self._collect_fiducials)
|
||||||
|
|
||||||
|
|
||||||
|
def get_data(self, fiducials=True, crystals=True, as_numpy=False):
|
||||||
|
"""return a list of tuples with all defined data
|
||||||
|
|
||||||
|
[
|
||||||
|
(is_fiducial(boolean), x, y, gonio_x, gonio_y),...
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
data = []
|
||||||
|
item = self.markersTable.item
|
||||||
|
|
||||||
|
for row in range(self.markersTable.rowCount()):
|
||||||
|
is_fiducial = Qt.Checked == item(row, 0).checkState()
|
||||||
|
ditem = item(row, DATA_ITEM)
|
||||||
|
|
||||||
|
x = ditem.data(RoleGoniometerCoord_X)
|
||||||
|
y = ditem.data(RoleGoniometerCoord_Y)
|
||||||
|
cx = ditem.data(RoleCameraCoord_X)
|
||||||
|
cy = ditem.data(RoleCameraCoord_Y)
|
||||||
|
origx = ditem.data(RoleOriginalCoord_X)
|
||||||
|
origy = ditem.data(RoleOriginalCoord_Y)
|
||||||
|
|
||||||
|
if is_fiducial and fiducials:
|
||||||
|
data.append([is_fiducial, x, y, cx, cy, origx, origy])
|
||||||
|
if not is_fiducial and crystals:
|
||||||
|
data.append([is_fiducial, x, y, cx, cy, origx, origy])
|
||||||
|
|
||||||
|
if as_numpy:
|
||||||
|
data = np.asarray(data)
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get_original_coordinates(self, fiducials=True):
|
||||||
|
"""return a numpy array with the original prelocated coordinates of the fiducial entries"""
|
||||||
|
data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True)
|
||||||
|
data = data[:, 5:]
|
||||||
|
zeros = np.zeros(data.shape)
|
||||||
|
zeros[:, 1] = 1
|
||||||
|
return np.concatenate((data, zeros), axis=1)
|
||||||
|
|
||||||
|
def get_goniometer_coordinates(self, fiducials=True):
|
||||||
|
"""return a numpy array with the goniometer coordinates of the fiducial entries"""
|
||||||
|
data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True)
|
||||||
|
data = data[:, 1:3]
|
||||||
|
zeros = np.zeros(data.shape)
|
||||||
|
zeros[:, 1] = 1
|
||||||
|
return np.concatenate((data, zeros), axis=1)
|
||||||
|
|
||||||
|
def get_camera_coordinates(self, fiducials=True):
|
||||||
|
"""return a numpy array with the goniometer coordinates of the fiducial entries"""
|
||||||
|
data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True)
|
||||||
|
data = data[:, 3:5]
|
||||||
|
zeros = np.zeros(data.shape)
|
||||||
|
zeros[:, 1] = 1
|
||||||
|
return np.concatenate((data, zeros), axis=1)
|
||||||
|
|
||||||
|
def dump_matrix(self, M):
|
||||||
|
scale, shear, angles, translate, perspective = tfs.decompose_matrix(M)
|
||||||
|
angles_deg = [a * 180 / np.pi for a in angles]
|
||||||
|
|
||||||
|
print("Transformation matrix Aerotech => SwissMX")
|
||||||
|
print(M)
|
||||||
|
print((" scale {:9.4f} {:9.4f} {:9.4f}".format(*scale)))
|
||||||
|
print((" shear {:9.4f} {:9.4f} {:9.4f}".format(*shear)))
|
||||||
|
print((" angles rad {:9.4f} {:9.4f} {:9.4f}".format(*angles)))
|
||||||
|
print((" angles deg {:9.4f} {:9.4f} {:9.4f}".format(*angles_deg)))
|
||||||
|
print((" translate {:9.4f} {:9.4f} {:9.4f}".format(*translate)))
|
||||||
|
print(("perspective {:9.4f} {:9.4f} {:9.4f}".format(*perspective)))
|
||||||
|
|
||||||
|
def transform_non_fiducials_in_model(self):
|
||||||
|
forg = self.get_original_coordinates(fiducials=True)
|
||||||
|
fgon = self.get_goniometer_coordinates(fiducials=True)
|
||||||
|
fcam = self.get_camera_coordinates(fiducials=True)
|
||||||
|
|
||||||
|
gmat = sort_cmass_3d(fgon)
|
||||||
|
omat = sort_cmass_3d(forg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
M_org2gon = tfs.superimposition_matrix(omat.T, gmat.T, scale=True)
|
||||||
|
M_org2cam = tfs.superimposition_matrix(forg.T, fcam.T, scale=True)
|
||||||
|
except:
|
||||||
|
QMessageBox.warning(self.parent(), title="failed to find superimposition matrix", text="Failed to find superimposition matrix.\n\tPlease try again.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# scale, shear, angles, translate, perspective = tfs.decompose_matrix(M_org2gon)
|
||||||
|
|
||||||
|
org_data = self.get_original_coordinates(fiducials=False)
|
||||||
|
|
||||||
|
gon_data = np.dot(M_org2gon, org_data.T)
|
||||||
|
cam_data = np.dot(M_org2cam, org_data.T)
|
||||||
|
|
||||||
|
tbl = self.markersTable
|
||||||
|
num_fiducials = forg.shape[0]
|
||||||
|
|
||||||
|
gon_data = (gon_data.T)[:, 0:2] # only X,Y matters
|
||||||
|
cam_data = (cam_data.T)[:, 0:2] # only X,Y matters
|
||||||
|
combined = np.concatenate((gon_data, cam_data), axis=1)
|
||||||
|
|
||||||
|
item = self.markersTable.item # function alias
|
||||||
|
for row, data in enumerate(
|
||||||
|
combined, num_fiducials
|
||||||
|
): # enumeration starts at *num_fiducials*
|
||||||
|
gx, gy, cx, cy = data
|
||||||
|
ditem = item(row, DATA_ITEM)
|
||||||
|
ditem.setData(RoleCameraCoord_X, cx)
|
||||||
|
ditem.setData(RoleCameraCoord_Y, cy)
|
||||||
|
ditem.setData(RoleGoniometerCoord_X, gx)
|
||||||
|
ditem.setData(RoleGoniometerCoord_Y, gy)
|
||||||
|
item(row, GONIO_X).setData(Qt.DisplayRole, f"{gx:8.5f} mm\n{cx:8.1f} px")
|
||||||
|
item(row, GONIO_Y).setData(Qt.DisplayRole, f"{gy:8.5f} mm\n{cy:8.1f} px")
|
||||||
|
self._xtals_transformed = True
|
||||||
|
self.prelocatedDataUpdated.emit()
|
||||||
|
|
||||||
|
def request_stage_movement(self):
|
||||||
|
logger = logging.getLogger("preloc.move_stage")
|
||||||
|
row = self._current_row
|
||||||
|
x = self.markersTable.item(row, DATA_ITEM).data(RoleGoniometerCoord_X)
|
||||||
|
y = self.markersTable.item(row, DATA_ITEM).data(RoleGoniometerCoord_Y)
|
||||||
|
logger.info(f"request move gonio to {x:.3f}, {y:.3f} mm")
|
||||||
|
self.moveFastStageRequest.emit(x, y)
|
||||||
|
|
||||||
|
def dump_numpy(self):
|
||||||
|
R = tfs.random_rotation_matrix(np.random.random(3))
|
||||||
|
d = self.get_goniometer_coordinates()
|
||||||
|
print("dumping")
|
||||||
|
print(d)
|
||||||
|
dR = np.dot(R, d)
|
||||||
|
print(dR.T)
|
||||||
|
|
||||||
|
def get_fiducials(self, as_numpy=False):
|
||||||
|
return self.get_data(crystals=False, as_numpy=as_numpy)
|
||||||
|
|
||||||
|
def get_crystals(self, as_numpy=False):
|
||||||
|
return self.get_data(fiducials=False, as_numpy=as_numpy)
|
||||||
|
|
||||||
|
def dump_data(self):
|
||||||
|
print(self._data)
|
||||||
|
#for ref, x, y, cx, cy, ox, oy in self.get_data():
|
||||||
|
# print(f"fiducial:{ref} [{x}, {y}, {cx}, {cy}]")
|
||||||
|
|
||||||
|
def append_data(self, data):
|
||||||
|
"""append data (a list of values) to the model
|
||||||
|
|
||||||
|
len(data) == 2 => (X, Y) from prelocated coordinate
|
||||||
|
len(data) == 4 => (X, Y, GX, GY) plus gonio coordinates
|
||||||
|
len(data) == 5 => (fiducial?, X, Y, GX, GY) plus fiducial
|
||||||
|
"""
|
||||||
|
row = self.markersTable.rowCount()
|
||||||
|
self.markersTable.setRowCount(row + 1)
|
||||||
|
|
||||||
|
data = list(data)
|
||||||
|
if len(data) == 2:
|
||||||
|
data.extend([0, 0])
|
||||||
|
if len(data) == 4:
|
||||||
|
data.insert(0, False) # fiducial flag
|
||||||
|
self.addSingleMarker(row, data)
|
||||||
|
self.prelocatedDataUpdated.emit()
|
||||||
|
|
||||||
|
def clearMarkers(self):
|
||||||
|
self.markersTable.setRowCount(0)
|
||||||
|
self.markersDeleted.emit()
|
||||||
|
|
||||||
|
def generate_random_data(self):
|
||||||
|
import io
|
||||||
|
|
||||||
|
data = io.StringIO()
|
||||||
|
npoints = self._num_random_points.value()
|
||||||
|
for n in range(npoints):
|
||||||
|
x, y, a, b = (
|
||||||
|
np.random.randint(0, 2000),
|
||||||
|
np.random.randint(0, 2000),
|
||||||
|
np.random.randint(-4000, 4000) / 1000.,
|
||||||
|
np.random.randint(-4000, 4000) / 1000.,
|
||||||
|
)
|
||||||
|
data.write("{}\t{}\t{}\t{}\n".format(x, y, a, b))
|
||||||
|
data.seek(0)
|
||||||
|
data.name = "random.csv"
|
||||||
|
self.loadMarkers(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def addSingleMarker(self, row, marker):
|
||||||
|
is_fiducial, origx, origy, gx, gy = marker
|
||||||
|
_log.debug(f": [{1+row}] | Original: {origx}, {origy} | Gonio: {gx}, {gy}")
|
||||||
|
item0 = QTableWidgetItem()
|
||||||
|
item0.setData(Qt.UserRole, is_fiducial)
|
||||||
|
item0.setFlags(item0.flags() & ~Qt.ItemIsEditable)
|
||||||
|
item0.setCheckState(Qt.Checked if is_fiducial else Qt.Unchecked)
|
||||||
|
item0.setTextAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
|
item1 = QTableWidgetItem("{:.1f}".format(origx))
|
||||||
|
item1.setTextAlignment(Qt.AlignRight)
|
||||||
|
|
||||||
|
item2 = QTableWidgetItem("{:.1f}".format(origy))
|
||||||
|
item2.setTextAlignment(Qt.AlignRight)
|
||||||
|
|
||||||
|
item3 = QTableWidgetItem("{:.3f} mm".format(gx))
|
||||||
|
item3.setFlags(item3.flags() & ~Qt.ItemIsEditable)
|
||||||
|
item3.setTextAlignment(Qt.AlignRight)
|
||||||
|
|
||||||
|
item4 = QTableWidgetItem("{:.3f} mm".format(gy))
|
||||||
|
item4.setFlags(item4.flags() & ~Qt.ItemIsEditable)
|
||||||
|
item4.setTextAlignment(Qt.AlignRight)
|
||||||
|
|
||||||
|
self.markersTable.setItem(row, 0, item0)
|
||||||
|
self.markersTable.setItem(row, ORIGINAL_X, item1)
|
||||||
|
self.markersTable.setItem(row, ORIGINAL_Y, item2)
|
||||||
|
self.markersTable.setItem(row, GONIO_X, item3)
|
||||||
|
self.markersTable.setItem(row, GONIO_Y, item4)
|
||||||
|
self.markerAdded.emit(is_fiducial, [origx, origy, gx, gy])
|
||||||
|
|
||||||
|
item = self.markersTable.item(row, DATA_ITEM)
|
||||||
|
item.setData(RoleCameraCoord_X, origx) # initially set to original
|
||||||
|
item.setData(RoleCameraCoord_Y, origy) # initially set to original
|
||||||
|
item.setData(RoleGoniometerCoord_X, gx)
|
||||||
|
item.setData(RoleGoniometerCoord_Y, gy)
|
||||||
|
item.setData(RoleOriginalCoord_X, origx)
|
||||||
|
item.setData(RoleOriginalCoord_Y, origy)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Signals QTableWidget
|
||||||
|
void cellActivated(int row, int column)
|
||||||
|
void cellChanged(int row, int column)
|
||||||
|
void cellClicked(int row, int column)
|
||||||
|
void cellDoubleClicked(int row, int column)
|
||||||
|
void cellEntered(int row, int column)
|
||||||
|
void cellPressed(int row, int column)
|
||||||
|
void currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
|
||||||
|
void currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
|
||||||
|
void itemActivated(QTableWidgetItem *item)
|
||||||
|
void itemChanged(QTableWidgetItem *item)
|
||||||
|
void itemClicked(QTableWidgetItem *item)
|
||||||
|
void itemDoubleClicked(QTableWidgetItem *item)
|
||||||
|
void itemEntered(QTableWidgetItem *item)
|
||||||
|
void itemPressed(QTableWidgetItem *item)
|
||||||
|
void itemSelectionChanged()
|
||||||
|
"""
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
import pyqtUsrObj as UsrGO
|
||||||
|
|
||||||
|
class Monster(yaml.YAMLObject):
|
||||||
|
yaml_tag = u'!Monster'
|
||||||
|
def __init__(self, name, hp, ac, attacks):
|
||||||
|
self.name = name
|
||||||
|
self.hp = hp
|
||||||
|
self.ac = ac
|
||||||
|
self.attacks = attacks
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
|
||||||
|
self.__class__.__name__, self.name, self.hp, self.ac, self.attacks)
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(MainWindow, self).__init__(parent)
|
||||||
|
self.move(100,100)
|
||||||
|
self.resize(500,800)
|
||||||
|
self.centralWidget=QWidget()
|
||||||
|
self.wndFixTrg=WndFixTarget(parent=self)
|
||||||
|
|
||||||
|
self.setCentralWidget(self.centralWidget)
|
||||||
|
mainLayout=QVBoxLayout()
|
||||||
|
mainLayout.addWidget(self.wndFixTrg)
|
||||||
|
self.centralWidget.setLayout(mainLayout)
|
||||||
|
|
||||||
|
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
mainWin = MainWindow()
|
||||||
|
|
||||||
|
t=3
|
||||||
|
if t==0:
|
||||||
|
data=[{'name':'John Doe', 'occupation':'gardener'}, {'name':'Lucy Black', 'occupation':'teacher'}]
|
||||||
|
elif t==1:
|
||||||
|
data ={
|
||||||
|
'name': 'John Doe', 'occupation': 'gardener',
|
||||||
|
'A':(1,2,3),
|
||||||
|
'B':[1,2,3],
|
||||||
|
'C':{1,2,3},
|
||||||
|
'D':
|
||||||
|
{'1':(1,2,3),
|
||||||
|
'2':'df',
|
||||||
|
'3':'dddd'},
|
||||||
|
'4':np.array(((1,2,3),(4,5,6))),
|
||||||
|
'5':np.array(range(40*2)).reshape(-1,2)
|
||||||
|
}
|
||||||
|
elif t==2:
|
||||||
|
data = {
|
||||||
|
'a list': [1,2,3,4,5,6, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"],
|
||||||
|
'a dict': {
|
||||||
|
'x': 1,
|
||||||
|
'y': 2,
|
||||||
|
'z': 'three'
|
||||||
|
},
|
||||||
|
'an array': np.random.randint(10, size=(40,10)),
|
||||||
|
#'a traceback': some_func1(),
|
||||||
|
#'a function': some_func1,
|
||||||
|
#'a class': pg.DataTreeWidget,
|
||||||
|
}
|
||||||
|
elif t==3:
|
||||||
|
data=[
|
||||||
|
UsrGO.Grid(pos=(120.0, -100.0), size=(1000.0, 500.0), cnt=(10, 5), ficucialScale=2),
|
||||||
|
Monster(name='Cave lizard', hp=[3,6], ac=16, attacks=['BITE','HURT'])
|
||||||
|
]
|
||||||
|
mainWin.wndFixTrg._data=data
|
||||||
|
mainWin.wndFixTrg._tree.setData(data)
|
||||||
|
mainWin.show()
|
||||||
|
sys.exit(app.exec_())
|
||||||
@@ -248,9 +248,9 @@ class epics_cam(object):
|
|||||||
hr=h//4
|
hr=h//4
|
||||||
imgSeq[:,0:hr,0:wr]+=np.random.randint(0,100,(t,hr,wr),dtype=np.uint16)
|
imgSeq[:,0:hr,0:wr]+=np.random.randint(0,100,(t,hr,wr),dtype=np.uint16)
|
||||||
elif mode==1:
|
elif mode==1:
|
||||||
import glob,PIL.Image
|
import os,glob,PIL.Image
|
||||||
#path='/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX/simCamImg/*.png'
|
#path='/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX/simCamImg/*.png'
|
||||||
path='simCamImg/*.png'
|
path=os.path.join(os.path.dirname(__file__),'simCamImg/*.png')
|
||||||
_log.info('generate simulation images:{}...'.format(path))
|
_log.info('generate simulation images:{}...'.format(path))
|
||||||
glb=glob.glob(path)
|
glb=glob.glob(path)
|
||||||
img = PIL.Image.open(glb[0])
|
img = PIL.Image.open(glb[0])
|
||||||
|
|||||||
@@ -138,6 +138,27 @@ class Marker(pg.ROI):
|
|||||||
# p.drawRect(-w / 2, -h / 2, w, h)
|
# p.drawRect(-w / 2, -h / 2, w, h)
|
||||||
# # p.drawText(-w, -h, '{:.0f}x{:.0f}'.format(*self._size))
|
# # p.drawText(-w, -h, '{:.0f}x{:.0f}'.format(*self._size))
|
||||||
|
|
||||||
|
class Fiducial(pg.ROI):
|
||||||
|
def __init__(self, pos, size, xyz, **kargs):
|
||||||
|
pg.ROI.__init__(self, pos, size, **kargs)
|
||||||
|
self._xyz=xyz
|
||||||
|
|
||||||
|
def paint(self, p, *args):
|
||||||
|
#pg.ROI.paint(self, p, *args)
|
||||||
|
r=QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized()
|
||||||
|
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
|
p.setPen(self.currentPen)
|
||||||
|
p.translate(r.left(), r.top())
|
||||||
|
p.scale(.01*r.width(), .01*r.height()) # -> values x,y 0 to 100
|
||||||
|
p.drawRect(0, 0, 100, 100)
|
||||||
|
p.setPen(pg.mkPen(width=1, color=[255, 0, 0]))
|
||||||
|
p.drawLine(pg.Point(50,10), pg.Point(50, 90))
|
||||||
|
p.drawLine(pg.Point(10,50), pg.Point(90, 50))
|
||||||
|
tr=p.transform()
|
||||||
|
tr.setMatrix(tr.m11(), tr.m12(), tr.m13(), tr.m21(), -tr.m22(), tr.m23(), tr.m31(), tr.m32(), tr.m33())
|
||||||
|
p.setTransform(tr)
|
||||||
|
|
||||||
|
|
||||||
class Grid(pg.ROI):
|
class Grid(pg.ROI):
|
||||||
'''a grid'''
|
'''a grid'''
|
||||||
|
|
||||||
@@ -200,6 +221,25 @@ class Grid(pg.ROI):
|
|||||||
#p.drawEllipse(0, 0, 1, 1)
|
#p.drawEllipse(0, 0, 1, 1)
|
||||||
#p.drawRect(0, 0, 1, 1)
|
#p.drawRect(0, 0, 1, 1)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
s=f'{self.__class__.__name__}:(pos:{tuple(self.pos())}, size:{tuple(self.size())}, cnt:{self._cnt}, ficucialScale:{self._fidScl}}}'
|
||||||
|
return s
|
||||||
|
import yaml
|
||||||
|
def yaml_repr_Grid(dumper, data):
|
||||||
|
#s=f'{{"pos":{tuple(data.pos())}, "size":{tuple(data.size())}, "cnt":{data._cnt}, "ficucialScale":{data._fidScl}}}'
|
||||||
|
#return dumper.represent_scalar(u'!Grid', s)
|
||||||
|
m={'pos':tuple(data.pos()),'size':tuple(data.size()),'cnt':data._cnt, 'ficucialScale':data._fidScl}
|
||||||
|
return dumper.represent_mapping(u'!Grid', m)
|
||||||
|
yaml.add_representer(Grid, yaml_repr_Grid)
|
||||||
|
|
||||||
|
def yaml_cnstr_Grid(loader, node):
|
||||||
|
#value = loader.construct_scalar(node)
|
||||||
|
#kwargs=eval(value)
|
||||||
|
#return Grid(**kwargs)
|
||||||
|
m = loader.construct_mapping(node)
|
||||||
|
return Grid(**m)
|
||||||
|
yaml.add_constructor(u'!Grid', yaml_cnstr_Grid)
|
||||||
|
|
||||||
|
|
||||||
class Path(pg.ROI):
|
class Path(pg.ROI):
|
||||||
'''
|
'''
|
||||||
@@ -524,6 +564,10 @@ if __name__=='__main__':
|
|||||||
vi=FixTargetFrame((400,-200),(400,400),tpl='12.5x12.5')
|
vi=FixTargetFrame((400,-200),(400,400),tpl='12.5x12.5')
|
||||||
vb.addItem(vi)
|
vb.addItem(vi)
|
||||||
|
|
||||||
|
vi=Fiducial((0,200),(40,40),(1,2,3))
|
||||||
|
vb.addItem(vi)
|
||||||
|
|
||||||
|
|
||||||
childTree(vb)
|
childTree(vb)
|
||||||
|
|
||||||
w.scene().sigMouseClicked.connect(mouse_click_event)
|
w.scene().sigMouseClicked.connect(mouse_click_event)
|
||||||
|
|||||||
101
swissmx.py
101
swissmx.py
@@ -69,6 +69,8 @@ TASK_PRELOCATED = "prelocated"
|
|||||||
TASK_HELICAL = "helical"
|
TASK_HELICAL = "helical"
|
||||||
TASK_EMBL = "embl"
|
TASK_EMBL = "embl"
|
||||||
ts.log('Import part 2/8:')
|
ts.log('Import part 2/8:')
|
||||||
|
|
||||||
|
import ModuleFixTarget
|
||||||
import PrelocatedCoordinatesModel # ZAC: orig. code
|
import PrelocatedCoordinatesModel # ZAC: orig. code
|
||||||
from EmblModule import EmblWidget #ZAC: orig. code
|
from EmblModule import EmblWidget #ZAC: orig. code
|
||||||
from HelicalTable import HelicalTableWidget #ZAC: orig. code
|
from HelicalTable import HelicalTableWidget #ZAC: orig. code
|
||||||
@@ -644,6 +646,19 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
camera.epics_cam.set_fiducial(pic, 255)
|
camera.epics_cam.set_fiducial(pic, 255)
|
||||||
self._goImg.setImage(pic)
|
self._goImg.setImage(pic)
|
||||||
|
|
||||||
|
def new_frame_sim_cb(self, **kwargs):
|
||||||
|
app=QApplication.instance()
|
||||||
|
sim=app._camera._sim
|
||||||
|
imgSeq=sim['imgSeq']
|
||||||
|
idx=sim['imgIdx']
|
||||||
|
sim['imgIdx']=(idx+1)%imgSeq.shape[0]
|
||||||
|
# _log.info('simulated idx:{}'.format(idx))
|
||||||
|
pic=imgSeq[idx]
|
||||||
|
self._goImg.setImage(pic)
|
||||||
|
|
||||||
|
delay=500 # ms -> 2fps
|
||||||
|
QtCore.QTimer.singleShot(delay, self.new_frame_sim_cb)
|
||||||
|
|
||||||
def load_stylesheet(self):
|
def load_stylesheet(self):
|
||||||
with open("swissmx.css", "r") as sheet:
|
with open("swissmx.css", "r") as sheet:
|
||||||
self.setStyleSheet(sheet.read())
|
self.setStyleSheet(sheet.read())
|
||||||
@@ -673,11 +688,11 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
toolbox = QToolBox()
|
toolbox = QToolBox()
|
||||||
layout.addWidget(toolbox)
|
layout.addWidget(toolbox)
|
||||||
|
|
||||||
self.build_faststage_group(toolbox)
|
self.build_group_faststage(toolbox)
|
||||||
# self.build_slits_group(toolbox)
|
# self.build_slits_group(toolbox)
|
||||||
self.build_collimator_group(toolbox)
|
self.build_group_collimator(toolbox)
|
||||||
self.build_posttube_group(toolbox)
|
self.build_group_posttube(toolbox)
|
||||||
self.build_xeye_group(toolbox)
|
self.build_group_xeye(toolbox)
|
||||||
#self.build_cryo_group(toolbox)
|
#self.build_cryo_group(toolbox)
|
||||||
|
|
||||||
# monitor all axis for an axis fault
|
# monitor all axis for an axis fault
|
||||||
@@ -801,7 +816,7 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
msg = ""
|
msg = ""
|
||||||
self._message_critical_fault.setText(msg)
|
self._message_critical_fault.setText(msg)
|
||||||
|
|
||||||
def build_faststage_group(self, toolbox):
|
def build_group_faststage(self, toolbox):
|
||||||
qutilities.add_item_to_toolbox(toolbox,"Fast Stage",
|
qutilities.add_item_to_toolbox(toolbox,"Fast Stage",
|
||||||
widget_list=[
|
widget_list=[
|
||||||
# self.get_tweaker('SAR-EXPMX:MOT_BLGT', alias='backlight', label='backlight'),
|
# self.get_tweaker('SAR-EXPMX:MOT_BLGT', alias='backlight', label='backlight'),
|
||||||
@@ -813,7 +828,7 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def build_collimator_group(self, toolbox):
|
def build_group_collimator(self, toolbox):
|
||||||
qutilities.add_item_to_toolbox(toolbox,"Collimator",
|
qutilities.add_item_to_toolbox(toolbox,"Collimator",
|
||||||
widget_list=[
|
widget_list=[
|
||||||
self.get_tweaker("SARES30-ESBMX1", alias="colli_x", label="colli X", mtype="smaract_motor",),
|
self.get_tweaker("SARES30-ESBMX1", alias="colli_x", label="colli X", mtype="smaract_motor",),
|
||||||
@@ -821,7 +836,7 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
def build_posttube_group(self, toolbox):
|
def build_group_posttube(self, toolbox):
|
||||||
widgets = [
|
widgets = [
|
||||||
self.get_tweaker("SARES30-ESBMX4", alias="tube_usx", label="upstream X", mtype="smaract_motor",),
|
self.get_tweaker("SARES30-ESBMX4", alias="tube_usx", label="upstream X", mtype="smaract_motor",),
|
||||||
self.get_tweaker("SARES30-ESBMX6", alias="tube_usy", label="upstream Y", mtype="smaract_motor",),
|
self.get_tweaker("SARES30-ESBMX6", alias="tube_usy", label="upstream Y", mtype="smaract_motor",),
|
||||||
@@ -851,7 +866,7 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
block.layout().addStretch()
|
block.layout().addStretch()
|
||||||
toolbox.addItem(block, label)
|
toolbox.addItem(block, label)
|
||||||
|
|
||||||
def build_xeye_group(self, toolbox):
|
def build_group_xeye(self, toolbox):
|
||||||
qutilities.add_item_to_toolbox(
|
qutilities.add_item_to_toolbox(
|
||||||
toolbox,
|
toolbox,
|
||||||
"X-Ray Eye",
|
"X-Ray Eye",
|
||||||
@@ -1509,12 +1524,33 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
exp_tab.layout().addStretch()
|
exp_tab.layout().addStretch()
|
||||||
|
|
||||||
# DAQ Methods Tabs
|
# DAQ Methods Tabs
|
||||||
|
self.build_tab_module_fix_target()
|
||||||
self._OLD_build_daq_methods_grid_tab()
|
self._OLD_build_daq_methods_grid_tab()
|
||||||
self._OLD_build_daq_methods_prelocated_tab() #ZAC: orig. code
|
self._OLD_build_daq_methods_prelocated_tab() #ZAC: orig. code
|
||||||
self._OLD_create_helical_widgets() #ZAC: orig. code
|
self._OLD_create_helical_widgets() #ZAC: orig. code
|
||||||
self._OLD_build_daq_methods_embl_tab()
|
self._OLD_build_daq_methods_embl_tab()
|
||||||
#self._OLD_build_sample_selection_tab()
|
#self._OLD_build_sample_selection_tab()
|
||||||
|
|
||||||
|
def build_tab_module_fix_target(self):
|
||||||
|
#tab = self._tab_daq_method_prelocated
|
||||||
|
data=self._goTracked['objLst']
|
||||||
|
|
||||||
|
self._moduleFixTarget =mft = ModuleFixTarget.WndFixTarget(self,data)
|
||||||
|
tab = self._tabs_daq_methods.insertTab(0,mft,'Fix Target')
|
||||||
|
mft._btnAdd.clicked.connect(self.module_fix_target_add_obj)
|
||||||
|
|
||||||
|
|
||||||
|
#tab.layout().addWidget(mft)
|
||||||
|
mft.prefixSelected.connect(lambda prefix: self._le_prefix.setText(prefix))
|
||||||
|
mft.dataFileLoaded.connect(self._OLD_daq_method_prelocated_update_markers)
|
||||||
|
mft.prelocatedDataUpdated.connect(self._OLD_daq_method_prelocated_update_markers)
|
||||||
|
mft.markersDeleted.connect(self._OLD_daq_method_prelocated_remove_markers)
|
||||||
|
mft.moveFastStageRequest.connect(self._OLD_move_fast_stage)
|
||||||
|
self.fiducialPositionSelected.connect(self._OLD_daq_method_prelocated_set_fiducial)
|
||||||
|
self.appendPrelocatedPosition.connect(self._OLD_daq_method_prelocated_append_data)
|
||||||
|
#self._preloc_inspect_area = QPlainTextEdit()
|
||||||
|
#tab.layout().addWidget(self._preloc_inspect_area)
|
||||||
|
|
||||||
|
|
||||||
def switch_task(self, index=0):
|
def switch_task(self, index=0):
|
||||||
stack = self._centerpiece_stack
|
stack = self._centerpiece_stack
|
||||||
@@ -1573,8 +1609,42 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
del app._raw_opt_ctr
|
del app._raw_opt_ctr
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def module_fix_target_add_obj(self,*args,**kwargs):
|
||||||
|
mft=self._moduleFixTarget
|
||||||
|
fx=self.tweakers["fast_x"].get_rbv()
|
||||||
|
fy=self.tweakers["fast_y"].get_rbv()
|
||||||
|
#cz=self.tweakers["fast_y"].get_rbv()
|
||||||
|
app=QApplication.instance()
|
||||||
|
geo=app._geometry
|
||||||
|
oc=geo._opt_ctr
|
||||||
|
idx=mft._cbType.currentIndex()
|
||||||
|
param=mft._txtParam.text()
|
||||||
|
|
||||||
# **************** OBSOLETE AND/OR OLD STUFF ****************
|
#cb.addItems(["Fiducial", "FixTarget(12.5x12.5)", "FixTarget(23.0x23.0)", "FixTarget(<param>)", "Grid(<param>)"])
|
||||||
|
|
||||||
|
if idx==0:
|
||||||
|
go=UsrGO.Fiducial((120, -100), (200, 150),(1,2,3))
|
||||||
|
elif idx==1:
|
||||||
|
v=geo.pos2pix((12.5, 0))
|
||||||
|
l=np.linalg.norm(v)
|
||||||
|
go=UsrGO.FixTargetFrame(-oc, (l, l), tpl='12.5x12.5')
|
||||||
|
elif idx==2:
|
||||||
|
v=geo.pos2pix((23, 0))
|
||||||
|
l=np.linalg.norm(v)
|
||||||
|
go=UsrGO.FixTargetFrame(-oc, (l, l), tpl='23.0x23.0')
|
||||||
|
elif idx==3:
|
||||||
|
go=UsrGO.FixTargetFrame((120, -100), (200, 150), tpl='test')
|
||||||
|
elif idx==4:
|
||||||
|
go=UsrGO.Grid((120, -100), (200, 150), (30, 22), 2)
|
||||||
|
else:
|
||||||
|
|
||||||
|
_log.error('set xstep 0..2 for tests')
|
||||||
|
self.vb.addItem(go)
|
||||||
|
obj=self._goTracked['objLst']
|
||||||
|
obj.append(go)
|
||||||
|
mft._tree.setData(obj)
|
||||||
|
|
||||||
|
# **************** OBSOLETE AND/OR OLD STUFF ****************
|
||||||
|
|
||||||
|
|
||||||
# functions are prefixed with _OLD_
|
# functions are prefixed with _OLD_
|
||||||
@@ -1677,19 +1747,6 @@ class SwissMxWnd(QMainWindow, Ui_MainWindow):
|
|||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
app._camera.pause()
|
app._camera.pause()
|
||||||
|
|
||||||
def _OLD_new_frame_sim_cb(self, **kwargs):
|
|
||||||
app=QApplication.instance()
|
|
||||||
sim=app._camera._sim
|
|
||||||
imgSeq=sim['imgSeq']
|
|
||||||
idx=sim['imgIdx']
|
|
||||||
sim['imgIdx']=(idx+1)%imgSeq.shape[0]
|
|
||||||
# _log.info('simulated idx:{}'.format(idx))
|
|
||||||
pic=imgSeq[idx]
|
|
||||||
self._goImg.setImage(pic)
|
|
||||||
|
|
||||||
delay=500 # ms -> 2fps
|
|
||||||
QtCore.QTimer.singleShot(delay, self.new_frame_sim_cb)
|
|
||||||
|
|
||||||
def _OLD_init_settings_tracker(self):
|
def _OLD_init_settings_tracker(self):
|
||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
cfg=app._cfg
|
cfg=app._cfg
|
||||||
|
|||||||
Reference in New Issue
Block a user