optimize imports and cleanup code
This commit is contained in:
445
EmblModule.py
445
EmblModule.py
@@ -1,445 +0,0 @@
|
|||||||
import logging
|
|
||||||
import numpy
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import struct
|
|
||||||
import time
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
#from scipy.misc import bytescale
|
|
||||||
|
|
||||||
import zmq
|
|
||||||
from os.path import join
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
#import qsingleton #ZAC: orig. code
|
|
||||||
#from CoordinatesModel import CoordinatesModel #ZAC: orig. code
|
|
||||||
from app_config import AppCfg #settings, option, appsconf
|
|
||||||
|
|
||||||
EMBL_RESULTS_TIMEOUT = "embl/results_timeout"
|
|
||||||
|
|
||||||
EMBL_SAVE_FILES = "embl/save_files"
|
|
||||||
|
|
||||||
#embl = appsconf["embl"]
|
|
||||||
|
|
||||||
#import imageio
|
|
||||||
import numpy as np
|
|
||||||
from PyQt5 import QtCore
|
|
||||||
from PyQt5.QtCore import pyqtSignal, Qt, QObject, pyqtSlot, QPoint
|
|
||||||
from PyQt5.QtGui import QStandardItemModel, QCursor
|
|
||||||
from PyQt5.QtWidgets import (
|
|
||||||
QWidget,
|
|
||||||
QVBoxLayout,
|
|
||||||
QHeaderView,
|
|
||||||
QPushButton,
|
|
||||||
QFormLayout,
|
|
||||||
QDoubleSpinBox,
|
|
||||||
QLabel,
|
|
||||||
QTableWidgetItem,
|
|
||||||
QLineEdit,
|
|
||||||
QTableWidget,
|
|
||||||
QTextEdit,
|
|
||||||
QProgressBar,
|
|
||||||
QHBoxLayout,
|
|
||||||
QSpinBox,
|
|
||||||
QTabWidget,
|
|
||||||
QTableView,
|
|
||||||
QMenu,
|
|
||||||
QProgressDialog,
|
|
||||||
)
|
|
||||||
|
|
||||||
#import storage
|
|
||||||
from app_utils import assert_motor_positions
|
|
||||||
|
|
||||||
#folders = storage.Folders()
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class EmblTaskResultTimeoutException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
ZPOS, FPATH = range(2)
|
|
||||||
|
|
||||||
# record separator
|
|
||||||
RS = 0x1e
|
|
||||||
|
|
||||||
|
|
||||||
#class EmblMessage(QObject, metaclass=qsingleton.Singleton): #ZAC: orig. code
|
|
||||||
class EmblMessage(QObject):
|
|
||||||
|
|
||||||
def __init__(self, parent=None, **kwargs):
|
|
||||||
super(EmblMessage, self).__init__(parent, **kwargs)
|
|
||||||
return #ZAC: orig. code
|
|
||||||
if not embl["enabled"]:
|
|
||||||
return
|
|
||||||
context = zmq.Context()
|
|
||||||
logger.info("Connecting to server...")
|
|
||||||
self.socket = context.socket(zmq.REQ)
|
|
||||||
uri = embl["uri"]
|
|
||||||
logger.info(f"EMBL alignment server at: {uri}")
|
|
||||||
self.socket.connect(uri)
|
|
||||||
|
|
||||||
def make_PAR(self, min: float, max: float, step: float, ppm: int, beam_xy: tuple):
|
|
||||||
puckid, sampleid = folders._prefix.split("_")
|
|
||||||
beam_x, beam_y = beam_xy
|
|
||||||
msg = (
|
|
||||||
f"PAR{RS:c}{min}{RS:c}{max}{RS:c}{step}{RS:c}{ppm}{RS:c}{beam_x:.0f}{RS:c}{beam_y:.0f}{RS:c}{puckid}{RS:c}{sampleid}"
|
|
||||||
)
|
|
||||||
logger.debug(f"PAR = {msg}")
|
|
||||||
self.socket.send_string(msg)
|
|
||||||
ans = self.socket.recv_string()
|
|
||||||
|
|
||||||
def make_IMG(self, pos: float, img):
|
|
||||||
width, height = img.shape
|
|
||||||
msg = f"IMG{RS:c}{pos:.3f}{RS:c}{width}{RS:c}{height}"
|
|
||||||
logger.info(f"sending img header: {msg}")
|
|
||||||
self.socket.send_string(msg)
|
|
||||||
self.socket.recv_string()
|
|
||||||
logger.info(
|
|
||||||
f"about to send img shape={img.shape} type={img.dtype} pos = {pos} mm"
|
|
||||||
)
|
|
||||||
self.socket.send(numpy.ascontiguousarray(img))
|
|
||||||
logger.info(f"waiting for recv")
|
|
||||||
ans = self.socket.recv_string()
|
|
||||||
logger.info(f"received!")
|
|
||||||
|
|
||||||
def finished(self):
|
|
||||||
self.make_STS("Finished")
|
|
||||||
|
|
||||||
def aborted(self):
|
|
||||||
self.make_STS("Aborted")
|
|
||||||
|
|
||||||
def make_STS(self, status):
|
|
||||||
msg = f"STS{RS:c}{status}"
|
|
||||||
self.socket.send_string(msg)
|
|
||||||
ans = self.socket.recv_string()
|
|
||||||
|
|
||||||
def make_RES(self):
|
|
||||||
n = 1
|
|
||||||
timeout = settings.value(EMBL_RESULTS_TIMEOUT, type=float) + time.time()
|
|
||||||
result = "failed"
|
|
||||||
while time.time() < timeout:
|
|
||||||
time.sleep(2.0)
|
|
||||||
logger.info(f"#{n}.requesting RES")
|
|
||||||
self.socket.send_string("RES")
|
|
||||||
result = self.socket.recv_string()
|
|
||||||
logger.info(f" RES = {result}")
|
|
||||||
if "Pending" != result:
|
|
||||||
break
|
|
||||||
n += 1
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
embl_tube = EmblMessage()
|
|
||||||
|
|
||||||
|
|
||||||
class EmblWidget(QWidget):
|
|
||||||
|
|
||||||
def __init__(self, parent):
|
|
||||||
super(EmblWidget, self).__init__(parent)
|
|
||||||
|
|
||||||
#parent.pixelsPerMillimeter.connect(self.save_ppm)
|
|
||||||
#parent.beamCameraCoordinatesChanged.connect(self.save_beam_coordinates)
|
|
||||||
self.setLayout(QVBoxLayout())
|
|
||||||
|
|
||||||
w = QWidget()
|
|
||||||
self.layout().addWidget(w)
|
|
||||||
w.setLayout(QFormLayout())
|
|
||||||
w.layout().setLabelAlignment(Qt.AlignRight)
|
|
||||||
|
|
||||||
self._startZ = QDoubleSpinBox()
|
|
||||||
self._startZ.setValue(0.6)
|
|
||||||
self._startZ.setSuffix(" mm")
|
|
||||||
self._startZ.setRange(-5, 5)
|
|
||||||
self._startZ.setSingleStep(0.1)
|
|
||||||
self._startZ.setDecimals(3)
|
|
||||||
|
|
||||||
self._endZ = QDoubleSpinBox()
|
|
||||||
self._endZ.setValue(1.4)
|
|
||||||
self._endZ.setSuffix(" mm")
|
|
||||||
self._endZ.setRange(-5, 5)
|
|
||||||
self._endZ.setSingleStep(0.1)
|
|
||||||
self._endZ.setDecimals(3)
|
|
||||||
|
|
||||||
self._stepZ = QDoubleSpinBox()
|
|
||||||
self._stepZ.setValue(0.050)
|
|
||||||
self._stepZ.setSuffix(" mm")
|
|
||||||
self._stepZ.setRange(0.005, 1.000)
|
|
||||||
self._stepZ.setSingleStep(0.010)
|
|
||||||
self._stepZ.setDecimals(3)
|
|
||||||
|
|
||||||
self._resultsTimeout = QDoubleSpinBox()
|
|
||||||
self._resultsTimeout.setRange(1., 2000.)
|
|
||||||
self._resultsTimeout.setValue(60)
|
|
||||||
self._resultsTimeout.setSuffix(" seconds")
|
|
||||||
self._resultsTimeout.setDecimals(0)
|
|
||||||
|
|
||||||
self._factors = QLineEdit("1 1 1")
|
|
||||||
but = QPushButton("update results")
|
|
||||||
but.clicked.connect(self.apply_factors)
|
|
||||||
|
|
||||||
w.layout().addRow(QLabel("Start Z"), self._startZ)
|
|
||||||
w.layout().addRow(QLabel("End Z"), self._endZ)
|
|
||||||
w.layout().addRow(QLabel("Step"), self._stepZ)
|
|
||||||
w.layout().addRow(QLabel("Task Result Timeout"), self._resultsTimeout)
|
|
||||||
w.layout().addRow(QLabel("Factors"), self._factors)
|
|
||||||
w.layout().addRow(QLabel("Apply Factors"), but)
|
|
||||||
|
|
||||||
|
|
||||||
but = QPushButton("Scan Z")
|
|
||||||
but.clicked.connect(self.executeScan)
|
|
||||||
but.setAccessibleName("emblScanZ")
|
|
||||||
self.layout().addWidget(but)
|
|
||||||
|
|
||||||
tabs = QTabWidget(self)
|
|
||||||
self.layout().addWidget(tabs)
|
|
||||||
|
|
||||||
self._table = QTableWidget()
|
|
||||||
self._table.setColumnCount(2)
|
|
||||||
self._table.setHorizontalHeaderLabels(("Z (mm)", "File Path"))
|
|
||||||
self._table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
||||||
self.layout().addWidget(self._table)
|
|
||||||
tabs.addTab(self._table, "Z Scans")
|
|
||||||
tabs.setAccessibleName("embl_tabs")
|
|
||||||
tabs.setObjectName("embl_tabs")
|
|
||||||
|
|
||||||
view = self._results_view = QTableView(self)
|
|
||||||
#view.setModel(CoordinatesModel()) #ZAC: orig. code
|
|
||||||
view.verticalHeader().show()
|
|
||||||
view.horizontalHeader().show()
|
|
||||||
view.setContextMenuPolicy(Qt.CustomContextMenu)
|
|
||||||
view.customContextMenuRequested.connect(self.results_menu)
|
|
||||||
tabs.addTab(view, "Results")
|
|
||||||
self._tabs = tabs
|
|
||||||
|
|
||||||
def apply_factors(self):
|
|
||||||
self.populate_results(self._results)
|
|
||||||
|
|
||||||
@pyqtSlot(float)
|
|
||||||
def save_ppm(self, ppm: float):
|
|
||||||
self._ppm = int(ppm)
|
|
||||||
|
|
||||||
@pyqtSlot(float, float)
|
|
||||||
def save_beam_coordinates(self, bx: float, by: float):
|
|
||||||
logger.debug(f"saving beam_xy {bx} & {by}")
|
|
||||||
self._beam_xy = (int(bx), int(by))
|
|
||||||
|
|
||||||
@pyqtSlot(QPoint)
|
|
||||||
def results_menu(self, at_point):
|
|
||||||
table = self.sender()
|
|
||||||
model = table.model()
|
|
||||||
|
|
||||||
index = table.indexAt(at_point)
|
|
||||||
if not index.isValid():
|
|
||||||
return
|
|
||||||
coords = model.coords_at(index)
|
|
||||||
logger.debug(f"coord: {coords}")
|
|
||||||
menu = QMenu(table)
|
|
||||||
|
|
||||||
gotoAction = menu.addAction("Go here")
|
|
||||||
if menu.exec_(QCursor.pos()) is gotoAction:
|
|
||||||
logger.info(f"going to: {index.row()} => {coords}")
|
|
||||||
self.goto_position(coords)
|
|
||||||
|
|
||||||
def configure(self, motors, camera, zoom_device):
|
|
||||||
self._camera = camera
|
|
||||||
self._zoom_device = zoom_device
|
|
||||||
self.motors = motors
|
|
||||||
|
|
||||||
def executeScan(self):
|
|
||||||
fx, fy, cx, cz, omega = self.motors
|
|
||||||
|
|
||||||
x, y, z = fx.get_position(), fy.get_position(), cz.get_position()
|
|
||||||
logger.info(f"scan started at gonio: x,y,z = {x}, {y}, {z}")
|
|
||||||
|
|
||||||
self._table.setRowCount(0) # clear previous information
|
|
||||||
|
|
||||||
zs = self._startZ.value()
|
|
||||||
ze = self._endZ.value()
|
|
||||||
step = self._stepZ.value()
|
|
||||||
scan_config = {
|
|
||||||
"z-start": zs,
|
|
||||||
"z-end": ze + step, # inclusive last value
|
|
||||||
"z-step": step,
|
|
||||||
"ppm": self._ppm,
|
|
||||||
"beam_xy": self._beam_xy,
|
|
||||||
}
|
|
||||||
|
|
||||||
self._gonio_at_start = (x, y, ze + step)
|
|
||||||
|
|
||||||
base_Z = self.motors[3] # base_Z
|
|
||||||
camera = self._camera
|
|
||||||
|
|
||||||
zvals = np.arange(zs, ze, step)
|
|
||||||
numZs = len(zvals)
|
|
||||||
|
|
||||||
dlg = QProgressDialog(self)
|
|
||||||
dlg.setWindowModality(Qt.WindowModal)
|
|
||||||
dlg.setMinimumDuration(0)
|
|
||||||
dlg.setCancelButton(None)
|
|
||||||
dlg.setRange(0, 0)
|
|
||||||
dlg.setLabelText(f"<b>EMBL Z-Scan</b><br/>")
|
|
||||||
dlg.setAutoClose(True)
|
|
||||||
dlg.show()
|
|
||||||
dlg.setValue(random.randint(1, 20))
|
|
||||||
self._progress_dialog = dlg
|
|
||||||
|
|
||||||
self._acq_thread = AcquisitionThread(base_Z, camera, scan_config)
|
|
||||||
self._acq_thread.image_acquired.connect(self.addImage)
|
|
||||||
self._acq_thread.acquisition_finished.connect(self.acquisition_finished)
|
|
||||||
self._acq_thread.results_fetched.connect(self.populate_results)
|
|
||||||
self._acq_thread.message.connect(
|
|
||||||
lambda msg: dlg.setLabelText(f"<b>EMBL Z-Scan</b><br/>{msg}")
|
|
||||||
)
|
|
||||||
self._acq_thread.start()
|
|
||||||
|
|
||||||
def createModel(self, parent):
|
|
||||||
model = QStandardItemModel(0, 2, parent)
|
|
||||||
model.setHeaderData(ZPOS, QtCore.Qt.Horizontal, "Z (mm)")
|
|
||||||
model.setHeaderData(FPATH, QtCore.Qt.Horizontal, "Image Path")
|
|
||||||
self._model = model
|
|
||||||
return model
|
|
||||||
|
|
||||||
def addImage(self, idx, zpos, fpath):
|
|
||||||
logger.info("zpos = {}, fpath = {}".format(zpos, fpath))
|
|
||||||
rows = self._table.rowCount()
|
|
||||||
# table.setRowCount(rows + 1)
|
|
||||||
self._table.insertRow(rows)
|
|
||||||
item = QTableWidgetItem()
|
|
||||||
item.setText("{:.03f}".format(zpos))
|
|
||||||
self._table.setItem(rows, ZPOS, item)
|
|
||||||
item = QTableWidgetItem()
|
|
||||||
item.setText(str(fpath))
|
|
||||||
self._table.setItem(rows, FPATH, item)
|
|
||||||
self._table.resizeColumnsToContents()
|
|
||||||
|
|
||||||
def acquisition_finished(self):
|
|
||||||
self._progress_dialog.reset()
|
|
||||||
|
|
||||||
def goto_position(self, coords):
|
|
||||||
fx, fy, cx, cz, o = self.motors
|
|
||||||
tx, ty, bb, tz, to = coords
|
|
||||||
|
|
||||||
logger.info(f"moving gonio to: {tx}, {ty}, {tz}")
|
|
||||||
fx.move(tx, wait=True, ignore_limits=True)
|
|
||||||
fy.move(ty, wait=True, ignore_limits=True)
|
|
||||||
cz.move(tz, wait=True, ignore_limits=True)
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def populate_results(self, results):
|
|
||||||
"""Results.txt
|
|
||||||
60.624%363.4026940025185%-768.32%-1052.52
|
|
||||||
|
|
||||||
angle between sample and camera, x, y, z
|
|
||||||
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
if "no results" in results:
|
|
||||||
return
|
|
||||||
|
|
||||||
s1, s2, s3 = [int(c) for c in self._factors.text().split()]
|
|
||||||
|
|
||||||
self._results = results
|
|
||||||
self.coords = []
|
|
||||||
ox, oy, oz = self._gonio_at_start
|
|
||||||
|
|
||||||
oz = self._endZ.value()
|
|
||||||
|
|
||||||
for n, line in enumerate(results.split("\n")):
|
|
||||||
# o, z, y, x = [float(n) for n in line.split("%")]
|
|
||||||
omega, x, y, z = [float(n) for n in line.split("%")]
|
|
||||||
no, nx, ny, nz = [omega, ox + s1*x, oy + s2*y, oz + s3*z]
|
|
||||||
|
|
||||||
self.coords.append([nx, ny, 0, nz, no])
|
|
||||||
model = self._results_view.model()
|
|
||||||
model.update_coordinates(self.coords)
|
|
||||||
self._tabs.setCurrentIndex(1)
|
|
||||||
|
|
||||||
|
|
||||||
class AcquisitionThread(QtCore.QThread):
|
|
||||||
|
|
||||||
image_acquired = pyqtSignal(int, float, str)
|
|
||||||
results_fetched = pyqtSignal(str)
|
|
||||||
message = pyqtSignal(str)
|
|
||||||
acquisition_finished = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, z_motor, camera, scan_config):
|
|
||||||
QtCore.QThread.__init__(self)
|
|
||||||
self._scanconfig = scan_config
|
|
||||||
logger.debug(f"scanconfig: {scan_config}")
|
|
||||||
self.z_motor = z_motor
|
|
||||||
self.camera = camera
|
|
||||||
|
|
||||||
def save_params(self, params):
|
|
||||||
fname = Path(folders.res_folder) / "z_scan" / "parameters.yaml"
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(fname, "w") as fp:
|
|
||||||
yaml.dump(params, fp)
|
|
||||||
except:
|
|
||||||
logger.warning(f"failed to save z-scan parameter file: {fname}")
|
|
||||||
|
|
||||||
def save_image(self, n, z, img):
|
|
||||||
if not option(EMBL_SAVE_FILES):
|
|
||||||
return
|
|
||||||
zp = f"{n:02d}_Z{z:.3f}".replace(".", "p") + ".png"
|
|
||||||
fname = Path(folders.res_folder) / "z_scan" / zp
|
|
||||||
try:
|
|
||||||
imageio.imsave(fname, img)
|
|
||||||
except:
|
|
||||||
logger.error(f"failed to write: {fname}")
|
|
||||||
return f"failed to write image {n}"
|
|
||||||
return fname
|
|
||||||
|
|
||||||
def save_result(self, result):
|
|
||||||
if not option(EMBL_SAVE_FILES):
|
|
||||||
return
|
|
||||||
fname = Path(folders.res_folder) / "z_scan" / "result.txt"
|
|
||||||
with open(fname, "w") as fp:
|
|
||||||
fp.write(result)
|
|
||||||
|
|
||||||
def make_folders(self):
|
|
||||||
if not option(EMBL_SAVE_FILES):
|
|
||||||
return
|
|
||||||
fold = Path(folders.res_folder) / "z_scan"
|
|
||||||
fold.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.make_folders()
|
|
||||||
cnf = self._scanconfig
|
|
||||||
zmin, zmax, zstep = cnf["z-start"], cnf["z-end"], cnf["z-step"]
|
|
||||||
zvals = np.arange(zmin, zmax, zstep)
|
|
||||||
num = len(zvals)
|
|
||||||
|
|
||||||
logger.debug(
|
|
||||||
f"Z-scan: min/max/step {zmin}/{zmax}/{zstep} ppm={cnf['ppm']} beam_xy={cnf['beam_xy']}"
|
|
||||||
)
|
|
||||||
logger.info(f"Z-vals: {', '.join([f'{z:.2f}' for z in zvals])}")
|
|
||||||
self.save_params(cnf)
|
|
||||||
embl_tube.make_PAR(zmin, zmax, zstep, cnf["ppm"], cnf["beam_xy"])
|
|
||||||
|
|
||||||
for n, z in enumerate(zvals):
|
|
||||||
idx = n + 1
|
|
||||||
self.message.emit(f"{idx}/{num} Z ➠ {z:.2f}")
|
|
||||||
self.z_motor.move(z, ignore_limits=True, wait=True)
|
|
||||||
assert_motor_positions([(self.z_motor, z, 0.1)], timeout=3.)
|
|
||||||
self.message.emit(f"{idx}/{num} acquiring")
|
|
||||||
img = self.camera.get_image()
|
|
||||||
self.message.emit(f"{idx}/{num} acquired")
|
|
||||||
img = np.rot90(img, 1)
|
|
||||||
img = bytescale(img)
|
|
||||||
fname = self.save_image(idx, z, img)
|
|
||||||
self.image_acquired.emit(idx, z, str(fname)) # just to populate table
|
|
||||||
self.message.emit(f"{idx}/{num} sending")
|
|
||||||
embl_tube.make_IMG(z, img)
|
|
||||||
self.message.emit(f"{idx}/{num} sent")
|
|
||||||
self.message.emit(f"acquisition finished")
|
|
||||||
embl_tube.finished()
|
|
||||||
self.message.emit(f"waiting for results")
|
|
||||||
result = embl_tube.make_RES()
|
|
||||||
self.save_result(result)
|
|
||||||
self.results_fetched.emit(result)
|
|
||||||
self.acquisition_finished.emit()
|
|
||||||
256
HelicalTable.py
256
HelicalTable.py
@@ -1,256 +0,0 @@
|
|||||||
import sys
|
|
||||||
import os
|
|
||||||
import logging
|
|
||||||
import csv
|
|
||||||
from PyQt5 import QtCore, QtGui
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
logger = logging.getLogger("helical")
|
|
||||||
|
|
||||||
from PyQt5.QtWidgets import (
|
|
||||||
QTableWidget,
|
|
||||||
QApplication,
|
|
||||||
QMainWindow,
|
|
||||||
QTableWidgetItem,
|
|
||||||
QFileDialog,
|
|
||||||
QHeaderView,
|
|
||||||
QAbstractItemView,
|
|
||||||
QMenu)
|
|
||||||
from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal, QPoint, pyqtSlot
|
|
||||||
|
|
||||||
DATA_ITEM = 1
|
|
||||||
|
|
||||||
START_OMEGA_0 = 0
|
|
||||||
START_OMEGA_120 = 1
|
|
||||||
START_OMEGA_240 = 2
|
|
||||||
STOP_OMEGA_0 = 3
|
|
||||||
STOP_OMEGA_120 = 4
|
|
||||||
STOP_OMEGA_240 = 5
|
|
||||||
|
|
||||||
ROLE_XTAL_START = 1 + Qt.UserRole
|
|
||||||
ROLE_XTAL_END = 2 + Qt.UserRole
|
|
||||||
|
|
||||||
|
|
||||||
class HelicalTableWidget(QTableWidget):
|
|
||||||
gonioMoveRequest = pyqtSignal(float, float, float, float, float)
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.check_change = True
|
|
||||||
self._scanAngularStep = 0.1
|
|
||||||
self._scanHorizontalCount = 5
|
|
||||||
self._scanVerticalCount = 10
|
|
||||||
self._current_xtal = None
|
|
||||||
self._start_angle = 0.0
|
|
||||||
self.init_ui()
|
|
||||||
|
|
||||||
def startAngle(self) -> float:
|
|
||||||
return self._start_angle
|
|
||||||
|
|
||||||
@pyqtSlot(float)
|
|
||||||
def setStartAngle(self, angle:float):
|
|
||||||
self._start_angle = angle
|
|
||||||
|
|
||||||
def init_ui(self):
|
|
||||||
self.setColumnCount(6)
|
|
||||||
self.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
|
||||||
self.resizeColumnsToContents()
|
|
||||||
self.setSelectionMode(QAbstractItemView.SingleSelection)
|
|
||||||
self.setSelectionBehavior(QAbstractItemView.SelectItems)
|
|
||||||
labels = [
|
|
||||||
"0\nbx, bz\n(mm)",
|
|
||||||
"120\nbx, bz\n(mm)",
|
|
||||||
"240\nbx, bz\n(mm)",
|
|
||||||
"0\nbx, bz\n(mm)",
|
|
||||||
"120\nbx, bz\n(mm)",
|
|
||||||
"240\nbx, bz\n(mm)",
|
|
||||||
]
|
|
||||||
self.setHorizontalHeaderLabels(labels)
|
|
||||||
|
|
||||||
self.verticalHeader().resizeSections(QHeaderView.ResizeToContents)
|
|
||||||
self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
|
||||||
|
|
||||||
self.cellChanged.connect(self.c_current)
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
def display_coords(self, x, y):
|
|
||||||
row = self.rowAt(y)
|
|
||||||
col = self.columnAt(x)
|
|
||||||
coords = self.gonio_coords_at(row, col)
|
|
||||||
omega = col % 3 * 120
|
|
||||||
data = coords[omega]
|
|
||||||
logger.info("gonio at {}, {}: {}".format(row, col, data))
|
|
||||||
|
|
||||||
def goto_gonio_position(self, x, y):
|
|
||||||
row = self.rowAt(y)
|
|
||||||
col = self.columnAt(x)
|
|
||||||
coords = self.gonio_coords_at(row, col)
|
|
||||||
omega = col % 3 * 120
|
|
||||||
data = coords[omega]
|
|
||||||
logger.info("move gonio to: {}".format(row, col, data))
|
|
||||||
self.gonioMoveRequest.emit(*data)
|
|
||||||
|
|
||||||
def remove_xtal(self, x, y):
|
|
||||||
row = self.rowAt(y)
|
|
||||||
col = self.columnAt(x)
|
|
||||||
logger.info("rowCount() = {}, removing row: {}".format(self.rowCount(), row))
|
|
||||||
self.removeRow(row)
|
|
||||||
if self.rowCount() == 0:
|
|
||||||
self._current_xtal = None
|
|
||||||
logger.info("rowCount() = {}".format(self.rowCount()))
|
|
||||||
|
|
||||||
def contextMenuEvent(self, event):
|
|
||||||
logger.info(event.pos())
|
|
||||||
x = event.pos().x()
|
|
||||||
y = event.pos().y()
|
|
||||||
menu = QMenu(self)
|
|
||||||
gotoAction = menu.addAction("Move Gonio Here")
|
|
||||||
gotoAction.triggered.connect(lambda b: self.goto_gonio_position(x, y))
|
|
||||||
removeAction = menu.addAction("Remove this line")
|
|
||||||
removeAction.triggered.connect(lambda b: self.remove_xtal(x, y))
|
|
||||||
menu.popup(QtGui.QCursor.pos())
|
|
||||||
|
|
||||||
def setScanHorizontalCount(self, count: int):
|
|
||||||
logger.debug("horizontal count: {}".format(count))
|
|
||||||
self._scanHorizontalCount = count
|
|
||||||
|
|
||||||
def scanHorizontalCount(self) -> int:
|
|
||||||
return self._scanHorizontalCount
|
|
||||||
|
|
||||||
def setScanVerticalCount(self, count: int):
|
|
||||||
logger.debug("vertical count: {}".format(count))
|
|
||||||
self._scanVerticalCount = count
|
|
||||||
|
|
||||||
def scanVerticalCount(self) -> int:
|
|
||||||
return self._scanVerticalCount
|
|
||||||
|
|
||||||
def setScanAngularStep(self, step: float):
|
|
||||||
self._scanAngularStep = step
|
|
||||||
|
|
||||||
def scanAngularStep(self) -> float:
|
|
||||||
return self._scanAngularStep
|
|
||||||
|
|
||||||
def scanTotalRange(self) -> float:
|
|
||||||
return self._scanVerticalCount * self._scanHorizontalCount * self._scanAngularStep
|
|
||||||
|
|
||||||
def gonio_coords_at(self, row, col):
|
|
||||||
role = ROLE_XTAL_START if col < 3 else ROLE_XTAL_END
|
|
||||||
coords = self.item(row, DATA_ITEM).data(role)
|
|
||||||
return coords
|
|
||||||
|
|
||||||
def add_xtal(self):
|
|
||||||
row = self.rowCount()
|
|
||||||
self.setRowCount(row + 1)
|
|
||||||
self._current_xtal = row
|
|
||||||
print(row)
|
|
||||||
for n in range(self.columnCount()):
|
|
||||||
self.setItem(row, n, QTableWidgetItem("unset"))
|
|
||||||
|
|
||||||
|
|
||||||
def set_xtal_start(self, data: list):
|
|
||||||
"""sets data to start position
|
|
||||||
|
|
||||||
data = [fx, fy, bx, bz, omega]
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.set_data_point(ROLE_XTAL_START, data)
|
|
||||||
|
|
||||||
def set_xtal_end(self, data: list):
|
|
||||||
self.set_data_point(ROLE_XTAL_END, data)
|
|
||||||
|
|
||||||
def set_data_point(self, role: int, data: list):
|
|
||||||
if self._current_xtal is None:
|
|
||||||
self.add_xtal()
|
|
||||||
row, col = self._current_xtal, DATA_ITEM
|
|
||||||
|
|
||||||
try:
|
|
||||||
coords = self.item(row, DATA_ITEM).data(role)
|
|
||||||
except:
|
|
||||||
print("empty coords; initializing...")
|
|
||||||
coords = None
|
|
||||||
|
|
||||||
if coords is None:
|
|
||||||
coords = {}
|
|
||||||
|
|
||||||
fx, fy, bx, bz, omega = data
|
|
||||||
o = int(omega)
|
|
||||||
coords[o] = data
|
|
||||||
print("coords = {}".format(coords))
|
|
||||||
|
|
||||||
if role == ROLE_XTAL_END:
|
|
||||||
col = 3
|
|
||||||
else:
|
|
||||||
col = 0
|
|
||||||
|
|
||||||
for n in range(3):
|
|
||||||
omega = n * 120
|
|
||||||
try:
|
|
||||||
fx, fy, bx, bz, omega = coords[omega]
|
|
||||||
info = "{bx:.3f} mm\n{bz:.3f} mm".format(bx=bx, bz=bz)
|
|
||||||
except:
|
|
||||||
info = "unset"
|
|
||||||
# self.item(row, col + n).setData(Qt.DisplayRole, info)
|
|
||||||
self.item(row, col + n).setText(info)
|
|
||||||
self.item(row, col + n).setToolTip(info)
|
|
||||||
|
|
||||||
self.item(row, DATA_ITEM).setData(role, coords)
|
|
||||||
|
|
||||||
def c_current(self):
|
|
||||||
if self.check_change:
|
|
||||||
row = self.currentRow()
|
|
||||||
col = self.currentColumn()
|
|
||||||
value = self.item(row, col)
|
|
||||||
# value = value.text()
|
|
||||||
|
|
||||||
def load_datapoints(self):
|
|
||||||
self.check_change = False
|
|
||||||
path = QFileDialog.getOpenFileName(
|
|
||||||
self, "Open CSV", os.getenv("HOME"), "CSV(*.csv)"
|
|
||||||
)
|
|
||||||
if path[0] != "":
|
|
||||||
with open(path[0], newline="") as csv_file:
|
|
||||||
self.setRowCount(0)
|
|
||||||
self.setColumnCount(10)
|
|
||||||
my_file = csv.reader(csv_file, delimiter=",", quotechar="|")
|
|
||||||
for row_data in my_file:
|
|
||||||
row = self.rowCount()
|
|
||||||
self.insertRow(row)
|
|
||||||
if len(row_data) > 10:
|
|
||||||
self.setColumnCount(len(row_data))
|
|
||||||
for column, stuff in enumerate(row_data):
|
|
||||||
item = QTableWidgetItem(stuff)
|
|
||||||
self.setItem(row, column, item)
|
|
||||||
self.check_change = True
|
|
||||||
|
|
||||||
def get_data(self, as_numpy=False):
|
|
||||||
"""return a list of tuples with all defined data
|
|
||||||
|
|
||||||
[
|
|
||||||
(is_fiducial(boolean), x, y, gonio_x, gonio_y),...
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
data = []
|
|
||||||
|
|
||||||
for row in range(self.rowCount()):
|
|
||||||
start = self.item(row, DATA_ITEM).data(ROLE_XTAL_START)
|
|
||||||
end = self.item(row, DATA_ITEM).data(ROLE_XTAL_END)
|
|
||||||
|
|
||||||
data.append([start, end])
|
|
||||||
# if as_numpy:
|
|
||||||
# data = np.asarray(data)
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
class Sheet(QMainWindow):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
self.form_widget = HelicalTableWidget()
|
|
||||||
self.setCentralWidget(self.form_widget)
|
|
||||||
self.show()
|
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
sheet = Sheet()
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
6
Makefile
6
Makefile
@@ -22,12 +22,6 @@ init:
|
|||||||
-ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/PBTools.git $(APP)/SwissMX/PBTools'
|
-ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/PBTools.git $(APP)/SwissMX/PBTools'
|
||||||
-ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/ppmac.git $(APP)/SwissMX/PBTools/ppmac'
|
-ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/ppmac.git $(APP)/SwissMX/PBTools/ppmac'
|
||||||
-rsync -vai simCamImg $(REMOTE):$(APP)/SwissMX/
|
-rsync -vai simCamImg $(REMOTE):$(APP)/SwissMX/
|
||||||
# -rsync -vai ../../PBTools $(REMOTE):$(APP)/SwissMX/
|
|
||||||
# -ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/PBTools.git $(APP)/PBTools'
|
|
||||||
# ssh $(REMOTE) 'pip3.6 install --user pandas zmq qtawesome'
|
|
||||||
# ssh $(REMOTE) '/opt/gfa/python-3.8/latest/bin/pip install --user pandas zmq qtawesome'
|
|
||||||
# ssh $(REMOTE) 'pip3.6 install --prefix /sf/cristallina/applications/SwissMX/module pandas zmq qtawesome'
|
|
||||||
# ssh $(REMOTE) '/opt/gfa/python-3.8/latest/bin/pip install --prefix /sf/cristallina/applications/SwissMX/module pandas zmq qtawesome'
|
|
||||||
|
|
||||||
update:
|
update:
|
||||||
ssh $(REMOTE) 'cd $(APP)/SwissMX && git fetch psigithub && git reset psigithub/master --hard'
|
ssh $(REMOTE) 'cd $(APP)/SwissMX && git fetch psigithub && git reset psigithub/master --hard'
|
||||||
|
|||||||
@@ -13,54 +13,17 @@ This contains a Widget to handle FixTargetFrames and fiducials, calculate final
|
|||||||
|
|
||||||
#https://stackoverflow.com/questions/27909658/json-encoder-and-decoder-for-complex-numpy-arrays
|
#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
|
import logging
|
||||||
_log=logging.getLogger(__name__)
|
_log=logging.getLogger(__name__)
|
||||||
|
|
||||||
import json, base64 #, os, pickle, yaml
|
import json, base64
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyqtUsrObj as UsrGO
|
import pyqtUsrObj as UsrGO
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QTableWidgetItem,
|
QFileDialog, QWidget, QGridLayout, QItemDelegate, QVBoxLayout, QPushButton, QApplication,
|
||||||
QFileDialog,
|
QMainWindow, QLineEdit, QMessageBox, QAction, QComboBox)
|
||||||
QGroupBox,
|
|
||||||
QWidget,
|
|
||||||
QGridLayout,
|
|
||||||
QTableWidget,
|
|
||||||
QAbstractItemView,
|
|
||||||
QItemDelegate,
|
|
||||||
QVBoxLayout,
|
|
||||||
QLabel,
|
|
||||||
QPushButton,
|
|
||||||
QApplication,
|
|
||||||
QMainWindow,
|
|
||||||
QHeaderView,
|
|
||||||
QLineEdit,
|
|
||||||
QSpinBox,
|
|
||||||
QMessageBox,
|
|
||||||
QAction,
|
|
||||||
QComboBox,
|
|
||||||
QCheckBox)
|
|
||||||
|
|
||||||
|
|
||||||
class MyJsonEncoder(json.JSONEncoder):
|
class MyJsonEncoder(json.JSONEncoder):
|
||||||
@@ -109,8 +72,6 @@ class MarkerDelegate(QItemDelegate):
|
|||||||
return comboBox
|
return comboBox
|
||||||
|
|
||||||
def setEditorData(self, editor, index):
|
def setEditorData(self, editor, index):
|
||||||
# pos = comboBox.findText(index.model().data(index), Qt.MatchExactly)
|
|
||||||
# comboBox.setCurrentIndex(pos)
|
|
||||||
editor.setText("{}".format(index.model().data(index)))
|
editor.setText("{}".format(index.model().data(index)))
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
@@ -158,27 +119,11 @@ class WndFixTarget(QWidget):
|
|||||||
btnSv.clicked.connect(lambda: self.save_file())
|
btnSv.clicked.connect(lambda: self.save_file())
|
||||||
bl.addWidget(btnSv, 0, 1)
|
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 = QPushButton("dump")
|
||||||
btnDump.clicked.connect(self.dump_data)
|
btnDump.clicked.connect(self.dump_data)
|
||||||
bl.addWidget(btnDump, 0, 2)
|
bl.addWidget(btnDump, 0, 2)
|
||||||
|
|
||||||
self._cbType=cb=QComboBox()
|
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)
|
bl.addWidget(cb, 1,0,1,1)
|
||||||
self._txtParam=param=QLineEdit()
|
self._txtParam=param=QLineEdit()
|
||||||
@@ -196,23 +141,7 @@ class WndFixTarget(QWidget):
|
|||||||
bl.addWidget(btnFit, 2, 1,1,1)
|
bl.addWidget(btnFit, 2, 1,1,1)
|
||||||
|
|
||||||
layout.addWidget(frame)
|
layout.addWidget(frame)
|
||||||
#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._data=data
|
||||||
self._tree=tree=pg.DataTreeWidget(data=data)
|
self._tree=tree=pg.DataTreeWidget(data=data)
|
||||||
layout.addWidget(tree, stretch=2)
|
layout.addWidget(tree, stretch=2)
|
||||||
|
|||||||
@@ -1,709 +0,0 @@
|
|||||||
# coding=utf-8
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
from os.path import join
|
|
||||||
from typing import List
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
try:
|
|
||||||
import pandas as pd
|
|
||||||
except ImportError as e:
|
|
||||||
print (f'{e} import failed')
|
|
||||||
#import transformations as tfs
|
|
||||||
|
|
||||||
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,
|
|
||||||
QCheckBox)
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# from coord_library import conversions
|
|
||||||
#import conversions #ZAC: orig. code
|
|
||||||
from app_config import AppCfg
|
|
||||||
|
|
||||||
#from storage import Folders #ZAC: orig. code
|
|
||||||
#folders = Folders() #ZAC: orig. code
|
|
||||||
|
|
||||||
XY_Coord = List[float]
|
|
||||||
|
|
||||||
DATA_ITEM = 1
|
|
||||||
ORIGINAL_X = 1
|
|
||||||
ORIGINAL_Y = 2
|
|
||||||
GONIO_X = 3
|
|
||||||
GONIO_Y = 4
|
|
||||||
|
|
||||||
|
|
||||||
RoleGoniometerCoord_X = 1 + Qt.UserRole
|
|
||||||
RoleGoniometerCoord_Y = 2 + Qt.UserRole
|
|
||||||
RoleCameraCoord_X = 3 + Qt.UserRole
|
|
||||||
RoleCameraCoord_Y = 4 + Qt.UserRole
|
|
||||||
RoleOriginalCoord_X = 5 + Qt.UserRole
|
|
||||||
RoleOriginalCoord_Y = 6 + Qt.UserRole
|
|
||||||
|
|
||||||
|
|
||||||
def sort_cmass_3d(coord):
|
|
||||||
"""sorts the 3D coordinates (np array 3 columns) with respect to their distane to the center of mass in 3d"""
|
|
||||||
cm = conversions.find_geo_center(coord)
|
|
||||||
# print cm
|
|
||||||
moved_coord = conversions.center_coord(coord, cm)
|
|
||||||
sorted_moved_coord = conversions.sort_center_3d(moved_coord)
|
|
||||||
minus_cm = np.multiply(cm, -1)
|
|
||||||
return conversions.center_coord(sorted_moved_coord, minus_cm)
|
|
||||||
|
|
||||||
|
|
||||||
def sort_cmass(coord):
|
|
||||||
"""sorts the 2D coordinates (np array 2 columns) with respect to their distane to the center of mass"""
|
|
||||||
cm = conversions.find_geo_center(coord)
|
|
||||||
# print cm
|
|
||||||
moved_coord = conversions.center_coord(coord, cm)
|
|
||||||
sorted_moved_coord = conversions.sort_center(moved_coord)
|
|
||||||
minus_cm = np.multiply(cm, -1)
|
|
||||||
return conversions.center_coord(sorted_moved_coord, minus_cm)
|
|
||||||
|
|
||||||
|
|
||||||
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 PrelocatedCoordinates(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):
|
|
||||||
super(PrelocatedCoordinates, self).__init__(parent)
|
|
||||||
self._xtals_transformed = True
|
|
||||||
|
|
||||||
self._current_row = None
|
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
|
||||||
|
|
||||||
self.setLayout(layout)
|
|
||||||
frame = QWidget()
|
|
||||||
bl = QGridLayout()
|
|
||||||
frame.setLayout(bl)
|
|
||||||
|
|
||||||
self._label_prefix = QLabel("not set")
|
|
||||||
self._label_datafile = QLabel("not loaded")
|
|
||||||
self._label_datafile.setWordWrap(True)
|
|
||||||
bl.addWidget(QLabel("Prefix"), 0, 0)
|
|
||||||
bl.addWidget(self._label_prefix, 0, 1)
|
|
||||||
bl.addWidget(QLabel("Data File"), 1, 0)
|
|
||||||
bl.addWidget(self._label_datafile, 1, 1)
|
|
||||||
|
|
||||||
but1 = QPushButton("Load Datafile")
|
|
||||||
but1.clicked.connect(lambda: self.loadMarkers(None))
|
|
||||||
bl.addWidget(but1, 2, 0)
|
|
||||||
|
|
||||||
but1 = QPushButton("Save Datafile")
|
|
||||||
but1.clicked.connect(lambda: self.saveDataAs())
|
|
||||||
bl.addWidget(but1, 2, 1)
|
|
||||||
|
|
||||||
but2 = QPushButton("Clear Data")
|
|
||||||
but2.clicked.connect(self.clearMarkers)
|
|
||||||
bl.addWidget(but2, 3, 0)
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
but = QPushButton("dump numpy")
|
|
||||||
but.clicked.connect(self.dump_numpy)
|
|
||||||
bl.addWidget(but, 5, 0)
|
|
||||||
|
|
||||||
|
|
||||||
# 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")
|
|
||||||
)
|
|
||||||
self.markersTable.horizontalHeader().setSectionResizeMode(
|
|
||||||
0, QHeaderView.ResizeToContents
|
|
||||||
)
|
|
||||||
self.markersTable.horizontalHeader().setSectionResizeMode(
|
|
||||||
1, QHeaderView.ResizeToContents
|
|
||||||
)
|
|
||||||
self.markersTable.horizontalHeader().setSectionResizeMode(
|
|
||||||
2, QHeaderView.ResizeToContents
|
|
||||||
)
|
|
||||||
self.markersTable.horizontalHeader().setSectionResizeMode(
|
|
||||||
3, QHeaderView.ResizeToContents
|
|
||||||
)
|
|
||||||
self.markersTable.horizontalHeader().setSectionResizeMode(
|
|
||||||
4, QHeaderView.ResizeToContents
|
|
||||||
)
|
|
||||||
self.markersTable.horizontalHeader().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()
|
|
||||||
|
|
||||||
def delete_selected(self):
|
|
||||||
row = self._current_row
|
|
||||||
try:
|
|
||||||
row += 0
|
|
||||||
except:
|
|
||||||
logger.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)
|
|
||||||
logger.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:
|
|
||||||
logger.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: XY_Coord):
|
|
||||||
tbl = self.markersTable
|
|
||||||
row = self._current_row
|
|
||||||
try:
|
|
||||||
row += 0
|
|
||||||
except:
|
|
||||||
logger.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
|
|
||||||
logger.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: XY_Coord):
|
|
||||||
tbl = self.markersTable
|
|
||||||
|
|
||||||
row = self._current_row
|
|
||||||
try:
|
|
||||||
row += 0
|
|
||||||
except:
|
|
||||||
logger.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):
|
|
||||||
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: List):
|
|
||||||
"""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 saveDataAs(self, filename=None):
|
|
||||||
# filename = folders.get_file("prelocated-save.dat")
|
|
||||||
data_folder = settings.value("folders/last_prelocation_folder")
|
|
||||||
if filename is None:
|
|
||||||
filename, _ = QFileDialog.getSaveFileName(
|
|
||||||
parent=None,
|
|
||||||
caption="Open CSV data file",
|
|
||||||
directory=data_folder,
|
|
||||||
filter="CSV Data Files (*.csv);;All Files (*)",
|
|
||||||
)
|
|
||||||
|
|
||||||
if not filename:
|
|
||||||
return
|
|
||||||
|
|
||||||
settings.setValue("folders/last_prelocation_folder", QFileInfo(filename).canonicalPath())
|
|
||||||
logger.info("Saving data in {}".format(filename))
|
|
||||||
data = self.get_data(as_numpy=True)
|
|
||||||
df = pd.DataFrame(data)
|
|
||||||
df.to_csv(filename, float_format="%.6f")
|
|
||||||
|
|
||||||
def addSingleMarker(self, row, marker):
|
|
||||||
is_fiducial, origx, origy, gx, gy = marker
|
|
||||||
logger.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)
|
|
||||||
|
|
||||||
def loadMarkers(self, filename=None):
|
|
||||||
logger = logging.getLogger("preloc.loadMarkers")
|
|
||||||
#def_folder = join(folders.pgroup_folder, "preloc_sheets") #ZAC: orig. code
|
|
||||||
def_folder =''
|
|
||||||
data_folder = settings.value("folders/last_prelocation_folder", def_folder)
|
|
||||||
|
|
||||||
if filename is None:
|
|
||||||
filename, _ = QFileDialog.getOpenFileName(
|
|
||||||
self,
|
|
||||||
"Open CSV data file",
|
|
||||||
data_folder,
|
|
||||||
"Any file.. (*.txt);;CSV Data Files (*.csv);;All Files (*)",
|
|
||||||
)
|
|
||||||
|
|
||||||
# filename = folders.get_file("preloc-in.csv")
|
|
||||||
|
|
||||||
|
|
||||||
if not filename: # cancelled dialog
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
settings.setValue("folders/last_prelocation_folder", QFileInfo(filename).canonicalPath())
|
|
||||||
settings.setValue("folders/last_prelocation_sheet", QFileInfo(filename).absolutePath())
|
|
||||||
except TypeError as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.clearMarkers()
|
|
||||||
|
|
||||||
logger.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)
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
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()
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
|
||||||
def __init__(self, parent=None):
|
|
||||||
super(MainWindow, self).__init__(parent)
|
|
||||||
self.centralWidget = QWidget()
|
|
||||||
|
|
||||||
self.markwi = PrelocatedCoordinates(parent=self)
|
|
||||||
|
|
||||||
self.setCentralWidget(self.centralWidget)
|
|
||||||
mainLayout = QVBoxLayout()
|
|
||||||
mainLayout.addWidget(self.markwi)
|
|
||||||
self.centralWidget.setLayout(mainLayout)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
mainWin = MainWindow()
|
|
||||||
mainWin.show()
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
200
app_config.py
200
app_config.py
@@ -6,14 +6,11 @@
|
|||||||
# #yaml is fixed and not altened by program
|
# #yaml is fixed and not altened by program
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
|
|
||||||
_log = logging.getLogger(__name__)
|
_log = logging.getLogger(__name__)
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui
|
|
||||||
from PyQt5.QtCore import QSettings
|
from PyQt5.QtCore import QSettings
|
||||||
from PyQt5.QtWidgets import QApplication, QMainWindow
|
from PyQt5.QtWidgets import QApplication, QMainWindow
|
||||||
import json
|
import json,re
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
class MyJsonEncoder(json.JSONEncoder):
|
class MyJsonEncoder(json.JSONEncoder):
|
||||||
@@ -636,206 +633,15 @@ verbose bits:
|
|||||||
for i,k in lut:
|
for i,k in lut:
|
||||||
cld[i].setValue(twk[k].get_val())
|
cld[i].setValue(twk[k].get_val())
|
||||||
|
|
||||||
#def cb_save(self):
|
|
||||||
# self._state=p.saveState()
|
|
||||||
|
|
||||||
#def cb_restore(self):
|
|
||||||
# p=self._p
|
|
||||||
# add=p['Save/Restore functionality', 'Restore State', 'Add missing items']
|
|
||||||
# rem=p['Save/Restore functionality', 'Restore State', 'Remove extra items']
|
|
||||||
# p.restoreState(self._state, addChildren=add, removeChildren=rem)
|
|
||||||
|
|
||||||
# ----------------------------- OBSOLETE -----------------------------
|
|
||||||
|
|
||||||
#inst_folder = Path(__file__).absolute().parent
|
|
||||||
#config_file = inst_folder / "swissmx.yaml"
|
|
||||||
#configs = yaml.load(config_file.read_text(),Loader=yaml.FullLoader)
|
|
||||||
#endstation = configs["configure_for"]
|
|
||||||
#appsconf = configs[endstation]
|
|
||||||
#simulated = appsconf.get("simulate", False)
|
|
||||||
#logger.info(f"configuring for endstation: {endstation.upper()}")
|
|
||||||
|
|
||||||
#if simulated:
|
|
||||||
# logger.warning("SIMULATION is ACTIVE")
|
|
||||||
#css_file = inst_folder / "swissmx.css"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#def font(name: str) -> str:
|
|
||||||
# p = Path(__file__).absolute().parent / "fonts" / name
|
|
||||||
# return str(p)
|
|
||||||
|
|
||||||
|
|
||||||
#def logo(size: int = 0) -> str:
|
|
||||||
# p = Path(__file__).absolute().parent / "logos" / "logo.png"
|
|
||||||
# if size:
|
|
||||||
# p = Path(__file__).absolute().parent / "logos" / f"tell_logo_{size}x{size}.png"
|
|
||||||
# return str(p)
|
|
||||||
|
|
||||||
|
|
||||||
# def dlg_geometry(self,obj):
|
|
||||||
# SPN=GenericDialog.Spinner
|
|
||||||
# app=QApplication.instance()
|
|
||||||
# cfg=app._cfg
|
|
||||||
# w, h = map(float,cfg.value(AppCfg.GEO_BEAM_SZ))
|
|
||||||
# d = GenericDialog.GenericDialog(
|
|
||||||
# title="geometry",
|
|
||||||
# message="Enter the size of the beam in microns",
|
|
||||||
# inputs={
|
|
||||||
# "bw": ("beam width um" ,w,SPN(w, min=1, max=200, suffix=" \u00B5m"),),
|
|
||||||
# "bh": ("beam height um",h,SPN(h, min=1, max=200, suffix=" \u00B5m"),),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# if d.exec():
|
|
||||||
# results = d.results
|
|
||||||
# _log.info("Updating beamsize to {}".format(results))
|
|
||||||
# bm_sz= (results["bw"], results["bh"])
|
|
||||||
# _log.debug("types {}".format(type(w)))
|
|
||||||
# cfg.setValue(AppCfg.GEO_BEAM_SZ, bm_sz)
|
|
||||||
# cfg.sync()
|
|
||||||
# bm=obj._goBeamMarker
|
|
||||||
# bm.setSize(bm_sz)
|
|
||||||
# #self._beammark.set_beam_size((w, h))
|
|
||||||
#
|
|
||||||
# def dlg_collimator_reference_positions(self):
|
|
||||||
# SPN=GenericDialog.Spinner
|
|
||||||
# app=QApplication.instance()
|
|
||||||
# cfg=app._cfg
|
|
||||||
# x_out = cfg.value(AppCfg.COL_DX , 0.0,type=float)
|
|
||||||
# y_out = cfg.value(AppCfg.COL_DY , 0.0,type=float)
|
|
||||||
# x_in = cfg.value(AppCfg.COL_X_IN, 0.0,type=float)
|
|
||||||
# y_in = cfg.value(AppCfg.COL_Y_IN, 0.0,type=float)
|
|
||||||
# d = GenericDialog.GenericDialog(
|
|
||||||
# title="Collimator configuration",
|
|
||||||
# message="Enter reference positions for the collimator",
|
|
||||||
# inputs={
|
|
||||||
# AppCfg.COL_DX: ("Collimator out deltaX", x_out, SPN(x_out, decimals=3, min=-15.9, max=15.9, suffix=" mm"),),
|
|
||||||
# AppCfg.COL_DY: ("Collimator out deltaY", y_out, SPN(y_out, decimals=3, min=-15.9, max=15.9, suffix=" mm"),),
|
|
||||||
# AppCfg.COL_X_IN: ("Collimator in X", x_in, SPN(x_in, decimals=3, min=-15.9, max=15.9, suffix=" mm"),),
|
|
||||||
# AppCfg.COL_Y_IN: ("Collimator in Y", y_in, SPN(y_in, decimals=3, min=-15.9, max=15.9, suffix=" mm"),),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# if d.exec():
|
|
||||||
# results = d.results
|
|
||||||
# _log.info("setting collimator reference positions {}".format(results))
|
|
||||||
# for k, v in results.items():
|
|
||||||
# cfg.setValue(k, v)
|
|
||||||
# cfg.sync()
|
|
||||||
#
|
|
||||||
# def dlg_backlight_positions(self):
|
|
||||||
# SPN=GenericDialog.Spinner
|
|
||||||
# app=QApplication.instance()
|
|
||||||
# cfg=app._cfg
|
|
||||||
# p_in = cfg.value(AppCfg.BKLGT_IN,0,type=int)
|
|
||||||
# p_out = cfg.value(AppCfg.BKLGT_OUT,0,type=int)
|
|
||||||
# d = GenericDialog.GenericDialog(
|
|
||||||
# title="Back Light configuration",
|
|
||||||
# message="Enter reference positions for the backlight",
|
|
||||||
# inputs={
|
|
||||||
# AppCfg.BKLGT_IN: ("In position" , p_in , SPN(p_in, min=-30000, max=10), ),
|
|
||||||
# AppCfg.BKLGT_OUT: ("Out position", p_out, SPN(p_out, min=-1000, max=10), ),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# if d.exec():
|
|
||||||
# results = d.results
|
|
||||||
# _log.info("setting back light reference positions {}".format(results))
|
|
||||||
# for k, v in results.items():
|
|
||||||
# cfg.setValue(k, v)
|
|
||||||
# cfg.sync()
|
|
||||||
#
|
|
||||||
# def dlg_cryojet_positions(self):
|
|
||||||
# p_in = settings.value(CRYOJET_NOZZLE_IN, type=float)
|
|
||||||
# p_out = settings.value(CRYOJET_NOZZLE_OUT, type=float)
|
|
||||||
# motion_enabled = option(CRYOJET_MOTION_ENABLED)
|
|
||||||
# d = GenericDialog(
|
|
||||||
# title="Cryojet Nozzle Configuration",
|
|
||||||
# message="Enter reference positions for the cryojet nozzle position",
|
|
||||||
# inputs={
|
|
||||||
# CRYOJET_NOZZLE_IN: ("In position", p_in, Spinner(p_in, min=3, max=15)),
|
|
||||||
# CRYOJET_NOZZLE_OUT: ("Out position",p_out,Spinner(p_out, min=-1000, max=10),),
|
|
||||||
# CRYOJET_MOTION_ENABLED: ("Move Cryojet in Transitions",motion_enabled,Checkbox(motion_enabled, "move cryojet"),),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# if d.exec():
|
|
||||||
# results = d.results
|
|
||||||
# _log.info("setting cryojet reference positions {}".format(results))
|
|
||||||
# for k, v in results.items():
|
|
||||||
# settings.setValue(k, v)
|
|
||||||
# settings.sync()
|
|
||||||
#
|
|
||||||
# def dlg_deltatau_parameters(self):
|
|
||||||
# SPN=GenericDialog.Spinner
|
|
||||||
# CB=GenericDialog.Checkbox
|
|
||||||
# app=QApplication.instance()
|
|
||||||
# cfg=app._cfg
|
|
||||||
# #dt1 = cfg.value(AppCfg.DT_HOST,'SAR-CPPM-EXPMX1')
|
|
||||||
# dt1 = cfg.value(AppCfg.DT_HOST)
|
|
||||||
# dt2 = cfg.value(AppCfg.DT_VEL_SCL, 1, type=float)
|
|
||||||
# dt3 = cfg.option(AppCfg.DT_SHOW_PLOTS)
|
|
||||||
#
|
|
||||||
# d = GenericDialog.GenericDialog(
|
|
||||||
# title="Delta Tau Parameters",
|
|
||||||
# message="These parameters affect the data collection.",
|
|
||||||
# inputs={
|
|
||||||
# AppCfg.DT_HOST:("host name (host[:port:port_gather])", dt1, QLineEdit(),),
|
|
||||||
# AppCfg.DT_VEL_SCL: ("Velocity Scale (1=optimal, 0=zero vel at target)", dt2,SPN(dt2, min=0, max=1, suffix=""),),
|
|
||||||
# AppCfg.DT_SHOW_PLOTS: ("show plots after collection", dt3,CB(dt3, "active"),),
|
|
||||||
# #DELTATAU_SORT_POINTS: ("Sort pointshoot/prelocated coords", b,CB(b, "sort points"),),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# if d.exec():
|
|
||||||
# results = d.results
|
|
||||||
# _log.info("setting delta tau parameters {}".format(results))
|
|
||||||
# for k, v in results.items():
|
|
||||||
# cfg.setValue(k, v)
|
|
||||||
# cfg.sync()
|
|
||||||
#
|
|
||||||
# def dlg_tell_mount_positions(self):
|
|
||||||
# AUTODRY_ENABLED = "tell/autodry_enabled"
|
|
||||||
# AUTODRY_MAXMOUNTS = "tell/autodry_max_number_of_mounts"
|
|
||||||
# AUTODRY_MAXTIME = "tell/autodry_max_time"
|
|
||||||
#
|
|
||||||
# SECS_HOURS = 60 * 60
|
|
||||||
#
|
|
||||||
# enabled = option(AUTODRY_ENABLED)
|
|
||||||
# maxtime = settings.value(AUTODRY_MAXTIME, type=float) / SECS_HOURS
|
|
||||||
# maxmounts = settings.value(AUTODRY_MAXMOUNTS, type=int)
|
|
||||||
#
|
|
||||||
# d = GenericDialog.GenericDialog(
|
|
||||||
# title="TELL Settings",
|
|
||||||
# message="These control some features of the TELL sample changer",
|
|
||||||
# inputs={
|
|
||||||
# AUTODRY_ENABLED: ("Auto dry", enabled,
|
|
||||||
# Checkbox(enabled, "enabled")),
|
|
||||||
# AUTODRY_MAXMOUNTS: ("Max. num. mounts between dry",maxmounts,
|
|
||||||
# Spinner(maxmounts, decimals=0, min=1, max=100, suffix=" mounts"),),
|
|
||||||
# AUTODRY_MAXTIME: ("Max. time between dry",maxtime,
|
|
||||||
# Spinner(maxtime, decimals=1, min=0.5, max=5, suffix=" hours"),),
|
|
||||||
# },
|
|
||||||
# )
|
|
||||||
# if d.exec():
|
|
||||||
# results = d.results
|
|
||||||
# _log.info("setting tell parameters {}".format(results))
|
|
||||||
# for k, v in results.items():
|
|
||||||
# if k == AUTODRY_MAXTIME:
|
|
||||||
# v = v * SECS_HOURS
|
|
||||||
# settings.setValue(k, v)
|
|
||||||
# settings.sync()
|
|
||||||
|
|
||||||
# ----------------------------------------------
|
|
||||||
|
|
||||||
## Start Qt event loop unless running in interactive mode or using pyside.
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
app=QApplication([])
|
app=QApplication([])
|
||||||
app._cfg=AppCfg()
|
app._cfg=AppCfg()
|
||||||
|
|
||||||
w=WndParameter(None)
|
w=WndParameter(None)
|
||||||
w.show()
|
w.show()
|
||||||
|
## Start Qt event loop unless running in interactive mode or using pyside.
|
||||||
|
|
||||||
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
||||||
QApplication.instance().exec_()
|
QApplication.instance().exec_()
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import time
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
_log=logging.getLogger(__name__)
|
_log=logging.getLogger(__name__)
|
||||||
|
|
||||||
|
import time
|
||||||
from epics.ca import pend_event
|
from epics.ca import pend_event
|
||||||
|
|
||||||
class PositionsNotReached(Exception):
|
class PositionsNotReached(Exception):
|
||||||
|
|||||||
@@ -10,9 +10,6 @@ import logging
|
|||||||
_log=logging.getLogger(__name__)
|
_log=logging.getLogger(__name__)
|
||||||
import epics
|
import epics
|
||||||
|
|
||||||
#from app_config import settings
|
|
||||||
#from app_utils import assert_motor_positions
|
|
||||||
|
|
||||||
class Backlight(object):
|
class Backlight(object):
|
||||||
def __init__(self, prefix: str='SAR-EXPMX:MOT_BLGT',pos={'pos_in':-30500,'pos_out':1000,'pos_diode':-30500}):
|
def __init__(self, prefix: str='SAR-EXPMX:MOT_BLGT',pos={'pos_in':-30500,'pos_out':1000,'pos_diode':-30500}):
|
||||||
if prefix is None:
|
if prefix is None:
|
||||||
@@ -44,7 +41,6 @@ class Backlight(object):
|
|||||||
m.move(target, ignore_limits=True, wait=wait)
|
m.move(target, ignore_limits=True, wait=wait)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import time,os
|
import time,os
|
||||||
import argparse
|
import argparse
|
||||||
|
|||||||
23
camera.py
23
camera.py
@@ -41,10 +41,9 @@ Best regards
|
|||||||
import logging
|
import logging
|
||||||
_log = logging.getLogger(__name__)
|
_log = logging.getLogger(__name__)
|
||||||
|
|
||||||
import enum, epics, time
|
import time, enum, epics
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Camera(enum.IntEnum):
|
class Camera(enum.IntEnum):
|
||||||
OFF = 0
|
OFF = 0
|
||||||
RUNNING = 1
|
RUNNING = 1
|
||||||
@@ -197,10 +196,6 @@ class epics_cam(object):
|
|||||||
elif k=='roi':
|
elif k=='roi':
|
||||||
pv_rxs=self.getPv('REGIONX_START');pv_rxe=self.getPv('REGIONX_END')
|
pv_rxs=self.getPv('REGIONX_START');pv_rxe=self.getPv('REGIONX_END')
|
||||||
pv_rys=self.getPv('REGIONY_START');pv_rye=self.getPv('REGIONY_END')
|
pv_rys=self.getPv('REGIONY_START');pv_rye=self.getPv('REGIONY_END')
|
||||||
#pv_rxs.put(v[0], wait=False)
|
|
||||||
#pv_rxe.put(v[0]+v[2], wait=False)
|
|
||||||
#pv_rys.put(v[1], wait=False)
|
|
||||||
#pv_rye.put(v[1]+v[3], wait=False)
|
|
||||||
param.append((pv_rxs,v[0]))
|
param.append((pv_rxs,v[0]))
|
||||||
param.append((pv_rxe,v[0]+v[2]))
|
param.append((pv_rxe,v[0]+v[2]))
|
||||||
param.append((pv_rys,v[1]))
|
param.append((pv_rys,v[1]))
|
||||||
@@ -277,9 +272,6 @@ class epics_cam(object):
|
|||||||
xx, yy = np.meshgrid(x, y)
|
xx, yy = np.meshgrid(x, y)
|
||||||
|
|
||||||
for i in range(t):
|
for i in range(t):
|
||||||
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin(yy+.01*i)**2)#+xx*t+yy*t)
|
|
||||||
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin((1+.1*np.sin(.2*i))*yy+.001*i**2)**2)#+xx*t+yy*t)
|
|
||||||
#imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+2*np.sin(i/t*2*np.pi))**2 + np.sin(yy)**2)
|
|
||||||
px=2*np.sin(i/t*2*np.pi)
|
px=2*np.sin(i/t*2*np.pi)
|
||||||
fx=1
|
fx=1
|
||||||
py=2*np.sin(i/t*2*np.pi)
|
py=2*np.sin(i/t*2*np.pi)
|
||||||
@@ -323,7 +315,7 @@ class epics_cam(object):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import time, os, PIL.Image, platform, subprocess
|
import os, PIL.Image, platform, subprocess
|
||||||
import argparse
|
import argparse
|
||||||
logging.basicConfig(level=logging.DEBUG,format='%(name)s:%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
logging.basicConfig(level=logging.DEBUG,format='%(name)s:%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
||||||
logging.getLogger('PIL').setLevel(logging.INFO)
|
logging.getLogger('PIL').setLevel(logging.INFO)
|
||||||
@@ -337,9 +329,6 @@ if __name__ == "__main__":
|
|||||||
else: # linux variants
|
else: # linux variants
|
||||||
subprocess.call(('xdg-open', file))
|
subprocess.call(('xdg-open', file))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--ui", "-u", help="qt test", type=int, default=0)
|
parser.add_argument("--ui", "-u", help="qt test", type=int, default=0)
|
||||||
parser.add_argument("--sim", "-s", help="simulation mode", type=int, default=None)
|
parser.add_argument("--sim", "-s", help="simulation mode", type=int, default=None)
|
||||||
@@ -355,20 +344,12 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
os.environ['EPICS_CA_ADDR_LIST'] ='129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
|
os.environ['EPICS_CA_ADDR_LIST'] ='129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
|
||||||
|
|
||||||
|
|
||||||
if not args.ui:
|
if not args.ui:
|
||||||
cam = epics_cam(prefix=args.prefix)
|
cam = epics_cam(prefix=args.prefix)
|
||||||
#cam._transformation=np.array(((-1,0),(0,1)),dtype=np.uint8) #ZAC: orig. code
|
#cam._transformation=np.array(((-1,0),(0,1)),dtype=np.uint8) #ZAC: orig. code
|
||||||
if args.prefix is None:
|
if args.prefix is None:
|
||||||
cam.sim_gen(mode=args.sim)
|
cam.sim_gen(mode=args.sim)
|
||||||
|
|
||||||
#sz=(2448,2048)
|
|
||||||
#ctr=(1200,1400)
|
|
||||||
#sz=(1200,1000)
|
|
||||||
#cam.set_roi(int(ctr[0]-sz[0]/2),int(ctr[0]+sz[0]/2),int(ctr[1]-sz[1]/2),int(ctr[1]+sz[1]/2))
|
|
||||||
#cam.set_exposure(3)
|
|
||||||
#cam.set_binning(1,1)
|
|
||||||
|
|
||||||
cam.run()
|
cam.run()
|
||||||
n = 1
|
n = 1
|
||||||
base = "/tmp/image_{:05d}.png"
|
base = "/tmp/image_{:05d}.png"
|
||||||
|
|||||||
11
detector.py
11
detector.py
@@ -1,17 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
_log=logging.getLogger(__name__)
|
_log=logging.getLogger(__name__)
|
||||||
|
|
||||||
#from glob import glob
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot
|
||||||
|
|
||||||
#import eventer
|
|
||||||
#import qsingleton
|
|
||||||
#from detector_integration_api import DetectorIntegrationClient
|
|
||||||
#from app_config import settings, appsconf, simulated
|
|
||||||
#config = appsconf['jungfrau']
|
|
||||||
#dia_client = DetectorIntegrationClient(config['uri'])
|
|
||||||
|
|
||||||
class JungfrauWaiter(QObject):
|
class JungfrauWaiter(QObject):
|
||||||
finished = pyqtSignal()
|
finished = pyqtSignal()
|
||||||
|
|
||||||
@@ -22,9 +13,11 @@ class JungfrauWaiter(QObject):
|
|||||||
def work(self):
|
def work(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class JungfrauMissingConfiguration(Exception):
|
class JungfrauMissingConfiguration(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Jungfrau(QObject):
|
class Jungfrau(QObject):
|
||||||
pedestal_selected = pyqtSignal(str)
|
pedestal_selected = pyqtSignal(str)
|
||||||
configured = pyqtSignal()
|
configured = pyqtSignal()
|
||||||
|
|||||||
3050
obsolete.py
3050
obsolete.py
File diff suppressed because it is too large
Load Diff
@@ -8,17 +8,15 @@ if __name__ == "__main__":
|
|||||||
logging.getLogger('matplotlib').setLevel(logging.INFO)
|
logging.getLogger('matplotlib').setLevel(logging.INFO)
|
||||||
|
|
||||||
if socket.gethostname()=='ganymede':
|
if socket.gethostname()=='ganymede':
|
||||||
sys.path.insert(0, os.path.expanduser('~/Documents/prj/SwissFEL/PBTools'))
|
base=os.path.abspath(os.path.dirname(__file__))
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(base,'../PBSwissMX/python')))
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(base,'../../PBTools')))
|
||||||
else:
|
else:
|
||||||
sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBTools')
|
base=os.path.abspath(os.path.dirname(__file__))
|
||||||
sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBSwissMX/python')
|
sys.path.insert(0, os.path.join(base,'PBTools'))
|
||||||
#_log.info(sys.path)
|
sys.path.insert(0, os.path.join(base,'PBSwissMX/python'))
|
||||||
elif socket.gethostname()!='ganymede':
|
elif socket.gethostname()!='ganymede':
|
||||||
#TODO: cleanup slic installation location
|
sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/slic/slic-package'))
|
||||||
sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/mx/slic'))
|
|
||||||
#sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/slic/slic-package'))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from PyQt5.QtWidgets import (QApplication,)
|
from PyQt5.QtWidgets import (QApplication,)
|
||||||
from app_config import AppCfg #settings, option, toggle_option
|
from app_config import AppCfg #settings, option, toggle_option
|
||||||
@@ -105,12 +103,6 @@ class Deltatau:
|
|||||||
|
|
||||||
class Jungfrau:
|
class Jungfrau:
|
||||||
def __init__(self,sim=False):
|
def __init__(self,sim=False):
|
||||||
#python /sf/jungfrau/applications/daq_client/daq_client.py -h
|
|
||||||
#python /sf/jungfrau/applications/daq_client/daq_client.py -p p19739 -t no_beam_test
|
|
||||||
# -c/sf/cristallina/config/channel_lists/channel_list_bs-e/sf/cristallina/config/channel_lists/channel_list_ca
|
|
||||||
# -f/sf/cristallina/config/jungfrau/jf_1d5M.json
|
|
||||||
# --start_pulseid 15382163895 --stop_pulseid 15382163905
|
|
||||||
#rsync -vai gac-cristall@saresc-cons-03:/sf/jungfrau/applications/daq_client/daq_client.py .
|
|
||||||
# setup slic parameters
|
# setup slic parameters
|
||||||
if sim:
|
if sim:
|
||||||
self._sim=True
|
self._sim=True
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ _log=logging.getLogger(__name__)
|
|||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
from pyqtgraph.Qt import QtCore, QtGui
|
from pyqtgraph.Qt import QtCore, QtGui
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PyQt5.QtGui import QPolygon,QPolygonF
|
from PyQt5.QtGui import QPolygonF
|
||||||
from PyQt5.QtCore import Qt,QPointF,QLineF
|
from PyQt5.QtCore import Qt,QPointF,QLineF
|
||||||
from PyQt5.QtWidgets import QMenu
|
from PyQt5.QtWidgets import QMenu
|
||||||
|
|
||||||
@@ -94,22 +94,12 @@ class Marker(UsrROI):
|
|||||||
#widget.signal.connect(slot_function)
|
#widget.signal.connect(slot_function)
|
||||||
#self.sigRegionChangeFinished.connect(self.OnRgnChanged)
|
#self.sigRegionChangeFinished.connect(self.OnRgnChanged)
|
||||||
|
|
||||||
#def OnRgnChanged(self, event):
|
|
||||||
# print(event)
|
|
||||||
# obj_info(self)
|
|
||||||
|
|
||||||
def paint(self, p, *args):
|
def paint(self, p, *args):
|
||||||
#pg.ROI.paint(self, p, *args)
|
#pg.ROI.paint(self, p, *args)
|
||||||
r=QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized()
|
r=QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized()
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
p.setPen(self.currentPen)
|
p.setPen(self.currentPen)
|
||||||
p.translate(r.left(), r.top())
|
p.translate(r.left(), r.top())
|
||||||
#p.scale(r.width(), r.height()) # -> values x,y 0 to 1
|
|
||||||
#f=p.font();
|
|
||||||
#f.setPixelSize(50)
|
|
||||||
#p.setFont(f)
|
|
||||||
# p.drawText(0, 0, '{:.0f}x{:.0f}'.format(*tuple(self.size())))
|
|
||||||
#p.drawText(0, 0, 'Thierry')
|
|
||||||
|
|
||||||
p.scale(.01*r.width(), .01*r.height()) # -> values x,y 0 to 100
|
p.scale(.01*r.width(), .01*r.height()) # -> values x,y 0 to 100
|
||||||
m=self._mode
|
m=self._mode
|
||||||
@@ -129,7 +119,6 @@ class Marker(UsrROI):
|
|||||||
ctr=tuple((self.pos()+self.size()/2)*1000)
|
ctr=tuple((self.pos()+self.size()/2)*1000)
|
||||||
sz=tuple(self.size()*1000)
|
sz=tuple(self.size()*1000)
|
||||||
p.drawText(ofx+5, ofy+45, '{:.1f}x{:.1f} um'.format(*sz))
|
p.drawText(ofx+5, ofy+45, '{:.1f}x{:.1f} um'.format(*sz))
|
||||||
#p.drawText(5, -35, '{:.1f}'.format(ctr[0]))
|
|
||||||
p.drawText(ofx+5, ofy+55,42,30,Qt.AlignRight, '{:.1f}'.format(ctr[0]))
|
p.drawText(ofx+5, ofy+55,42,30,Qt.AlignRight, '{:.1f}'.format(ctr[0]))
|
||||||
p.drawText(ofx+55, ofy+65, '{:.1f} um'.format(ctr[1]))
|
p.drawText(ofx+55, ofy+65, '{:.1f} um'.format(ctr[1]))
|
||||||
|
|
||||||
@@ -145,8 +134,6 @@ class Marker(UsrROI):
|
|||||||
f=p.font();
|
f=p.font();
|
||||||
f.setPixelSize(10)
|
f.setPixelSize(10)
|
||||||
p.setFont(f)
|
p.setFont(f)
|
||||||
#p.drawText(ofx+0, ofy+0, 'FFF')
|
|
||||||
#p.drawText(ofx+100, ofy+100, 'GGG')
|
|
||||||
px=tuple(self.pos()+self.size()/2)
|
px=tuple(self.pos()+self.size()/2)
|
||||||
p.drawText(ofx+18, ofy+10, 'optical center')
|
p.drawText(ofx+18, ofy+10, 'optical center')
|
||||||
p.drawText(ofx+5, ofy+80,42,30,Qt.AlignRight, '{:.1f}'.format(px[0]))
|
p.drawText(ofx+5, ofy+80,42,30,Qt.AlignRight, '{:.1f}'.format(px[0]))
|
||||||
@@ -184,17 +171,11 @@ class Fiducial(UsrROI):
|
|||||||
p.setPen(pg.mkPen(width=1, color=[255, 0, 0]))
|
p.setPen(pg.mkPen(width=1, color=[255, 0, 0]))
|
||||||
p.drawLine(pg.Point(50,10), pg.Point(50, 90))
|
p.drawLine(pg.Point(50,10), pg.Point(50, 90))
|
||||||
p.drawLine(pg.Point(10,50), pg.Point(90, 50))
|
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)
|
|
||||||
f=p.font()
|
f=p.font()
|
||||||
f.setPixelSize(10)
|
f.setPixelSize(10)
|
||||||
p.setFont(f)
|
p.setFont(f)
|
||||||
#p.drawText(24, 20, 'beam marker')
|
|
||||||
ctr=tuple(self.pos()+self.size()/2)
|
ctr=tuple(self.pos()+self.size()/2)
|
||||||
sz=tuple(self.size())
|
sz=tuple(self.size())
|
||||||
#print((*ctr,self._z))
|
|
||||||
#p.drawText(5, 25, 'x{:.4g}\ny{:.4g}\nz{:.4g}'.format(*ctr,self._z))
|
|
||||||
p.drawText(52, 10,40,40,Qt.TextWordWrap, 'x{:.5g}\ny{:.5g}\nz{:.5g}'.format(*ctr,self._z))
|
p.drawText(52, 10,40,40,Qt.TextWordWrap, 'x{:.5g}\ny{:.5g}\nz{:.5g}'.format(*ctr,self._z))
|
||||||
|
|
||||||
def ctr(self):
|
def ctr(self):
|
||||||
@@ -253,11 +234,6 @@ class Grid(UsrROI):
|
|||||||
x=i*px
|
x=i*px
|
||||||
p.drawEllipse(QPointF(x,y), rx, ry)
|
p.drawEllipse(QPointF(x,y), rx, ry)
|
||||||
|
|
||||||
#p.translate(r.left(), r.top())
|
|
||||||
#p.scale(r.width(), r.height())
|
|
||||||
#p.drawEllipse(0, 0, 1, 1)
|
|
||||||
#p.drawRect(0, 0, 1, 1)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
s=f'{self.__class__.__name__}:(pos:{itr2str(self.pos())}, size:{itr2str(self.size())}, cnt:{self._cnt}, fidSize:{self._fidSz}, param:{self._param})'
|
s=f'{self.__class__.__name__}:(pos:{itr2str(self.pos())}, size:{itr2str(self.size())}, cnt:{self._cnt}, fidSize:{self._fidSz}, param:{self._param})'
|
||||||
return s
|
return s
|
||||||
@@ -276,7 +252,6 @@ class Grid(UsrROI):
|
|||||||
def get_scan_param(self):
|
def get_scan_param(self):
|
||||||
'returns scan parameters for scanning with deltatau. the format is as used for shapepath'
|
'returns scan parameters for scanning with deltatau. the format is as used for shapepath'
|
||||||
scan=1 # snake motion Y fast, X slow (default)
|
scan=1 # snake motion Y fast, X slow (default)
|
||||||
#pos=np.array(self.pos())
|
|
||||||
cnt=np.array(self._cnt,np.int32)
|
cnt=np.array(self._cnt,np.int32)
|
||||||
sz=np.array(self.size())
|
sz=np.array(self.size())
|
||||||
pitch=sz/cnt
|
pitch=sz/cnt
|
||||||
@@ -292,7 +267,6 @@ class Grid(UsrROI):
|
|||||||
for i in range(1, cnt[0], 2):
|
for i in range(1, cnt[0], 2):
|
||||||
yy[i]=yy[i][::-1]
|
yy[i]=yy[i][::-1]
|
||||||
pts=np.array([xx.reshape(-1), yy.reshape(-1)], dtype=np.float64).transpose()*pitch
|
pts=np.array([xx.reshape(-1), yy.reshape(-1)], dtype=np.float64).transpose()*pitch
|
||||||
#pts+=pos
|
|
||||||
param={'points':pts}
|
param={'points':pts}
|
||||||
param.update(self._param)
|
param.update(self._param)
|
||||||
assert(param.get('code_gen',0)==0) # this provides fully x,y motor coordinates
|
assert(param.get('code_gen',0)==0) # this provides fully x,y motor coordinates
|
||||||
@@ -348,8 +322,6 @@ class Path(UsrROI):
|
|||||||
r=self._rect
|
r=self._rect
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
p.setPen(self.currentPen)
|
p.setPen(self.currentPen)
|
||||||
#p.drawEllipse(0, 0, int(sz[0]), int(sz[1]))
|
|
||||||
#p.drawRect(0, 0, int(sz[0]), int(sz[1]))
|
|
||||||
p.drawRect(QtCore.QRectF(0, 0, sz[0], sz[1]).normalized())
|
p.drawRect(QtCore.QRectF(0, 0, sz[0], sz[1]).normalized())
|
||||||
#obj_info(p)
|
#obj_info(p)
|
||||||
p.scale(sz[0]/r.width(), sz[1]/r.height())
|
p.scale(sz[0]/r.width(), sz[1]/r.height())
|
||||||
@@ -470,19 +442,12 @@ class FixTargetFrame(UsrROI):
|
|||||||
self.addScaleHandle([1, 1], [0, 0])
|
self.addScaleHandle([1, 1], [0, 0])
|
||||||
self.addScaleHandle([0, 0], [1, 1])
|
self.addScaleHandle([0, 0], [1, 1])
|
||||||
self.addScaleRotateHandle([1, 0], [0, 0])
|
self.addScaleRotateHandle([1, 0], [0, 0])
|
||||||
#self.sigHoverEvent.connect(self.hover)
|
|
||||||
# def hover(self):
|
|
||||||
# _log.debug(f'hover {self}')
|
|
||||||
|
|
||||||
def paint(self, p, *args):
|
def paint(self, p, *args):
|
||||||
#pg.ROI.paint(self, p, *args)
|
|
||||||
sz=self.state['size']
|
sz=self.state['size']
|
||||||
#nx, ny=self._cnt
|
|
||||||
#px, py=sz[0]/(nx-1), sz[1]/(ny-1)
|
|
||||||
r=QtCore.QRectF(0, 0, sz[0], sz[1]).normalized()
|
r=QtCore.QRectF(0, 0, sz[0], sz[1]).normalized()
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
p.setPen(self.currentPen)
|
p.setPen(self.currentPen)
|
||||||
#p.drawRect(0, 0, int(sz[0]), int(sz[1]))
|
|
||||||
p.drawRect(r)
|
p.drawRect(r)
|
||||||
|
|
||||||
dscr=self._dscr
|
dscr=self._dscr
|
||||||
@@ -496,8 +461,6 @@ class FixTargetFrame(UsrROI):
|
|||||||
ox,oy=g['pos']
|
ox,oy=g['pos']
|
||||||
px,py=g['pitch']
|
px,py=g['pitch']
|
||||||
nx,ny=g['count']
|
nx,ny=g['count']
|
||||||
#x0=ox; x1=ox+(ny-1)*py
|
|
||||||
#y0=oy; y1=oy+(nx-1)*px
|
|
||||||
x0=ox-.5*px; x1=ox+(nx-.5)*px
|
x0=ox-.5*px; x1=ox+(nx-.5)*px
|
||||||
y0=oy-.5*py; y1=oy+(ny-.5)*py
|
y0=oy-.5*py; y1=oy+(ny-.5)*py
|
||||||
for i in range(nx):
|
for i in range(nx):
|
||||||
@@ -558,10 +521,7 @@ class FixTargetFrame(UsrROI):
|
|||||||
scan=1 # snake motion Y fast, X slow (default)
|
scan=1 # snake motion Y fast, X slow (default)
|
||||||
grid=self._dscr['grid']
|
grid=self._dscr['grid']
|
||||||
self._dscr['size']
|
self._dscr['size']
|
||||||
#pos=np.array(self.pos())
|
|
||||||
cnt =np.array(grid['count'],np.int32)
|
cnt =np.array(grid['count'],np.int32)
|
||||||
#pos =np.array(grid['pos'],np.float64)
|
|
||||||
#pitch=np.array(grid['pitch'],np.float64)
|
|
||||||
xx, yy=np.meshgrid(range(cnt[0]), range(cnt[1]))
|
xx, yy=np.meshgrid(range(cnt[0]), range(cnt[1]))
|
||||||
if scan==0: # snake motion X fast, Y slow
|
if scan==0: # snake motion X fast, Y slow
|
||||||
for i in range(1,cnt[1],2):
|
for i in range(1,cnt[1],2):
|
||||||
@@ -592,11 +552,6 @@ class FixTargetFrame(UsrROI):
|
|||||||
param={'grid':grid, 'points':pts, 'trf':trf}
|
param={'grid':grid, 'points':pts, 'trf':trf}
|
||||||
param.update(self._param)
|
param.update(self._param)
|
||||||
|
|
||||||
# trf*'gridpos' -> motor pos in mm
|
|
||||||
# {'pos': [2080, 2080], 'pitch': [120, 120], 'count': [162, 162]}
|
|
||||||
#np.array((0,0,1))*trf grid 0,0 (top left)
|
|
||||||
#np.array((161,0,1))*trf # grid 161,0 (top right)
|
|
||||||
#np.array((161,161,1))*trf # grid 161,161 (bottom right)
|
|
||||||
return param
|
return param
|
||||||
|
|
||||||
|
|
||||||
@@ -645,9 +600,6 @@ if __name__=='__main__':
|
|||||||
|
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||||
p.setPen(self.currentPen)
|
p.setPen(self.currentPen)
|
||||||
# p.translate(r.left(), r.top())
|
|
||||||
# p.scale(r.width(), r.height())
|
|
||||||
# p.drawRect(0, 0, 1, 1)
|
|
||||||
p.drawRect(r)
|
p.drawRect(r)
|
||||||
tr=p.worldTransform()
|
tr=p.worldTransform()
|
||||||
obj_info(tr)
|
obj_info(tr)
|
||||||
@@ -702,15 +654,9 @@ if __name__=='__main__':
|
|||||||
|
|
||||||
|
|
||||||
def mouse_click_event(event):
|
def mouse_click_event(event):
|
||||||
#event.pos(): return Point(self.currentItem.mapFromScene(self._scenePos))
|
|
||||||
pos=event.pos()
|
pos=event.pos()
|
||||||
scn=event.scenePos() # there is a small black border, that makes the difference
|
scn=event.scenePos() # there is a small black border, that makes the difference
|
||||||
print(f'mouse-> scene pos:{pt2str(scn)} currentItem pos:{pt2str(pos)}')
|
print(f'mouse-> scene pos:{pt2str(scn)} currentItem pos:{pt2str(pos)}')
|
||||||
#img=viImg.mapFromScene(scn)
|
|
||||||
#roi=viUsrRoi.mapFromScene(scn)
|
|
||||||
#print(f'mouse-> img:{pt2str(img)} roi:{pt2str(roi)}')
|
|
||||||
#childTree(vb)
|
|
||||||
#obj_info(viImg)
|
|
||||||
m=int(event.modifiers())
|
m=int(event.modifiers())
|
||||||
o=event.currentItem
|
o=event.currentItem
|
||||||
if m&Qt.ShiftModifier:
|
if m&Qt.ShiftModifier:
|
||||||
@@ -721,9 +667,6 @@ if __name__=='__main__':
|
|||||||
elif m&Qt.ControlModifier:
|
elif m&Qt.ControlModifier:
|
||||||
tr=o.transform()
|
tr=o.transform()
|
||||||
obj_info(tr)
|
obj_info(tr)
|
||||||
#tr.setMatrix(tr.m11(),tr.m12(),tr.m13()+100,tr.m21(),tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33())
|
|
||||||
#tr.setMatrix(tr.m11(),tr.m12(),tr.m13(),tr.m21(),tr.m22(),tr.m23(),tr.m31(),tr.m32()+20,tr.m33())
|
|
||||||
#tr.setMatrix(tr.m11(),tr.m12(),tr.m13(),tr.m21(),-tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33())
|
|
||||||
tr.setMatrix(-tr.m11(),tr.m12(),tr.m13(),tr.m21(),-tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33())
|
tr.setMatrix(-tr.m11(),tr.m12(),tr.m13(),tr.m21(),-tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33())
|
||||||
obj_info(tr)
|
obj_info(tr)
|
||||||
o.setTransform(tr)
|
o.setTransform(tr)
|
||||||
@@ -774,24 +717,16 @@ if __name__=='__main__':
|
|||||||
|
|
||||||
viImg=pg.ImageItem(arr, border='y')
|
viImg=pg.ImageItem(arr, border='y')
|
||||||
vb.addItem(viImg)
|
vb.addItem(viImg)
|
||||||
# Custom ROI for selecting an image region
|
|
||||||
#viRoi=pg.ROI([20, -50], [60, 40])
|
|
||||||
#viRoi=TxtROI([20, -50], [60, 40])
|
|
||||||
#viRoi.addScaleHandle([1, 1], [0, 0])
|
|
||||||
#viRoi.addScaleHandle([.7, .5], [0, 0])
|
|
||||||
|
|
||||||
#vb.addItem(viRoi)
|
|
||||||
viUsrRoi=Marker([50, 120], [30, 20],mode=0)
|
viUsrRoi=Marker([50, 120], [30, 20],mode=0)
|
||||||
vb.addItem(viUsrRoi)
|
vb.addItem(viUsrRoi)
|
||||||
#obj=Marker([250, 220], [30, 20],mode=1)
|
|
||||||
#vb.addItem(obj)
|
|
||||||
vi=Grid( (120,-100), (200,150), (30,20),2)
|
vi=Grid( (120,-100), (200,150), (30,20),2)
|
||||||
tr=QtGui.QTransform() # prepare ImageItem transformation:
|
tr=QtGui.QTransform() # prepare ImageItem transformation:
|
||||||
tr.setMatrix(1, -.1, 0,
|
tr.setMatrix(1, -.1, 0,
|
||||||
.2, 1, 0,
|
.2, 1, 0,
|
||||||
10, 10, 1)
|
10, 10, 1)
|
||||||
vi.setTransform(tr) # assign transform
|
vi.setTransform(tr) # assign transform
|
||||||
#vi=Grid( (50,10), (200,150), (6,4))
|
|
||||||
vb.addItem(vi) #vi= visual item
|
vb.addItem(vi) #vi= visual item
|
||||||
|
|
||||||
grp=pg.ItemGroup()
|
grp=pg.ItemGroup()
|
||||||
@@ -811,11 +746,6 @@ if __name__=='__main__':
|
|||||||
fiducial=np.array(((18, 7), (25, 16), (70, 20)))
|
fiducial=np.array(((18, 7), (25, 16), (70, 20)))
|
||||||
path=gen_swissmx_points(ofs=(10, 5), width=200)
|
path=gen_swissmx_points(ofs=(10, 5), width=200)
|
||||||
vi=Path((120,100),path,fiducial,fidScl)
|
vi=Path((120,100),path,fiducial,fidScl)
|
||||||
#tr=QtGui.QTransform() # prepare ImageItem transformation:
|
|
||||||
#tr.setMatrix(1, 0, 0,
|
|
||||||
# 0, 1, 0,
|
|
||||||
# 10, 10, 1)
|
|
||||||
#vi.setTransform(tr) # assign transform
|
|
||||||
vb.addItem(vi)
|
vb.addItem(vi)
|
||||||
|
|
||||||
vi=FixTargetFrame((100,300),(100,100),tpl='test')
|
vi=FixTargetFrame((100,300),(100,100),tpl='test')
|
||||||
@@ -833,9 +763,6 @@ if __name__=='__main__':
|
|||||||
viRoi=pg.ROI([-200, -200], [100, 80],movable=True, rotatable=True, resizable=True)
|
viRoi=pg.ROI([-200, -200], [100, 80],movable=True, rotatable=True, resizable=True)
|
||||||
|
|
||||||
viRoi.addFreeHandle(pos=[.7, .5], axes=None, item=None, name=None, index=None) # rechteck , frei beweglich ??? verschwinden anch bewegung
|
viRoi.addFreeHandle(pos=[.7, .5], axes=None, item=None, name=None, index=None) # rechteck , frei beweglich ??? verschwinden anch bewegung
|
||||||
#viRoi.addRotateFreeHandle([.7, .5], [0, 0], axes=None, item=None, name=None, index=None) # kreis ??? verschwinden anch erstem gebrauch
|
|
||||||
#viRoi.addRotateHandle([.7, .5], [0, 0], item=None, name=None, index=None) # kreis, nur rot
|
|
||||||
#viRoi.addScaleHandle([.7, .5], [0, 0], axes=None, item=None, name=None, lockAspect=False, index=None) # raute scale x,y
|
|
||||||
#viRoi.addScaleRotateHandle([0, .5], [1, .5], item=None, name=None, index=None) # kreis
|
#viRoi.addScaleRotateHandle([0, .5], [1, .5], item=None, name=None, index=None) # kreis
|
||||||
#viRoi.addTranslateHandle([.7, .5], axes=None, item=None, name=None, index=None) #quadrat
|
#viRoi.addTranslateHandle([.7, .5], axes=None, item=None, name=None, index=None) #quadrat
|
||||||
vb.addItem(viRoi)
|
vb.addItem(viRoi)
|
||||||
@@ -846,9 +773,6 @@ if __name__=='__main__':
|
|||||||
childTree(vb)
|
childTree(vb)
|
||||||
|
|
||||||
w.scene().sigMouseClicked.connect(mouse_click_event)
|
w.scene().sigMouseClicked.connect(mouse_click_event)
|
||||||
#viImg.sigImageChanged
|
|
||||||
#print(vb.pos())
|
|
||||||
#vb.setPos(50,50)
|
|
||||||
|
|
||||||
if (sys.flags.interactive!=1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
if (sys.flags.interactive!=1) or not hasattr(QtCore, 'PYQT_VERSION'):
|
||||||
QtGui.QApplication.instance().exec_()
|
QtGui.QApplication.instance().exec_()
|
||||||
|
|||||||
@@ -1,44 +1,11 @@
|
|||||||
from PyQt5 import QtWidgets, QtGui
|
from PyQt5 import QtWidgets, QtGui
|
||||||
from PyQt5.QtWidgets import QWidget, QSizePolicy, QVBoxLayout, QDoubleSpinBox, QMessageBox
|
from PyQt5.QtWidgets import QWidget, QSizePolicy, QVBoxLayout, QMessageBox
|
||||||
|
|
||||||
from app_config import AppCfg #option, toggle_option
|
|
||||||
|
|
||||||
|
|
||||||
def toggle_warn(key):
|
|
||||||
toggle_option(key)
|
|
||||||
m = f"Option {key} => {option(key)}"
|
|
||||||
QMessageBox.warning(None, m, m)
|
|
||||||
|
|
||||||
def horiz_spacer():
|
def horiz_spacer():
|
||||||
spacer = QWidget()
|
spacer = QWidget()
|
||||||
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
return spacer
|
return spacer
|
||||||
|
|
||||||
|
|
||||||
def toggle_visibility(widget, state):
|
|
||||||
if state:
|
|
||||||
widget.show()
|
|
||||||
else:
|
|
||||||
widget.hide()
|
|
||||||
|
|
||||||
|
|
||||||
def get_sep_line():
|
|
||||||
line = QtWidgets.QFrame()
|
|
||||||
line.setFixedHeight(2)
|
|
||||||
line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
|
||||||
line.setFrameShape(QtWidgets.QFrame.HLine)
|
|
||||||
return line
|
|
||||||
|
|
||||||
|
|
||||||
def check_font_by_id(id):
|
|
||||||
for family in QtGui.QFontDatabase.applicationFontFamilies(id):
|
|
||||||
print(family)
|
|
||||||
|
|
||||||
|
|
||||||
def toggle_groupbox(gbox, state):
|
|
||||||
widget = gbox.layout().itemAt(0).widget()
|
|
||||||
widget.setVisible(state)
|
|
||||||
|
|
||||||
def add_item_to_toolbox(toolbox, label, widget_list=[]):
|
def add_item_to_toolbox(toolbox, label, widget_list=[]):
|
||||||
block = QWidget()
|
block = QWidget()
|
||||||
block.setAccessibleName(label)
|
block.setAccessibleName(label)
|
||||||
|
|||||||
40
swissmx.py
40
swissmx.py
@@ -22,7 +22,7 @@ bitmask for simulation:
|
|||||||
0x100: Deltatau motion code
|
0x100: Deltatau motion code
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging,time,os,sys,socket
|
||||||
class col:
|
class col:
|
||||||
d='\033[0m' # default
|
d='\033[0m' # default
|
||||||
r='\033[31m' # red
|
r='\033[31m' # red
|
||||||
@@ -74,33 +74,22 @@ class logHandler(logging.StreamHandler):
|
|||||||
except Exception:
|
except Exception:
|
||||||
self.handleError(record)
|
self.handleError(record)
|
||||||
|
|
||||||
|
|
||||||
# logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s',
|
logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s',
|
||||||
handlers=[logHandler()])
|
handlers=[logHandler()])
|
||||||
|
|
||||||
#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("swissmx")
|
_log = logging.getLogger("swissmx")
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
import os,sys,socket
|
|
||||||
if socket.gethostname()=='ganymede':
|
if socket.gethostname()=='ganymede':
|
||||||
base=os.path.abspath(os.path.dirname(__file__))
|
base=os.path.abspath(os.path.dirname(__file__))
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(base,'../PBSwissMX/python')))
|
sys.path.insert(0, os.path.abspath(os.path.join(base,'../PBSwissMX/python')))
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(base,'../../PBTools')))
|
sys.path.insert(0, os.path.abspath(os.path.join(base,'../../PBTools')))
|
||||||
else:
|
else:
|
||||||
sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBTools')
|
base=os.path.abspath(os.path.dirname(__file__))
|
||||||
sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBSwissMX/python')
|
sys.path.insert(0, os.path.join(base,'PBTools'))
|
||||||
|
sys.path.insert(0, os.path.join(base,'PBSwissMX/python'))
|
||||||
|
|
||||||
|
|
||||||
import time
|
|
||||||
class timestamp():
|
class timestamp():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.t=time.time()
|
self.t=time.time()
|
||||||
@@ -110,9 +99,9 @@ class timestamp():
|
|||||||
self.t=t
|
self.t=t
|
||||||
ts=timestamp()
|
ts=timestamp()
|
||||||
ts.log('Import part 1/8:')
|
ts.log('Import part 1/8:')
|
||||||
import sys, os, time
|
import sys, os
|
||||||
import json, re
|
import json, re
|
||||||
import random, signal, subprocess
|
import signal, subprocess
|
||||||
import matplotlib as mpl
|
import matplotlib as mpl
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
@@ -132,22 +121,18 @@ 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 ModuleFixTarget
|
||||||
import PrelocatedCoordinatesModel # ZAC: orig. code
|
|
||||||
from EmblModule import EmblWidget #ZAC: orig. code
|
|
||||||
from HelicalTable import HelicalTableWidget #ZAC: orig. code
|
|
||||||
|
|
||||||
ts.log('Import part 3/8:')
|
ts.log('Import part 3/8:')
|
||||||
import qtawesome
|
import qtawesome
|
||||||
import qutilities
|
import qutilities
|
||||||
from PyQt5 import QtCore, QtGui
|
from PyQt5 import QtCore, QtGui
|
||||||
from PyQt5.QtCore import Qt, pyqtSlot, QSize, QRegExp, pyqtSignal, QObject, QThread, QRectF,QT_VERSION_STR
|
from PyQt5.QtCore import Qt, pyqtSlot, QSize, pyqtSignal, QObject, QRectF,QT_VERSION_STR
|
||||||
from PyQt5.QtGui import QKeySequence, QPixmap, QRegExpValidator, QFont
|
from PyQt5.QtGui import QKeySequence, QPixmap
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAction, QApplication, QDoubleSpinBox, QFileDialog, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
|
QAction, QApplication, QFileDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit,
|
||||||
QMessageBox, QPlainTextEdit, QProgressBar, QProgressDialog, QPushButton, QShortcut, QSizePolicy, QSpinBox,
|
QMessageBox, QProgressBar, QPushButton, QShortcut, QSizePolicy,
|
||||||
QSplashScreen, QTextBrowser, QToolBox, QVBoxLayout, QWidget,)
|
QSplashScreen, QToolBox, QVBoxLayout, QWidget,)
|
||||||
from PyQt5.uic import loadUiType
|
from PyQt5.uic import loadUiType
|
||||||
ts.log('Import part 4/8:')
|
ts.log('Import part 4/8:')
|
||||||
import pyqtUsrObj as UsrGO
|
import pyqtUsrObj as UsrGO
|
||||||
@@ -165,7 +150,6 @@ import app_utils
|
|||||||
from app_config import AppCfg,WndParameter #settings, option, toggle_option
|
from app_config import AppCfg,WndParameter #settings, option, toggle_option
|
||||||
|
|
||||||
import epics
|
import epics
|
||||||
from epics.ca import pend_event
|
|
||||||
import camera,backlight,zoom,illumination,geometry
|
import camera,backlight,zoom,illumination,geometry
|
||||||
ts.log('Import part 7/8:')
|
ts.log('Import part 7/8:')
|
||||||
import psi_device
|
import psi_device
|
||||||
|
|||||||
67
zoom.py
67
zoom.py
@@ -8,30 +8,18 @@
|
|||||||
'''
|
'''
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
_log=logging.getLogger(__name__)
|
_log=logging.getLogger(__name__)
|
||||||
import os
|
import os
|
||||||
from PyQt5 import QtWidgets, uic
|
|
||||||
import PyQt5.QtWidgets as qtw
|
|
||||||
from PyQt5.QtCore import pyqtSignal
|
from PyQt5.QtCore import pyqtSignal
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QApplication,
|
QApplication, QPushButton, QGroupBox, QGridLayout, QLabel, QDoubleSpinBox, QSpinBox,
|
||||||
QPushButton,
|
QVBoxLayout, QHBoxLayout, QCheckBox,
|
||||||
QGroupBox,
|
|
||||||
QGridLayout,
|
|
||||||
QLabel,
|
|
||||||
QDoubleSpinBox,
|
|
||||||
QSpinBox,
|
|
||||||
QVBoxLayout,
|
|
||||||
QHBoxLayout,
|
|
||||||
QCheckBox,
|
|
||||||
)
|
)
|
||||||
from PyQt5.uic import loadUiType
|
from PyQt5.uic import loadUiType
|
||||||
|
|
||||||
import backlight, illumination, camera
|
import backlight, illumination, camera
|
||||||
import epics
|
import epics
|
||||||
from app_config import AppCfg #settings
|
|
||||||
|
|
||||||
Ui_Zoom, QWidget = loadUiType(os.path.join(os.path.dirname(__file__),"zoom.ui"))
|
Ui_Zoom, QWidget = loadUiType(os.path.join(os.path.dirname(__file__),"zoom.ui"))
|
||||||
MIN_ZOOM = 1
|
MIN_ZOOM = 1
|
||||||
@@ -50,22 +38,6 @@ class Zoom(QGroupBox, Ui_Zoom):
|
|||||||
|
|
||||||
def init_settings(self):
|
def init_settings(self):
|
||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
#cfg=app._cfg
|
|
||||||
#keys=cfg.allKeys()
|
|
||||||
#if cfg.ZOOM_BUTTONS in keys:
|
|
||||||
# buttons=json.loads(cfg.value(cfg.ZOOM_BUTTONS))
|
|
||||||
#else:
|
|
||||||
# buttons=((1, "1"),(200, "200"),(400, "400"),(600, "600"),(800, "800"),(1000, "1000"),)
|
|
||||||
# cfg.setValue(cfg.ZOOM_BUTTONS,json.dumps(buttons))
|
|
||||||
#self.get_zoom_pv = PV(zoom_api + ":ZOOM-RBV", callback=self.zoom_update_cb)
|
|
||||||
#self.status_pv = PV(zoom_api + ":ZOOM-STATUS", callback=self.zoom_status_cb)
|
|
||||||
#try:
|
|
||||||
# pv=app._zoom.getPv('POS_RB')
|
|
||||||
#except AttributeError as e:
|
|
||||||
# _log.debug('Simulated zoom')
|
|
||||||
#else:
|
|
||||||
# pv.callbacks ... = self.zoom_update_cb
|
|
||||||
# check also: pv.clear_auto_monitor() # disconnect PV monitor callback -> program exit faster.
|
|
||||||
buttons=((1, "1"), (200, "200"), (400, "400"), (600, "600"), (800, "800"), (1000, "1000"),)
|
buttons=((1, "1"), (200, "200"), (400, "400"), (600, "600"), (800, "800"), (1000, "1000"),)
|
||||||
|
|
||||||
zoom=QApplication.instance()._zoom
|
zoom=QApplication.instance()._zoom
|
||||||
@@ -80,7 +52,6 @@ class Zoom(QGroupBox, Ui_Zoom):
|
|||||||
self._zoom_spinner.setRange(MIN_ZOOM, MAX_ZOOM)
|
self._zoom_spinner.setRange(MIN_ZOOM, MAX_ZOOM)
|
||||||
self._zoom_spinner.setValue(current_zoom_value)
|
self._zoom_spinner.setValue(current_zoom_value)
|
||||||
self._zoom_spinner.editingFinished.connect(self.move_zoom_a)
|
self._zoom_spinner.editingFinished.connect(self.move_zoom_a)
|
||||||
# self._zoom_spinner.setSingleStep(SPINNER_SINGLE_STEP)
|
|
||||||
self._zoom_spinner.setSingleStep(SPINNER_LARGE_STEP)
|
self._zoom_spinner.setSingleStep(SPINNER_LARGE_STEP)
|
||||||
_box = QWidget()
|
_box = QWidget()
|
||||||
_box.setLayout(QHBoxLayout())
|
_box.setLayout(QHBoxLayout())
|
||||||
@@ -178,14 +149,6 @@ class Zoom(QGroupBox, Ui_Zoom):
|
|||||||
self.slid.setSuffix(" ms")
|
self.slid.setSuffix(" ms")
|
||||||
grid.addWidget(self.slid, 0, 1)
|
grid.addWidget(self.slid, 0, 1)
|
||||||
|
|
||||||
#grid.addWidget(QLabel("Acq.Mode"), 1, 0)
|
|
||||||
#cbox = QComboBox()
|
|
||||||
#for mode in Camera.AcquisitionMode:
|
|
||||||
# cbox.addItem(mode.name, mode)
|
|
||||||
#cbox.setCurrentIndex(cam.pv_acqmode.get())
|
|
||||||
#cbox.currentIndexChanged.connect(self.update_camera_acqmode)
|
|
||||||
#grid.addWidget(cbox, 1, 1)
|
|
||||||
|
|
||||||
lbox.layout().addWidget(grp)
|
lbox.layout().addWidget(grp)
|
||||||
self.slid.editingFinished.connect(lambda: self.update_exposure(self.slid.value()))
|
self.slid.editingFinished.connect(lambda: self.update_exposure(self.slid.value()))
|
||||||
|
|
||||||
@@ -270,21 +233,6 @@ class Zoom(QGroupBox, Ui_Zoom):
|
|||||||
self._zoom_spinner.blockSignals(False)
|
self._zoom_spinner.blockSignals(False)
|
||||||
self.zoomChanged.emit(float(value))
|
self.zoomChanged.emit(float(value))
|
||||||
|
|
||||||
# def get_zoom(self) -> int:
|
|
||||||
# zoom=QApplication.instance()._zoom
|
|
||||||
# pos = zoom.get()
|
|
||||||
# _log.debug("get_zoom(epics) => {}".format(pos))
|
|
||||||
# return pos
|
|
||||||
|
|
||||||
# def zoom_update_cb(self, pvname, value, char_value, **kwargs):
|
|
||||||
# self._zoom_spinner.blockSignals(True)
|
|
||||||
# self._zoom_spinner.setValue(value)
|
|
||||||
# self._zoom_spinner.blockSignals(False)
|
|
||||||
|
|
||||||
# def zoom_status_cb(self, pvname, value, char_value, **kwargs):
|
|
||||||
# busy = bool(value)
|
|
||||||
# self.setDisabled(busy)
|
|
||||||
|
|
||||||
|
|
||||||
class QopticZoom(object):
|
class QopticZoom(object):
|
||||||
|
|
||||||
@@ -336,7 +284,7 @@ class QopticZoom(object):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import time, os, PIL.Image, platform, subprocess
|
import sys, os
|
||||||
import argparse
|
import argparse
|
||||||
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
|
||||||
|
|
||||||
@@ -344,18 +292,11 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument("--sim", "-s", help="simulate all devices", action='store_true')
|
parser.add_argument("--sim", "-s", help="simulate all devices", action='store_true')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
_log.info('Arguments:{}'.format(args.__dict__))
|
_log.info('Arguments:{}'.format(args.__dict__))
|
||||||
os.environ['EPICS_CA_ADDR_LIST'] = '129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
|
os.environ['EPICS_CA_ADDR_LIST'] = '129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066'
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
from app_config import appsconf
|
from app_config import appsconf
|
||||||
|
|
||||||
#from PyQt5 import QtGui
|
|
||||||
#qtawesome.load_font("material","MaterialIcons-Regular.ttf","MaterialIcons-Regular.json","fonts/",)
|
|
||||||
#QtGui.QFontDatabase.addApplicationFont("fonts/Inconsolata-Bold.ttf")
|
|
||||||
#QtGui.QFontDatabase.addApplicationFont("fonts/Baloo-Regular.ttf")
|
|
||||||
|
|
||||||
if args.sim:
|
if args.sim:
|
||||||
app._backlight = backlight.Backlight(None)
|
app._backlight = backlight.Backlight(None)
|
||||||
app._illumination = illumination.IlluminationControl(None)
|
app._illumination = illumination.IlluminationControl(None)
|
||||||
@@ -367,8 +308,6 @@ if __name__ == "__main__":
|
|||||||
app._zoom = QopticZoom()
|
app._zoom = QopticZoom()
|
||||||
app._camera = camera.epics_cam()
|
app._camera = camera.epics_cam()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
simulated = appsconf["microscope"]["zoom"].get("simulate", False)
|
simulated = appsconf["microscope"]["zoom"].get("simulate", False)
|
||||||
|
|
||||||
obj=Zoom()
|
obj=Zoom()
|
||||||
|
|||||||
Reference in New Issue
Block a user