cleanup
This commit is contained in:
595
CustomROI.py
595
CustomROI.py
@@ -1,595 +0,0 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtCore
|
|
||||||
from PyQt5.QtGui import QColor, QTransform
|
|
||||||
from PyQt5.QtWidgets import QMenu, QAction, QSpinBox, QMenu
|
|
||||||
|
|
||||||
#from GenericDialog import GenericDialog #ZAC: orig. code
|
|
||||||
from pyqtgraph import ROI, Point, RectROI, mkPen
|
|
||||||
from pyqtgraph import functions as fn
|
|
||||||
|
|
||||||
from app_config import AppCfg# settings
|
|
||||||
|
|
||||||
from math import *
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
logger.setLevel(logging.DEBUG)
|
|
||||||
|
|
||||||
|
|
||||||
class Grid(ROI):
|
|
||||||
"""a grid"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
x_step,
|
|
||||||
y_step,
|
|
||||||
x_offset,
|
|
||||||
y_offset,
|
|
||||||
grid_index=0,
|
|
||||||
parent=None,
|
|
||||||
gonio_xy=(0, 0),
|
|
||||||
**kargs
|
|
||||||
):
|
|
||||||
self._grid_index = grid_index
|
|
||||||
self._size = None
|
|
||||||
self._pos = None
|
|
||||||
self._shape = None
|
|
||||||
ROI.__init__(self, (500, 500), (300, 300), **kargs)
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.addScaleHandle([1, 1], [0, 0])
|
|
||||||
self.addScaleHandle([0, 0], [1, 1])
|
|
||||||
self.addScaleRotateHandle([1, 0], [0, 0])
|
|
||||||
# self.addScaleRotateHandle([1, 0.5], [0.5, 0.5])
|
|
||||||
|
|
||||||
self._steps = x_step / 1000., y_step / 1000.
|
|
||||||
self._offsets = x_offset / 1000, y_offset / 1000
|
|
||||||
self._beam_position = parent.get_beam_mark_on_camera_xy()
|
|
||||||
self.set_gonio_xy(*gonio_xy)
|
|
||||||
|
|
||||||
self.setToolTip("grid")
|
|
||||||
|
|
||||||
parent.pixelsPerMillimeter.connect(self.update_ppm)
|
|
||||||
parent.beamCameraCoordinatesChanged.connect(self.update_beam_position)
|
|
||||||
self.enable_stage_tracking()
|
|
||||||
|
|
||||||
self._ppm = parent.getPpm()
|
|
||||||
self._mm_size = 300 / self._ppm, 300 / self._ppm
|
|
||||||
self._original_ppm = self._ppm # marker only works at original zoom
|
|
||||||
# because zoom axis is not aligned
|
|
||||||
# with viewing axis
|
|
||||||
self._fx, self._fy = self.parent.getFastX(), self.parent.getFastY()
|
|
||||||
self.invertible = True
|
|
||||||
self.sigRegionChanged.connect(self.invalidate)
|
|
||||||
self.sigRegionChangeFinished.connect(self.calculate_gonio_xy)
|
|
||||||
self.scaleSnap = False
|
|
||||||
self.aspectLocked = False
|
|
||||||
self.translatable = True
|
|
||||||
self.rotateAllowed = False
|
|
||||||
self.removable = True
|
|
||||||
|
|
||||||
self.follow_stage()
|
|
||||||
# self.calculate_gonio_xy()
|
|
||||||
|
|
||||||
def enable_stage_tracking(self):
|
|
||||||
self.parent.fast_x_position.connect(self.follow_x)
|
|
||||||
self.parent.fast_y_position.connect(self.follow_y)
|
|
||||||
|
|
||||||
def disable_stage_tracking(self):
|
|
||||||
self.parent.fast_x_position.disconnect(self.follow_x)
|
|
||||||
self.parent.fast_y_position.disconnect(self.follow_y)
|
|
||||||
|
|
||||||
def follow_x(self, v):
|
|
||||||
self.follow_stage(fx=v)
|
|
||||||
|
|
||||||
def follow_y(self, v):
|
|
||||||
self.follow_stage(fy=v)
|
|
||||||
|
|
||||||
def removeClicked(self):
|
|
||||||
self.parent.pixelsPerMillimeter.disconnect(self.update_ppm)
|
|
||||||
self.parent.beamCameraCoordinatesChanged.disconnect(self.update_beam_position)
|
|
||||||
self.parent.fast_x_position.disconnect(self.follow_x)
|
|
||||||
self.parent.fast_y_position.disconnect(self.follow_y)
|
|
||||||
super(Grid, self).removeClicked()
|
|
||||||
|
|
||||||
def calculate_gonio_xy(self):
|
|
||||||
self.update_grid_pos()
|
|
||||||
state = self.getState()
|
|
||||||
angle = state["angle"]
|
|
||||||
w, h = state["size"]
|
|
||||||
w, h = 1000 * w / self._ppm, 1000 * h / self._ppm
|
|
||||||
self._mm_size = w / 1000, h / 1000
|
|
||||||
self.calculate_targets()
|
|
||||||
|
|
||||||
def update_ppm(self, ppm):
|
|
||||||
self._ppm = ppm
|
|
||||||
self.update_grid_size(ppm)
|
|
||||||
self.update_grid_pos()
|
|
||||||
self.stateChanged()
|
|
||||||
|
|
||||||
def update_grid_size(self, ppm, finish=False):
|
|
||||||
mmw, mmh = self._mm_size
|
|
||||||
w, h = mmw * ppm, mmh * ppm
|
|
||||||
self.setSize((w, h), update=False)
|
|
||||||
|
|
||||||
def follow_stage(self, fx=None, fy=None):
|
|
||||||
self._fx, self._fy = self.parent.getFastX(), self.parent.getFastY()
|
|
||||||
self.update_grid_pos()
|
|
||||||
self.stateChanged()
|
|
||||||
|
|
||||||
def set_gonio_xy(self, x, y):
|
|
||||||
self._gx, self._gy = x, y
|
|
||||||
|
|
||||||
def update_grid_pos(self):
|
|
||||||
idx = self._grid_index
|
|
||||||
ppm = self._ppm
|
|
||||||
bx, by = self.parent.get_beam_mark_on_camera_xy()
|
|
||||||
gx, gy = self._gx, self._gy # marker position in gonio coords
|
|
||||||
fx, fy = self._fx, self._fy
|
|
||||||
dx, dy = (
|
|
||||||
ppm * (fx - gx),
|
|
||||||
ppm * (fy - gy),
|
|
||||||
) # distance to beam in pixels for new ppm
|
|
||||||
x, y = bx - dx, by + dy
|
|
||||||
self.setPos(x, y, update=False)
|
|
||||||
mmw, mmh = self._mm_size
|
|
||||||
|
|
||||||
def calculate_targets(self):
|
|
||||||
state = self.getState()
|
|
||||||
angle = radians(state["angle"])
|
|
||||||
cosa = cos(angle)
|
|
||||||
sina = sin(angle)
|
|
||||||
w, h = state["size"]
|
|
||||||
xs, ys = self._steps
|
|
||||||
w, h = w / self._ppm, h / self._ppm # mm
|
|
||||||
gx, gy = self._gx, self._gy
|
|
||||||
nx = int(abs(w) / xs)
|
|
||||||
ny = int(abs(h) / ys)
|
|
||||||
points = []
|
|
||||||
dx = xs
|
|
||||||
dy = ys
|
|
||||||
for yi in range(ny):
|
|
||||||
ly = yi * dy
|
|
||||||
y = gy + ly
|
|
||||||
for xi in range(nx):
|
|
||||||
lx = xi * dx
|
|
||||||
x = gx + lx
|
|
||||||
l = sqrt((lx) ** 2 + (ly) ** 2)
|
|
||||||
try:
|
|
||||||
alpha = acos((lx) / l)
|
|
||||||
except:
|
|
||||||
alpha = 0
|
|
||||||
x2 = gx + l * cos(alpha + angle)
|
|
||||||
y2 = gy - l * sin(alpha + angle)
|
|
||||||
# print(
|
|
||||||
# "l={:8.3f} alpha={:.3f} xy={:8.3f}{:8.3f} xy2={:8.3f}{:8.3f}".format(
|
|
||||||
# l, degrees(alpha), x, y, x2, y2
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
|
|
||||||
points.append((x2, y2))
|
|
||||||
self._grid_dimensions = (nx, ny)
|
|
||||||
self._points = points
|
|
||||||
self.parent.gridUpdated.emit(self._grid_index)
|
|
||||||
|
|
||||||
def get_sorted_grid_targets(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_grid_targets(self):
|
|
||||||
return self._points
|
|
||||||
|
|
||||||
def update_beam_position(self, pos):
|
|
||||||
self._beam_position = pos
|
|
||||||
|
|
||||||
def invalidate(self):
|
|
||||||
state = self.getState()
|
|
||||||
x, y = state["pos"]
|
|
||||||
w, h = state["size"]
|
|
||||||
self._mm_size = w / self._ppm, h / self._ppm
|
|
||||||
fx, fy = self.camera2gonio(x, y)
|
|
||||||
self.set_gonio_xy(fx, fy)
|
|
||||||
self._shape = None
|
|
||||||
self.prepareGeometryChange()
|
|
||||||
|
|
||||||
def boundingRect(self):
|
|
||||||
return self.shape().boundingRect()
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
w, h = self.getState()["size"]
|
|
||||||
if self._shape is None:
|
|
||||||
radius = self.getState()["size"][1]
|
|
||||||
p = QtGui.QPainterPath()
|
|
||||||
p.addRect(0, 0, w, h)
|
|
||||||
stroker = QtGui.QPainterPathStroker()
|
|
||||||
stroker.setWidth(10)
|
|
||||||
outline = stroker.createStroke(p)
|
|
||||||
self._shape = outline
|
|
||||||
return self._shape
|
|
||||||
|
|
||||||
def paint(self, p, *args):
|
|
||||||
state = self.getState()
|
|
||||||
w, h = state["size"]
|
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
|
||||||
p.setPen(fn.mkPen(width=5, color=[200, 200, 100]))
|
|
||||||
p.drawRect(0, 0, w, h)
|
|
||||||
|
|
||||||
p.setPen(fn.mkPen(width=3, color=[200, 100, 100]))
|
|
||||||
ppm = self._ppm
|
|
||||||
xs, ys = self._steps
|
|
||||||
w1, h1 = w / ppm, h / ppm # mm
|
|
||||||
nx = int(abs(w1) / xs)
|
|
||||||
ny = int(abs(h1) / ys)
|
|
||||||
sw = (xs) * ppm
|
|
||||||
sh = (ys) * ppm
|
|
||||||
# print((nx,ny), (w1, h1), (sw, sh))
|
|
||||||
r = 10
|
|
||||||
a, b = state["pos"]
|
|
||||||
if nx * ny > 1000:
|
|
||||||
return
|
|
||||||
for y in range(ny):
|
|
||||||
for x in range(nx):
|
|
||||||
p.drawEllipse((x * sw) - r, (y * sh) - r, 2 * r, 2 * r)
|
|
||||||
|
|
||||||
def camera2gonio(self, x, y):
|
|
||||||
bx, by = self.parent.get_beam_mark_on_camera_xy()
|
|
||||||
ppm = self._ppm
|
|
||||||
dx, dy = (x - bx) / ppm, (y - by) / ppm
|
|
||||||
fx, fy = self._fx + dx, self._fy - dy
|
|
||||||
return fx, fy
|
|
||||||
|
|
||||||
def gonio2camera(self, x, y):
|
|
||||||
ppm = self._ppm
|
|
||||||
bx, by = self.parent.get_beam_mark_on_camera_xy()
|
|
||||||
gx, gy = self._gx, self._gy # marker position in gonio coords
|
|
||||||
fx, fy = self._fx, self._fy
|
|
||||||
dx, dy = (
|
|
||||||
ppm * (fx - gx),
|
|
||||||
ppm * (fy - gy),
|
|
||||||
) # distance to beam in pixels for new ppm
|
|
||||||
x, y = bx - dx, by + dy
|
|
||||||
return x, y
|
|
||||||
|
|
||||||
|
|
||||||
class BeamMark(ROI):
|
|
||||||
"""A crosshair ROI whose position is at the center of the crosshairs. By default, it is scalable, rotatable and translatable."""
|
|
||||||
|
|
||||||
def __init__(self, pos=None, size=None, parent=None, **kargs):
|
|
||||||
if size is None:
|
|
||||||
size = [20, 20]
|
|
||||||
if pos is None:
|
|
||||||
pos = [0, 0]
|
|
||||||
self._size = size
|
|
||||||
self._pos = pos
|
|
||||||
self._shape = None
|
|
||||||
ROI.__init__(self, pos, size, **kargs)
|
|
||||||
|
|
||||||
parent.pixelsPerMillimeter.connect(self.my_update_ppm)
|
|
||||||
parent.beamCameraCoordinatesChanged.connect(lambda x, y: self.setPos((x, y)))
|
|
||||||
|
|
||||||
self._scale_handler = None
|
|
||||||
self.sigRegionChanged.connect(self.invalidate)
|
|
||||||
self.aspectLocked = False
|
|
||||||
self.translatable = False
|
|
||||||
self.rotateAllowed = False
|
|
||||||
self.invertible = False
|
|
||||||
self.removable = False
|
|
||||||
self.scaleSnap = True
|
|
||||||
self.snapSize = 1
|
|
||||||
self.sigRegionChangeFinished.connect(self.show_size)
|
|
||||||
self.flip_ud()
|
|
||||||
|
|
||||||
def show_size(self):
|
|
||||||
try:
|
|
||||||
ppm = self._ppm
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
w, h = self.getState()["size"]
|
|
||||||
# convert to micrometer
|
|
||||||
nw, nh = (w * 1000) / ppm, (h * 1000) / ppm
|
|
||||||
logger.debug("persisting new beam marker size: {}".format((nw, nh)))
|
|
||||||
settings.setValue("beam/size", (nw, nh))
|
|
||||||
|
|
||||||
def toggle_handle(self):
|
|
||||||
if self._scale_handler is None:
|
|
||||||
logger.debug("adding beam marker resize handle")
|
|
||||||
self._scale_handler = self.addScaleHandle([0.5, 0.5], [0, 0])
|
|
||||||
else:
|
|
||||||
logger.debug("removing beam marker resize handle")
|
|
||||||
self.removeHandle(self._scale_handler)
|
|
||||||
self._scale_handler = None
|
|
||||||
|
|
||||||
def get_camera_beam_position(self):
|
|
||||||
return self.getState()["pos"]
|
|
||||||
|
|
||||||
def set_beam_size_marker_dialog(self):
|
|
||||||
w, h = settings.value("beam/size")
|
|
||||||
d = GenericDialog(
|
|
||||||
title="Beamsize",
|
|
||||||
message="Enter the size of the beam in microns",
|
|
||||||
inputs={
|
|
||||||
"width": ("Width (\u00B5)", int(w), QSpinBox()),
|
|
||||||
"height": ("Height (\u00B5)", int(h), QSpinBox()),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if d.exec():
|
|
||||||
results = d.results
|
|
||||||
logger.info("Updating beamsize to {}".format(results))
|
|
||||||
w, h = results["width"], results["height"]
|
|
||||||
logger.debug("types {}".format(type(w)))
|
|
||||||
settings.setValue("beam/size", (w, h))
|
|
||||||
self.set_beam_size((w, h))
|
|
||||||
|
|
||||||
def flip_ud(self):
|
|
||||||
"""flip up-down"""
|
|
||||||
t = self.transform()
|
|
||||||
m11 = t.m11()
|
|
||||||
m12 = t.m12()
|
|
||||||
m13 = t.m13()
|
|
||||||
m21 = t.m21()
|
|
||||||
m22 = t.m22()
|
|
||||||
m23 = t.m23()
|
|
||||||
m31 = t.m31()
|
|
||||||
m32 = t.m32()
|
|
||||||
m33 = t.m33()
|
|
||||||
t.setMatrix(m11, m12, m13, m21, -m22, m23, m31, m32, m33)
|
|
||||||
self.setTransform(t)
|
|
||||||
|
|
||||||
def set_beam_size(self, size=None):
|
|
||||||
if size is not None:
|
|
||||||
self._size = size
|
|
||||||
ppm = self._ppm
|
|
||||||
w, h = self._size
|
|
||||||
nw, nh = (w / 1000) * ppm, (h / 1000) * ppm
|
|
||||||
self.setSize((nw, nh))
|
|
||||||
self.setToolTip("Beamsize (W x H): {:.1f}\u00B5 x {:.1f}\u00B5".format(w, h))
|
|
||||||
|
|
||||||
def my_update_ppm(self, ppm):
|
|
||||||
self._ppm = ppm
|
|
||||||
self.set_beam_size()
|
|
||||||
|
|
||||||
def invalidate(self):
|
|
||||||
self._shape = None
|
|
||||||
self.prepareGeometryChange()
|
|
||||||
|
|
||||||
def boundingRect(self):
|
|
||||||
return self.shape().boundingRect()
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
w, h = self.size()
|
|
||||||
if self._shape is None:
|
|
||||||
p = QtGui.QPainterPath()
|
|
||||||
p.moveTo(Point(0, -h))
|
|
||||||
p.lineTo(Point(0, h))
|
|
||||||
p.moveTo(Point(-w, 0))
|
|
||||||
p.lineTo(Point(w, 0))
|
|
||||||
#
|
|
||||||
p.moveTo(Point(-w, -h))
|
|
||||||
p.lineTo(Point(w, -h))
|
|
||||||
p.lineTo(Point(w, h))
|
|
||||||
p.lineTo(Point(-w, -h))
|
|
||||||
stroker = QtGui.QPainterPathStroker()
|
|
||||||
outline = stroker.createStroke(p)
|
|
||||||
self._shape = outline
|
|
||||||
|
|
||||||
return self._shape
|
|
||||||
|
|
||||||
def paint(self, p, *args):
|
|
||||||
w, h = self.getState()["size"]
|
|
||||||
|
|
||||||
v1, v2 = -(h * 0.8) / 2, (h * 0.8) / 2
|
|
||||||
h1, h2 = -(w * 0.8) / 2, (w * 0.8) / 2
|
|
||||||
|
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
|
||||||
p.setPen(fn.mkPen(width=3, color=[200, 100, 100]))
|
|
||||||
p.drawLine(Point(0, v1), Point(0, v2))
|
|
||||||
p.drawLine(Point(h1, 0), Point(h2, 0))
|
|
||||||
|
|
||||||
p.setPen(fn.mkPen(width=3, color=[200, 200, 100]))
|
|
||||||
p.drawRect(-w / 2, -h / 2, w, h)
|
|
||||||
# p.drawText(-w, -h, '{:.0f}x{:.0f}'.format(*self._size))
|
|
||||||
|
|
||||||
|
|
||||||
class CrystalCircle(ROI):
|
|
||||||
"""A crosshair ROI whose position is at the center of the crosshairs. By default, it is scalable, rotatable and translatable."""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
pos=None,
|
|
||||||
size=None,
|
|
||||||
parent=None,
|
|
||||||
gonio_xy=(0, 0),
|
|
||||||
model_row_index=1,
|
|
||||||
is_fiducial=False,
|
|
||||||
ppm=False,
|
|
||||||
**kargs
|
|
||||||
):
|
|
||||||
if size is None:
|
|
||||||
size = [20, 20]
|
|
||||||
if pos is None:
|
|
||||||
pos = [0, 0]
|
|
||||||
self._size = size
|
|
||||||
self._shape = None
|
|
||||||
self.parent = parent
|
|
||||||
self._model_row_index = model_row_index
|
|
||||||
self._is_fiducial = is_fiducial
|
|
||||||
ROI.__init__(self, pos, size, **kargs)
|
|
||||||
|
|
||||||
self._beam_position = parent.get_beam_mark_on_camera_xy()
|
|
||||||
self.set_gonio_xy(*gonio_xy)
|
|
||||||
|
|
||||||
self.setToolTip(f"{'fiducial' if is_fiducial else 'crystal'} {model_row_index}")
|
|
||||||
|
|
||||||
# parent.pixelsPerMillimeter.connect(self.update_pixels_per_millimeter)
|
|
||||||
# parent.beamCameraCoordinatesChanged.connect(self.update_beam_position)
|
|
||||||
# parent.fast_x_position.connect(self.follow_x)
|
|
||||||
# parent.fast_y_position.connect(self.follow_y)
|
|
||||||
self._ppm = ppm
|
|
||||||
self._original_ppm = ppm # marker only works at original zoom
|
|
||||||
# because zoom axis is not aligned
|
|
||||||
# with viewing axis
|
|
||||||
|
|
||||||
# self.calculate_gonio_xy()
|
|
||||||
self.sigRegionChanged.connect(self.invalidate)
|
|
||||||
# self.sigRegionChangeFinished.connect(self.calculate_gonio_xy)
|
|
||||||
# self.sigHoverEvent.connect(self.my_hovering)
|
|
||||||
self.aspectLocked = False
|
|
||||||
self.translatable = True
|
|
||||||
self.rotateAllowed = False
|
|
||||||
self.invertible = False
|
|
||||||
self.deletable = False
|
|
||||||
|
|
||||||
def enable_stage_tracking(self):
|
|
||||||
self.parent.fast_x_position.connect(self.follow_x)
|
|
||||||
self.parent.fast_y_position.connect(self.follow_y)
|
|
||||||
|
|
||||||
def disable_stage_tracking(self):
|
|
||||||
self.parent.fast_x_position.disconnect(self.follow_x)
|
|
||||||
self.parent.fast_y_position.disconnect(self.follow_y)
|
|
||||||
|
|
||||||
def follow_x(self, v):
|
|
||||||
self.follow_stage(fx=v)
|
|
||||||
|
|
||||||
def follow_y(self, v):
|
|
||||||
self.follow_stage(fy=v)
|
|
||||||
|
|
||||||
def my_hovering(self, event):
|
|
||||||
print("hovering: {}".format(self.mouseHovering))
|
|
||||||
|
|
||||||
def get_model_row(self):
|
|
||||||
return self._model_row_index
|
|
||||||
|
|
||||||
def update_ppm(self, ppm):
|
|
||||||
self._ppm = ppm
|
|
||||||
self.recalc_camera_position()
|
|
||||||
|
|
||||||
def follow_stage(self, fx=None, fy=None):
|
|
||||||
self._fx, self._fy = self.parent.getFastX(), self.parent.getFastY()
|
|
||||||
self.recalc_camera_position()
|
|
||||||
|
|
||||||
def set_gonio_xy(self, x, y):
|
|
||||||
self._gx, self._gy = x, y
|
|
||||||
|
|
||||||
def disconnect_signals(self):
|
|
||||||
self.parent.pixelsPerMillimeter.disconnect(self.update_ppm)
|
|
||||||
self.parent.beamCameraCoordinatesChanged.disconnect(self.update_beam_position)
|
|
||||||
self.parent.fast_x_position.disconnect(self.follow_x)
|
|
||||||
self.parent.fast_y_position.disconnect(self.follow_y)
|
|
||||||
|
|
||||||
def reconnect_signals(self):
|
|
||||||
self.parent.pixelsPerMillimeter.connect(self.update_ppm)
|
|
||||||
self.parent.beamCameraCoordinatesChanged.connect(self.update_beam_position)
|
|
||||||
self.parent.fast_x_position.connect(self.follow_x)
|
|
||||||
self.parent.fast_y_position.connect(self.follow_y)
|
|
||||||
|
|
||||||
def removeClicked(self):
|
|
||||||
self.disconnect_signals()
|
|
||||||
super(CrystalCircle, self).removeClicked()
|
|
||||||
|
|
||||||
def recalc_camera_position(self):
|
|
||||||
idx = self._model_row_index
|
|
||||||
ppm = self._ppm
|
|
||||||
bx, by = self.parent.get_beam_mark_on_camera_xy()
|
|
||||||
gx, gy = self._gx, self._gy # marker position in gonio coords
|
|
||||||
fx, fy = self._fx, self._fy
|
|
||||||
# distance to beam in pixels for new ppm
|
|
||||||
dx, dy = (ppm * (fx - gx), ppm * (fy - gy))
|
|
||||||
x, y = bx - dx, by + dy
|
|
||||||
# logger.debug(f"recalc {idx}: cam = {(x,y)}, gonio = {(gx, gy)}")
|
|
||||||
self.setPos(x, y)
|
|
||||||
|
|
||||||
def update_beam_position(self, pos):
|
|
||||||
self._beam_position = pos
|
|
||||||
|
|
||||||
def show_size(self):
|
|
||||||
try:
|
|
||||||
ppm = self._ppm
|
|
||||||
except:
|
|
||||||
return
|
|
||||||
w, h = self.getState()["size"]
|
|
||||||
# convert to micrometer
|
|
||||||
nw, nh = (w * 1000) / ppm, (h * 1000) / ppm
|
|
||||||
|
|
||||||
def invalidate(self):
|
|
||||||
self._shape = None
|
|
||||||
self.prepareGeometryChange()
|
|
||||||
|
|
||||||
def boundingRect(self):
|
|
||||||
return self.shape().boundingRect()
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
if self._shape is None:
|
|
||||||
radius = self.getState()["size"][1]
|
|
||||||
p = QtGui.QPainterPath()
|
|
||||||
p.moveTo(Point(0, -radius))
|
|
||||||
p.lineTo(Point(0, radius))
|
|
||||||
p.moveTo(Point(-radius, 0))
|
|
||||||
p.lineTo(Point(radius, 0))
|
|
||||||
stroker = QtGui.QPainterPathStroker()
|
|
||||||
stroker.setWidth(10)
|
|
||||||
outline = stroker.createStroke(p)
|
|
||||||
self._shape = outline
|
|
||||||
|
|
||||||
return self._shape
|
|
||||||
|
|
||||||
def paint(self, p, *args):
|
|
||||||
if abs(self._ppm - self._original_ppm) < 1.:
|
|
||||||
if self._is_fiducial:
|
|
||||||
pen = mkPen(color="r", width=2)
|
|
||||||
else:
|
|
||||||
pen = mkPen(color="y", width=2)
|
|
||||||
else:
|
|
||||||
pen = mkPen(color="#ffffaa88", width=2)
|
|
||||||
x, y = self.getState()["size"]
|
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
|
||||||
p.setPen(pen)
|
|
||||||
|
|
||||||
p.drawLine(Point(0, -x), Point(0, x))
|
|
||||||
p.drawLine(Point(-x, 0), Point(x, 0))
|
|
||||||
p.drawEllipse(-x, -y, 2 * x, 2 * y)
|
|
||||||
|
|
||||||
|
|
||||||
class Crosshair(ROI):
|
|
||||||
"""A crosshair ROI whose position is at the center of the crosshairs. By default, it is scalable, rotatable and translatable."""
|
|
||||||
|
|
||||||
def __init__(self, pos=None, size=None, **kargs):
|
|
||||||
if size is None:
|
|
||||||
size = [10, 10]
|
|
||||||
if pos is None:
|
|
||||||
pos = [0, 0]
|
|
||||||
self._shape = None
|
|
||||||
ROI.__init__(self, pos, size, **kargs)
|
|
||||||
|
|
||||||
self.sigRegionChanged.connect(self.invalidate)
|
|
||||||
self.aspectLocked = True
|
|
||||||
|
|
||||||
def invalidate(self):
|
|
||||||
self._shape = None
|
|
||||||
self.prepareGeometryChange()
|
|
||||||
|
|
||||||
def boundingRect(self):
|
|
||||||
return self.shape().boundingRect()
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
if self._shape is None:
|
|
||||||
radius = self.getState()["size"][1]
|
|
||||||
p = QtGui.QPainterPath()
|
|
||||||
p.moveTo(Point(0, -radius))
|
|
||||||
p.lineTo(Point(0, radius))
|
|
||||||
p.moveTo(Point(-radius, 0))
|
|
||||||
p.lineTo(Point(radius, 0))
|
|
||||||
# p = self.mapToDevice(p)
|
|
||||||
stroker = QtGui.QPainterPathStroker()
|
|
||||||
stroker.setWidth(10)
|
|
||||||
outline = stroker.createStroke(p)
|
|
||||||
# self._shape = self.mapFromDevice(outline)
|
|
||||||
self._shape = outline
|
|
||||||
|
|
||||||
return self._shape
|
|
||||||
|
|
||||||
def paint(self, p, *args):
|
|
||||||
radius = self.getState()["size"][1]
|
|
||||||
p.setRenderHint(QtGui.QPainter.Antialiasing)
|
|
||||||
p.setPen(self.currentPen)
|
|
||||||
|
|
||||||
p.drawLine(Point(0, -radius), Point(0, radius))
|
|
||||||
p.drawLine(Point(-radius, 0), Point(radius, 0))
|
|
||||||
204
GenericDialog.py
204
GenericDialog.py
@@ -1,204 +0,0 @@
|
|||||||
import logging
|
|
||||||
_log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
import re
|
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal
|
|
||||||
from PyQt5.QtWidgets import QLineEdit, QTextEdit, QGridLayout, QVBoxLayout, QWidget, QDialog, QDialogButtonBox, QPushButton
|
|
||||||
from PyQt5.QtWidgets import QDoubleSpinBox, QSpinBox, QCheckBox, QLabel
|
|
||||||
|
|
||||||
def Spinner(value, min=None, max=None, decimals=None, single_step=None, prefix=None, suffix=None):
|
|
||||||
if type(value) is float:
|
|
||||||
s = QDoubleSpinBox()
|
|
||||||
else:
|
|
||||||
s = QSpinBox()
|
|
||||||
|
|
||||||
if min is not None:
|
|
||||||
s.setMinimum(min)
|
|
||||||
if max is not None:
|
|
||||||
s.setMaximum(max)
|
|
||||||
try:
|
|
||||||
if decimals is not None:
|
|
||||||
s.setDecimals(decimals)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if single_step is not None:
|
|
||||||
s.setSingleStep(single_step)
|
|
||||||
if prefix is not None:
|
|
||||||
s.setPrefix(prefix)
|
|
||||||
if suffix is not None:
|
|
||||||
s.setSuffix(suffix)
|
|
||||||
return s
|
|
||||||
|
|
||||||
def Checkbox(value: bool, label: str):
|
|
||||||
box = QCheckBox(label)
|
|
||||||
box.setChecked(value)
|
|
||||||
return box
|
|
||||||
|
|
||||||
class MagicLabel(QLabel):
|
|
||||||
entered = pyqtSignal(str)
|
|
||||||
left = pyqtSignal()
|
|
||||||
|
|
||||||
def __init__(self, label, help_str, help_buddy=None):
|
|
||||||
super(MagicLabel, self).__init__(label)
|
|
||||||
self._help_buddy = help_buddy
|
|
||||||
self._help_str = help_str
|
|
||||||
|
|
||||||
def enterEvent(self, event):
|
|
||||||
print(self._help_str)
|
|
||||||
if self._help_buddy:
|
|
||||||
print(f"yay!: {self._help_str}")
|
|
||||||
else:
|
|
||||||
super().enterEvent(event)
|
|
||||||
|
|
||||||
def leaveEvent(self, event):
|
|
||||||
super().leaveEvent(event)
|
|
||||||
|
|
||||||
|
|
||||||
class GenericDialog(QDialog):
|
|
||||||
def __init__(self, parent=None, settings=None, title=None, message=None, inputs={}, use_buttons=True):
|
|
||||||
super(GenericDialog, self).__init__()
|
|
||||||
|
|
||||||
self.settings = settings
|
|
||||||
|
|
||||||
# self.setModal(True)
|
|
||||||
self.setAccessibleName("genericDialog")
|
|
||||||
self.setLayout(QVBoxLayout())
|
|
||||||
|
|
||||||
|
|
||||||
bbox = QDialogButtonBox()
|
|
||||||
doneButton = QPushButton("Done")
|
|
||||||
doneButton.clicked.connect(self.accept)
|
|
||||||
bbox.addButton(doneButton, QDialogButtonBox.AcceptRole)
|
|
||||||
|
|
||||||
if use_buttons:
|
|
||||||
undoButton = QPushButton("Undo")
|
|
||||||
undoButton.clicked.connect(self.undo_all)
|
|
||||||
|
|
||||||
discardButton = QPushButton("Discard")
|
|
||||||
discardButton.clicked.connect(self.discard)
|
|
||||||
|
|
||||||
bbox.addButton(undoButton, QDialogButtonBox.ActionRole)
|
|
||||||
bbox.addButton(discardButton, QDialogButtonBox.RejectRole)
|
|
||||||
|
|
||||||
lb = QLabel(title)
|
|
||||||
lb.setAccessibleName("genericDialogTitle")
|
|
||||||
lb.setAlignment(Qt.AlignHCenter)
|
|
||||||
self.layout().addWidget(lb)
|
|
||||||
|
|
||||||
gbox = QWidget()
|
|
||||||
self.layout().addWidget(gbox)
|
|
||||||
gbox.setLayout(QVBoxLayout())
|
|
||||||
mlabel = QLabel(message)
|
|
||||||
mlabel.setAccessibleName("genericDialogMessage")
|
|
||||||
|
|
||||||
gbox.layout().addWidget(mlabel)
|
|
||||||
self.setWindowTitle(title)
|
|
||||||
|
|
||||||
self.contents = QWidget()
|
|
||||||
self.contents.setAccessibleName("genericDialogContents")
|
|
||||||
self.layout().addWidget(self.contents)
|
|
||||||
self.layout().addStretch()
|
|
||||||
self.layout().addWidget(bbox)
|
|
||||||
if not inputs:
|
|
||||||
inputs = {'test': ('Text test', 'initial', QLineEdit()),
|
|
||||||
'float': ('Text test 2', 3.14, QDoubleSpinBox(), 5.0),
|
|
||||||
'integer': ('Text test 2', 42, QSpinBox()),
|
|
||||||
}
|
|
||||||
|
|
||||||
self.contents.setLayout(QGridLayout())
|
|
||||||
layout = self.contents.layout()
|
|
||||||
layout.setColumnStretch(1, 2)
|
|
||||||
self.results = {}
|
|
||||||
self._undo = {}
|
|
||||||
for row, config in enumerate(inputs.items()):
|
|
||||||
key, config = config
|
|
||||||
config = list(config)
|
|
||||||
if len(config) == 3:
|
|
||||||
config.extend([""])
|
|
||||||
label, value, widget, help_str = config
|
|
||||||
labwig = MagicLabel(label, help_str)
|
|
||||||
layout.addWidget(labwig, row, 0)
|
|
||||||
layout.addWidget(widget, row, 1)
|
|
||||||
|
|
||||||
if hasattr(widget, 'setChecked'):
|
|
||||||
widget.setChecked(value)
|
|
||||||
widget.stateChanged.connect(lambda v, k=key, w=widget.isChecked: self.update_results(k, w))
|
|
||||||
|
|
||||||
elif hasattr(widget, 'setValue'):
|
|
||||||
widget.setValue(value)
|
|
||||||
widget.valueChanged.connect(lambda v, k=key, w=widget.value: self.update_results(k, w))
|
|
||||||
|
|
||||||
elif hasattr(widget, 'setPlainText'):
|
|
||||||
widget.setPlainText(value)
|
|
||||||
widget.textChanged.connect(lambda k=key, w=widget.toPlainText: self.update_results(k, w))
|
|
||||||
|
|
||||||
elif hasattr(widget, 'setText'):
|
|
||||||
widget.setText(value)
|
|
||||||
widget.editingFinished.connect(lambda k=key, w=widget.text: self.update_results(k, w))
|
|
||||||
|
|
||||||
self.results[key] = value
|
|
||||||
self._undo[key] = (widget, value)
|
|
||||||
|
|
||||||
def undo_all(self):
|
|
||||||
for k, uinfo in self._undo.items():
|
|
||||||
widget, value = uinfo
|
|
||||||
if hasattr(widget, 'setChecked'):
|
|
||||||
widget.setChecked(value)
|
|
||||||
|
|
||||||
elif hasattr(widget, 'setValue'):
|
|
||||||
widget.setValue(value)
|
|
||||||
|
|
||||||
elif hasattr(widget, 'setPlainText'):
|
|
||||||
widget.setPlainText(value)
|
|
||||||
|
|
||||||
elif hasattr(widget, 'setText'):
|
|
||||||
widget.setText(value)
|
|
||||||
|
|
||||||
def discard(self):
|
|
||||||
self.undo_all()
|
|
||||||
self.reject()
|
|
||||||
|
|
||||||
def set_value(self, widget, url):
|
|
||||||
m = re.match("^(.*?)://(.*)", url, re.MULTILINE|re.DOTALL)
|
|
||||||
method, value = m.groups()
|
|
||||||
if method == "setValue":
|
|
||||||
widget.setValue(float(value))
|
|
||||||
elif method == "setText":
|
|
||||||
widget.setText(value)
|
|
||||||
else:
|
|
||||||
widget.setPlainText(value)
|
|
||||||
if self.settings is not None:
|
|
||||||
self.settings.setValue(k, value)
|
|
||||||
|
|
||||||
def update_results(self, key, get_value):
|
|
||||||
value = get_value()
|
|
||||||
_log.debug(f"settigns {key} => {value}")
|
|
||||||
self.results[key] = value
|
|
||||||
if self.settings is not None:
|
|
||||||
self.settings.setValue(k, value)
|
|
||||||
|
|
||||||
def keyPressEvent(self, key_event):
|
|
||||||
if key_event != Qt.Key_Escape:
|
|
||||||
super().keyPressEvent(key_event)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
title = 'A Lovely Title'
|
|
||||||
message = 'thisn sohudl explain what do tod ow with this dialog and in fact we should make sure that it will be wrapping aorufnnfb'
|
|
||||||
main = GenericDialog(title=title, message=message, inputs={
|
|
||||||
'bananas': ('Number of Bananas', 2, QSpinBox(), 10),
|
|
||||||
'apples': ('Number of Apples', 5.5, QDoubleSpinBox(), 23),
|
|
||||||
'really': ('Indeed?', True, Checkbox(True, "Contr")),
|
|
||||||
'words': ('Words', 'words go here', QLineEdit(), "a few words"),
|
|
||||||
'texts': ('Words', 'big words go here', QTextEdit(), """quite a drama\n to write here, really something awfull long"""),
|
|
||||||
})
|
|
||||||
if main.exec():
|
|
||||||
print(main.results)
|
|
||||||
for k, v in main.results.items():
|
|
||||||
print('{} {} = {}'.format(k, type(v), v))
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
|
|
||||||
@@ -195,63 +195,20 @@ class WndFixTarget(QWidget):
|
|||||||
#btnDelAll.clicked.connect(lambda x: _log.warning("TODO: IMPLEMENT") )
|
#btnDelAll.clicked.connect(lambda x: _log.warning("TODO: IMPLEMENT") )
|
||||||
bl.addWidget(btnFit, 2, 1,1,1)
|
bl.addWidget(btnFit, 2, 1,1,1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# but = QPushButton("Dump to console")
|
|
||||||
# but.clicked.connect(self.dump_data)
|
|
||||||
# bl.addWidget(but, 10, 0, 1, 1)
|
|
||||||
|
|
||||||
but = QCheckBox("collect fiducials")
|
|
||||||
but.setChecked(False)
|
|
||||||
but.setToolTip("Collect or not the fiducial positions.")
|
|
||||||
self._collect_fiducials = False
|
|
||||||
but.stateChanged.connect(self.set_collect_fiducials)
|
|
||||||
bl.addWidget(but, 10, 0, 1, 1)
|
|
||||||
|
|
||||||
|
|
||||||
but = QCheckBox("draw crystal marks")
|
|
||||||
but.setChecked(False)
|
|
||||||
self._draw_crystal_marks = False
|
|
||||||
but.stateChanged.connect(self.set_draw_crystal_marks)
|
|
||||||
bl.addWidget(but, 10, 1, 1, 1)
|
|
||||||
|
|
||||||
|
|
||||||
but = QPushButton("Transform")
|
|
||||||
but.clicked.connect(self.transform_non_fiducials_in_model)
|
|
||||||
bl.addWidget(but, 20, 0, 2, 2)
|
|
||||||
|
|
||||||
layout.addWidget(frame)
|
layout.addWidget(frame)
|
||||||
self.markersTable = QTableWidget()
|
#self.markersTable.itemSelectionChanged.connect(self.selection_changed)
|
||||||
self.markersTable.setSelectionMode(QAbstractItemView.SingleSelection)
|
#self.markersTable.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||||
self.markersTable.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
||||||
self.markersTable.setItemDelegate(MarkerDelegate(self))
|
|
||||||
|
|
||||||
# self.markersTable.horizontalHeader().setDefaultSectionSize(80)
|
#deleteRowAction = QAction("Delete this row", self)
|
||||||
self.markersTable.setColumnCount(5)
|
#deleteRowAction.triggered.connect(self.delete_selected)
|
||||||
self.markersTable.setHorizontalHeaderLabels(("Fiducial?", "orig X", "orig Y", "X", "Y"))
|
#self.markersTable.addAction(deleteRowAction)
|
||||||
hh=self.markersTable.horizontalHeader()
|
|
||||||
hh.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
|
||||||
hh.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
|
||||||
hh.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
|
||||||
hh.setSectionResizeMode(3, QHeaderView.ResizeToContents)
|
|
||||||
hh.setSectionResizeMode(4, QHeaderView.ResizeToContents)
|
|
||||||
hh.setSectionResizeMode(QHeaderView.Stretch)
|
|
||||||
|
|
||||||
self.markersTable.itemSelectionChanged.connect(self.selection_changed)
|
#moveRequestAction = QAction("Move Here", self)
|
||||||
|
#moveRequestAction.triggered.connect(self.request_stage_movement)
|
||||||
|
#self.markersTable.addAction(moveRequestAction)
|
||||||
|
|
||||||
self.markersTable.setContextMenuPolicy(Qt.ActionsContextMenu)
|
#layout.addWidget(self.markersTable, stretch=2)
|
||||||
|
#self.connect_all_signals()
|
||||||
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._yamlFn=fn=os.path.expanduser('~/.config/PSI/SwissMX.yaml')
|
||||||
|
|
||||||
@@ -259,15 +216,74 @@ class WndFixTarget(QWidget):
|
|||||||
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)
|
||||||
|
#Context menu: by default the function
|
||||||
|
# def contextMenuEvent(self, event) is called... but this requests to overload the function
|
||||||
|
# and to build an own context menu
|
||||||
|
# much simpler is to use Qt.ActionsContextMenu
|
||||||
|
# and to handle the context in the parent plass
|
||||||
|
|
||||||
|
tree.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||||
|
|
||||||
|
act = QAction("delete", self)
|
||||||
|
act.triggered.connect(self.tree_ctx_delete)
|
||||||
|
tree.addAction(act)
|
||||||
|
|
||||||
|
act = QAction("center in view", self)
|
||||||
|
act.triggered.connect(self.tree_ctx_center)
|
||||||
|
tree.addAction(act)
|
||||||
|
|
||||||
|
#contextMenuEvent
|
||||||
|
def tree_get_path(self):
|
||||||
|
path=[]
|
||||||
|
it=self._tree.currentItem()
|
||||||
|
while it:
|
||||||
|
d=it.data(0,0)
|
||||||
|
try:
|
||||||
|
d=int(d)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if d!= '':
|
||||||
|
path.append(d)
|
||||||
|
it=it.parent()
|
||||||
|
return path
|
||||||
|
|
||||||
|
def tree_ctx_delete(self):
|
||||||
|
app=QApplication.instance()
|
||||||
|
path=self.tree_get_path()
|
||||||
|
if len(path)==1:
|
||||||
|
try:
|
||||||
|
wnd=app._mainWnd
|
||||||
|
except AttributeError:
|
||||||
|
_log.info('_mainWnd not handeled')
|
||||||
|
else:
|
||||||
|
vb=wnd.vb
|
||||||
|
grp=wnd._goTracked
|
||||||
|
go=grp.childItems()[path[0]]
|
||||||
|
vb.removeItem(go)
|
||||||
|
data=grp.childItems()
|
||||||
|
if not len(data):
|
||||||
|
grp.setFlag(grp.ItemHasNoContents)
|
||||||
|
self._tree.setData(data)
|
||||||
|
|
||||||
|
def tree_ctx_center(self):
|
||||||
|
app=QApplication.instance()
|
||||||
|
path=self.tree_get_path()
|
||||||
|
if len(path)==1:
|
||||||
|
try:
|
||||||
|
wnd=app._mainWnd
|
||||||
|
except AttributeError:
|
||||||
|
_log.info('_mainWnd not handeled')
|
||||||
|
else:
|
||||||
|
vb=wnd.vb
|
||||||
|
grp=wnd._goTracked
|
||||||
|
go=grp.childItems()[path[0]]
|
||||||
|
vb.autoRange(items=(go,))
|
||||||
|
#r1=vb.viewRect()
|
||||||
|
#r2=vb.itemBoundingRect(go)
|
||||||
|
#if not r1.intersects(r2):
|
||||||
|
|
||||||
def load_file(self, filename=None):
|
def load_file(self, filename=None):
|
||||||
app = QApplication.instance()
|
app = QApplication.instance()
|
||||||
#cfg = app._cfg
|
|
||||||
#logger = logging.getLogger("preloc.loadMarkers")
|
|
||||||
#def_folder = join(folders.pgroup_folder, "preloc_sheets") #ZAC: orig. code
|
|
||||||
#def_folder =''
|
|
||||||
#data_folder = cfg.value("folders/last_prelocation_folder", def_folder)
|
|
||||||
data_folder=''
|
|
||||||
if filename is None:
|
if filename is None:
|
||||||
filename, _ = QFileDialog.getOpenFileName(self,"Load data file",None,
|
filename, _ = QFileDialog.getOpenFileName(self,"Load data file",None,
|
||||||
"json files (*.json);;all files (*)",)
|
"json files (*.json);;all files (*)",)
|
||||||
@@ -282,14 +298,7 @@ class WndFixTarget(QWidget):
|
|||||||
data=json.load(f,object_hook=MyJsonDecoder)
|
data=json.load(f,object_hook=MyJsonDecoder)
|
||||||
else:
|
else:
|
||||||
raise(IOError('unsupported file type'))
|
raise(IOError('unsupported file type'))
|
||||||
#elif ext=='yaml':
|
|
||||||
# with open(filename, 'r') as f:
|
|
||||||
# data = yaml.load(f)
|
|
||||||
#elif ext=='pkl':
|
|
||||||
# with open(filename, 'rb') as f:
|
|
||||||
# data=pickle.load(f)
|
|
||||||
|
|
||||||
#self._data=data
|
|
||||||
self._tree.setData(data)
|
self._tree.setData(data)
|
||||||
try:
|
try:
|
||||||
wnd=app._mainWnd
|
wnd=app._mainWnd
|
||||||
@@ -399,6 +408,14 @@ class WndFixTarget(QWidget):
|
|||||||
# pickle.dump(self._data, f)
|
# pickle.dump(self._data, f)
|
||||||
#print(self._data)
|
#print(self._data)
|
||||||
|
|
||||||
|
|
||||||
|
def dump_data(self):
|
||||||
|
print(self._data)
|
||||||
|
#for ref, x, y, cx, cy, ox, oy in self.get_data():
|
||||||
|
# print(f"fiducial:{ref} [{x}, {y}, {cx}, {cy}]")
|
||||||
|
|
||||||
|
# **********3 OBSOLETE
|
||||||
|
|
||||||
def delete_selected(self):
|
def delete_selected(self):
|
||||||
row = self._current_row
|
row = self._current_row
|
||||||
try:
|
try:
|
||||||
@@ -418,337 +435,6 @@ class WndFixTarget(QWidget):
|
|||||||
self.selectedRowChanged.emit(row)
|
self.selectedRowChanged.emit(row)
|
||||||
_log.debug("selection changed: current row {}".format(row))
|
_log.debug("selection changed: current row {}".format(row))
|
||||||
|
|
||||||
def connect_all_signals(self):
|
|
||||||
self.prefixSelected.connect(lambda t: self._label_prefix.setText(t))
|
|
||||||
self.dataFileLoaded.connect(lambda t: self._label_datafile.setText(t))
|
|
||||||
|
|
||||||
def markerItemChanged(self, item):
|
|
||||||
print(item.row(), item.column())
|
|
||||||
|
|
||||||
def set_fiducial_coords(self, camx, camy, gx, gy):
|
|
||||||
tbl = self.markersTable
|
|
||||||
row = self._current_row
|
|
||||||
try:
|
|
||||||
row += 0
|
|
||||||
except:
|
|
||||||
_log.warning("select a row first")
|
|
||||||
QMessageBox.warning(self,"Select a marker first","You must select a marker first before updating its goniometer position",)
|
|
||||||
return
|
|
||||||
|
|
||||||
origx = tbl.item(row, ORIGINAL_X).data(RoleOriginalCoord_X)
|
|
||||||
origy = tbl.item(row, ORIGINAL_Y).data(RoleOriginalCoord_Y)
|
|
||||||
|
|
||||||
item = tbl.item(row, DATA_ITEM)
|
|
||||||
item.setData(RoleCameraCoord_X, camx)
|
|
||||||
item.setData(RoleCameraCoord_Y, camy)
|
|
||||||
item.setData(RoleGoniometerCoord_X, gx)
|
|
||||||
item.setData(RoleGoniometerCoord_Y, gy)
|
|
||||||
# item.setData(RoleOriginalCoord_X, origx)
|
|
||||||
# item.setData(RoleOriginalCoord_Y, origy)
|
|
||||||
# logger.debug(': [{}] = Original: {}, {} | Camera: {}, {} | Gonio: {}, {}'.format(1+row, origx, origy, camx, camy, gx, gy))
|
|
||||||
logger.debug(f": [{1+row}] = Original: {origx}, {origy} | Camera: {camx}, {camy} | Gonio: {gx}, {gy}")
|
|
||||||
|
|
||||||
tbl.item(row, GONIO_X).setData(Qt.DisplayRole, f"{gx:8.5f} mm\n{camx:8.1f} px")
|
|
||||||
tbl.item(row, GONIO_Y).setData(Qt.DisplayRole, f"{gy:8.5f} mm\n{camy:8.1f} px")
|
|
||||||
|
|
||||||
# mark row as a fiducial
|
|
||||||
tbl.item(row, 0).setCheckState(Qt.Checked)
|
|
||||||
tbl.item(row, 0).setData(Qt.UserRole, True)
|
|
||||||
tbl.selectRow(row + 1)
|
|
||||||
self.prelocatedDataUpdated.emit()
|
|
||||||
|
|
||||||
def set_selected_gonio_coords(self, xy):
|
|
||||||
tbl = self.markersTable
|
|
||||||
row = self._current_row
|
|
||||||
try:
|
|
||||||
row += 0
|
|
||||||
except:
|
|
||||||
_log.warning("select a row first")
|
|
||||||
QMessageBox.warning(self,"Select a marker first","You must select a marker first before updating its goniometer position",)
|
|
||||||
return
|
|
||||||
|
|
||||||
for n, v in enumerate(xy):
|
|
||||||
idx = 3 + n
|
|
||||||
tbl.setCurrentCell(row, idx) # gonio X
|
|
||||||
_log.debug("item: [{},{}] = {}".format(row, idx, v))
|
|
||||||
item = tbl.currentItem()
|
|
||||||
item.setData(Qt.EditRole, "{:.3f}".format(v))
|
|
||||||
item.setData(Qt.UserRole, v)
|
|
||||||
|
|
||||||
# mark row as a fiducial
|
|
||||||
tbl.setCurrentCell(row, 0)
|
|
||||||
tbl.currentItem().setCheckState(Qt.Checked)
|
|
||||||
tbl.currentItem().setData(Qt.UserRole, True)
|
|
||||||
|
|
||||||
def set_data_goniometer(self, row: int, xy):
|
|
||||||
tbl = self.markersTable
|
|
||||||
|
|
||||||
row = self._current_row
|
|
||||||
try:
|
|
||||||
row += 0
|
|
||||||
except:
|
|
||||||
_log.warning("select a row first")
|
|
||||||
QMessageBox.warning(self,"Select a marker first","You must select a marker first before updating its goniometer position",)
|
|
||||||
return
|
|
||||||
|
|
||||||
for n, v in enumerate(xy):
|
|
||||||
idx = 3 + n
|
|
||||||
tbl.setCurrentCell(row, idx) # gonio X
|
|
||||||
item = tbl.currentItem()
|
|
||||||
item.setData(Qt.EditRole, "{:.3f}".format(v))
|
|
||||||
item.setData(Qt.UserRole, v)
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def set_draw_crystal_marks(self, val):
|
|
||||||
logger.info(f"{'' if val else 'not '}drawing crystal markers")
|
|
||||||
self._draw_crystal_marks = val
|
|
||||||
|
|
||||||
@pyqtSlot(int)
|
|
||||||
def set_collect_fiducials(self, val):
|
|
||||||
logger.info(f"{'' if val else 'not '}collecting fiducials")
|
|
||||||
self._collect_fiducials = val
|
|
||||||
|
|
||||||
def get_collection_targets(self):
|
|
||||||
return self.get_data(fiducials=self._collect_fiducials)
|
|
||||||
|
|
||||||
|
|
||||||
def get_data(self, fiducials=True, crystals=True, as_numpy=False):
|
|
||||||
"""return a list of tuples with all defined data
|
|
||||||
|
|
||||||
[
|
|
||||||
(is_fiducial(boolean), x, y, gonio_x, gonio_y),...
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
data = []
|
|
||||||
item = self.markersTable.item
|
|
||||||
|
|
||||||
for row in range(self.markersTable.rowCount()):
|
|
||||||
is_fiducial = Qt.Checked == item(row, 0).checkState()
|
|
||||||
ditem = item(row, DATA_ITEM)
|
|
||||||
|
|
||||||
x = ditem.data(RoleGoniometerCoord_X)
|
|
||||||
y = ditem.data(RoleGoniometerCoord_Y)
|
|
||||||
cx = ditem.data(RoleCameraCoord_X)
|
|
||||||
cy = ditem.data(RoleCameraCoord_Y)
|
|
||||||
origx = ditem.data(RoleOriginalCoord_X)
|
|
||||||
origy = ditem.data(RoleOriginalCoord_Y)
|
|
||||||
|
|
||||||
if is_fiducial and fiducials:
|
|
||||||
data.append([is_fiducial, x, y, cx, cy, origx, origy])
|
|
||||||
if not is_fiducial and crystals:
|
|
||||||
data.append([is_fiducial, x, y, cx, cy, origx, origy])
|
|
||||||
|
|
||||||
if as_numpy:
|
|
||||||
data = np.asarray(data)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_original_coordinates(self, fiducials=True):
|
|
||||||
"""return a numpy array with the original prelocated coordinates of the fiducial entries"""
|
|
||||||
data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True)
|
|
||||||
data = data[:, 5:]
|
|
||||||
zeros = np.zeros(data.shape)
|
|
||||||
zeros[:, 1] = 1
|
|
||||||
return np.concatenate((data, zeros), axis=1)
|
|
||||||
|
|
||||||
def get_goniometer_coordinates(self, fiducials=True):
|
|
||||||
"""return a numpy array with the goniometer coordinates of the fiducial entries"""
|
|
||||||
data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True)
|
|
||||||
data = data[:, 1:3]
|
|
||||||
zeros = np.zeros(data.shape)
|
|
||||||
zeros[:, 1] = 1
|
|
||||||
return np.concatenate((data, zeros), axis=1)
|
|
||||||
|
|
||||||
def get_camera_coordinates(self, fiducials=True):
|
|
||||||
"""return a numpy array with the goniometer coordinates of the fiducial entries"""
|
|
||||||
data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True)
|
|
||||||
data = data[:, 3:5]
|
|
||||||
zeros = np.zeros(data.shape)
|
|
||||||
zeros[:, 1] = 1
|
|
||||||
return np.concatenate((data, zeros), axis=1)
|
|
||||||
|
|
||||||
def dump_matrix(self, M):
|
|
||||||
scale, shear, angles, translate, perspective = tfs.decompose_matrix(M)
|
|
||||||
angles_deg = [a * 180 / np.pi for a in angles]
|
|
||||||
|
|
||||||
print("Transformation matrix Aerotech => SwissMX")
|
|
||||||
print(M)
|
|
||||||
print((" scale {:9.4f} {:9.4f} {:9.4f}".format(*scale)))
|
|
||||||
print((" shear {:9.4f} {:9.4f} {:9.4f}".format(*shear)))
|
|
||||||
print((" angles rad {:9.4f} {:9.4f} {:9.4f}".format(*angles)))
|
|
||||||
print((" angles deg {:9.4f} {:9.4f} {:9.4f}".format(*angles_deg)))
|
|
||||||
print((" translate {:9.4f} {:9.4f} {:9.4f}".format(*translate)))
|
|
||||||
print(("perspective {:9.4f} {:9.4f} {:9.4f}".format(*perspective)))
|
|
||||||
|
|
||||||
def transform_non_fiducials_in_model(self):
|
|
||||||
forg = self.get_original_coordinates(fiducials=True)
|
|
||||||
fgon = self.get_goniometer_coordinates(fiducials=True)
|
|
||||||
fcam = self.get_camera_coordinates(fiducials=True)
|
|
||||||
|
|
||||||
gmat = sort_cmass_3d(fgon)
|
|
||||||
omat = sort_cmass_3d(forg)
|
|
||||||
|
|
||||||
try:
|
|
||||||
M_org2gon = tfs.superimposition_matrix(omat.T, gmat.T, scale=True)
|
|
||||||
M_org2cam = tfs.superimposition_matrix(forg.T, fcam.T, scale=True)
|
|
||||||
except:
|
|
||||||
QMessageBox.warning(self.parent(), title="failed to find superimposition matrix", text="Failed to find superimposition matrix.\n\tPlease try again.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# scale, shear, angles, translate, perspective = tfs.decompose_matrix(M_org2gon)
|
|
||||||
|
|
||||||
org_data = self.get_original_coordinates(fiducials=False)
|
|
||||||
|
|
||||||
gon_data = np.dot(M_org2gon, org_data.T)
|
|
||||||
cam_data = np.dot(M_org2cam, org_data.T)
|
|
||||||
|
|
||||||
tbl = self.markersTable
|
|
||||||
num_fiducials = forg.shape[0]
|
|
||||||
|
|
||||||
gon_data = (gon_data.T)[:, 0:2] # only X,Y matters
|
|
||||||
cam_data = (cam_data.T)[:, 0:2] # only X,Y matters
|
|
||||||
combined = np.concatenate((gon_data, cam_data), axis=1)
|
|
||||||
|
|
||||||
item = self.markersTable.item # function alias
|
|
||||||
for row, data in enumerate(
|
|
||||||
combined, num_fiducials
|
|
||||||
): # enumeration starts at *num_fiducials*
|
|
||||||
gx, gy, cx, cy = data
|
|
||||||
ditem = item(row, DATA_ITEM)
|
|
||||||
ditem.setData(RoleCameraCoord_X, cx)
|
|
||||||
ditem.setData(RoleCameraCoord_Y, cy)
|
|
||||||
ditem.setData(RoleGoniometerCoord_X, gx)
|
|
||||||
ditem.setData(RoleGoniometerCoord_Y, gy)
|
|
||||||
item(row, GONIO_X).setData(Qt.DisplayRole, f"{gx:8.5f} mm\n{cx:8.1f} px")
|
|
||||||
item(row, GONIO_Y).setData(Qt.DisplayRole, f"{gy:8.5f} mm\n{cy:8.1f} px")
|
|
||||||
self._xtals_transformed = True
|
|
||||||
self.prelocatedDataUpdated.emit()
|
|
||||||
|
|
||||||
def request_stage_movement(self):
|
|
||||||
logger = logging.getLogger("preloc.move_stage")
|
|
||||||
row = self._current_row
|
|
||||||
x = self.markersTable.item(row, DATA_ITEM).data(RoleGoniometerCoord_X)
|
|
||||||
y = self.markersTable.item(row, DATA_ITEM).data(RoleGoniometerCoord_Y)
|
|
||||||
logger.info(f"request move gonio to {x:.3f}, {y:.3f} mm")
|
|
||||||
self.moveFastStageRequest.emit(x, y)
|
|
||||||
|
|
||||||
def dump_numpy(self):
|
|
||||||
R = tfs.random_rotation_matrix(np.random.random(3))
|
|
||||||
d = self.get_goniometer_coordinates()
|
|
||||||
print("dumping")
|
|
||||||
print(d)
|
|
||||||
dR = np.dot(R, d)
|
|
||||||
print(dR.T)
|
|
||||||
|
|
||||||
def get_fiducials(self, as_numpy=False):
|
|
||||||
return self.get_data(crystals=False, as_numpy=as_numpy)
|
|
||||||
|
|
||||||
def get_crystals(self, as_numpy=False):
|
|
||||||
return self.get_data(fiducials=False, as_numpy=as_numpy)
|
|
||||||
|
|
||||||
def dump_data(self):
|
|
||||||
print(self._data)
|
|
||||||
#for ref, x, y, cx, cy, ox, oy in self.get_data():
|
|
||||||
# print(f"fiducial:{ref} [{x}, {y}, {cx}, {cy}]")
|
|
||||||
|
|
||||||
def append_data(self, data):
|
|
||||||
"""append data (a list of values) to the model
|
|
||||||
|
|
||||||
len(data) == 2 => (X, Y) from prelocated coordinate
|
|
||||||
len(data) == 4 => (X, Y, GX, GY) plus gonio coordinates
|
|
||||||
len(data) == 5 => (fiducial?, X, Y, GX, GY) plus fiducial
|
|
||||||
"""
|
|
||||||
row = self.markersTable.rowCount()
|
|
||||||
self.markersTable.setRowCount(row + 1)
|
|
||||||
|
|
||||||
data = list(data)
|
|
||||||
if len(data) == 2:
|
|
||||||
data.extend([0, 0])
|
|
||||||
if len(data) == 4:
|
|
||||||
data.insert(0, False) # fiducial flag
|
|
||||||
self.addSingleMarker(row, data)
|
|
||||||
self.prelocatedDataUpdated.emit()
|
|
||||||
|
|
||||||
def clearMarkers(self):
|
|
||||||
self.markersTable.setRowCount(0)
|
|
||||||
self.markersDeleted.emit()
|
|
||||||
|
|
||||||
def generate_random_data(self):
|
|
||||||
import io
|
|
||||||
|
|
||||||
data = io.StringIO()
|
|
||||||
npoints = self._num_random_points.value()
|
|
||||||
for n in range(npoints):
|
|
||||||
x, y, a, b = (
|
|
||||||
np.random.randint(0, 2000),
|
|
||||||
np.random.randint(0, 2000),
|
|
||||||
np.random.randint(-4000, 4000) / 1000.,
|
|
||||||
np.random.randint(-4000, 4000) / 1000.,
|
|
||||||
)
|
|
||||||
data.write("{}\t{}\t{}\t{}\n".format(x, y, a, b))
|
|
||||||
data.seek(0)
|
|
||||||
data.name = "random.csv"
|
|
||||||
self.loadMarkers(data)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def addSingleMarker(self, row, marker):
|
|
||||||
is_fiducial, origx, origy, gx, gy = marker
|
|
||||||
_log.debug(f": [{1+row}] | Original: {origx}, {origy} | Gonio: {gx}, {gy}")
|
|
||||||
item0 = QTableWidgetItem()
|
|
||||||
item0.setData(Qt.UserRole, is_fiducial)
|
|
||||||
item0.setFlags(item0.flags() & ~Qt.ItemIsEditable)
|
|
||||||
item0.setCheckState(Qt.Checked if is_fiducial else Qt.Unchecked)
|
|
||||||
item0.setTextAlignment(Qt.AlignCenter)
|
|
||||||
|
|
||||||
item1 = QTableWidgetItem("{:.1f}".format(origx))
|
|
||||||
item1.setTextAlignment(Qt.AlignRight)
|
|
||||||
|
|
||||||
item2 = QTableWidgetItem("{:.1f}".format(origy))
|
|
||||||
item2.setTextAlignment(Qt.AlignRight)
|
|
||||||
|
|
||||||
item3 = QTableWidgetItem("{:.3f} mm".format(gx))
|
|
||||||
item3.setFlags(item3.flags() & ~Qt.ItemIsEditable)
|
|
||||||
item3.setTextAlignment(Qt.AlignRight)
|
|
||||||
|
|
||||||
item4 = QTableWidgetItem("{:.3f} mm".format(gy))
|
|
||||||
item4.setFlags(item4.flags() & ~Qt.ItemIsEditable)
|
|
||||||
item4.setTextAlignment(Qt.AlignRight)
|
|
||||||
|
|
||||||
self.markersTable.setItem(row, 0, item0)
|
|
||||||
self.markersTable.setItem(row, ORIGINAL_X, item1)
|
|
||||||
self.markersTable.setItem(row, ORIGINAL_Y, item2)
|
|
||||||
self.markersTable.setItem(row, GONIO_X, item3)
|
|
||||||
self.markersTable.setItem(row, GONIO_Y, item4)
|
|
||||||
self.markerAdded.emit(is_fiducial, [origx, origy, gx, gy])
|
|
||||||
|
|
||||||
item = self.markersTable.item(row, DATA_ITEM)
|
|
||||||
item.setData(RoleCameraCoord_X, origx) # initially set to original
|
|
||||||
item.setData(RoleCameraCoord_Y, origy) # initially set to original
|
|
||||||
item.setData(RoleGoniometerCoord_X, gx)
|
|
||||||
item.setData(RoleGoniometerCoord_Y, gy)
|
|
||||||
item.setData(RoleOriginalCoord_X, origx)
|
|
||||||
item.setData(RoleOriginalCoord_Y, origy)
|
|
||||||
|
|
||||||
"""
|
|
||||||
Signals QTableWidget
|
|
||||||
void cellActivated(int row, int column)
|
|
||||||
void cellChanged(int row, int column)
|
|
||||||
void cellClicked(int row, int column)
|
|
||||||
void cellDoubleClicked(int row, int column)
|
|
||||||
void cellEntered(int row, int column)
|
|
||||||
void cellPressed(int row, int column)
|
|
||||||
void currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
|
|
||||||
void currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
|
|
||||||
void itemActivated(QTableWidgetItem *item)
|
|
||||||
void itemChanged(QTableWidgetItem *item)
|
|
||||||
void itemClicked(QTableWidgetItem *item)
|
|
||||||
void itemDoubleClicked(QTableWidgetItem *item)
|
|
||||||
void itemEntered(QTableWidgetItem *item)
|
|
||||||
void itemPressed(QTableWidgetItem *item)
|
|
||||||
void itemSelectionChanged()
|
|
||||||
"""
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,9 @@ _log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
from PyQt5 import QtCore, QtGui
|
from PyQt5 import QtCore, QtGui
|
||||||
from PyQt5.QtCore import QSettings
|
from PyQt5.QtCore import QSettings
|
||||||
from PyQt5.QtWidgets import QApplication, QMainWindow #QLineEdit, QWidget, QGridLayout, QLabel
|
from PyQt5.QtWidgets import QApplication, QMainWindow
|
||||||
import json
|
import json
|
||||||
import pyqtgraph as pg
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import GenericDialog
|
|
||||||
|
|
||||||
#from pyqtgraph.Qt import QtCore, QtGui
|
|
||||||
|
|
||||||
class MyJsonEncoder(json.JSONEncoder):
|
class MyJsonEncoder(json.JSONEncoder):
|
||||||
""" Special json encoder for numpy types """
|
""" Special json encoder for numpy types """
|
||||||
@@ -60,26 +56,20 @@ class AppCfg(QSettings):
|
|||||||
DT_MISC="deltatau/miscellaneous"
|
DT_MISC="deltatau/miscellaneous"
|
||||||
# ---------- OBSOLETE ??? ----------
|
# ---------- OBSOLETE ??? ----------
|
||||||
#ZOOM_BUTTONS="sample_viewing/zoom_buttons"
|
#ZOOM_BUTTONS="sample_viewing/zoom_buttons"
|
||||||
|
#SKIP_ESCAPE_TRANSITIONS_IF_SAFE="escape/skip_transitions_if_safe"
|
||||||
SKIP_ESCAPE_TRANSITIONS_IF_SAFE="escape/skip_transitions_if_safe"
|
#CRYOJET_MOTION_ENABLED="cryojet/motion_enabled"
|
||||||
|
#CRYOJET_NOZZLE_OUT="cryojet/nozzle_out"
|
||||||
CRYOJET_MOTION_ENABLED="cryojet/motion_enabled"
|
#CRYOJET_NOZZLE_IN="cryojet/nozzle_in"
|
||||||
CRYOJET_NOZZLE_OUT="cryojet/nozzle_out"
|
|
||||||
CRYOJET_NOZZLE_IN="cryojet/nozzle_in"
|
|
||||||
|
|
||||||
#DELTATAU_HOST="deltatau/host"
|
#DELTATAU_HOST="deltatau/host"
|
||||||
#DELTATAU_SHOW_PLOTS="deltatau/show_plots"
|
#DELTATAU_SHOW_PLOTS="deltatau/show_plots"
|
||||||
DELTATAU_OMEGACOS="deltatau/omegacos"
|
#DELTATAU_OMEGACOS="deltatau/omegacos"
|
||||||
DELTATAU_SORT_POINTS="deltatau/sort_points"
|
#DELTATAU_SORT_POINTS="deltatau/sort_points"
|
||||||
#DELTATAU_VELOCITY_SCALE="deltatau/velocity_scale"
|
#DELTATAU_VELOCITY_SCALE="deltatau/velocity_scale"
|
||||||
|
#CAMERA_TRANSFORMATIONS="camera/transformations"
|
||||||
CAMERA_TRANSFORMATIONS="camera/transformations"
|
#CAMERA_ZOOM_TO_PPM="camera/zoom_to_ppm"
|
||||||
CAMERA_ZOOM_TO_PPM="camera/zoom_to_ppm"
|
#EXPERIMENT_PGROUP="experiment/pgroup"
|
||||||
|
#EXPERIMENT_UID="experiment/uid"
|
||||||
EXPERIMENT_PGROUP="experiment/pgroup"
|
#ACTIVATE_PULSE_PICKER="scanning/activate_pulse_picker"
|
||||||
EXPERIMENT_UID="experiment/uid"
|
|
||||||
|
|
||||||
ACTIVATE_PULSE_PICKER="scanning/activate_pulse_picker"
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(AppCfg, self).__init__("PSI", "SwissMX")
|
super(AppCfg, self).__init__("PSI", "SwissMX")
|
||||||
@@ -220,6 +210,8 @@ from pyqtgraph.parametertree import Parameter, ParameterTree
|
|||||||
class WndParameter(QMainWindow):
|
class WndParameter(QMainWindow):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(WndParameter, self).__init__(parent)
|
super(WndParameter, self).__init__(parent)
|
||||||
|
|
||||||
|
self.setWindowTitle('SwissMX Preferences')
|
||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
cfg=app._cfg
|
cfg=app._cfg
|
||||||
#GBL_FLD_SCR_SHOT="global/folder_screenshot"
|
#GBL_FLD_SCR_SHOT="global/folder_screenshot"
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class Deltatau:
|
|||||||
try:
|
try:
|
||||||
self._comm=comm=PPComm(**param,timeout=2.0)
|
self._comm=comm=PPComm(**param,timeout=2.0)
|
||||||
self._gather=gather=Gather(comm)
|
self._gather=gather=Gather(comm)
|
||||||
except socket.timeout as e:
|
except (socket.timeout,socket.gaierror) as e:
|
||||||
_log.critical(f'can not connect to deltatau:"{host}" -> {e}')
|
_log.critical(f'can not connect to deltatau:"{host}" -> {e}')
|
||||||
self._comm=comm=None
|
self._comm=comm=None
|
||||||
self._gather=gather=None
|
self._gather=gather=None
|
||||||
|
|||||||
222
swissmx.py
222
swissmx.py
@@ -45,20 +45,10 @@ ts=timestamp()
|
|||||||
ts.log('Import part 1/8:')
|
ts.log('Import part 1/8:')
|
||||||
import sys, os, time
|
import sys, os, time
|
||||||
import json, re
|
import json, re
|
||||||
import random, signal,threading
|
import random, signal, subprocess
|
||||||
|
|
||||||
import matplotlib as mpl
|
import matplotlib as mpl
|
||||||
mpl.use('Qt5Agg') # needed to avoid blocking of ui !
|
mpl.use('Qt5Agg') # needed to avoid blocking of ui !
|
||||||
|
|
||||||
#import Wigis #ZAC: orig. code
|
|
||||||
#import jungfrau_widget #ZAC: orig. code
|
|
||||||
#import bernina_pulse_picker #ZAC: orig. code
|
|
||||||
#import storage #ZAC: orig. code
|
|
||||||
#from zmq_escape import zescape #ZAC: orig. code
|
|
||||||
#from helicalscan import HelicalScanGui #ZAC: orig. code
|
|
||||||
# publisher = pubber.Publisher()
|
|
||||||
|
|
||||||
|
|
||||||
TASK_JUNGFRAU_SETTINGS = "jungfrau_settings"
|
TASK_JUNGFRAU_SETTINGS = "jungfrau_settings"
|
||||||
TASK_SETUP_GEOMETRY_CALIB = "geometry_calib"
|
TASK_SETUP_GEOMETRY_CALIB = "geometry_calib"
|
||||||
TASK_SETUP_PPM_CALIBRATION_TBOX = "ppm_calibration_tbox"
|
TASK_SETUP_PPM_CALIBRATION_TBOX = "ppm_calibration_tbox"
|
||||||
@@ -78,17 +68,12 @@ import ModuleFixTarget
|
|||||||
import PrelocatedCoordinatesModel # ZAC: orig. code
|
import PrelocatedCoordinatesModel # ZAC: orig. code
|
||||||
from EmblModule import EmblWidget #ZAC: orig. code
|
from EmblModule import EmblWidget #ZAC: orig. code
|
||||||
from HelicalTable import HelicalTableWidget #ZAC: orig. code
|
from HelicalTable import HelicalTableWidget #ZAC: orig. code
|
||||||
#from Wigis import Spinner, Checkbox #ZAC: orig. code
|
|
||||||
#from exceptions import * #ZAC: orig. code
|
|
||||||
#import qoptic #ZAC: orig. code
|
|
||||||
#import mx_swissfel #ZAC: orig. code
|
|
||||||
#swissfel = mx_swissfel.SwissFELMachine() #ZAC: orig. code
|
|
||||||
#from bernina_pulse_picker import pulsePicker #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
|
from PyQt5.QtCore import Qt, pyqtSlot, QSize, QRegExp, pyqtSignal, QObject, QThread, QRectF,QT_VERSION_STR
|
||||||
from PyQt5.QtGui import QKeySequence, QPixmap, QRegExpValidator, QFont
|
from PyQt5.QtGui import QKeySequence, QPixmap, QRegExpValidator, QFont
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAction, QApplication, QDoubleSpinBox, QFileDialog, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
|
QAction, QApplication, QDoubleSpinBox, QFileDialog, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
|
||||||
@@ -96,20 +81,11 @@ from PyQt5.QtWidgets import (
|
|||||||
QSplashScreen, QTextBrowser, QToolBox, QVBoxLayout, QWidget,)
|
QSplashScreen, QTextBrowser, 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 CustomROI as CstROI
|
|
||||||
import pyqtUsrObj as UsrGO
|
import pyqtUsrObj as UsrGO
|
||||||
|
|
||||||
#from CustomROI import BeamMark, Grid, CrystalCircle #ZAC: orig. code
|
|
||||||
|
|
||||||
#from GenericDialog import GenericDialog #ZAC: orig. code
|
|
||||||
#from dialogs.PreferencesDialog import PreferencesDialog #ZAC: orig. code
|
|
||||||
#from epics_widgets import zoom #ZAC: orig. code
|
|
||||||
from epics_widgets.MotorTweak import MotorTweak
|
from epics_widgets.MotorTweak import MotorTweak
|
||||||
from epics_widgets.SmaractMotorTweak import SmaractMotorTweak
|
from epics_widgets.SmaractMotorTweak import SmaractMotorTweak
|
||||||
from epics_widgets.SimMotorTweak import SimMotorTweak
|
from epics_widgets.SimMotorTweak import SimMotorTweak
|
||||||
ts.log('Import part 5/8:')
|
ts.log('Import part 5/8:')
|
||||||
#import matplotlib as mpl
|
|
||||||
#import matplotlib.pyplot as plt
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
np.set_printoptions(suppress=True,linewidth=196)
|
np.set_printoptions(suppress=True,linewidth=196)
|
||||||
import pyqtgraph as pg
|
import pyqtgraph as pg
|
||||||
@@ -128,47 +104,24 @@ import deltatau
|
|||||||
import detector
|
import detector
|
||||||
ts.log('Import part 8/8:')
|
ts.log('Import part 8/8:')
|
||||||
|
|
||||||
|
|
||||||
#_URL = "http://PC12288:8080"
|
|
||||||
# import TellClient
|
|
||||||
# tell = TellClient.TellClient(_URL)
|
|
||||||
|
|
||||||
#import eventer #ZAC: orig. code
|
|
||||||
#from detector_control import jungfrau_detector #ZAC: orig. code
|
|
||||||
#from findxtal import findObj #ZAC: orig. code
|
|
||||||
|
|
||||||
#if simulated: #ZAC: orig. code #ZAC: orig. code
|
|
||||||
# _log.warning("simulation mode enabled")
|
|
||||||
# qoptic_zoom = qoptic.FeturaClientBogus()
|
|
||||||
#else:
|
|
||||||
# qoptic_zoom = qoptic.FeturaClient()
|
|
||||||
|
|
||||||
#from epics_widgets import MotorTweak
|
|
||||||
|
|
||||||
|
|
||||||
#user = getpass.getuser() #ZAC: orig. code
|
|
||||||
#home = os.path.expanduser("~")
|
|
||||||
#just_quit = user in ["e10003", "gac-esbmx"]
|
|
||||||
|
|
||||||
#folders = storage.Folders() #ZAC: orig. code
|
|
||||||
|
|
||||||
#from deltatau import DeltaTau, shapepath, helical, DebugPlot #ZAC: orig. code
|
|
||||||
#delta_tau = DeltaTau() #ZAC: orig. code
|
|
||||||
|
|
||||||
#BROKER_SERVER = "127.0.0.1" #ZAC: orig. code
|
|
||||||
#BROKER_PORT = 61613 #ZAC: orig. code
|
|
||||||
|
|
||||||
# sample_camera = camera.camera_server(basename="SARES20-PROF142-M1")
|
|
||||||
|
|
||||||
#_log.info(f"connecting to microscope to camera server: {appsconf['microscope']['sample_camera']['pv_prefix']} ")
|
|
||||||
#sample_camera = camera.camera_server(basename=appsconf["microscope"]["sample_camera"]["pv_prefix"]) #ZAC: orig. code
|
|
||||||
|
|
||||||
def tdstamp():
|
def tdstamp():
|
||||||
return time.strftime("%Y%m%dH%H%M%S")
|
return time.strftime("%Y%m%dH%H%M%S")
|
||||||
|
|
||||||
def datestamp():
|
def datestamp():
|
||||||
return time.strftime("%Y%m%d")
|
return time.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
def get_version(path='.'):
|
||||||
|
#sys.stdout.write('getVersion() -> using git command -> ')
|
||||||
|
p = subprocess.Popen(f'git -C {path} describe --match ''*.*.*'' --long --tags --dirty', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
retval = p.wait()
|
||||||
|
res=p.stdout.readline()
|
||||||
|
p.stdout.close()
|
||||||
|
#res=res.decode()[1:-1].split('-',2)
|
||||||
|
res=res.decode()[:-1].split('-',2)
|
||||||
|
ver='.'.join(res[:2])
|
||||||
|
gitcmt=res[2][1:]
|
||||||
|
return (ver,gitcmt)
|
||||||
|
|
||||||
def sigint_handler(*args):
|
def sigint_handler(*args):
|
||||||
"""Handler for the SIGINT signal."""
|
"""Handler for the SIGINT signal."""
|
||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
@@ -177,7 +130,6 @@ def sigint_handler(*args):
|
|||||||
class AcquisitionAbortedException(Exception):
|
class AcquisitionAbortedException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Sequencer(QObject):
|
class Sequencer(QObject):
|
||||||
finished = pyqtSignal()
|
finished = pyqtSignal()
|
||||||
timeoutExpired = pyqtSignal()
|
timeoutExpired = pyqtSignal()
|
||||||
@@ -260,13 +212,6 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
QtGui.QFontDatabase.addApplicationFont("fonts/Inconsolata-Bold.ttf")
|
QtGui.QFontDatabase.addApplicationFont("fonts/Inconsolata-Bold.ttf")
|
||||||
QtGui.QFontDatabase.addApplicationFont("fonts/Baloo-Regular.ttf")
|
QtGui.QFontDatabase.addApplicationFont("fonts/Baloo-Regular.ttf")
|
||||||
|
|
||||||
# TODO: Cleanup many member functions that are unused or obsolete
|
|
||||||
self._pv_shutter = None # epics.PV('X06SA-ES-MD2:SHUTTER')
|
|
||||||
self._has_pulse_picker = False
|
|
||||||
self._at_x06sa = False
|
|
||||||
self._at_cristalina = True
|
|
||||||
self._at_lab_eh060 = False
|
|
||||||
|
|
||||||
self.init_settings()
|
self.init_settings()
|
||||||
|
|
||||||
# self.create_escape_toolbar()
|
# self.create_escape_toolbar()
|
||||||
@@ -333,13 +278,13 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
self.init_actions()
|
self.init_actions()
|
||||||
#self.prepare_microscope_page()
|
#self.prepare_microscope_page()
|
||||||
self.prepare_left_tabs()
|
self.prepare_wd_tabs_left()
|
||||||
#self.update_beam_marker(qoptic_zoom.get_sp()) #ZAC: orig. code
|
#self.update_beam_marker(qoptic_zoom.get_sp()) #ZAC: orig. code
|
||||||
self._centerpiece_stack.setCurrentIndex(0)
|
self._wd_stack.setCurrentIndex(0)
|
||||||
self._centerpiece_stack.currentChanged.connect(self.cb_update_center_widget)
|
self._wd_stack.currentChanged.connect(self.cb_update_center_widget)
|
||||||
self._OLD_init_validators()
|
#self._OLD_init_validators()
|
||||||
#self.init_settings_tracker() ? not needed, was for TELL ?
|
#self.init_settings_tracker() ? not needed, was for TELL ?
|
||||||
self._OLD_wire_storage()
|
#self._OLD_wire_storage()
|
||||||
|
|
||||||
self.cb_update_center_widget(0) # start camera updater
|
self.cb_update_center_widget(0) # start camera updater
|
||||||
curzoom = app._zoom.get_val()
|
curzoom = app._zoom.get_val()
|
||||||
@@ -364,7 +309,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
sz = [int(s) for s in cfg.value(cfg.WINDOW_SPLITTER)]
|
sz = [int(s) for s in cfg.value(cfg.WINDOW_SPLITTER)]
|
||||||
else:
|
else:
|
||||||
sz=(500, 1200)
|
sz=(500, 1200)
|
||||||
self._main_splitter.setSizes(sz)
|
self._wd_splitter.setSizes(sz)
|
||||||
|
|
||||||
#if AppCfg.BEAM_MARKER_POSITIONS in keys:
|
#if AppCfg.BEAM_MARKER_POSITIONS in keys:
|
||||||
# self._beam_markers = s.value(AppCfg.BEAM_MARKER_POSITIONS)
|
# self._beam_markers = s.value(AppCfg.BEAM_MARKER_POSITIONS)
|
||||||
@@ -523,11 +468,11 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
self.toolBar.addAction(action)
|
self.toolBar.addAction(action)
|
||||||
|
|
||||||
# icon = qtawesome.icon("material.shutter_speed")
|
# icon = qtawesome.icon("material.shutter_speed")
|
||||||
action = QAction("Use Pulse Picker", self)
|
#action = QAction("Use Pulse Picker", self)
|
||||||
action.setCheckable(True)
|
#action.setCheckable(True)
|
||||||
action.setChecked(cfg.option(AppCfg.ACTIVATE_PULSE_PICKER))
|
#action.setChecked(cfg.option(AppCfg.ACTIVATE_PULSE_PICKER))
|
||||||
action.triggered.connect(lambda: cfg.toggle_option(AppCfg.ACTIVATE_PULSE_PICKER))
|
#action.triggered.connect(lambda: cfg.toggle_option(AppCfg.ACTIVATE_PULSE_PICKER))
|
||||||
self.toolBar.addAction(action)
|
#self.toolBar.addAction(action)
|
||||||
|
|
||||||
icon = qtawesome.icon("material.timeline")
|
icon = qtawesome.icon("material.timeline")
|
||||||
action = QAction(icon, "Add Line", self)
|
action = QAction(icon, "Add Line", self)
|
||||||
@@ -575,9 +520,9 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
self.toolBar.widgetForAction(action).setAccessibleName("action_DataCollection")
|
self.toolBar.widgetForAction(action).setAccessibleName("action_DataCollection")
|
||||||
|
|
||||||
self.actionQuit.triggered.connect(self.cb_really_quit)
|
self.actionQuit.triggered.connect(self.cb_really_quit)
|
||||||
self.actionPreferences.triggered.connect(self._OLD_openPreferencesDialog)
|
self.actionPreferences.triggered.connect(self.cb_modify_app_param)
|
||||||
self.actionHome_Fast_Stages.triggered.connect(self.cb_deltatau_home_faststages)
|
self.actionHome_Fast_Stages.triggered.connect(self.cb_deltatau_home_faststages)
|
||||||
self.actionUser_Storage.triggered.connect(self._OLD_update_user_and_storage)
|
self.actionAbout.triggered.connect(self.cb_about)
|
||||||
|
|
||||||
self.shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_L), self)
|
self.shortcut = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_L), self)
|
||||||
self.shortcut.activated.connect(self._OLD_roi_add_line)
|
self.shortcut.activated.connect(self._OLD_roi_add_line)
|
||||||
@@ -601,6 +546,12 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
self.shortcut.activated.connect(self._OLD_camera_pause_toggle)
|
self.shortcut.activated.connect(self._OLD_camera_pause_toggle)
|
||||||
|
|
||||||
# adding a menu entry to one of the menus
|
# adding a menu entry to one of the menus
|
||||||
|
#action = QAction("parameters", self)
|
||||||
|
#action.setToolTip("modify application parameters")
|
||||||
|
#action.setStatusTip("modify application parameters")
|
||||||
|
#action.triggered.connect(self.cb_modify_app_param)
|
||||||
|
#self.menuAdvanced.addAction(action)
|
||||||
|
|
||||||
#action = QAction("geometry", self)
|
#action = QAction("geometry", self)
|
||||||
#action.setToolTip("Update optical center, beam marker size etc.")
|
#action.setToolTip("Update optical center, beam marker size etc.")
|
||||||
#action.setStatusTip("Update optical center, beam marker size etc.")
|
#action.setStatusTip("Update optical center, beam marker size etc.")
|
||||||
@@ -631,14 +582,6 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
#action.triggered.connect(cfg.dlg_deltatau_parameters)
|
#action.triggered.connect(cfg.dlg_deltatau_parameters)
|
||||||
#self.menuAdvanced.addAction(action)
|
#self.menuAdvanced.addAction(action)
|
||||||
|
|
||||||
action = QAction("parameters", self)
|
|
||||||
action.setToolTip("modify application parameters")
|
|
||||||
action.setStatusTip("modify application parameters")
|
|
||||||
|
|
||||||
action.triggered.connect(self.cb_modify_app_param)
|
|
||||||
|
|
||||||
self.menuAdvanced.addAction(action)
|
|
||||||
|
|
||||||
#action = QAction("Cryojet Reference Positions", self)
|
#action = QAction("Cryojet Reference Positions", self)
|
||||||
#action.setToolTip("Update the reference positions for the cryojet nozzle position")
|
#action.setToolTip("Update the reference positions for the cryojet nozzle position")
|
||||||
#action.setStatusTip("Update the reference positions for the cryojet nozzle position")
|
#action.setStatusTip("Update the reference positions for the cryojet nozzle position")
|
||||||
@@ -665,7 +608,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
_log.info('disconnect PV callback')
|
_log.info('disconnect PV callback')
|
||||||
cfg.setValue(cfg.WINDOW_GEOMETRY, self.saveGeometry())
|
cfg.setValue(cfg.WINDOW_GEOMETRY, self.saveGeometry())
|
||||||
cfg.setValue(cfg.WINDOW_STATE, self.saveState())
|
cfg.setValue(cfg.WINDOW_STATE, self.saveState())
|
||||||
cfg.setValue(cfg.WINDOW_SPLITTER, self._main_splitter.sizes())
|
cfg.setValue(cfg.WINDOW_SPLITTER, self._wd_splitter.sizes())
|
||||||
cfg.setValue('last_active', time.time())
|
cfg.setValue('last_active', time.time())
|
||||||
_log.info('save settings')
|
_log.info('save settings')
|
||||||
#QMainWindow.closeEvent(self, event)
|
#QMainWindow.closeEvent(self, event)
|
||||||
@@ -755,19 +698,13 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
self.setStyleSheet(sheet.read())
|
self.setStyleSheet(sheet.read())
|
||||||
|
|
||||||
def setup_sliders(self):
|
def setup_sliders(self):
|
||||||
cont = self._rightmost
|
cont = self._wd_right
|
||||||
self._tweak_container = QWidget()
|
self._tweak_container = QWidget()
|
||||||
self._tweak_container.setLayout(QVBoxLayout())
|
self._tweak_container.setLayout(QVBoxLayout())
|
||||||
cont.layout().addWidget(self._tweak_container)
|
cont.layout().addWidget(self._tweak_container)
|
||||||
layout = self._tweak_container.layout()
|
layout = self._tweak_container.layout()
|
||||||
layout.setSpacing(0)
|
layout.setSpacing(0)
|
||||||
layout.setContentsMargins(0, 0, 0, 0)
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
if self._at_x06sa:
|
|
||||||
zoom_base = "ESBMX-SAMCAM" # fetura IOC by Jose Gabadinho
|
|
||||||
elif self._at_lab_eh060:
|
|
||||||
zoom_base = "/dev/ttyUSB0" # direct connection using fetura.py package
|
|
||||||
elif self._at_cristalina:
|
|
||||||
zoom_base = ("rest://pc12818.psi.ch:9999") # direct connection using fetura.py package
|
|
||||||
|
|
||||||
self.zoombox = zoom.Zoom()
|
self.zoombox = zoom.Zoom()
|
||||||
self.zoombox.init_settings()
|
self.zoombox.init_settings()
|
||||||
@@ -1506,46 +1443,44 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
def cb_esc_sample_exchange(self):
|
def cb_esc_sample_exchange(self):
|
||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
self._esc_state ="busy"
|
|
||||||
steps = []
|
steps = []
|
||||||
#if option(CRYOJET_MOTION_ENABLED):
|
#if option(CRYOJET_MOTION_ENABLED):
|
||||||
# steps.append(lambda: self.move_cryojet_nozzle("out"))
|
# steps.append(lambda: self.move_cryojet_nozzle("out"))
|
||||||
steps.extend(
|
steps=[
|
||||||
[
|
lambda:self.move_detector("out"),
|
||||||
lambda: self.move_post_tube("out"),
|
lambda: self.move_post_tube("out"),
|
||||||
lambda: app._backlight.move("out", wait=True),
|
lambda: app._backlight.move("out"),
|
||||||
lambda: self.move_collimator("out"),
|
lambda: self.move_collimator("out"),
|
||||||
]
|
]
|
||||||
)
|
self.esc_run_steps(steps, "Transitioning to Sample Exchange","ManualSampleExchange")
|
||||||
self.esc_run_steps(steps, "Transitioning to Sample Exchange")
|
|
||||||
self._esc_state ="ManualSampleExchange"
|
|
||||||
|
|
||||||
def cb_esc_sample_alignment(self):
|
def cb_esc_sample_alignment(self):
|
||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
self._esc_state ="busy"
|
|
||||||
steps = [
|
steps = [
|
||||||
# lambda: sample_selection.tell.set_current(30.0),
|
# lambda: sample_selection.tell.set_current(30.0),
|
||||||
lambda: self.move_collimator("ready")
|
lambda: self.move_collimator("ready"),
|
||||||
|
lambda:self.move_detector("out"),
|
||||||
|
lambda:self.move_post_tube("out"),
|
||||||
|
lambda:app._backlight.move("in"),
|
||||||
|
lambda:self.move_collimator("out"),
|
||||||
]
|
]
|
||||||
#if option(CRYOJET_MOTION_ENABLED):
|
#if option(CRYOJET_MOTION_ENABLED):
|
||||||
# steps.extend([lambda: self.move_cryojet_nozzle("in")])
|
# steps.extend([lambda: self.move_cryojet_nozzle("in")])
|
||||||
steps.extend([lambda: self.move_post_tube("out"), lambda: app._backlight.move("in")])
|
#steps.extend([lambda: self.move_post_tube("out"), lambda: app._backlight.move("in")])
|
||||||
self.esc_run_steps(steps, "Transitioning to Sample Alignment")
|
self.esc_run_steps(steps, "Transitioning to Sample Alignment","SampleAlignment")
|
||||||
self._esc_state ="SampleAlignment"
|
|
||||||
|
|
||||||
def cb_esc_data_collection(self):
|
def cb_esc_data_collection(self):
|
||||||
app=QApplication.instance()
|
app=QApplication.instance()
|
||||||
self._esc_state ="busy"
|
|
||||||
steps = [
|
steps = [
|
||||||
# lambda: sample_selection.tell.set_current(30.0),
|
# lambda: sample_selection.tell.set_current(30.0),
|
||||||
lambda: app._backlight.move("out"),
|
lambda: app._backlight.move("out"),
|
||||||
lambda: self.move_post_tube("in"),
|
lambda: self.move_post_tube("in"),
|
||||||
lambda: self.move_collimator("in"),
|
lambda: self.move_collimator("in"),
|
||||||
|
lambda:self.move_detector("in"),
|
||||||
]
|
]
|
||||||
#if option(CRYOJET_MOTION_ENABLED):
|
#if option(CRYOJET_MOTION_ENABLED):
|
||||||
# steps.extend([lambda: self.move_cryojet_nozzle("in")])
|
# steps.extend([lambda: self.move_cryojet_nozzle("in")])
|
||||||
self.esc_run_steps(steps, "Transitioning to Data Collection")
|
self.esc_run_steps(steps, "Transitioning to Data Collection","DataCollection")
|
||||||
self._esc_state ="DataCollection"
|
|
||||||
|
|
||||||
def cb_really_quit(self):
|
def cb_really_quit(self):
|
||||||
"""called when user Ctrl-Q the app"""
|
"""called when user Ctrl-Q the app"""
|
||||||
@@ -1555,9 +1490,43 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
def cb_deltatau_home_faststages(self):
|
def cb_deltatau_home_faststages(self):
|
||||||
pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0]
|
pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0]
|
||||||
_log.warning("homing fast stages")
|
_log.info("homing fast stages")
|
||||||
epics.PV(f"{pfx}1:ASYN.AOUT").put(b"enable plc 1")
|
epics.PV(f"{pfx}1:ASYN.AOUT").put(b"enable plc 1")
|
||||||
|
|
||||||
|
def cb_about(self):
|
||||||
|
try:
|
||||||
|
ver,gitcmt=get_version()
|
||||||
|
v_SMX=f'{ver} git:{gitcmt}'
|
||||||
|
except:
|
||||||
|
v_SMX='git version failed'
|
||||||
|
try:
|
||||||
|
ver,gitcmt=get_version('..')
|
||||||
|
v_SMXT=f'{ver} git:{gitcmt}'
|
||||||
|
except:
|
||||||
|
v_SMXT='git version failed'
|
||||||
|
|
||||||
|
txt=f'''About Swissmx:
|
||||||
|
|
||||||
|
SwissMX: {v_SMX}
|
||||||
|
SwissMXTools: {v_SMXT}
|
||||||
|
|
||||||
|
qt:{QT_VERSION_STR}
|
||||||
|
pyqtgraph:{pg.__version__}
|
||||||
|
numpy:{np.__version__}
|
||||||
|
matplotlib:{mpl.__version__}
|
||||||
|
epics:{epics.__version__}
|
||||||
|
|
||||||
|
Copyright (c) 2022 by Paul Scherrer Institute
|
||||||
|
(http://www.psi.ch)
|
||||||
|
|
||||||
|
Based on Zac great first implementation
|
||||||
|
Author Thierry Zamofing (thierry.zamofing@psi.ch)
|
||||||
|
'''
|
||||||
|
|
||||||
|
QMessageBox.about(self, "SwissMX", txt)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def cb_testcode(self):
|
def cb_testcode(self):
|
||||||
try:
|
try:
|
||||||
tc=self._testCode
|
tc=self._testCode
|
||||||
@@ -1602,8 +1571,8 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
#print(vb.childGroup.childItems())
|
#print(vb.childGroup.childItems())
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def prepare_left_tabs(self):
|
def prepare_wd_tabs_left(self):
|
||||||
tabs = self._left_tabs
|
tabs = self._wd_tabs_left
|
||||||
tabs.currentChanged.connect(self.cb_switch_task)
|
tabs.currentChanged.connect(self.cb_switch_task)
|
||||||
|
|
||||||
setup_tab = self._tab_setup
|
setup_tab = self._tab_setup
|
||||||
@@ -1832,8 +1801,8 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
|
|
||||||
def cb_switch_task(self, index=0):
|
def cb_switch_task(self, index=0):
|
||||||
stack = self._centerpiece_stack
|
stack = self._wd_stack
|
||||||
task = self._left_tabs.currentWidget().accessibleName()
|
task = self._wd_tabs_left.currentWidget().accessibleName()
|
||||||
setup_task = self._setup_toolbox.currentWidget().accessibleName()
|
setup_task = self._setup_toolbox.currentWidget().accessibleName()
|
||||||
method = self._tabs_daq_methods.currentWidget().accessibleName()
|
method = self._tabs_daq_methods.currentWidget().accessibleName()
|
||||||
|
|
||||||
@@ -1992,7 +1961,6 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
dt_misc = cfg.value(AppCfg.DT_MISC)
|
dt_misc = cfg.value(AppCfg.DT_MISC)
|
||||||
|
|
||||||
geo = app._geometry
|
geo = app._geometry
|
||||||
verbose=0xff
|
|
||||||
fn='/tmp/shapepath'
|
fn='/tmp/shapepath'
|
||||||
try:
|
try:
|
||||||
dt=app._deltatau
|
dt=app._deltatau
|
||||||
@@ -2006,12 +1974,9 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
sp=dt._shapepath
|
sp=dt._shapepath
|
||||||
sp.verbose=dt_misc['verbose']
|
sp.verbose=dt_misc['verbose']
|
||||||
sp.points=kwargs['points']
|
sp.points=kwargs['points']
|
||||||
#sp.gen_grid_points(w=15, h=15, pitch=3, rnd=0, ofs=(0, +2000))
|
|
||||||
#sp.gen_grid_points(w=5, h=10, pitch=1, rnd=0, ofs=(0, 0));sp.sort_points(False, 10);sp.points
|
|
||||||
#sp.sort_points(False, 15);
|
|
||||||
sp.meta['pt2pt_time']=dt_misc['pt2pt_time']
|
sp.meta['pt2pt_time']=dt_misc['pt2pt_time']
|
||||||
sp.setup_gather()
|
sp.setup_gather()
|
||||||
sp.setup_sync(verbose=verbose&32, timeOfs=0.05)
|
sp.setup_sync(verbose=sp.verbose&0x20, timeOfs=0.05)
|
||||||
try:
|
try:
|
||||||
p=geo._fitPlane
|
p=geo._fitPlane
|
||||||
sp.setup_coord_trf(cz=f'{p[0]:+.18g}X{p[1]:+.18g}Y{p[2]:+.18g}') # reset to shape path system
|
sp.setup_coord_trf(cz=f'{p[0]:+.18g}X{p[1]:+.18g}Y{p[2]:+.18g}') # reset to shape path system
|
||||||
@@ -2037,7 +2002,8 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
plt.show(block=False)
|
plt.show(block=False)
|
||||||
#plt.show(block=True)
|
#plt.show(block=True)
|
||||||
|
|
||||||
def esc_run_steps(self, steps, title):
|
def esc_run_steps(self, steps, title, esc_state):
|
||||||
|
self._esc_state ="busy"
|
||||||
with pg.ProgressDialog(title, 0, len(steps)) as dlg:
|
with pg.ProgressDialog(title, 0, len(steps)) as dlg:
|
||||||
for step in steps:
|
for step in steps:
|
||||||
step()
|
step()
|
||||||
@@ -2045,8 +2011,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
if dlg.wasCanceled():
|
if dlg.wasCanceled():
|
||||||
QMessageBox.warning(self, "escape steps", "ABORTED" + title)
|
QMessageBox.warning(self, "escape steps", "ABORTED" + title)
|
||||||
break
|
break
|
||||||
|
self._esc_state = esc_state
|
||||||
#backlight="{'pos_in': -10.0, 'pos_out': 0.0}"
|
|
||||||
|
|
||||||
def move_post_tube(self, pos):
|
def move_post_tube(self, pos):
|
||||||
# post_sample_tube="{'x_up': -0.2, 'y_up': 0.0, 'x_down': 0.0, 'y_down': 0.0, 'x_out_delta': 0.0, 'y_out_delta': 0.0, 'z_in': 0.0, 'z_out': 0.0}"
|
# post_sample_tube="{'x_up': -0.2, 'y_up': 0.0, 'x_down': 0.0, 'y_down': 0.0, 'x_out_delta': 0.0, 'y_out_delta': 0.0, 'z_in': 0.0, 'z_out': 0.0}"
|
||||||
@@ -3554,7 +3519,7 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
self.re_connect_collect_button()
|
self.re_connect_collect_button()
|
||||||
|
|
||||||
def _OLD_create_escape_toolbar(self):
|
def _OLD_create_escape_toolbar(self):
|
||||||
cont = self._rightmost
|
cont = self._wd_right
|
||||||
w = QGroupBox("Escape")
|
w = QGroupBox("Escape")
|
||||||
layout = QHBoxLayout()
|
layout = QHBoxLayout()
|
||||||
w.setLayout(layout)
|
w.setLayout(layout)
|
||||||
@@ -3725,7 +3690,6 @@ class WndSwissMx(QMainWindow, Ui_MainWindow):
|
|||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
def main():
|
def main():
|
||||||
from PyQt5.QtCore import QT_VERSION_STR
|
|
||||||
#_log.info(f'Version: pyqtgraph:{pg.__version__} matplotlib:{mpl.__version__} numpy:{np.__version__} epics:{epics.__version__} qt:{QT_VERSION_STR}' )
|
#_log.info(f'Version: pyqtgraph:{pg.__version__} matplotlib:{mpl.__version__} numpy:{np.__version__} epics:{epics.__version__} qt:{QT_VERSION_STR}' )
|
||||||
_log.info(f'Version: pyqtgraph:{pg.__version__} epics:{epics.__version__} qt:{QT_VERSION_STR}' )
|
_log.info(f'Version: pyqtgraph:{pg.__version__} epics:{epics.__version__} qt:{QT_VERSION_STR}' )
|
||||||
import argparse, socket
|
import argparse, socket
|
||||||
|
|||||||
215
swissmx.ui
215
swissmx.ui
@@ -16,7 +16,7 @@
|
|||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="_wd_hlayout">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSplitter" name="_main_splitter">
|
<widget class="QSplitter" name="_wd_splitter">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
<property name="childrenCollapsible">
|
<property name="childrenCollapsible">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QTabWidget" name="_left_tabs">
|
<widget class="QTabWidget" name="_wd_tabs_left">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
@@ -107,81 +107,13 @@
|
|||||||
<string>Data Storage</string>
|
<string>Data Storage</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_5">
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
<item row="2" column="0">
|
<item row="0" column="1">
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Prefix</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Folder</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QLabel" name="_label_folder">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Folder where the data will be stored; triple-click to select.</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Folder where the data will be stored; triple-click to select. Type 'folder' in a console to go here.</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>TextLabel</string>
|
|
||||||
</property>
|
|
||||||
<property name="textFormat">
|
|
||||||
<enum>Qt::PlainText</enum>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="textInteractionFlags">
|
|
||||||
<set>Qt::TextSelectableByMouse</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Project</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLineEdit" name="_le_project"/>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QLineEdit" name="_le_prefix"/>
|
<widget class="QLineEdit" name="_le_prefix"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="1" column="1">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLineEdit" name="_le_runnumber"/>
|
||||||
<property name="text">
|
|
||||||
<string>Filenames</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Run</string>
|
<string>Run</string>
|
||||||
@@ -191,46 +123,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
|
||||||
<widget class="QLineEdit" name="_label_actual_prefix">
|
|
||||||
<property name="frame">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QLineEdit" name="_label_runnumber">
|
|
||||||
<property name="frame">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_14">
|
<widget class="QLabel" name="label_3">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>P-group</string>
|
<string>Prefix</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="_label_pgroup">
|
|
||||||
<property name="accessibleName">
|
|
||||||
<string>pgroup</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>p-group-undefined</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -239,89 +141,7 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Experimental Parameters</string>
|
<string>Experimental Parameters</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<layout class="QGridLayout" name="gridLayout_4"/>
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QDoubleSpinBox" name="_dsb_exposure_time">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="suffix">
|
|
||||||
<string> s</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>3</number>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>0.010000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>1000.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.100000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<double>0.100000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>Oscillation Step</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string>Exposure Time</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="label_12">
|
|
||||||
<property name="text">
|
|
||||||
<string>Blast radius</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="2">
|
|
||||||
<widget class="QDoubleSpinBox" name="_dsb_blast_radius">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> µm</string>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>200.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QDoubleSpinBox" name="_dsb_oscillation_step">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="suffix">
|
|
||||||
<string> deg</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@@ -614,16 +434,16 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStackedWidget" name="_centerpiece_stack">
|
<widget class="QStackedWidget" name="_wd_stack">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>1</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="microscope_page"/>
|
<widget class="QWidget" name="microscope_page"/>
|
||||||
<widget class="QWidget" name="sample_select">
|
<widget class="QWidget" name="sample_select">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout"/>
|
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="_rightmost" native="true">
|
<widget class="QWidget" name="_wd_right" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@@ -664,7 +484,6 @@
|
|||||||
<string>&Advanced</string>
|
<string>&Advanced</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="actionHome_Fast_Stages"/>
|
<addaction name="actionHome_Fast_Stages"/>
|
||||||
<addaction name="actionUser_Storage"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuSetup">
|
<widget class="QMenu" name="menuSetup">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -718,16 +537,12 @@
|
|||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>_le_project</tabstop>
|
|
||||||
<tabstop>_le_prefix</tabstop>
|
<tabstop>_le_prefix</tabstop>
|
||||||
<tabstop>_dsb_exposure_time</tabstop>
|
|
||||||
<tabstop>_dsb_oscillation_step</tabstop>
|
|
||||||
<tabstop>_tabs_daq_methods</tabstop>
|
<tabstop>_tabs_daq_methods</tabstop>
|
||||||
<tabstop>_sb_grid_y_step</tabstop>
|
<tabstop>_sb_grid_y_step</tabstop>
|
||||||
<tabstop>_left_tabs</tabstop>
|
<tabstop>_wd_tabs_left</tabstop>
|
||||||
<tabstop>_label_actual_prefix</tabstop>
|
|
||||||
<tabstop>_grid_inspect_area</tabstop>
|
<tabstop>_grid_inspect_area</tabstop>
|
||||||
<tabstop>_label_runnumber</tabstop>
|
<tabstop>_le_runnumber</tabstop>
|
||||||
<tabstop>_bt_add_grid</tabstop>
|
<tabstop>_bt_add_grid</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
Reference in New Issue
Block a user