diff --git a/hexrdgui/calibration/cartesian_plot.py b/hexrdgui/calibration/cartesian_plot.py index 1b329e5d8..45548722d 100644 --- a/hexrdgui/calibration/cartesian_plot.py +++ b/hexrdgui/calibration/cartesian_plot.py @@ -22,6 +22,8 @@ def cartesian_viewer(): return InstrumentViewer() +def get_xray_propagation_sign(instr): + return np.sign(instr.beam_vector[2]) class InstrumentViewer: @@ -29,6 +31,10 @@ def __init__(self): self.type = ViewType.cartesian self.instr = create_hedm_instrument() self.images_dict = HexrdConfig().images_dict + + # Set invalid pixels to be nan + HexrdConfig().apply_panel_buffer_to_images(self.images_dict) + self.img = None # Perform some checks before proceeding @@ -40,7 +46,8 @@ def __init__(self): self.detector_corners = {} dist = HexrdConfig().cartesian_virtual_plane_distance - dplane_tvec = np.array([0., 0., -dist]) + sgn = get_xray_propagation_sign(self.instr) + dplane_tvec = np.array([0., 0., sgn*dist]) rotate_x = HexrdConfig().cartesian_plane_normal_rotate_x rotate_y = HexrdConfig().cartesian_plane_normal_rotate_y @@ -280,8 +287,15 @@ def create_warped_image(self, detector_id): res = tf.warp(img, tform3, output_shape=(self.dpanel.rows, self.dpanel.cols), - preserve_range=True) - self.warp_dict[detector_id] = res + preserve_range=True, cval=np.nan) + nan_mask = np.isnan(res) + + self.warp_dict[detector_id] = np.ma.masked_array( + res, + mask=nan_mask, + fill_value=0, + ) + return res @property @@ -290,8 +304,15 @@ def display_img(self): def generate_image(self): img = np.zeros((self.dpanel.rows, self.dpanel.cols)) + always_nan = np.ones(img.shape, dtype=bool) for key in self.images_dict.keys(): - img += self.warp_dict[key] + # Use zeros when summing, but identify pixels that + # are nans in all images and set those to nan. + warp_img = self.warp_dict[key] + img += warp_img.filled(0) + always_nan = np.logical_and(always_nan, warp_img.mask) + + img[always_nan] = np.nan # In case there were any nans... nan_mask = np.isnan(img) diff --git a/hexrdgui/hexrd_config.py b/hexrdgui/hexrd_config.py index 8f8afe5b4..2ba5c2b5f 100644 --- a/hexrdgui/hexrd_config.py +++ b/hexrdgui/hexrd_config.py @@ -535,6 +535,12 @@ def load_from_state(self, state): pinhole_settings.pop('pinhole_radius') * 2 ) + if self.cartesian_virtual_plane_distance < 0: + # We used to allow this to be negative, but now must be positive. + # Taking the absolute value should correct this adequately. + self.cartesian_virtual_plane_distance = abs( + self.cartesian_virtual_plane_distance) + # All QSettings come back as strings. So check that we are dealing with # a boolean and convert if necessary if not isinstance(self.live_update, bool): @@ -2511,7 +2517,8 @@ def _cartesian_pixel_size(self): def _set_cartesian_pixel_size(self, v): if v != self.cartesian_pixel_size: self.config['image']['cartesian']['pixel_size'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_pixel_size = property(_cartesian_pixel_size, _set_cartesian_pixel_size) @@ -2520,9 +2527,13 @@ def _cartesian_virtual_plane_distance(self): return self.config['image']['cartesian']['virtual_plane_distance'] def set_cartesian_virtual_plane_distance(self, v): + if v < 0: + raise RuntimeError(f'Invalid plane distance: {v}') + if v != self.cartesian_virtual_plane_distance: self.config['image']['cartesian']['virtual_plane_distance'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_virtual_plane_distance = property( _cartesian_virtual_plane_distance, @@ -2534,7 +2545,8 @@ def _cartesian_plane_normal_rotate_x(self): def set_cartesian_plane_normal_rotate_x(self, v): if v != self.cartesian_plane_normal_rotate_x: self.config['image']['cartesian']['plane_normal_rotate_x'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_plane_normal_rotate_x = property( _cartesian_plane_normal_rotate_x, @@ -2546,7 +2558,8 @@ def _cartesian_plane_normal_rotate_y(self): def set_cartesian_plane_normal_rotate_y(self, v): if v != self.cartesian_plane_normal_rotate_y: self.config['image']['cartesian']['plane_normal_rotate_y'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_plane_normal_rotate_y = property( _cartesian_plane_normal_rotate_y, diff --git a/hexrdgui/image_mode_widget.py b/hexrdgui/image_mode_widget.py index 6fa540285..cf1f833c3 100644 --- a/hexrdgui/image_mode_widget.py +++ b/hexrdgui/image_mode_widget.py @@ -40,6 +40,9 @@ def __init__(self, parent=None): # Always start with raw tab self.ui.tab_widget.setCurrentIndex(0) + # Don't allow negative distances + self.ui.cartesian_virtual_plane_distance.setMinimum(1e-8) + # Hide stereo_project_from_polar for now, as projecting from polar # appears to give a better image (lines up better with overlays) # than projecting from raw. diff --git a/hexrdgui/resources/ui/image_mode_widget.ui b/hexrdgui/resources/ui/image_mode_widget.ui index fa96859e7..051cb5f0f 100644 --- a/hexrdgui/resources/ui/image_mode_widget.ui +++ b/hexrdgui/resources/ui/image_mode_widget.ui @@ -38,7 +38,7 @@ QTabWidget::Rounded - 2 + 1 @@ -167,6 +167,9 @@ 8 + + 0.000000000000000 + 1000000.000000000000000